--- a/.hgtags Tue Dec 23 12:40:06 2014 -0800
+++ b/.hgtags Thu Dec 25 19:46:17 2014 -0800
@@ -285,3 +285,4 @@
82f4cb44b2d7af2352f48568a64b7b6a5ae960cd jdk9-b40
9fffb959eb4197ff806e4ac12244761815b4deee jdk9-b41
3107be2ba9c6e208a0b86bc7100a141abbc5b5fb jdk9-b42
+6494b13f88a867026ee316b444d9a4fa589dd6bd jdk9-b43
--- a/.hgtags-top-repo Tue Dec 23 12:40:06 2014 -0800
+++ b/.hgtags-top-repo Thu Dec 25 19:46:17 2014 -0800
@@ -285,3 +285,4 @@
cf136458ee747e151a27aa9ea0c1492ea55ef3e7 jdk9-b40
67395f7ca2db3b52e3a62a84888487de5cb9210a jdk9-b41
f7c11da0b0481d49cc7a65a453336c108191e821 jdk9-b42
+02ee8c65622e8bd97496d584e22fc7dcf0edc4ae jdk9-b43
--- a/common/autoconf/generated-configure.sh Tue Dec 23 12:40:06 2014 -0800
+++ b/common/autoconf/generated-configure.sh Thu Dec 25 19:46:17 2014 -0800
@@ -4329,7 +4329,7 @@
#CUSTOM_AUTOCONF_INCLUDE
# Do not change or remove the following line, it is needed for consistency checks:
-DATE_WHEN_GENERATED=1418036274
+DATE_WHEN_GENERATED=1418395009
###############################################################################
#
@@ -13965,7 +13965,8 @@
# ZERO_ARCHDEF is used to enable architecture-specific code
case "${OPENJDK_TARGET_CPU}" in
- ppc*) ZERO_ARCHDEF=PPC ;;
+ ppc) ZERO_ARCHDEF=PPC32 ;;
+ ppc64) ZERO_ARCHDEF=PPC64 ;;
s390*) ZERO_ARCHDEF=S390 ;;
sparc*) ZERO_ARCHDEF=SPARC ;;
x86_64*) ZERO_ARCHDEF=AMD64 ;;
--- a/common/autoconf/platform.m4 Tue Dec 23 12:40:06 2014 -0800
+++ b/common/autoconf/platform.m4 Thu Dec 25 19:46:17 2014 -0800
@@ -367,7 +367,8 @@
# ZERO_ARCHDEF is used to enable architecture-specific code
case "${OPENJDK_TARGET_CPU}" in
- ppc*) ZERO_ARCHDEF=PPC ;;
+ ppc) ZERO_ARCHDEF=PPC32 ;;
+ ppc64) ZERO_ARCHDEF=PPC64 ;;
s390*) ZERO_ARCHDEF=S390 ;;
sparc*) ZERO_ARCHDEF=SPARC ;;
x86_64*) ZERO_ARCHDEF=AMD64 ;;
--- a/common/bin/hgforest.sh Tue Dec 23 12:40:06 2014 -0800
+++ b/common/bin/hgforest.sh Thu Dec 25 19:46:17 2014 -0800
@@ -106,12 +106,15 @@
echo "# Mercurial command: ${command}" > ${status_output}
fi
-
-# capture command options and arguments (if any)
-command_args="${@:-}"
+# At this point all command options and args are in "$@".
+# Always use "$@" (within double quotes) to avoid breaking
+# args with spaces into separate args.
if [ ${vflag} = "true" ] ; then
- echo "# Mercurial command arguments: ${command_args}" > ${status_output}
+ echo "# Mercurial command argument count: $#" > ${status_output}
+ for cmdarg in "$@" ; do
+ echo "# Mercurial command argument: ${cmdarg}" > ${status_output}
+ done
fi
# Clean out the temporary directory that stores the pid files.
@@ -205,13 +208,14 @@
pull_default_tail=`echo ${pull_default} | sed -e 's@^.*://[^/]*/\(.*\)@\1@'`
- if [ -n "${command_args}" ] ; then
+ if [ $# -gt 0 ] ; then
# if there is an "extra sources" path then reparent "extra" repos to that path
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}"
+ # assume that "extra sources" path is the first arg
+ pull_extra="${1}/${pull_default_tail}"
# determine which extra subrepos need to be cloned.
for i in ${subrepos_extra} ; do
@@ -356,8 +360,8 @@
(PYTHONUNBUFFERED=true hg${global_opts} clone ${clone_newrepo} ${i}; echo "$?" > ${tmp}/${repopidfile}.pid.rc ) 2>&1 &
else
# run the command.
- 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 &
+ echo "cd ${i} && hg${global_opts} ${command} ${@}" > ${status_output}
+ cd ${i} && (PYTHONUNBUFFERED=true hg${global_opts} ${command} "${@}"; echo "$?" > ${tmp}/${repopidfile}.pid.rc ) 2>&1 &
fi
echo $! > ${tmp}/${repopidfile}.pid
--- a/corba/.hgtags Tue Dec 23 12:40:06 2014 -0800
+++ b/corba/.hgtags Thu Dec 25 19:46:17 2014 -0800
@@ -285,3 +285,4 @@
e27c725d6c9d155667b35255f442d4ceb8c3c084 jdk9-b40
1908b886ba1eda46fa725cf1160fe5d30fd1a7e5 jdk9-b41
078bb11af876fe528d4b516f33ad4dd9bb60549e jdk9-b42
+9645e35616b60c5c07b4fdf11a132afc8081dfa8 jdk9-b43
--- a/hotspot/.hgtags Tue Dec 23 12:40:06 2014 -0800
+++ b/hotspot/.hgtags Thu Dec 25 19:46:17 2014 -0800
@@ -445,3 +445,4 @@
6b09b3193d731e3288e2a240c504a20d0a06c766 jdk9-b40
1d29b13e8a515a7ea3b882f140576d5d675bc11f jdk9-b41
38cb4fbd47e3472bd1b5ebac83bda96fe4869c4f jdk9-b42
+65a9747147b8090037541040ba67156ec914db6a jdk9-b43
--- a/hotspot/src/cpu/x86/vm/c1_Runtime1_x86.cpp Tue Dec 23 12:40:06 2014 -0800
+++ b/hotspot/src/cpu/x86/vm/c1_Runtime1_x86.cpp Thu Dec 25 19:46:17 2014 -0800
@@ -675,7 +675,7 @@
case handle_exception_nofpu_id:
case handle_exception_id:
// At this point all registers MAY be live.
- oop_map = save_live_registers(sasm, 1 /*thread*/, id == handle_exception_nofpu_id);
+ oop_map = save_live_registers(sasm, 1 /*thread*/, id != handle_exception_nofpu_id);
break;
case handle_exception_from_callee_id: {
// At this point all registers except exception oop (RAX) and
@@ -748,7 +748,7 @@
case handle_exception_nofpu_id:
case handle_exception_id:
// Restore the registers that were saved at the beginning.
- restore_live_registers(sasm, id == handle_exception_nofpu_id);
+ restore_live_registers(sasm, id != handle_exception_nofpu_id);
break;
case handle_exception_from_callee_id:
// WIN64_ONLY: No need to add frame::arg_reg_save_area_bytes to SP
--- a/hotspot/src/os/windows/vm/os_windows.cpp Tue Dec 23 12:40:06 2014 -0800
+++ b/hotspot/src/os/windows/vm/os_windows.cpp Thu Dec 25 19:46:17 2014 -0800
@@ -3074,7 +3074,7 @@
char* os::pd_reserve_memory(size_t bytes, char* addr, size_t alignment_hint) {
assert((size_t)addr % os::vm_allocation_granularity() == 0,
"reserve alignment");
- assert(bytes % os::vm_allocation_granularity() == 0, "reserve block size");
+ assert(bytes % os::vm_page_size() == 0, "reserve page size");
char* res;
// note that if UseLargePages is on, all the areas that require interleaving
// will go thru reserve_memory_special rather than thru here.
--- a/hotspot/src/share/vm/classfile/classFileParser.cpp Tue Dec 23 12:40:06 2014 -0800
+++ b/hotspot/src/share/vm/classfile/classFileParser.cpp Thu Dec 25 19:46:17 2014 -0800
@@ -3108,21 +3108,39 @@
}
}
-// Transfer ownership of metadata allocated to the InstanceKlass.
-void ClassFileParser::apply_parsed_class_metadata(
- instanceKlassHandle this_klass,
- int java_fields_count, TRAPS) {
- // Assign annotations if needed
- if (_annotations != NULL || _type_annotations != NULL ||
- _fields_annotations != NULL || _fields_type_annotations != NULL) {
+// Create the Annotations object that will
+// hold the annotations array for the Klass.
+void ClassFileParser::create_combined_annotations(TRAPS) {
+ if (_annotations == NULL &&
+ _type_annotations == NULL &&
+ _fields_annotations == NULL &&
+ _fields_type_annotations == NULL) {
+ // Don't create the Annotations object unnecessarily.
+ return;
+ }
+
Annotations* annotations = Annotations::allocate(_loader_data, CHECK);
annotations->set_class_annotations(_annotations);
annotations->set_class_type_annotations(_type_annotations);
annotations->set_fields_annotations(_fields_annotations);
annotations->set_fields_type_annotations(_fields_type_annotations);
- this_klass->set_annotations(annotations);
- }
-
+
+ // This is the Annotations object that will be
+ // assigned to InstanceKlass being constructed.
+ _combined_annotations = annotations;
+
+ // The annotations arrays below has been transfered the
+ // _combined_annotations so these fields can now be cleared.
+ _annotations = NULL;
+ _type_annotations = NULL;
+ _fields_annotations = NULL;
+ _fields_type_annotations = NULL;
+}
+
+// Transfer ownership of metadata allocated to the InstanceKlass.
+void ClassFileParser::apply_parsed_class_metadata(
+ instanceKlassHandle this_klass,
+ int java_fields_count, TRAPS) {
_cp->set_pool_holder(this_klass());
this_klass->set_constants(_cp);
this_klass->set_fields(_fields, java_fields_count);
@@ -3130,6 +3148,7 @@
this_klass->set_inner_classes(_inner_classes);
this_klass->set_local_interfaces(_local_interfaces);
this_klass->set_transitive_interfaces(_transitive_interfaces);
+ this_klass->set_annotations(_combined_annotations);
// Clear out these fields so they don't get deallocated by the destructor
clear_class_metadata();
@@ -4002,6 +4021,10 @@
ClassAnnotationCollector parsed_annotations;
parse_classfile_attributes(&parsed_annotations, CHECK_(nullHandle));
+ // Finalize the Annotations metadata object,
+ // now that all annotation arrays have been created.
+ create_combined_annotations(CHECK_(nullHandle));
+
// Make sure this is the end of class file stream
guarantee_property(cfs->at_eos(), "Extra bytes at the end of class file %s", CHECK_(nullHandle));
@@ -4302,10 +4325,27 @@
InstanceKlass::deallocate_interfaces(_loader_data, _super_klass(),
_local_interfaces, _transitive_interfaces);
- MetadataFactory::free_array<u1>(_loader_data, _annotations);
- MetadataFactory::free_array<u1>(_loader_data, _type_annotations);
- Annotations::free_contents(_loader_data, _fields_annotations);
- Annotations::free_contents(_loader_data, _fields_type_annotations);
+ if (_combined_annotations != NULL) {
+ // After all annotations arrays have been created, they are installed into the
+ // Annotations object that will be assigned to the InstanceKlass being created.
+
+ // Deallocate the Annotations object and the installed annotations arrays.
+ _combined_annotations->deallocate_contents(_loader_data);
+
+ // If the _combined_annotations pointer is non-NULL,
+ // then the other annotations fields should have been cleared.
+ assert(_annotations == NULL, "Should have been cleared");
+ assert(_type_annotations == NULL, "Should have been cleared");
+ assert(_fields_annotations == NULL, "Should have been cleared");
+ assert(_fields_type_annotations == NULL, "Should have been cleared");
+ } else {
+ // If the annotations arrays were not installed into the Annotations object,
+ // then they have to be deallocated explicitly.
+ MetadataFactory::free_array<u1>(_loader_data, _annotations);
+ MetadataFactory::free_array<u1>(_loader_data, _type_annotations);
+ Annotations::free_contents(_loader_data, _fields_annotations);
+ Annotations::free_contents(_loader_data, _fields_type_annotations);
+ }
clear_class_metadata();
--- a/hotspot/src/share/vm/classfile/classFileParser.hpp Tue Dec 23 12:40:06 2014 -0800
+++ b/hotspot/src/share/vm/classfile/classFileParser.hpp Thu Dec 25 19:46:17 2014 -0800
@@ -75,6 +75,7 @@
Array<u2>* _inner_classes;
Array<Klass*>* _local_interfaces;
Array<Klass*>* _transitive_interfaces;
+ Annotations* _combined_annotations;
AnnotationArray* _annotations;
AnnotationArray* _type_annotations;
Array<AnnotationArray*>* _fields_annotations;
@@ -86,6 +87,8 @@
void set_class_generic_signature_index(u2 x) { _generic_signature_index = x; }
void set_class_sde_buffer(char* x, int len) { _sde_buffer = x; _sde_length = len; }
+ void create_combined_annotations(TRAPS);
+
void init_parsed_class_attributes(ClassLoaderData* loader_data) {
_loader_data = loader_data;
_synthetic_flag = false;
@@ -110,6 +113,7 @@
_inner_classes = NULL;
_local_interfaces = NULL;
_transitive_interfaces = NULL;
+ _combined_annotations = NULL;
_annotations = _type_annotations = NULL;
_fields_annotations = _fields_type_annotations = NULL;
}
--- a/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/concurrentMarkSweepGeneration.cpp Tue Dec 23 12:40:06 2014 -0800
+++ b/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/concurrentMarkSweepGeneration.cpp Thu Dec 25 19:46:17 2014 -0800
@@ -793,11 +793,6 @@
}
}
-CompactibleSpace*
-ConcurrentMarkSweepGeneration::first_compaction_space() const {
- return _cmsSpace;
-}
-
void ConcurrentMarkSweepGeneration::reset_after_compaction() {
// Clear the promotion information. These pointers can be adjusted
// along with all the other pointers into the heap but
@@ -808,10 +803,6 @@
}
}
-void ConcurrentMarkSweepGeneration::space_iterate(SpaceClosure* blk, bool usedOnly) {
- blk->do_space(_cmsSpace);
-}
-
void ConcurrentMarkSweepGeneration::compute_new_size() {
assert_locked_or_safepoint(Heap_lock);
@@ -882,7 +873,7 @@
expand_bytes);
}
// safe if expansion fails
- expand(expand_bytes, 0, CMSExpansionCause::_satisfy_free_ratio);
+ expand_for_gc_cause(expand_bytes, 0, CMSExpansionCause::_satisfy_free_ratio);
if (PrintGCDetails && Verbose) {
gclog_or_tty->print_cr(" Expanded free fraction %f",
((double) free()) / capacity());
@@ -1048,8 +1039,7 @@
if (res == NULL) {
// expand and retry
size_t s = _cmsSpace->expansionSpaceRequired(obj_size); // HeapWords
- expand(s*HeapWordSize, MinHeapDeltaBytes,
- CMSExpansionCause::_satisfy_promotion);
+ expand_for_gc_cause(s*HeapWordSize, MinHeapDeltaBytes, CMSExpansionCause::_satisfy_promotion);
// Since there's currently no next generation, we don't try to promote
// into a more senior generation.
assert(next_gen() == NULL, "assumption, based upon which no attempt "
@@ -2625,13 +2615,6 @@
ALL_SINCE_SAVE_MARKS_CLOSURES(CMS_SINCE_SAVE_MARKS_DEFN)
void
-ConcurrentMarkSweepGeneration::younger_refs_iterate(OopsInGenClosure* cl) {
- cl->set_generation(this);
- younger_refs_in_space_iterate(_cmsSpace, cl);
- cl->reset_generation();
-}
-
-void
ConcurrentMarkSweepGeneration::oop_iterate(ExtendedOopClosure* cl) {
if (freelistLock()->owned_by_self()) {
Generation::oop_iterate(cl);
@@ -2803,23 +2786,17 @@
CMSSynchronousYieldRequest yr;
assert(!tlab, "Can't deal with TLAB allocation");
MutexLockerEx x(freelistLock(), Mutex::_no_safepoint_check_flag);
- expand(word_size*HeapWordSize, MinHeapDeltaBytes,
- CMSExpansionCause::_satisfy_allocation);
+ expand_for_gc_cause(word_size*HeapWordSize, MinHeapDeltaBytes, CMSExpansionCause::_satisfy_allocation);
if (GCExpandToAllocateDelayMillis > 0) {
os::sleep(Thread::current(), GCExpandToAllocateDelayMillis, false);
}
return have_lock_and_allocate(word_size, tlab);
}
-// YSR: All of this generation expansion/shrinking stuff is an exact copy of
-// TenuredGeneration, which makes me wonder if we should move this
-// to CardGeneration and share it...
-bool ConcurrentMarkSweepGeneration::expand(size_t bytes, size_t expand_bytes) {
- return CardGeneration::expand(bytes, expand_bytes);
-}
-
-void ConcurrentMarkSweepGeneration::expand(size_t bytes, size_t expand_bytes,
- CMSExpansionCause::Cause cause)
+void ConcurrentMarkSweepGeneration::expand_for_gc_cause(
+ size_t bytes,
+ size_t expand_bytes,
+ CMSExpansionCause::Cause cause)
{
bool success = expand(bytes, expand_bytes);
@@ -2848,8 +2825,7 @@
return NULL;
}
// Otherwise, we try expansion.
- expand(word_sz*HeapWordSize, MinHeapDeltaBytes,
- CMSExpansionCause::_allocate_par_lab);
+ expand_for_gc_cause(word_sz*HeapWordSize, MinHeapDeltaBytes, CMSExpansionCause::_allocate_par_lab);
// Now go around the loop and try alloc again;
// A competing par_promote might beat us to the expansion space,
// so we may go around the loop again if promotion fails again.
@@ -2876,8 +2852,7 @@
return false;
}
// Otherwise, we try expansion.
- expand(refill_size_bytes, MinHeapDeltaBytes,
- CMSExpansionCause::_allocate_par_spooling_space);
+ expand_for_gc_cause(refill_size_bytes, MinHeapDeltaBytes, CMSExpansionCause::_allocate_par_spooling_space);
// Now go around the loop and try alloc again;
// A competing allocation might beat us to the expansion space,
// so we may go around the loop again if allocation fails again.
@@ -2887,77 +2862,16 @@
}
}
-
-void ConcurrentMarkSweepGeneration::shrink_by(size_t bytes) {
- assert_locked_or_safepoint(ExpandHeap_lock);
- // Shrink committed space
- _virtual_space.shrink_by(bytes);
- // Shrink space; this also shrinks the space's BOT
- _cmsSpace->set_end((HeapWord*) _virtual_space.high());
- size_t new_word_size = heap_word_size(_cmsSpace->capacity());
- // Shrink the shared block offset array
- _bts->resize(new_word_size);
- MemRegion mr(_cmsSpace->bottom(), new_word_size);
- // Shrink the card table
- Universe::heap()->barrier_set()->resize_covered_region(mr);
-
- if (Verbose && PrintGC) {
- size_t new_mem_size = _virtual_space.committed_size();
- size_t old_mem_size = new_mem_size + bytes;
- gclog_or_tty->print_cr("Shrinking %s from " SIZE_FORMAT "K to " SIZE_FORMAT "K",
- name(), old_mem_size/K, new_mem_size/K);
- }
-}
-
void ConcurrentMarkSweepGeneration::shrink(size_t bytes) {
- assert_locked_or_safepoint(Heap_lock);
- size_t size = ReservedSpace::page_align_size_down(bytes);
// Only shrink if a compaction was done so that all the free space
// in the generation is in a contiguous block at the end.
- if (size > 0 && did_compact()) {
- shrink_by(size);
- }
-}
-
-bool ConcurrentMarkSweepGeneration::grow_by(size_t bytes) {
+ if (did_compact()) {
+ CardGeneration::shrink(bytes);
+ }
+}
+
+void ConcurrentMarkSweepGeneration::assert_correct_size_change_locking() {
assert_locked_or_safepoint(Heap_lock);
- bool result = _virtual_space.expand_by(bytes);
- if (result) {
- size_t new_word_size =
- heap_word_size(_virtual_space.committed_size());
- MemRegion mr(_cmsSpace->bottom(), new_word_size);
- _bts->resize(new_word_size); // resize the block offset shared array
- Universe::heap()->barrier_set()->resize_covered_region(mr);
- // Hmmmm... why doesn't CFLS::set_end verify locking?
- // This is quite ugly; FIX ME XXX
- _cmsSpace->assert_locked(freelistLock());
- _cmsSpace->set_end((HeapWord*)_virtual_space.high());
-
- // update the space and generation capacity counters
- if (UsePerfData) {
- _space_counters->update_capacity();
- _gen_counters->update_all();
- }
-
- if (Verbose && PrintGC) {
- size_t new_mem_size = _virtual_space.committed_size();
- size_t old_mem_size = new_mem_size - bytes;
- gclog_or_tty->print_cr("Expanding %s from " SIZE_FORMAT "K by " SIZE_FORMAT "K to " SIZE_FORMAT "K",
- name(), old_mem_size/K, bytes/K, new_mem_size/K);
- }
- }
- return result;
-}
-
-bool ConcurrentMarkSweepGeneration::grow_to_reserved() {
- assert_locked_or_safepoint(Heap_lock);
- bool success = true;
- const size_t remaining_bytes = _virtual_space.uncommitted_size();
- if (remaining_bytes > 0) {
- success = grow_by(remaining_bytes);
- DEBUG_ONLY(if (!success) warning("grow to reserved failed");)
- }
- return success;
}
void ConcurrentMarkSweepGeneration::shrink_free_list_by(size_t bytes) {
--- a/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/concurrentMarkSweepGeneration.hpp Tue Dec 23 12:40:06 2014 -0800
+++ b/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/concurrentMarkSweepGeneration.hpp Thu Dec 25 19:46:17 2014 -0800
@@ -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
@@ -30,9 +30,10 @@
#include "gc_implementation/shared/gcStats.hpp"
#include "gc_implementation/shared/gcWhen.hpp"
#include "gc_implementation/shared/generationCounters.hpp"
+#include "memory/cardGeneration.hpp"
#include "memory/freeBlockDictionary.hpp"
-#include "memory/generation.hpp"
#include "memory/iterator.hpp"
+#include "memory/space.hpp"
#include "runtime/mutexLocker.hpp"
#include "runtime/virtualspace.hpp"
#include "services/memoryService.hpp"
@@ -171,9 +172,7 @@
// Represents a marking stack used by the CMS collector.
// Ideally this should be GrowableArray<> just like MSC's marking stack(s).
class CMSMarkStack: public CHeapObj<mtGC> {
- //
friend class CMSCollector; // To get at expansion stats further below.
- //
VirtualSpace _virtual_space; // Space for the stack
oop* _base; // Bottom of stack
@@ -1031,6 +1030,9 @@
void set_expansion_cause(CMSExpansionCause::Cause v) { _expansion_cause = v;}
CMSExpansionCause::Cause expansion_cause() const { return _expansion_cause; }
+ // Accessing spaces
+ CompactibleSpace* space() const { return (CompactibleSpace*)_cmsSpace; }
+
private:
// For parallel young-gen GC support.
CMSParGCThreadState** _par_gc_thread_states;
@@ -1064,6 +1066,10 @@
double initiating_occupancy() const { return _initiating_occupancy; }
void init_initiating_occupancy(intx io, uintx tr);
+ void expand_for_gc_cause(size_t bytes, size_t expand_bytes, CMSExpansionCause::Cause cause);
+
+ void assert_correct_size_change_locking();
+
public:
ConcurrentMarkSweepGeneration(ReservedSpace rs, size_t initial_byte_size,
int level, CardTableRS* ct,
@@ -1100,23 +1106,14 @@
// Override
virtual void ref_processor_init();
- // Grow generation by specified size (returns false if unable to grow)
- bool grow_by(size_t bytes);
- // Grow generation to reserved size.
- bool grow_to_reserved();
-
void clear_expansion_cause() { _expansion_cause = CMSExpansionCause::_no_expansion; }
// Space enquiries
- size_t capacity() const;
- size_t used() const;
- size_t free() const;
double occupancy() const { return ((double)used())/((double)capacity()); }
size_t contiguous_available() const;
size_t unsafe_max_alloc_nogc() const;
// over-rides
- MemRegion used_region() const;
MemRegion used_region_at_save_marks() const;
// Does a "full" (forced) collection invoked on this generation collect
@@ -1127,10 +1124,6 @@
return !ScavengeBeforeFullGC;
}
- void space_iterate(SpaceClosure* blk, bool usedOnly = false);
-
- // Support for compaction
- CompactibleSpace* first_compaction_space() const;
// Adjust quantities in the generation affected by
// the compaction.
void reset_after_compaction();
@@ -1190,18 +1183,13 @@
}
// Allocation failure
- void expand(size_t bytes, size_t expand_bytes,
- CMSExpansionCause::Cause cause);
- virtual bool expand(size_t bytes, size_t expand_bytes);
void shrink(size_t bytes);
- void shrink_by(size_t bytes);
HeapWord* expand_and_par_lab_allocate(CMSParGCThreadState* ps, size_t word_sz);
bool expand_and_ensure_spooling_space(PromotionInfo* promo);
// Iteration support and related enquiries
void save_marks();
bool no_allocs_since_save_marks();
- void younger_refs_iterate(OopsInGenClosure* cl);
// Iteration support specific to CMS generations
void save_sweep_limit();
--- a/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/concurrentMarkSweepGeneration.inline.hpp Tue Dec 23 12:40:06 2014 -0800
+++ b/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/concurrentMarkSweepGeneration.inline.hpp Thu Dec 25 19:46:17 2014 -0800
@@ -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
@@ -369,22 +369,6 @@
cmsSpace()->save_sweep_limit();
}
-inline size_t ConcurrentMarkSweepGeneration::capacity() const {
- return _cmsSpace->capacity();
-}
-
-inline size_t ConcurrentMarkSweepGeneration::used() const {
- return _cmsSpace->used();
-}
-
-inline size_t ConcurrentMarkSweepGeneration::free() const {
- return _cmsSpace->free();
-}
-
-inline MemRegion ConcurrentMarkSweepGeneration::used_region() const {
- return _cmsSpace->used_region();
-}
-
inline MemRegion ConcurrentMarkSweepGeneration::used_region_at_save_marks() const {
return _cmsSpace->used_region_at_save_marks();
}
--- a/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp Tue Dec 23 12:40:06 2014 -0800
+++ b/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp Thu Dec 25 19:46:17 2014 -0800
@@ -352,7 +352,7 @@
}
void G1RegionMappingChangedListener::reset_from_card_cache(uint start_idx, size_t num_regions) {
- OtherRegionsTable::invalidate(start_idx, num_regions);
+ HeapRegionRemSet::invalidate_from_card_cache(start_idx, num_regions);
}
void G1RegionMappingChangedListener::on_commit(uint start_idx, size_t num_regions, bool zero_filled) {
--- a/hotspot/src/share/vm/gc_implementation/g1/heapRegionRemSet.cpp Tue Dec 23 12:40:06 2014 -0800
+++ b/hotspot/src/share/vm/gc_implementation/g1/heapRegionRemSet.cpp Thu Dec 25 19:46:17 2014 -0800
@@ -407,20 +407,8 @@
}
}
-void OtherRegionsTable::initialize(uint max_regions) {
- FromCardCache::initialize(HeapRegionRemSet::num_par_rem_sets(), max_regions);
-}
-
-void OtherRegionsTable::invalidate(uint start_idx, size_t num_regions) {
- FromCardCache::invalidate(start_idx, num_regions);
-}
-
-void OtherRegionsTable::print_from_card_cache() {
- FromCardCache::print();
-}
-
void OtherRegionsTable::add_reference(OopOrNarrowOopStar from, uint tid) {
- uint cur_hrm_ind = hr()->hrm_index();
+ uint cur_hrm_ind = _hr->hrm_index();
if (G1TraceHeapRegionRememberedSet) {
gclog_or_tty->print_cr("ORT::add_reference_work(" PTR_FORMAT "->" PTR_FORMAT ").",
@@ -434,7 +422,7 @@
if (G1TraceHeapRegionRememberedSet) {
gclog_or_tty->print_cr("Table for [" PTR_FORMAT "...): card %d (cache = %d)",
- hr()->bottom(), from_card,
+ _hr->bottom(), from_card,
FromCardCache::at(tid, cur_hrm_ind));
}
@@ -477,13 +465,13 @@
if (G1HRRSUseSparseTable &&
_sparse_table.add_card(from_hrm_ind, card_index)) {
if (G1RecordHRRSOops) {
- HeapRegionRemSet::record(hr(), from);
+ HeapRegionRemSet::record(_hr, from);
if (G1TraceHeapRegionRememberedSet) {
gclog_or_tty->print(" Added card " PTR_FORMAT " to region "
"[" PTR_FORMAT "...) for ref " PTR_FORMAT ".\n",
align_size_down(uintptr_t(from),
CardTableModRefBS::card_size),
- hr()->bottom(), from);
+ _hr->bottom(), from);
}
}
if (G1TraceHeapRegionRememberedSet) {
@@ -539,13 +527,13 @@
prt->add_reference(from);
if (G1RecordHRRSOops) {
- HeapRegionRemSet::record(hr(), from);
+ HeapRegionRemSet::record(_hr, from);
if (G1TraceHeapRegionRememberedSet) {
gclog_or_tty->print("Added card " PTR_FORMAT " to region "
"[" PTR_FORMAT "...) for ref " PTR_FORMAT ".\n",
align_size_down(uintptr_t(from),
CardTableModRefBS::card_size),
- hr()->bottom(), from);
+ _hr->bottom(), from);
}
}
assert(contains_reference(from), "We just added it!");
@@ -614,7 +602,7 @@
if (G1TraceHeapRegionRememberedSet) {
gclog_or_tty->print("Coarsened entry in region [" PTR_FORMAT "...] "
"for region [" PTR_FORMAT "...] (" SIZE_FORMAT " coarse entries).\n",
- hr()->bottom(),
+ _hr->bottom(),
max->hr()->bottom(),
_n_coarse_entries);
}
@@ -627,13 +615,11 @@
return max;
}
-
-// At present, this must be called stop-world single-threaded.
void OtherRegionsTable::scrub(CardTableModRefBS* ctbs,
BitMap* region_bm, BitMap* card_bm) {
// First eliminated garbage regions from the coarse map.
if (G1RSScrubVerbose) {
- gclog_or_tty->print_cr("Scrubbing region %u:", hr()->hrm_index());
+ gclog_or_tty->print_cr("Scrubbing region %u:", _hr->hrm_index());
}
assert(_coarse_map.size() == region_bm->size(), "Precondition");
@@ -752,7 +738,7 @@
}
void OtherRegionsTable::clear_fcc() {
- FromCardCache::clear(hr()->hrm_index());
+ FromCardCache::clear(_hr->hrm_index());
}
void OtherRegionsTable::clear() {
@@ -774,27 +760,6 @@
clear_fcc();
}
-bool OtherRegionsTable::del_single_region_table(size_t ind,
- HeapRegion* hr) {
- assert(0 <= ind && ind < _max_fine_entries, "Preconditions.");
- PerRegionTable** prev_addr = &_fine_grain_regions[ind];
- PerRegionTable* prt = *prev_addr;
- while (prt != NULL && prt->hr() != hr) {
- prev_addr = prt->collision_list_next_addr();
- prt = prt->collision_list_next();
- }
- if (prt != NULL) {
- assert(prt->hr() == hr, "Loop postcondition.");
- *prev_addr = prt->collision_list_next();
- unlink_from_all(prt);
- PerRegionTable::free(prt);
- _n_fine_entries--;
- return true;
- } else {
- return false;
- }
-}
-
bool OtherRegionsTable::contains_reference(OopOrNarrowOopStar from) const {
// Cast away const in this case.
MutexLockerEx x((Mutex*)_m, Mutex::_no_safepoint_check_flag);
@@ -975,7 +940,7 @@
_hrrs(hrrs),
_g1h(G1CollectedHeap::heap()),
_coarse_map(&hrrs->_other_regions._coarse_map),
- _bosa(hrrs->bosa()),
+ _bosa(hrrs->_bosa),
_is(Sparse),
// Set these values so that we increment to the first region.
_coarse_cur_region_index(-1),
--- a/hotspot/src/share/vm/gc_implementation/g1/heapRegionRemSet.hpp Tue Dec 23 12:40:06 2014 -0800
+++ b/hotspot/src/share/vm/gc_implementation/g1/heapRegionRemSet.hpp Thu Dec 25 19:46:17 2014 -0800
@@ -162,32 +162,36 @@
// to hold _m, and the fine-grain table to be full.
PerRegionTable* delete_region_table();
- // If a PRT for "hr" is in the bucket list indicated by "ind" (which must
- // be the correct index for "hr"), delete it and return true; else return
- // false.
- bool del_single_region_table(size_t ind, HeapRegion* hr);
-
// 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
void unlink_from_all(PerRegionTable * prt);
+ bool contains_reference_locked(OopOrNarrowOopStar from) const;
+
+ // Clear the from_card_cache entries for this region.
+ void clear_fcc();
public:
+ // Create a new remembered set for the given heap region. The given mutex should
+ // be used to ensure consistency.
OtherRegionsTable(HeapRegion* hr, Mutex* m);
- HeapRegion* hr() const { return _hr; }
-
// For now. Could "expand" some tables in the future, so that this made
// sense.
void add_reference(OopOrNarrowOopStar from, uint tid);
+ // Returns whether the remembered set contains the given reference.
+ bool contains_reference(OopOrNarrowOopStar from) const;
+
// Removes any entries shown by the given bitmaps to contain only dead
- // objects.
+ // objects. Not thread safe.
+ // Set bits in the bitmaps indicate that the given region or card is live.
void scrub(CardTableModRefBS* ctbs, BitMap* region_bm, BitMap* card_bm);
- // Returns whether this remembered set (and all sub-sets) contain no entries.
+ // Returns whether this remembered set (and all sub-sets) does not contain any entry.
bool is_empty() const;
+ // Returns the number of cards contained in this remembered set.
size_t occupied() const;
size_t occ_fine() const;
size_t occ_coarse() const;
@@ -195,31 +199,17 @@
static jint n_coarsenings() { return _n_coarsenings; }
- // Returns size in bytes.
- // Not const because it takes a lock.
+ // Returns size of the actual remembered set containers in bytes.
size_t mem_size() const;
+ // Returns the size of static data in bytes.
static size_t static_mem_size();
+ // Returns the size of the free list content in bytes.
static size_t fl_mem_size();
- bool contains_reference(OopOrNarrowOopStar from) const;
- bool contains_reference_locked(OopOrNarrowOopStar from) const;
-
+ // Clear the entire contents of this remembered set.
void clear();
- // Specifically clear the from_card_cache.
- void clear_fcc();
-
void do_cleanup_work(HRRSCleanupTask* hrrs_cleanup_task);
-
- // Declare the heap size (in # of regions) to the OtherRegionsTable.
- // (Uses it to initialize from_card_cache).
- static void initialize(uint max_regions);
-
- // Declares that regions between start_idx <= i < start_idx + num_regions are
- // not in use. Make sure that any entries for these regions are invalid.
- static void invalidate(uint start_idx, size_t num_regions);
-
- static void print_from_card_cache();
};
class HeapRegionRemSet : public CHeapObj<mtGC> {
@@ -233,7 +223,6 @@
private:
G1BlockOffsetSharedArray* _bosa;
- G1BlockOffsetSharedArray* bosa() const { return _bosa; }
// A set of code blobs (nmethods) whose code contains pointers into
// the region that owns this RSet.
@@ -268,10 +257,6 @@
static uint num_par_rem_sets();
static void setup_remset_size();
- HeapRegion* hr() const {
- return _other_regions.hr();
- }
-
bool is_empty() const {
return (strong_code_roots_list_length() == 0) && _other_regions.is_empty();
}
@@ -305,8 +290,9 @@
_other_regions.add_reference(from, tid);
}
- // Removes any entries shown by the given bitmaps to contain only dead
- // objects.
+ // Removes any entries in the remembered set shown by the given bitmaps to
+ // contain only dead objects. Not thread safe.
+ // One bits in the bitmaps indicate that the given region or card is live.
void scrub(CardTableModRefBS* ctbs, BitMap* region_bm, BitMap* card_bm);
// The region is being reclaimed; clear its remset, and any mention of
@@ -397,16 +383,16 @@
// 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) {
- OtherRegionsTable::initialize(max_regions);
+ FromCardCache::initialize(num_par_rem_sets(), max_regions);
}
- static void invalidate(uint start_idx, uint num_regions) {
- OtherRegionsTable::invalidate(start_idx, num_regions);
+ static void invalidate_from_card_cache(uint start_idx, size_t num_regions) {
+ FromCardCache::invalidate(start_idx, num_regions);
}
#ifndef PRODUCT
static void print_from_card_cache() {
- OtherRegionsTable::print_from_card_cache();
+ FromCardCache::print();
}
#endif
--- a/hotspot/src/share/vm/gc_implementation/shared/gcTrace.cpp Tue Dec 23 12:40:06 2014 -0800
+++ b/hotspot/src/share/vm/gc_implementation/shared/gcTrace.cpp Thu Dec 25 19:46:17 2014 -0800
@@ -172,6 +172,27 @@
_tenuring_threshold = tenuring_threshold;
}
+bool YoungGCTracer::should_report_promotion_in_new_plab_event() const {
+ return should_send_promotion_in_new_plab_event();
+}
+
+bool YoungGCTracer::should_report_promotion_outside_plab_event() const {
+ return should_send_promotion_outside_plab_event();
+}
+
+void YoungGCTracer::report_promotion_in_new_plab_event(Klass* klass, size_t obj_size,
+ uint age, bool tenured,
+ size_t plab_size) const {
+ assert_set_gc_id();
+ send_promotion_in_new_plab_event(klass, obj_size, age, tenured, plab_size);
+}
+
+void YoungGCTracer::report_promotion_outside_plab_event(Klass* klass, size_t obj_size,
+ uint age, bool tenured) const {
+ assert_set_gc_id();
+ send_promotion_outside_plab_event(klass, obj_size, age, tenured);
+}
+
void OldGCTracer::report_gc_end_impl(const Ticks& timestamp, TimePartitions* time_partitions) {
assert_set_gc_id();
--- a/hotspot/src/share/vm/gc_implementation/shared/gcTrace.hpp Tue Dec 23 12:40:06 2014 -0800
+++ b/hotspot/src/share/vm/gc_implementation/shared/gcTrace.hpp Thu Dec 25 19:46:17 2014 -0800
@@ -156,9 +156,38 @@
void report_promotion_failed(const PromotionFailedInfo& pf_info);
void report_tenuring_threshold(const uint tenuring_threshold);
+ /*
+ * Methods for reporting Promotion in new or outside PLAB Events.
+ *
+ * The object age is always required as it is not certain that the mark word
+ * of the oop can be trusted at this stage.
+ *
+ * obj_size is the size of the promoted object in bytes.
+ *
+ * tenured should be true if the object has been promoted to the old
+ * space during this GC, if the object is copied to survivor space
+ * from young space or survivor space (aging) tenured should be false.
+ *
+ * plab_size is the size of the newly allocated PLAB in bytes.
+ */
+ bool should_report_promotion_in_new_plab_event() const;
+ bool should_report_promotion_outside_plab_event() const;
+ void report_promotion_in_new_plab_event(Klass* klass, size_t obj_size,
+ uint age, bool tenured,
+ size_t plab_size) const;
+ void report_promotion_outside_plab_event(Klass* klass, size_t obj_size,
+ uint age, bool tenured) const;
+
private:
void send_young_gc_event() const;
void send_promotion_failed_event(const PromotionFailedInfo& pf_info) const;
+ bool should_send_promotion_in_new_plab_event() const;
+ bool should_send_promotion_outside_plab_event() const;
+ void send_promotion_in_new_plab_event(Klass* klass, size_t obj_size,
+ uint age, bool tenured,
+ size_t plab_size) const;
+ void send_promotion_outside_plab_event(Klass* klass, size_t obj_size,
+ uint age, bool tenured) const;
};
class OldGCTracer : public GCTracer {
--- a/hotspot/src/share/vm/gc_implementation/shared/gcTraceSend.cpp Tue Dec 23 12:40:06 2014 -0800
+++ b/hotspot/src/share/vm/gc_implementation/shared/gcTraceSend.cpp Thu Dec 25 19:46:17 2014 -0800
@@ -111,6 +111,44 @@
}
}
+bool YoungGCTracer::should_send_promotion_in_new_plab_event() const {
+ return EventPromoteObjectInNewPLAB::is_enabled();
+}
+
+bool YoungGCTracer::should_send_promotion_outside_plab_event() const {
+ return EventPromoteObjectOutsidePLAB::is_enabled();
+}
+
+void YoungGCTracer::send_promotion_in_new_plab_event(Klass* klass, size_t obj_size,
+ uint age, bool tenured,
+ size_t plab_size) const {
+
+ EventPromoteObjectInNewPLAB event;
+ if (event.should_commit()) {
+ event.set_gcId(_shared_gc_info.gc_id().id());
+ event.set_class(klass);
+ event.set_objectSize(obj_size);
+ event.set_tenured(tenured);
+ event.set_tenuringAge(age);
+ event.set_plabSize(plab_size);
+ event.commit();
+ }
+}
+
+void YoungGCTracer::send_promotion_outside_plab_event(Klass* klass, size_t obj_size,
+ uint age, bool tenured) const {
+
+ EventPromoteObjectOutsidePLAB event;
+ if (event.should_commit()) {
+ event.set_gcId(_shared_gc_info.gc_id().id());
+ event.set_class(klass);
+ event.set_objectSize(obj_size);
+ event.set_tenured(tenured);
+ event.set_tenuringAge(age);
+ event.commit();
+ }
+}
+
void OldGCTracer::send_old_gc_event() const {
EventGCOldGarbageCollection e(UNTIMED);
if (e.should_commit()) {
--- a/hotspot/src/share/vm/interpreter/interpreterRuntime.cpp Tue Dec 23 12:40:06 2014 -0800
+++ b/hotspot/src/share/vm/interpreter/interpreterRuntime.cpp Thu Dec 25 19:46:17 2014 -0800
@@ -385,6 +385,18 @@
int handler_bci;
int current_bci = bci(thread);
+ if (thread->frames_to_pop_failed_realloc() > 0) {
+ // Allocation of scalar replaced object used in this frame
+ // failed. Unconditionally pop the frame.
+ thread->dec_frames_to_pop_failed_realloc();
+ thread->set_vm_result(h_exception());
+ // If the method is synchronized we already unlocked the monitor
+ // during deoptimization so the interpreter needs to skip it when
+ // the frame is popped.
+ thread->set_do_not_unlock_if_synchronized(true);
+ return Interpreter::remove_activation_entry();
+ }
+
// Need to do this check first since when _do_not_unlock_if_synchronized
// is set, we don't want to trigger any classloading which may make calls
// into java, or surprisingly find a matching exception handler for bci 0
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/src/share/vm/memory/cardGeneration.cpp Thu Dec 25 19:46:17 2014 -0800
@@ -0,0 +1,360 @@
+/*
+ * 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/blockOffsetTable.inline.hpp"
+#include "memory/cardGeneration.inline.hpp"
+#include "memory/gcLocker.hpp"
+#include "memory/generationSpec.hpp"
+#include "memory/genOopClosures.inline.hpp"
+#include "memory/genRemSet.hpp"
+#include "memory/iterator.hpp"
+#include "memory/memRegion.hpp"
+#include "memory/space.inline.hpp"
+#include "runtime/java.hpp"
+
+CardGeneration::CardGeneration(ReservedSpace rs, size_t initial_byte_size,
+ int level,
+ GenRemSet* remset) :
+ Generation(rs, initial_byte_size, level), _rs(remset),
+ _shrink_factor(0), _min_heap_delta_bytes(), _capacity_at_prologue(),
+ _used_at_prologue()
+{
+ HeapWord* start = (HeapWord*)rs.base();
+ size_t reserved_byte_size = rs.size();
+ assert((uintptr_t(start) & 3) == 0, "bad alignment");
+ assert((reserved_byte_size & 3) == 0, "bad alignment");
+ MemRegion reserved_mr(start, heap_word_size(reserved_byte_size));
+ _bts = new BlockOffsetSharedArray(reserved_mr,
+ heap_word_size(initial_byte_size));
+ MemRegion committed_mr(start, heap_word_size(initial_byte_size));
+ _rs->resize_covered_region(committed_mr);
+ if (_bts == NULL) {
+ vm_exit_during_initialization("Could not allocate a BlockOffsetArray");
+ }
+
+ // Verify that the start and end of this generation is the start of a card.
+ // If this wasn't true, a single card could span more than on generation,
+ // which would cause problems when we commit/uncommit memory, and when we
+ // clear and dirty cards.
+ guarantee(_rs->is_aligned(reserved_mr.start()), "generation must be card aligned");
+ if (reserved_mr.end() != Universe::heap()->reserved_region().end()) {
+ // Don't check at the very end of the heap as we'll assert that we're probing off
+ // the end if we try.
+ guarantee(_rs->is_aligned(reserved_mr.end()), "generation must be card aligned");
+ }
+ _min_heap_delta_bytes = MinHeapDeltaBytes;
+ _capacity_at_prologue = initial_byte_size;
+ _used_at_prologue = 0;
+}
+
+bool CardGeneration::grow_by(size_t bytes) {
+ assert_correct_size_change_locking();
+ bool result = _virtual_space.expand_by(bytes);
+ if (result) {
+ size_t new_word_size =
+ heap_word_size(_virtual_space.committed_size());
+ MemRegion mr(space()->bottom(), new_word_size);
+ // Expand card table
+ Universe::heap()->barrier_set()->resize_covered_region(mr);
+ // Expand shared block offset array
+ _bts->resize(new_word_size);
+
+ // Fix for bug #4668531
+ if (ZapUnusedHeapArea) {
+ MemRegion mangle_region(space()->end(),
+ (HeapWord*)_virtual_space.high());
+ SpaceMangler::mangle_region(mangle_region);
+ }
+
+ // Expand space -- also expands space's BOT
+ // (which uses (part of) shared array above)
+ space()->set_end((HeapWord*)_virtual_space.high());
+
+ // update the space and generation capacity counters
+ update_counters();
+
+ if (Verbose && PrintGC) {
+ size_t new_mem_size = _virtual_space.committed_size();
+ size_t old_mem_size = new_mem_size - bytes;
+ gclog_or_tty->print_cr("Expanding %s from " SIZE_FORMAT "K by "
+ SIZE_FORMAT "K to " SIZE_FORMAT "K",
+ name(), old_mem_size/K, bytes/K, new_mem_size/K);
+ }
+ }
+ return result;
+}
+
+bool CardGeneration::expand(size_t bytes, size_t expand_bytes) {
+ assert_locked_or_safepoint(Heap_lock);
+ if (bytes == 0) {
+ return true; // That's what grow_by(0) would return
+ }
+ size_t aligned_bytes = ReservedSpace::page_align_size_up(bytes);
+ if (aligned_bytes == 0){
+ // The alignment caused the number of bytes to wrap. An expand_by(0) will
+ // return true with the implication that an expansion was done when it
+ // was not. A call to expand implies a best effort to expand by "bytes"
+ // but not a guarantee. Align down to give a best effort. This is likely
+ // the most that the generation can expand since it has some capacity to
+ // start with.
+ aligned_bytes = ReservedSpace::page_align_size_down(bytes);
+ }
+ size_t aligned_expand_bytes = ReservedSpace::page_align_size_up(expand_bytes);
+ bool success = false;
+ if (aligned_expand_bytes > aligned_bytes) {
+ success = grow_by(aligned_expand_bytes);
+ }
+ if (!success) {
+ success = grow_by(aligned_bytes);
+ }
+ if (!success) {
+ success = grow_to_reserved();
+ }
+ if (PrintGC && Verbose) {
+ if (success && GC_locker::is_active_and_needs_gc()) {
+ gclog_or_tty->print_cr("Garbage collection disabled, expanded heap instead");
+ }
+ }
+
+ return success;
+}
+
+bool CardGeneration::grow_to_reserved() {
+ assert_correct_size_change_locking();
+ bool success = true;
+ const size_t remaining_bytes = _virtual_space.uncommitted_size();
+ if (remaining_bytes > 0) {
+ success = grow_by(remaining_bytes);
+ DEBUG_ONLY(if (!success) warning("grow to reserved failed");)
+ }
+ return success;
+}
+
+void CardGeneration::shrink(size_t bytes) {
+ assert_correct_size_change_locking();
+
+ size_t size = ReservedSpace::page_align_size_down(bytes);
+ if (size == 0) {
+ return;
+ }
+
+ // Shrink committed space
+ _virtual_space.shrink_by(size);
+ // Shrink space; this also shrinks the space's BOT
+ space()->set_end((HeapWord*) _virtual_space.high());
+ size_t new_word_size = heap_word_size(space()->capacity());
+ // Shrink the shared block offset array
+ _bts->resize(new_word_size);
+ MemRegion mr(space()->bottom(), new_word_size);
+ // Shrink the card table
+ Universe::heap()->barrier_set()->resize_covered_region(mr);
+
+ if (Verbose && PrintGC) {
+ size_t new_mem_size = _virtual_space.committed_size();
+ size_t old_mem_size = new_mem_size + size;
+ gclog_or_tty->print_cr("Shrinking %s from " SIZE_FORMAT "K to " SIZE_FORMAT "K",
+ name(), old_mem_size/K, new_mem_size/K);
+ }
+}
+
+// No young generation references, clear this generation's cards.
+void CardGeneration::clear_remembered_set() {
+ _rs->clear(reserved());
+}
+
+// Objects in this generation may have moved, invalidate this
+// generation's cards.
+void CardGeneration::invalidate_remembered_set() {
+ _rs->invalidate(used_region());
+}
+
+void CardGeneration::compute_new_size() {
+ assert(_shrink_factor <= 100, "invalid shrink factor");
+ size_t current_shrink_factor = _shrink_factor;
+ _shrink_factor = 0;
+
+ // We don't have floating point command-line arguments
+ // Note: argument processing ensures that MinHeapFreeRatio < 100.
+ const double minimum_free_percentage = MinHeapFreeRatio / 100.0;
+ const double maximum_used_percentage = 1.0 - minimum_free_percentage;
+
+ // Compute some numbers about the state of the heap.
+ const size_t used_after_gc = used();
+ const size_t capacity_after_gc = capacity();
+
+ const double min_tmp = used_after_gc / maximum_used_percentage;
+ size_t minimum_desired_capacity = (size_t)MIN2(min_tmp, double(max_uintx));
+ // Don't shrink less than the initial generation size
+ minimum_desired_capacity = MAX2(minimum_desired_capacity,
+ spec()->init_size());
+ assert(used_after_gc <= minimum_desired_capacity, "sanity check");
+
+ if (PrintGC && Verbose) {
+ const size_t free_after_gc = free();
+ const double free_percentage = ((double)free_after_gc) / capacity_after_gc;
+ gclog_or_tty->print_cr("TenuredGeneration::compute_new_size: ");
+ gclog_or_tty->print_cr(" "
+ " minimum_free_percentage: %6.2f"
+ " maximum_used_percentage: %6.2f",
+ minimum_free_percentage,
+ maximum_used_percentage);
+ gclog_or_tty->print_cr(" "
+ " free_after_gc : %6.1fK"
+ " used_after_gc : %6.1fK"
+ " capacity_after_gc : %6.1fK",
+ free_after_gc / (double) K,
+ used_after_gc / (double) K,
+ capacity_after_gc / (double) K);
+ gclog_or_tty->print_cr(" "
+ " free_percentage: %6.2f",
+ free_percentage);
+ }
+
+ if (capacity_after_gc < minimum_desired_capacity) {
+ // If we have less free space than we want then expand
+ size_t expand_bytes = minimum_desired_capacity - capacity_after_gc;
+ // Don't expand unless it's significant
+ if (expand_bytes >= _min_heap_delta_bytes) {
+ expand(expand_bytes, 0); // safe if expansion fails
+ }
+ if (PrintGC && Verbose) {
+ gclog_or_tty->print_cr(" expanding:"
+ " minimum_desired_capacity: %6.1fK"
+ " expand_bytes: %6.1fK"
+ " _min_heap_delta_bytes: %6.1fK",
+ minimum_desired_capacity / (double) K,
+ expand_bytes / (double) K,
+ _min_heap_delta_bytes / (double) K);
+ }
+ return;
+ }
+
+ // No expansion, now see if we want to shrink
+ size_t shrink_bytes = 0;
+ // We would never want to shrink more than this
+ size_t max_shrink_bytes = capacity_after_gc - minimum_desired_capacity;
+
+ if (MaxHeapFreeRatio < 100) {
+ const double maximum_free_percentage = MaxHeapFreeRatio / 100.0;
+ const double minimum_used_percentage = 1.0 - maximum_free_percentage;
+ const double max_tmp = used_after_gc / minimum_used_percentage;
+ size_t maximum_desired_capacity = (size_t)MIN2(max_tmp, double(max_uintx));
+ maximum_desired_capacity = MAX2(maximum_desired_capacity,
+ spec()->init_size());
+ if (PrintGC && Verbose) {
+ gclog_or_tty->print_cr(" "
+ " maximum_free_percentage: %6.2f"
+ " minimum_used_percentage: %6.2f",
+ maximum_free_percentage,
+ minimum_used_percentage);
+ gclog_or_tty->print_cr(" "
+ " _capacity_at_prologue: %6.1fK"
+ " minimum_desired_capacity: %6.1fK"
+ " maximum_desired_capacity: %6.1fK",
+ _capacity_at_prologue / (double) K,
+ minimum_desired_capacity / (double) K,
+ maximum_desired_capacity / (double) K);
+ }
+ assert(minimum_desired_capacity <= maximum_desired_capacity,
+ "sanity check");
+
+ if (capacity_after_gc > maximum_desired_capacity) {
+ // Capacity too large, compute shrinking size
+ shrink_bytes = capacity_after_gc - maximum_desired_capacity;
+ // We don't want shrink all the way back to initSize if people call
+ // System.gc(), because some programs do that between "phases" and then
+ // we'd just have to grow the heap up again for the next phase. So we
+ // damp the shrinking: 0% on the first call, 10% on the second call, 40%
+ // on the third call, and 100% by the fourth call. But if we recompute
+ // size without shrinking, it goes back to 0%.
+ shrink_bytes = shrink_bytes / 100 * current_shrink_factor;
+ assert(shrink_bytes <= max_shrink_bytes, "invalid shrink size");
+ if (current_shrink_factor == 0) {
+ _shrink_factor = 10;
+ } else {
+ _shrink_factor = MIN2(current_shrink_factor * 4, (size_t) 100);
+ }
+ if (PrintGC && Verbose) {
+ gclog_or_tty->print_cr(" "
+ " shrinking:"
+ " initSize: %.1fK"
+ " maximum_desired_capacity: %.1fK",
+ spec()->init_size() / (double) K,
+ maximum_desired_capacity / (double) K);
+ gclog_or_tty->print_cr(" "
+ " shrink_bytes: %.1fK"
+ " current_shrink_factor: " SIZE_FORMAT
+ " new shrink factor: " SIZE_FORMAT
+ " _min_heap_delta_bytes: %.1fK",
+ shrink_bytes / (double) K,
+ current_shrink_factor,
+ _shrink_factor,
+ _min_heap_delta_bytes / (double) K);
+ }
+ }
+ }
+
+ if (capacity_after_gc > _capacity_at_prologue) {
+ // We might have expanded for promotions, in which case we might want to
+ // take back that expansion if there's room after GC. That keeps us from
+ // stretching the heap with promotions when there's plenty of room.
+ size_t expansion_for_promotion = capacity_after_gc - _capacity_at_prologue;
+ expansion_for_promotion = MIN2(expansion_for_promotion, max_shrink_bytes);
+ // We have two shrinking computations, take the largest
+ shrink_bytes = MAX2(shrink_bytes, expansion_for_promotion);
+ assert(shrink_bytes <= max_shrink_bytes, "invalid shrink size");
+ if (PrintGC && Verbose) {
+ gclog_or_tty->print_cr(" "
+ " aggressive shrinking:"
+ " _capacity_at_prologue: %.1fK"
+ " capacity_after_gc: %.1fK"
+ " expansion_for_promotion: %.1fK"
+ " shrink_bytes: %.1fK",
+ capacity_after_gc / (double) K,
+ _capacity_at_prologue / (double) K,
+ expansion_for_promotion / (double) K,
+ shrink_bytes / (double) K);
+ }
+ }
+ // Don't shrink unless it's significant
+ if (shrink_bytes >= _min_heap_delta_bytes) {
+ shrink(shrink_bytes);
+ }
+}
+
+// Currently nothing to do.
+void CardGeneration::prepare_for_verify() {}
+
+void CardGeneration::space_iterate(SpaceClosure* blk,
+ bool usedOnly) {
+ blk->do_space(space());
+}
+
+void CardGeneration::younger_refs_iterate(OopsInGenClosure* blk) {
+ blk->set_generation(this);
+ younger_refs_in_space_iterate(space(), blk);
+ blk->reset_generation();
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/src/share/vm/memory/cardGeneration.hpp Thu Dec 25 19:46:17 2014 -0800
@@ -0,0 +1,99 @@
+/*
+ * 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_CARDGENERATION_HPP
+#define SHARE_VM_MEMORY_CARDGENERATION_HPP
+
+// Class CardGeneration is a generation that is covered by a card table,
+// and uses a card-size block-offset array to implement block_start.
+
+#include "memory/generation.hpp"
+
+class BlockOffsetSharedArray;
+class CompactibleSpace;
+
+class CardGeneration: public Generation {
+ friend class VMStructs;
+ protected:
+ // This is shared with other generations.
+ GenRemSet* _rs;
+ // This is local to this generation.
+ BlockOffsetSharedArray* _bts;
+
+ // Current shrinking effect: this damps shrinking when the heap gets empty.
+ size_t _shrink_factor;
+
+ size_t _min_heap_delta_bytes; // Minimum amount to expand.
+
+ // Some statistics from before gc started.
+ // These are gathered in the gc_prologue (and should_collect)
+ // to control growing/shrinking policy in spite of promotions.
+ size_t _capacity_at_prologue;
+ size_t _used_at_prologue;
+
+ CardGeneration(ReservedSpace rs, size_t initial_byte_size, int level,
+ GenRemSet* remset);
+
+ virtual void assert_correct_size_change_locking() = 0;
+
+ virtual CompactibleSpace* space() const = 0;
+
+ public:
+
+ // Attempt to expand the generation by "bytes". Expand by at a
+ // minimum "expand_bytes". Return true if some amount (not
+ // necessarily the full "bytes") was done.
+ virtual bool expand(size_t bytes, size_t expand_bytes);
+
+ // Shrink generation with specified size
+ virtual void shrink(size_t bytes);
+
+ virtual void compute_new_size();
+
+ virtual void clear_remembered_set();
+
+ virtual void invalidate_remembered_set();
+
+ virtual void prepare_for_verify();
+
+ // Grow generation with specified size (returns false if unable to grow)
+ bool grow_by(size_t bytes);
+ // Grow generation to reserved size.
+ bool grow_to_reserved();
+
+ size_t capacity() const;
+ size_t used() const;
+ size_t free() const;
+ MemRegion used_region() const;
+
+ void space_iterate(SpaceClosure* blk, bool usedOnly = false);
+
+ void younger_refs_iterate(OopsInGenClosure* blk);
+
+ bool is_in(const void* p) const;
+
+ CompactibleSpace* first_compaction_space() const;
+};
+
+#endif // SHARE_VM_MEMORY_CARDGENERATION_HPP
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/src/share/vm/memory/cardGeneration.inline.hpp Thu Dec 25 19:46:17 2014 -0800
@@ -0,0 +1,55 @@
+/*
+ * 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_CARDGENERATION_INLINE_HPP
+#define SHARE_VM_MEMORY_CARDGENERATION_INLINE_HPP
+
+#include "memory/cardGeneration.hpp"
+#include "memory/space.hpp"
+
+inline size_t CardGeneration::capacity() const {
+ return space()->capacity();
+}
+
+inline size_t CardGeneration::used() const {
+ return space()->used();
+}
+
+inline size_t CardGeneration::free() const {
+ return space()->free();
+}
+
+inline MemRegion CardGeneration::used_region() const {
+ return space()->used_region();
+}
+
+inline bool CardGeneration::is_in(const void* p) const {
+ return space()->is_in(p);
+}
+
+inline CompactibleSpace* CardGeneration::first_compaction_space() const {
+ return space();
+}
+
+#endif // SHARE_VM_MEMORY_CARDGENERATION_INLINE_HPP
--- a/hotspot/src/share/vm/memory/cardTableModRefBS.cpp Tue Dec 23 12:40:06 2014 -0800
+++ b/hotspot/src/share/vm/memory/cardTableModRefBS.cpp Thu Dec 25 19:46:17 2014 -0800
@@ -275,29 +275,26 @@
// the new_end_aligned does not intrude onto the committed
// space of another region.
int ri = 0;
- for (ri = 0; ri < _cur_covered_regions; ri++) {
- if (ri != ind) {
- if (_committed[ri].contains(new_end_aligned)) {
- // The prior check included in the assert
- // (new_end_aligned >= _committed[ri].start())
- // is redundant with the "contains" test.
- // Any region containing the new end
- // should start at or beyond the region found (ind)
- // for the new end (committed regions are not expected to
- // be proper subsets of other committed regions).
- assert(_committed[ri].start() >= _committed[ind].start(),
- "New end of committed region is inconsistent");
- new_end_aligned = _committed[ri].start();
- // new_end_aligned can be equal to the start of its
- // committed region (i.e., of "ind") if a second
- // region following "ind" also start at the same location
- // as "ind".
- assert(new_end_aligned >= _committed[ind].start(),
- "New end of committed region is before start");
- debug_only(collided = true;)
- // Should only collide with 1 region
- break;
- }
+ for (ri = ind + 1; ri < _cur_covered_regions; ri++) {
+ if (new_end_aligned > _committed[ri].start()) {
+ assert(new_end_aligned <= _committed[ri].end(),
+ "An earlier committed region can't cover a later committed region");
+ // Any region containing the new end
+ // should start at or beyond the region found (ind)
+ // for the new end (committed regions are not expected to
+ // be proper subsets of other committed regions).
+ assert(_committed[ri].start() >= _committed[ind].start(),
+ "New end of committed region is inconsistent");
+ new_end_aligned = _committed[ri].start();
+ // new_end_aligned can be equal to the start of its
+ // committed region (i.e., of "ind") if a second
+ // region following "ind" also start at the same location
+ // as "ind".
+ assert(new_end_aligned >= _committed[ind].start(),
+ "New end of committed region is before start");
+ debug_only(collided = true;)
+ // Should only collide with 1 region
+ break;
}
}
#ifdef ASSERT
--- a/hotspot/src/share/vm/memory/filemap.cpp Tue Dec 23 12:40:06 2014 -0800
+++ b/hotspot/src/share/vm/memory/filemap.cpp Thu Dec 25 19:46:17 2014 -0800
@@ -98,11 +98,11 @@
tty->print_cr("UseSharedSpaces: %s", msg);
}
}
+ UseSharedSpaces = false;
+ assert(current_info() != NULL, "singleton must be registered");
+ current_info()->close();
}
va_end(ap);
- UseSharedSpaces = false;
- assert(current_info() != NULL, "singleton must be registered");
- current_info()->close();
}
// Fill in the fileMapInfo structure with data about this VM instance.
--- a/hotspot/src/share/vm/memory/generation.cpp Tue Dec 23 12:40:06 2014 -0800
+++ b/hotspot/src/share/vm/memory/generation.cpp Thu Dec 25 19:46:17 2014 -0800
@@ -361,244 +361,3 @@
sp = sp->next_compaction_space();
}
}
-
-CardGeneration::CardGeneration(ReservedSpace rs, size_t initial_byte_size,
- int level,
- GenRemSet* remset) :
- Generation(rs, initial_byte_size, level), _rs(remset),
- _shrink_factor(0), _min_heap_delta_bytes(), _capacity_at_prologue(),
- _used_at_prologue()
-{
- HeapWord* start = (HeapWord*)rs.base();
- size_t reserved_byte_size = rs.size();
- assert((uintptr_t(start) & 3) == 0, "bad alignment");
- assert((reserved_byte_size & 3) == 0, "bad alignment");
- MemRegion reserved_mr(start, heap_word_size(reserved_byte_size));
- _bts = new BlockOffsetSharedArray(reserved_mr,
- heap_word_size(initial_byte_size));
- MemRegion committed_mr(start, heap_word_size(initial_byte_size));
- _rs->resize_covered_region(committed_mr);
- if (_bts == NULL)
- vm_exit_during_initialization("Could not allocate a BlockOffsetArray");
-
- // Verify that the start and end of this generation is the start of a card.
- // If this wasn't true, a single card could span more than on generation,
- // which would cause problems when we commit/uncommit memory, and when we
- // clear and dirty cards.
- guarantee(_rs->is_aligned(reserved_mr.start()), "generation must be card aligned");
- if (reserved_mr.end() != Universe::heap()->reserved_region().end()) {
- // Don't check at the very end of the heap as we'll assert that we're probing off
- // the end if we try.
- guarantee(_rs->is_aligned(reserved_mr.end()), "generation must be card aligned");
- }
- _min_heap_delta_bytes = MinHeapDeltaBytes;
- _capacity_at_prologue = initial_byte_size;
- _used_at_prologue = 0;
-}
-
-bool CardGeneration::expand(size_t bytes, size_t expand_bytes) {
- assert_locked_or_safepoint(Heap_lock);
- if (bytes == 0) {
- return true; // That's what grow_by(0) would return
- }
- size_t aligned_bytes = ReservedSpace::page_align_size_up(bytes);
- if (aligned_bytes == 0){
- // The alignment caused the number of bytes to wrap. An expand_by(0) will
- // return true with the implication that an expansion was done when it
- // was not. A call to expand implies a best effort to expand by "bytes"
- // but not a guarantee. Align down to give a best effort. This is likely
- // the most that the generation can expand since it has some capacity to
- // start with.
- aligned_bytes = ReservedSpace::page_align_size_down(bytes);
- }
- size_t aligned_expand_bytes = ReservedSpace::page_align_size_up(expand_bytes);
- bool success = false;
- if (aligned_expand_bytes > aligned_bytes) {
- success = grow_by(aligned_expand_bytes);
- }
- if (!success) {
- success = grow_by(aligned_bytes);
- }
- if (!success) {
- success = grow_to_reserved();
- }
- if (PrintGC && Verbose) {
- if (success && GC_locker::is_active_and_needs_gc()) {
- gclog_or_tty->print_cr("Garbage collection disabled, expanded heap instead");
- }
- }
-
- return success;
-}
-
-
-// No young generation references, clear this generation's cards.
-void CardGeneration::clear_remembered_set() {
- _rs->clear(reserved());
-}
-
-
-// Objects in this generation may have moved, invalidate this
-// generation's cards.
-void CardGeneration::invalidate_remembered_set() {
- _rs->invalidate(used_region());
-}
-
-
-void CardGeneration::compute_new_size() {
- assert(_shrink_factor <= 100, "invalid shrink factor");
- size_t current_shrink_factor = _shrink_factor;
- _shrink_factor = 0;
-
- // We don't have floating point command-line arguments
- // Note: argument processing ensures that MinHeapFreeRatio < 100.
- const double minimum_free_percentage = MinHeapFreeRatio / 100.0;
- const double maximum_used_percentage = 1.0 - minimum_free_percentage;
-
- // Compute some numbers about the state of the heap.
- const size_t used_after_gc = used();
- const size_t capacity_after_gc = capacity();
-
- const double min_tmp = used_after_gc / maximum_used_percentage;
- size_t minimum_desired_capacity = (size_t)MIN2(min_tmp, double(max_uintx));
- // Don't shrink less than the initial generation size
- minimum_desired_capacity = MAX2(minimum_desired_capacity,
- spec()->init_size());
- assert(used_after_gc <= minimum_desired_capacity, "sanity check");
-
- if (PrintGC && Verbose) {
- const size_t free_after_gc = free();
- const double free_percentage = ((double)free_after_gc) / capacity_after_gc;
- gclog_or_tty->print_cr("TenuredGeneration::compute_new_size: ");
- gclog_or_tty->print_cr(" "
- " minimum_free_percentage: %6.2f"
- " maximum_used_percentage: %6.2f",
- minimum_free_percentage,
- maximum_used_percentage);
- gclog_or_tty->print_cr(" "
- " free_after_gc : %6.1fK"
- " used_after_gc : %6.1fK"
- " capacity_after_gc : %6.1fK",
- free_after_gc / (double) K,
- used_after_gc / (double) K,
- capacity_after_gc / (double) K);
- gclog_or_tty->print_cr(" "
- " free_percentage: %6.2f",
- free_percentage);
- }
-
- if (capacity_after_gc < minimum_desired_capacity) {
- // If we have less free space than we want then expand
- size_t expand_bytes = minimum_desired_capacity - capacity_after_gc;
- // Don't expand unless it's significant
- if (expand_bytes >= _min_heap_delta_bytes) {
- expand(expand_bytes, 0); // safe if expansion fails
- }
- if (PrintGC && Verbose) {
- gclog_or_tty->print_cr(" expanding:"
- " minimum_desired_capacity: %6.1fK"
- " expand_bytes: %6.1fK"
- " _min_heap_delta_bytes: %6.1fK",
- minimum_desired_capacity / (double) K,
- expand_bytes / (double) K,
- _min_heap_delta_bytes / (double) K);
- }
- return;
- }
-
- // No expansion, now see if we want to shrink
- size_t shrink_bytes = 0;
- // We would never want to shrink more than this
- size_t max_shrink_bytes = capacity_after_gc - minimum_desired_capacity;
-
- if (MaxHeapFreeRatio < 100) {
- const double maximum_free_percentage = MaxHeapFreeRatio / 100.0;
- const double minimum_used_percentage = 1.0 - maximum_free_percentage;
- const double max_tmp = used_after_gc / minimum_used_percentage;
- size_t maximum_desired_capacity = (size_t)MIN2(max_tmp, double(max_uintx));
- maximum_desired_capacity = MAX2(maximum_desired_capacity,
- spec()->init_size());
- if (PrintGC && Verbose) {
- gclog_or_tty->print_cr(" "
- " maximum_free_percentage: %6.2f"
- " minimum_used_percentage: %6.2f",
- maximum_free_percentage,
- minimum_used_percentage);
- gclog_or_tty->print_cr(" "
- " _capacity_at_prologue: %6.1fK"
- " minimum_desired_capacity: %6.1fK"
- " maximum_desired_capacity: %6.1fK",
- _capacity_at_prologue / (double) K,
- minimum_desired_capacity / (double) K,
- maximum_desired_capacity / (double) K);
- }
- assert(minimum_desired_capacity <= maximum_desired_capacity,
- "sanity check");
-
- if (capacity_after_gc > maximum_desired_capacity) {
- // Capacity too large, compute shrinking size
- shrink_bytes = capacity_after_gc - maximum_desired_capacity;
- // We don't want shrink all the way back to initSize if people call
- // System.gc(), because some programs do that between "phases" and then
- // we'd just have to grow the heap up again for the next phase. So we
- // damp the shrinking: 0% on the first call, 10% on the second call, 40%
- // on the third call, and 100% by the fourth call. But if we recompute
- // size without shrinking, it goes back to 0%.
- shrink_bytes = shrink_bytes / 100 * current_shrink_factor;
- assert(shrink_bytes <= max_shrink_bytes, "invalid shrink size");
- if (current_shrink_factor == 0) {
- _shrink_factor = 10;
- } else {
- _shrink_factor = MIN2(current_shrink_factor * 4, (size_t) 100);
- }
- if (PrintGC && Verbose) {
- gclog_or_tty->print_cr(" "
- " shrinking:"
- " initSize: %.1fK"
- " maximum_desired_capacity: %.1fK",
- spec()->init_size() / (double) K,
- maximum_desired_capacity / (double) K);
- gclog_or_tty->print_cr(" "
- " shrink_bytes: %.1fK"
- " current_shrink_factor: " SIZE_FORMAT
- " new shrink factor: " SIZE_FORMAT
- " _min_heap_delta_bytes: %.1fK",
- shrink_bytes / (double) K,
- current_shrink_factor,
- _shrink_factor,
- _min_heap_delta_bytes / (double) K);
- }
- }
- }
-
- if (capacity_after_gc > _capacity_at_prologue) {
- // We might have expanded for promotions, in which case we might want to
- // take back that expansion if there's room after GC. That keeps us from
- // stretching the heap with promotions when there's plenty of room.
- size_t expansion_for_promotion = capacity_after_gc - _capacity_at_prologue;
- expansion_for_promotion = MIN2(expansion_for_promotion, max_shrink_bytes);
- // We have two shrinking computations, take the largest
- shrink_bytes = MAX2(shrink_bytes, expansion_for_promotion);
- assert(shrink_bytes <= max_shrink_bytes, "invalid shrink size");
- if (PrintGC && Verbose) {
- gclog_or_tty->print_cr(" "
- " aggressive shrinking:"
- " _capacity_at_prologue: %.1fK"
- " capacity_after_gc: %.1fK"
- " expansion_for_promotion: %.1fK"
- " shrink_bytes: %.1fK",
- capacity_after_gc / (double) K,
- _capacity_at_prologue / (double) K,
- expansion_for_promotion / (double) K,
- shrink_bytes / (double) K);
- }
- }
- // Don't shrink unless it's significant
- if (shrink_bytes >= _min_heap_delta_bytes) {
- shrink(shrink_bytes);
- }
-}
-
-// Currently nothing to do.
-void CardGeneration::prepare_for_verify() {}
-
--- a/hotspot/src/share/vm/memory/generation.hpp Tue Dec 23 12:40:06 2014 -0800
+++ b/hotspot/src/share/vm/memory/generation.hpp Thu Dec 25 19:46:17 2014 -0800
@@ -584,57 +584,4 @@
virtual CollectorCounters* counters() { return _gc_counters; }
};
-// Class CardGeneration is a generation that is covered by a card table,
-// and uses a card-size block-offset array to implement block_start.
-
-// class BlockOffsetArray;
-// class BlockOffsetArrayContigSpace;
-class BlockOffsetSharedArray;
-
-class CardGeneration: public Generation {
- friend class VMStructs;
- protected:
- // This is shared with other generations.
- GenRemSet* _rs;
- // This is local to this generation.
- BlockOffsetSharedArray* _bts;
-
- // current shrinking effect: this damps shrinking when the heap gets empty.
- size_t _shrink_factor;
-
- size_t _min_heap_delta_bytes; // Minimum amount to expand.
-
- // Some statistics from before gc started.
- // These are gathered in the gc_prologue (and should_collect)
- // to control growing/shrinking policy in spite of promotions.
- size_t _capacity_at_prologue;
- size_t _used_at_prologue;
-
- CardGeneration(ReservedSpace rs, size_t initial_byte_size, int level,
- GenRemSet* remset);
-
- public:
-
- // Attempt to expand the generation by "bytes". Expand by at a
- // minimum "expand_bytes". Return true if some amount (not
- // necessarily the full "bytes") was done.
- virtual bool expand(size_t bytes, size_t expand_bytes);
-
- // Shrink generation with specified size (returns false if unable to shrink)
- virtual void shrink(size_t bytes) = 0;
-
- virtual void compute_new_size();
-
- virtual void clear_remembered_set();
-
- virtual void invalidate_remembered_set();
-
- virtual void prepare_for_verify();
-
- // Grow generation with specified size (returns false if unable to grow)
- virtual bool grow_by(size_t bytes) = 0;
- // Grow generation to reserved size.
- virtual bool grow_to_reserved() = 0;
-};
-
#endif // SHARE_VM_MEMORY_GENERATION_HPP
--- a/hotspot/src/share/vm/memory/metaspace.cpp Tue Dec 23 12:40:06 2014 -0800
+++ b/hotspot/src/share/vm/memory/metaspace.cpp Thu Dec 25 19:46:17 2014 -0800
@@ -3158,7 +3158,25 @@
SharedMiscDataSize = align_size_up(SharedMiscDataSize, max_alignment);
SharedMiscCodeSize = align_size_up(SharedMiscCodeSize, max_alignment);
- // the min_misc_code_size estimate is based on MetaspaceShared::generate_vtable_methods()
+ // make sure SharedReadOnlySize and SharedReadWriteSize are not less than
+ // the minimum values.
+ if (SharedReadOnlySize < MetaspaceShared::min_ro_size){
+ report_out_of_shared_space(SharedReadOnly);
+ }
+
+ if (SharedReadWriteSize < MetaspaceShared::min_rw_size){
+ report_out_of_shared_space(SharedReadWrite);
+ }
+
+ // the min_misc_data_size and min_misc_code_size estimates are based on
+ // MetaspaceShared::generate_vtable_methods()
+ uint min_misc_data_size = align_size_up(
+ MetaspaceShared::num_virtuals * MetaspaceShared::vtbl_list_size * sizeof(void*), max_alignment);
+
+ if (SharedMiscDataSize < min_misc_data_size) {
+ report_out_of_shared_space(SharedMiscData);
+ }
+
uintx min_misc_code_size = align_size_up(
(MetaspaceShared::num_virtuals * MetaspaceShared::vtbl_list_size) *
(sizeof(void*) + MetaspaceShared::vtbl_method_size) + MetaspaceShared::vtbl_common_code_size,
--- a/hotspot/src/share/vm/memory/metaspaceShared.cpp Tue Dec 23 12:40:06 2014 -0800
+++ b/hotspot/src/share/vm/memory/metaspaceShared.cpp Thu Dec 25 19:46:17 2014 -0800
@@ -969,7 +969,7 @@
#endif
// If -Xshare:on is specified, print out the error message and exit VM,
// otherwise, set UseSharedSpaces to false and continue.
- if (RequireSharedSpaces) {
+ if (RequireSharedSpaces || PrintSharedArchiveAndExit) {
vm_exit_during_initialization("Unable to use shared archive.", "Failed map_region for using -Xshare:on.");
} else {
FLAG_SET_DEFAULT(UseSharedSpaces, false);
--- a/hotspot/src/share/vm/memory/metaspaceShared.hpp Tue Dec 23 12:40:06 2014 -0800
+++ b/hotspot/src/share/vm/memory/metaspaceShared.hpp Thu Dec 25 19:46:17 2014 -0800
@@ -70,6 +70,11 @@
};
enum {
+ min_ro_size = NOT_LP64(8*M) LP64_ONLY(9*M), // minimum ro and rw regions sizes based on dumping
+ min_rw_size = NOT_LP64(7*M) LP64_ONLY(12*M) // of a shared archive using the default classlist
+ };
+
+ enum {
ro = 0, // read-only shared space in the heap
rw = 1, // read-write shared space in the heap
md = 2, // miscellaneous data for initializing tables, etc.
--- a/hotspot/src/share/vm/memory/tenuredGeneration.cpp Tue Dec 23 12:40:06 2014 -0800
+++ b/hotspot/src/share/vm/memory/tenuredGeneration.cpp Thu Dec 25 19:46:17 2014 -0800
@@ -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
@@ -235,34 +235,6 @@
return CardGeneration::expand(bytes, expand_bytes);
}
-
-void TenuredGeneration::shrink(size_t bytes) {
- assert_locked_or_safepoint(ExpandHeap_lock);
- size_t size = ReservedSpace::page_align_size_down(bytes);
- if (size > 0) {
- shrink_by(size);
- }
-}
-
-
-size_t TenuredGeneration::capacity() const {
- return _the_space->capacity();
-}
-
-
-size_t TenuredGeneration::used() const {
- return _the_space->used();
-}
-
-
-size_t TenuredGeneration::free() const {
- return _the_space->free();
-}
-
-MemRegion TenuredGeneration::used_region() const {
- return the_space()->used_region();
-}
-
size_t TenuredGeneration::unsafe_max_alloc_nogc() const {
return _the_space->free();
}
@@ -271,74 +243,8 @@
return _the_space->free() + _virtual_space.uncommitted_size();
}
-bool TenuredGeneration::grow_by(size_t bytes) {
+void TenuredGeneration::assert_correct_size_change_locking() {
assert_locked_or_safepoint(ExpandHeap_lock);
- bool result = _virtual_space.expand_by(bytes);
- if (result) {
- size_t new_word_size =
- heap_word_size(_virtual_space.committed_size());
- MemRegion mr(_the_space->bottom(), new_word_size);
- // Expand card table
- Universe::heap()->barrier_set()->resize_covered_region(mr);
- // Expand shared block offset array
- _bts->resize(new_word_size);
-
- // Fix for bug #4668531
- if (ZapUnusedHeapArea) {
- MemRegion mangle_region(_the_space->end(),
- (HeapWord*)_virtual_space.high());
- SpaceMangler::mangle_region(mangle_region);
- }
-
- // Expand space -- also expands space's BOT
- // (which uses (part of) shared array above)
- _the_space->set_end((HeapWord*)_virtual_space.high());
-
- // update the space and generation capacity counters
- update_counters();
-
- if (Verbose && PrintGC) {
- size_t new_mem_size = _virtual_space.committed_size();
- size_t old_mem_size = new_mem_size - bytes;
- gclog_or_tty->print_cr("Expanding %s from " SIZE_FORMAT "K by "
- SIZE_FORMAT "K to " SIZE_FORMAT "K",
- name(), old_mem_size/K, bytes/K, new_mem_size/K);
- }
- }
- return result;
-}
-
-
-bool TenuredGeneration::grow_to_reserved() {
- assert_locked_or_safepoint(ExpandHeap_lock);
- bool success = true;
- const size_t remaining_bytes = _virtual_space.uncommitted_size();
- if (remaining_bytes > 0) {
- success = grow_by(remaining_bytes);
- DEBUG_ONLY(if (!success) warning("grow to reserved failed");)
- }
- return success;
-}
-
-void TenuredGeneration::shrink_by(size_t bytes) {
- assert_locked_or_safepoint(ExpandHeap_lock);
- // Shrink committed space
- _virtual_space.shrink_by(bytes);
- // Shrink space; this also shrinks the space's BOT
- _the_space->set_end((HeapWord*) _virtual_space.high());
- size_t new_word_size = heap_word_size(_the_space->capacity());
- // Shrink the shared block offset array
- _bts->resize(new_word_size);
- MemRegion mr(_the_space->bottom(), new_word_size);
- // Shrink the card table
- Universe::heap()->barrier_set()->resize_covered_region(mr);
-
- if (Verbose && PrintGC) {
- size_t new_mem_size = _virtual_space.committed_size();
- size_t old_mem_size = new_mem_size + bytes;
- gclog_or_tty->print_cr("Shrinking %s from " SIZE_FORMAT "K to " SIZE_FORMAT "K",
- name(), old_mem_size/K, new_mem_size/K);
- }
}
// Currently nothing to do.
@@ -348,27 +254,14 @@
_the_space->object_iterate(blk);
}
-void TenuredGeneration::space_iterate(SpaceClosure* blk,
- bool usedOnly) {
- blk->do_space(_the_space);
-}
-
-void TenuredGeneration::younger_refs_iterate(OopsInGenClosure* blk) {
- blk->set_generation(this);
- younger_refs_in_space_iterate(_the_space, blk);
- blk->reset_generation();
-}
-
void TenuredGeneration::save_marks() {
_the_space->set_saved_mark();
}
-
void TenuredGeneration::reset_saved_marks() {
_the_space->reset_saved_mark();
}
-
bool TenuredGeneration::no_allocs_since_save_marks() {
return _the_space->saved_mark_at_top();
}
@@ -387,28 +280,25 @@
#undef TenuredGen_SINCE_SAVE_MARKS_ITERATE_DEFN
-
void TenuredGeneration::gc_epilogue(bool full) {
- _last_gc = WaterMark(the_space(), the_space()->top());
-
// update the generation and space performance counters
update_counters();
if (ZapUnusedHeapArea) {
- the_space()->check_mangled_unused_area_complete();
+ _the_space->check_mangled_unused_area_complete();
}
}
void TenuredGeneration::record_spaces_top() {
assert(ZapUnusedHeapArea, "Not mangling unused space");
- the_space()->set_top_for_allocations();
+ _the_space->set_top_for_allocations();
}
void TenuredGeneration::verify() {
- the_space()->verify();
+ _the_space->verify();
}
void TenuredGeneration::print_on(outputStream* st) const {
Generation::print_on(st);
st->print(" the");
- the_space()->print_on(st);
+ _the_space->print_on(st);
}
--- a/hotspot/src/share/vm/memory/tenuredGeneration.hpp Tue Dec 23 12:40:06 2014 -0800
+++ b/hotspot/src/share/vm/memory/tenuredGeneration.hpp Thu Dec 25 19:46:17 2014 -0800
@@ -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 @@
#include "gc_implementation/shared/cSpaceCounters.hpp"
#include "gc_implementation/shared/gcStats.hpp"
#include "gc_implementation/shared/generationCounters.hpp"
-#include "memory/generation.hpp"
+#include "memory/cardGeneration.hpp"
#include "utilities/macros.hpp"
// TenuredGeneration models the heap containing old (promoted/tenured) objects
@@ -42,27 +42,18 @@
friend class VM_PopulateDumpSharedSpace;
protected:
- ContiguousSpace* _the_space; // actual space holding objects
- WaterMark _last_gc; // watermark between objects allocated before
- // and after last GC.
+ ContiguousSpace* _the_space; // Actual space holding objects
GenerationCounters* _gen_counters;
CSpaceCounters* _space_counters;
- // Grow generation with specified size (returns false if unable to grow)
- virtual bool grow_by(size_t bytes);
- // Grow generation to reserved size.
- virtual bool grow_to_reserved();
- // Shrink generation with specified size (returns false if unable to shrink)
- void shrink_by(size_t bytes);
-
// Allocation failure
virtual bool expand(size_t bytes, size_t expand_bytes);
- void shrink(size_t bytes);
// Accessing spaces
- ContiguousSpace* the_space() const { return _the_space; }
+ ContiguousSpace* space() const { return _the_space; }
+ void assert_correct_size_change_locking();
public:
TenuredGeneration(ReservedSpace rs, size_t initial_byte_size,
int level, GenRemSet* remset);
@@ -81,33 +72,15 @@
return !ScavengeBeforeFullGC;
}
- inline bool is_in(const void* p) const;
-
- // Space enquiries
- size_t capacity() const;
- size_t used() const;
- size_t free() const;
-
- MemRegion used_region() const;
-
size_t unsafe_max_alloc_nogc() const;
size_t contiguous_available() const;
// Iteration
void object_iterate(ObjectClosure* blk);
- void space_iterate(SpaceClosure* blk, bool usedOnly = false);
-
- void younger_refs_iterate(OopsInGenClosure* blk);
-
- inline CompactibleSpace* first_compaction_space() const;
virtual inline HeapWord* allocate(size_t word_size, bool is_tlab);
virtual inline HeapWord* par_allocate(size_t word_size, bool is_tlab);
- // Accessing marks
- inline WaterMark top_mark();
- inline WaterMark bottom_mark();
-
#define TenuredGen_SINCE_SAVE_MARKS_DECL(OopClosureType, nv_suffix) \
void oop_since_save_marks_iterate##nv_suffix(OopClosureType* cl);
TenuredGen_SINCE_SAVE_MARKS_DECL(OopsInGenClosure,_v)
--- a/hotspot/src/share/vm/memory/tenuredGeneration.inline.hpp Tue Dec 23 12:40:06 2014 -0800
+++ b/hotspot/src/share/vm/memory/tenuredGeneration.inline.hpp Thu Dec 25 19:46:17 2014 -0800
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2000, 2010, 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
@@ -22,53 +22,35 @@
*
*/
-#ifndef SHARE_VM_MEMORY_GENERATION_INLINE_HPP
-#define SHARE_VM_MEMORY_GENERATION_INLINE_HPP
+#ifndef SHARE_VM_MEMORY_TENUREDGENERATION_INLINE_HPP
+#define SHARE_VM_MEMORY_TENUREDGENERATION_INLINE_HPP
-#include "memory/genCollectedHeap.hpp"
#include "memory/space.hpp"
#include "memory/tenuredGeneration.hpp"
-bool TenuredGeneration::is_in(const void* p) const {
- return the_space()->is_in(p);
-}
-
-
-WaterMark TenuredGeneration::top_mark() {
- return the_space()->top_mark();
-}
-
-CompactibleSpace*
-TenuredGeneration::first_compaction_space() const {
- return the_space();
-}
-
HeapWord* TenuredGeneration::allocate(size_t word_size,
bool is_tlab) {
assert(!is_tlab, "TenuredGeneration does not support TLAB allocation");
- return the_space()->allocate(word_size);
+ return _the_space->allocate(word_size);
}
HeapWord* TenuredGeneration::par_allocate(size_t word_size,
bool is_tlab) {
assert(!is_tlab, "TenuredGeneration does not support TLAB allocation");
- return the_space()->par_allocate(word_size);
-}
-
-WaterMark TenuredGeneration::bottom_mark() {
- return the_space()->bottom_mark();
+ return _the_space->par_allocate(word_size);
}
size_t TenuredGeneration::block_size(const HeapWord* addr) const {
- if (addr < the_space()->top()) return oop(addr)->size();
- else {
- assert(addr == the_space()->top(), "non-block head arg to block_size");
- return the_space()->end() - the_space()->top();
+ if (addr < _the_space->top()) {
+ return oop(addr)->size();
+ } else {
+ assert(addr == _the_space->top(), "non-block head arg to block_size");
+ return _the_space->end() - _the_space->top();
}
}
bool TenuredGeneration::block_is_obj(const HeapWord* addr) const {
- return addr < the_space()->top();
+ return addr < _the_space ->top();
}
-#endif // SHARE_VM_MEMORY_GENERATION_INLINE_HPP
+#endif // SHARE_VM_MEMORY_TENUREDGENERATION_INLINE_HPP
--- a/hotspot/src/share/vm/memory/universe.cpp Tue Dec 23 12:40:06 2014 -0800
+++ b/hotspot/src/share/vm/memory/universe.cpp Thu Dec 25 19:46:17 2014 -0800
@@ -120,6 +120,7 @@
oop Universe::_out_of_memory_error_class_metaspace = NULL;
oop Universe::_out_of_memory_error_array_size = NULL;
oop Universe::_out_of_memory_error_gc_overhead_limit = NULL;
+oop Universe::_out_of_memory_error_realloc_objects = NULL;
objArrayOop Universe::_preallocated_out_of_memory_error_array = NULL;
volatile jint Universe::_preallocated_out_of_memory_error_avail_count = 0;
bool Universe::_verify_in_progress = false;
@@ -191,6 +192,7 @@
f->do_oop((oop*)&_out_of_memory_error_class_metaspace);
f->do_oop((oop*)&_out_of_memory_error_array_size);
f->do_oop((oop*)&_out_of_memory_error_gc_overhead_limit);
+ f->do_oop((oop*)&_out_of_memory_error_realloc_objects);
f->do_oop((oop*)&_preallocated_out_of_memory_error_array);
f->do_oop((oop*)&_null_ptr_exception_instance);
f->do_oop((oop*)&_arithmetic_exception_instance);
@@ -575,7 +577,8 @@
(throwable() != Universe::_out_of_memory_error_metaspace) &&
(throwable() != Universe::_out_of_memory_error_class_metaspace) &&
(throwable() != Universe::_out_of_memory_error_array_size) &&
- (throwable() != Universe::_out_of_memory_error_gc_overhead_limit));
+ (throwable() != Universe::_out_of_memory_error_gc_overhead_limit) &&
+ (throwable() != Universe::_out_of_memory_error_realloc_objects));
}
@@ -1039,6 +1042,7 @@
Universe::_out_of_memory_error_array_size = k_h->allocate_instance(CHECK_false);
Universe::_out_of_memory_error_gc_overhead_limit =
k_h->allocate_instance(CHECK_false);
+ Universe::_out_of_memory_error_realloc_objects = k_h->allocate_instance(CHECK_false);
// Setup preallocated NullPointerException
// (this is currently used for a cheap & dirty solution in compiler exception handling)
@@ -1078,6 +1082,9 @@
msg = java_lang_String::create_from_str("GC overhead limit exceeded", CHECK_false);
java_lang_Throwable::set_message(Universe::_out_of_memory_error_gc_overhead_limit, msg());
+ msg = java_lang_String::create_from_str("Java heap space: failed reallocation of scalar replaced objects", CHECK_false);
+ java_lang_Throwable::set_message(Universe::_out_of_memory_error_realloc_objects, msg());
+
msg = java_lang_String::create_from_str("/ by zero", CHECK_false);
java_lang_Throwable::set_message(Universe::_arithmetic_exception_instance, msg());
--- a/hotspot/src/share/vm/memory/universe.hpp Tue Dec 23 12:40:06 2014 -0800
+++ b/hotspot/src/share/vm/memory/universe.hpp Thu Dec 25 19:46:17 2014 -0800
@@ -157,6 +157,7 @@
static oop _out_of_memory_error_class_metaspace;
static oop _out_of_memory_error_array_size;
static oop _out_of_memory_error_gc_overhead_limit;
+ static oop _out_of_memory_error_realloc_objects;
static Array<int>* _the_empty_int_array; // Canonicalized int array
static Array<u2>* _the_empty_short_array; // Canonicalized short array
@@ -328,6 +329,7 @@
static oop out_of_memory_error_class_metaspace() { return gen_out_of_memory_error(_out_of_memory_error_class_metaspace); }
static oop out_of_memory_error_array_size() { return gen_out_of_memory_error(_out_of_memory_error_array_size); }
static oop out_of_memory_error_gc_overhead_limit() { return gen_out_of_memory_error(_out_of_memory_error_gc_overhead_limit); }
+ static oop out_of_memory_error_realloc_objects() { return gen_out_of_memory_error(_out_of_memory_error_realloc_objects); }
// Accessors needed for fast allocation
static Klass** boolArrayKlassObj_addr() { return &_boolArrayKlassObj; }
--- a/hotspot/src/share/vm/oops/cpCache.cpp Tue Dec 23 12:40:06 2014 -0800
+++ b/hotspot/src/share/vm/oops/cpCache.cpp Thu Dec 25 19:46:17 2014 -0800
@@ -287,9 +287,13 @@
// the lock, so that when the losing writer returns, he can use the linked
// cache entry.
- // Use the lock from the metaspace for this, which cannot stop for safepoint.
- Mutex* metaspace_lock = cpool->pool_holder()->class_loader_data()->metaspace_lock();
- MutexLockerEx ml(metaspace_lock, Mutex::_no_safepoint_check_flag);
+ objArrayHandle resolved_references = cpool->resolved_references();
+ // Use the resolved_references() lock for this cpCache entry.
+ // resolved_references are created for all classes with Invokedynamic, MethodHandle
+ // or MethodType constant pool cache entries.
+ assert(resolved_references() != NULL,
+ "a resolved_references array should have been created for this class");
+ ObjectLocker ol(resolved_references, Thread::current());
if (!is_f1_null()) {
return;
}
@@ -336,7 +340,6 @@
// This allows us to create fewer Methods, while keeping type safety.
//
- objArrayHandle resolved_references = cpool->resolved_references();
// Store appendix, if any.
if (has_appendix) {
const int appendix_index = f2_as_index() + _indy_resolved_references_appendix_offset;
--- a/hotspot/src/share/vm/opto/castnode.cpp Tue Dec 23 12:40:06 2014 -0800
+++ b/hotspot/src/share/vm/opto/castnode.cpp Thu Dec 25 19:46:17 2014 -0800
@@ -104,7 +104,8 @@
// Try to improve the type of the CastII if we recognize a CmpI/If
// pattern.
if (_carry_dependency) {
- if (in(0) != NULL && (in(0)->is_IfFalse() || in(0)->is_IfTrue())) {
+ if (in(0) != NULL && in(0)->in(0) != NULL && in(0)->in(0)->is_If()) {
+ assert(in(0)->is_IfFalse() || in(0)->is_IfTrue(), "should be If proj");
Node* proj = in(0);
if (proj->in(0)->in(1)->is_Bool()) {
Node* b = proj->in(0)->in(1);
--- a/hotspot/src/share/vm/opto/ifnode.cpp Tue Dec 23 12:40:06 2014 -0800
+++ b/hotspot/src/share/vm/opto/ifnode.cpp Thu Dec 25 19:46:17 2014 -0800
@@ -820,6 +820,11 @@
static IfNode* idealize_test(PhaseGVN* phase, IfNode* iff);
+struct RangeCheck {
+ Node* ctl;
+ jint off;
+};
+
//------------------------------Ideal------------------------------------------
// Return a node which is more "ideal" than the current node. Strip out
// control copies
@@ -861,83 +866,141 @@
jint offset1;
int flip1 = is_range_check(range1, index1, offset1);
if( flip1 ) {
- Node *first_prev_dom = NULL;
-
// Try to remove extra range checks. All 'up_one_dom' gives up at merges
// so all checks we inspect post-dominate the top-most check we find.
// If we are going to fail the current check and we reach the top check
// then we are guaranteed to fail, so just start interpreting there.
- // We 'expand' the top 2 range checks to include all post-dominating
+ // We 'expand' the top 3 range checks to include all post-dominating
// checks.
- // The top 2 range checks seen
- Node *prev_chk1 = NULL;
- Node *prev_chk2 = NULL;
+ // The top 3 range checks seen
+ const int NRC =3;
+ RangeCheck prev_checks[NRC];
+ int nb_checks = 0;
+
// Low and high offsets seen so far
jint off_lo = offset1;
jint off_hi = offset1;
- // Scan for the top 2 checks and collect range of offsets
- for( int dist = 0; dist < 999; dist++ ) { // Range-Check scan limit
- if( dom->Opcode() == Op_If && // Not same opcode?
- prev_dom->in(0) == dom ) { // One path of test does dominate?
- if( dom == this ) return NULL; // dead loop
+ bool found_immediate_dominator = false;
+
+ // Scan for the top checks and collect range of offsets
+ for (int dist = 0; dist < 999; dist++) { // Range-Check scan limit
+ if (dom->Opcode() == Op_If && // Not same opcode?
+ prev_dom->in(0) == dom) { // One path of test does dominate?
+ if (dom == this) return NULL; // dead loop
// See if this is a range check
Node *index2, *range2;
jint offset2;
int flip2 = dom->as_If()->is_range_check(range2, index2, offset2);
// See if this is a _matching_ range check, checking against
// the same array bounds.
- if( flip2 == flip1 && range2 == range1 && index2 == index1 &&
- dom->outcnt() == 2 ) {
+ if (flip2 == flip1 && range2 == range1 && index2 == index1 &&
+ dom->outcnt() == 2) {
+ if (nb_checks == 0 && dom->in(1) == in(1)) {
+ // Found an immediately dominating test at the same offset.
+ // This kind of back-to-back test can be eliminated locally,
+ // and there is no need to search further for dominating tests.
+ assert(offset2 == offset1, "Same test but different offsets");
+ found_immediate_dominator = true;
+ break;
+ }
// Gather expanded bounds
off_lo = MIN2(off_lo,offset2);
off_hi = MAX2(off_hi,offset2);
- // Record top 2 range checks
- prev_chk2 = prev_chk1;
- prev_chk1 = prev_dom;
- // If we match the test exactly, then the top test covers
- // both our lower and upper bounds.
- if( dom->in(1) == in(1) )
- prev_chk2 = prev_chk1;
+ // Record top NRC range checks
+ prev_checks[nb_checks%NRC].ctl = prev_dom;
+ prev_checks[nb_checks%NRC].off = offset2;
+ nb_checks++;
}
}
prev_dom = dom;
- dom = up_one_dom( dom );
- if( !dom ) break;
+ dom = up_one_dom(dom);
+ if (!dom) break;
}
-
- // Attempt to widen the dominating range check to cover some later
- // ones. Since range checks "fail" by uncommon-trapping to the
- // interpreter, widening a check can make us speculative enter the
- // interpreter. If we see range-check deopt's, do not widen!
- if (!phase->C->allow_range_check_smearing()) return NULL;
+ if (!found_immediate_dominator) {
+ // Attempt to widen the dominating range check to cover some later
+ // ones. Since range checks "fail" by uncommon-trapping to the
+ // interpreter, widening a check can make us speculatively enter
+ // the interpreter. If we see range-check deopt's, do not widen!
+ if (!phase->C->allow_range_check_smearing()) return NULL;
- // Constant indices only need to check the upper bound.
- // Non-constance indices must check both low and high.
- if( index1 ) {
- // Didn't find 2 prior covering checks, so cannot remove anything.
- if( !prev_chk2 ) return NULL;
- // 'Widen' the offsets of the 1st and 2nd covering check
- adjust_check( prev_chk1, range1, index1, flip1, off_lo, igvn );
- // Do not call adjust_check twice on the same projection
- // as the first call may have transformed the BoolNode to a ConI
- if( prev_chk1 != prev_chk2 ) {
- adjust_check( prev_chk2, range1, index1, flip1, off_hi, igvn );
+ // Didn't find prior covering check, so cannot remove anything.
+ if (nb_checks == 0) {
+ return NULL;
}
- // Test is now covered by prior checks, dominate it out
- prev_dom = prev_chk2;
- } else {
- // Didn't find prior covering check, so cannot remove anything.
- if( !prev_chk1 ) return NULL;
- // 'Widen' the offset of the 1st and only covering check
- adjust_check( prev_chk1, range1, index1, flip1, off_hi, igvn );
- // Test is now covered by prior checks, dominate it out
- prev_dom = prev_chk1;
+ // Constant indices only need to check the upper bound.
+ // Non-constant indices must check both low and high.
+ int chk0 = (nb_checks - 1) % NRC;
+ if (index1) {
+ if (nb_checks == 1) {
+ return NULL;
+ } else {
+ // If the top range check's constant is the min or max of
+ // all constants we widen the next one to cover the whole
+ // range of constants.
+ RangeCheck rc0 = prev_checks[chk0];
+ int chk1 = (nb_checks - 2) % NRC;
+ RangeCheck rc1 = prev_checks[chk1];
+ if (rc0.off == off_lo) {
+ adjust_check(rc1.ctl, range1, index1, flip1, off_hi, igvn);
+ prev_dom = rc1.ctl;
+ } else if (rc0.off == off_hi) {
+ adjust_check(rc1.ctl, range1, index1, flip1, off_lo, igvn);
+ prev_dom = rc1.ctl;
+ } else {
+ // If the top test's constant is not the min or max of all
+ // constants, we need 3 range checks. We must leave the
+ // top test unchanged because widening it would allow the
+ // accesses it protects to successfully read/write out of
+ // bounds.
+ if (nb_checks == 2) {
+ return NULL;
+ }
+ int chk2 = (nb_checks - 3) % NRC;
+ RangeCheck rc2 = prev_checks[chk2];
+ // The top range check a+i covers interval: -a <= i < length-a
+ // The second range check b+i covers interval: -b <= i < length-b
+ if (rc1.off <= rc0.off) {
+ // if b <= a, we change the second range check to:
+ // -min_of_all_constants <= i < length-min_of_all_constants
+ // Together top and second range checks now cover:
+ // -min_of_all_constants <= i < length-a
+ // which is more restrictive than -b <= i < length-b:
+ // -b <= -min_of_all_constants <= i < length-a <= length-b
+ // The third check is then changed to:
+ // -max_of_all_constants <= i < length-max_of_all_constants
+ // so 2nd and 3rd checks restrict allowed values of i to:
+ // -min_of_all_constants <= i < length-max_of_all_constants
+ adjust_check(rc1.ctl, range1, index1, flip1, off_lo, igvn);
+ adjust_check(rc2.ctl, range1, index1, flip1, off_hi, igvn);
+ } else {
+ // if b > a, we change the second range check to:
+ // -max_of_all_constants <= i < length-max_of_all_constants
+ // Together top and second range checks now cover:
+ // -a <= i < length-max_of_all_constants
+ // which is more restrictive than -b <= i < length-b:
+ // -b < -a <= i < length-max_of_all_constants <= length-b
+ // The third check is then changed to:
+ // -max_of_all_constants <= i < length-max_of_all_constants
+ // so 2nd and 3rd checks restrict allowed values of i to:
+ // -min_of_all_constants <= i < length-max_of_all_constants
+ adjust_check(rc1.ctl, range1, index1, flip1, off_hi, igvn);
+ adjust_check(rc2.ctl, range1, index1, flip1, off_lo, igvn);
+ }
+ prev_dom = rc2.ctl;
+ }
+ }
+ } else {
+ RangeCheck rc0 = prev_checks[chk0];
+ // 'Widen' the offset of the 1st and only covering check
+ adjust_check(rc0.ctl, range1, index1, flip1, off_hi, igvn);
+ // Test is now covered by prior checks, dominate it out
+ prev_dom = rc0.ctl;
+ }
}
-
} else { // Scan for an equivalent test
Node *cmp;
@@ -1019,7 +1082,7 @@
// for lower and upper bounds.
ProjNode* unc_proj = proj_out(1 - prev_dom->as_Proj()->_con)->as_Proj();
if (unc_proj->is_uncommon_trap_proj(Deoptimization::Reason_predicate))
- prev_dom = idom;
+ prev_dom = idom;
// Now walk the current IfNode's projections.
// Loop ends when 'this' has no more uses.
--- a/hotspot/src/share/vm/opto/loopopts.cpp Tue Dec 23 12:40:06 2014 -0800
+++ b/hotspot/src/share/vm/opto/loopopts.cpp Thu Dec 25 19:46:17 2014 -0800
@@ -241,8 +241,13 @@
ProjNode* dp_proj = dp->as_Proj();
ProjNode* unc_proj = iff->as_If()->proj_out(1 - dp_proj->_con)->as_Proj();
if (exclude_loop_predicate &&
- unc_proj->is_uncommon_trap_proj(Deoptimization::Reason_predicate))
+ (unc_proj->is_uncommon_trap_proj(Deoptimization::Reason_predicate) ||
+ unc_proj->is_uncommon_trap_proj(Deoptimization::Reason_range_check))) {
+ // If this is a range check (IfNode::is_range_check), do not
+ // reorder because Compile::allow_range_check_smearing might have
+ // changed the check.
return; // Let IGVN transformation change control dependence.
+ }
IdealLoopTree *old_loop = get_loop(dp);
@@ -898,23 +903,23 @@
int n_op = n->Opcode();
// Check for an IF being dominated by another IF same test
- if( n_op == Op_If ) {
+ if (n_op == Op_If) {
Node *bol = n->in(1);
uint max = bol->outcnt();
// Check for same test used more than once?
- if( n_op == Op_If && max > 1 && bol->is_Bool() ) {
+ if (max > 1 && bol->is_Bool()) {
// Search up IDOMs to see if this IF is dominated.
Node *cutoff = get_ctrl(bol);
// Now search up IDOMs till cutoff, looking for a dominating test
Node *prevdom = n;
Node *dom = idom(prevdom);
- while( dom != cutoff ) {
- if( dom->req() > 1 && dom->in(1) == bol && prevdom->in(0) == dom ) {
+ while (dom != cutoff) {
+ if (dom->req() > 1 && dom->in(1) == bol && prevdom->in(0) == dom) {
// Replace the dominated test with an obvious true or false.
// Place it on the IGVN worklist for later cleanup.
C->set_major_progress();
- dominated_by( prevdom, n, false, true );
+ dominated_by(prevdom, n, false, true);
#ifndef PRODUCT
if( VerifyLoopOptimizations ) verify();
#endif
--- a/hotspot/src/share/vm/opto/macro.cpp Tue Dec 23 12:40:06 2014 -0800
+++ b/hotspot/src/share/vm/opto/macro.cpp Thu Dec 25 19:46:17 2014 -0800
@@ -971,7 +971,11 @@
}
bool PhaseMacroExpand::eliminate_allocate_node(AllocateNode *alloc) {
- if (!EliminateAllocations || !alloc->_is_non_escaping) {
+ // Don't do scalar replacement if the frame can be popped by JVMTI:
+ // if reallocation fails during deoptimization we'll pop all
+ // interpreter frames for this compiled frame and that won't play
+ // nice with JVMTI popframe.
+ if (!EliminateAllocations || JvmtiExport::can_pop_frame() || !alloc->_is_non_escaping) {
return false;
}
Node* klass = alloc->in(AllocateNode::KlassNode);
--- a/hotspot/src/share/vm/prims/whitebox.hpp Tue Dec 23 12:40:06 2014 -0800
+++ b/hotspot/src/share/vm/prims/whitebox.hpp Thu Dec 25 19:46:17 2014 -0800
@@ -74,7 +74,7 @@
static JavaThread* create_sweeper_thread(TRAPS);
static int get_blob_type(const CodeBlob* code);
static CodeHeap* get_code_heap(int blob_type);
- static CodeBlob* allocate_code_blob(int blob_type, int size);
+ static CodeBlob* allocate_code_blob(int size, int blob_type);
static int array_bytes_to_length(size_t bytes);
static void register_methods(JNIEnv* env, jclass wbclass, JavaThread* thread,
JNINativeMethod* method_array, int method_count);
--- a/hotspot/src/share/vm/runtime/arguments.cpp Tue Dec 23 12:40:06 2014 -0800
+++ b/hotspot/src/share/vm/runtime/arguments.cpp Thu Dec 25 19:46:17 2014 -0800
@@ -125,8 +125,8 @@
char* Arguments::_meta_index_dir = NULL;
char* Arguments::_ext_dirs = NULL;
-// Check if head of 'option' matches 'name', and sets 'tail' remaining part of option string
-
+// Check if head of 'option' matches 'name', and sets 'tail' to the remaining
+// part of the option string.
static bool match_option(const JavaVMOption *option, const char* name,
const char** tail) {
int len = (int)strlen(name);
@@ -138,6 +138,32 @@
}
}
+// Check if 'option' matches 'name'. No "tail" is allowed.
+static bool match_option(const JavaVMOption *option, const char* name) {
+ const char* tail = NULL;
+ bool result = match_option(option, name, &tail);
+ if (tail != NULL && *tail == '\0') {
+ return result;
+ } else {
+ return false;
+ }
+}
+
+// Return true if any of the strings in null-terminated array 'names' matches.
+// If tail_allowed is true, then the tail must begin with a colon; otherwise,
+// the option must match exactly.
+static bool match_option(const JavaVMOption* option, const char** names, const char** tail,
+ bool tail_allowed) {
+ for (/* empty */; *names != NULL; ++names) {
+ if (match_option(option, *names, tail)) {
+ if (**tail == '\0' || tail_allowed && **tail == ':') {
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
static void logOption(const char* opt) {
if (PrintVMOptions) {
jio_fprintf(defaultStream::output_stream(), "VM option '%s'\n", opt);
@@ -2526,21 +2552,6 @@
"-dsa", "-esa", "-disablesystemassertions", "-enablesystemassertions", 0
};
-// Return true if any of the strings in null-terminated array 'names' matches.
-// If tail_allowed is true, then the tail must begin with a colon; otherwise,
-// the option must match exactly.
-static bool match_option(const JavaVMOption* option, const char** names, const char** tail,
- bool tail_allowed) {
- for (/* empty */; *names != NULL; ++names) {
- if (match_option(option, *names, tail)) {
- if (**tail == '\0' || tail_allowed && **tail == ':') {
- return true;
- }
- }
- }
- return false;
-}
-
bool Arguments::parse_uintx(const char* value,
uintx* uintx_arg,
uintx min_size) {
@@ -2782,16 +2793,16 @@
}
#endif // !INCLUDE_JVMTI
// -Xnoclassgc
- } else if (match_option(option, "-Xnoclassgc", &tail)) {
+ } else if (match_option(option, "-Xnoclassgc")) {
FLAG_SET_CMDLINE(bool, ClassUnloading, false);
// -Xconcgc
- } else if (match_option(option, "-Xconcgc", &tail)) {
+ } else if (match_option(option, "-Xconcgc")) {
FLAG_SET_CMDLINE(bool, UseConcMarkSweepGC, true);
// -Xnoconcgc
- } else if (match_option(option, "-Xnoconcgc", &tail)) {
+ } else if (match_option(option, "-Xnoconcgc")) {
FLAG_SET_CMDLINE(bool, UseConcMarkSweepGC, false);
// -Xbatch
- } else if (match_option(option, "-Xbatch", &tail)) {
+ } else if (match_option(option, "-Xbatch")) {
FLAG_SET_CMDLINE(bool, BackgroundCompilation, false);
// -Xmn for compatibility with other JVM vendors
} else if (match_option(option, "-Xmn", &tail)) {
@@ -2936,28 +2947,28 @@
}
FLAG_SET_CMDLINE(uintx, IncreaseFirstTierCompileThresholdAt, (uintx)uint_IncreaseFirstTierCompileThresholdAt);
// -green
- } else if (match_option(option, "-green", &tail)) {
+ } else if (match_option(option, "-green")) {
jio_fprintf(defaultStream::error_stream(),
"Green threads support not available\n");
return JNI_EINVAL;
// -native
- } else if (match_option(option, "-native", &tail)) {
+ } else if (match_option(option, "-native")) {
// HotSpot always uses native threads, ignore silently for compatibility
// -Xsqnopause
- } else if (match_option(option, "-Xsqnopause", &tail)) {
+ } else if (match_option(option, "-Xsqnopause")) {
// EVM option, ignore silently for compatibility
// -Xrs
- } else if (match_option(option, "-Xrs", &tail)) {
+ } else if (match_option(option, "-Xrs")) {
// Classic/EVM option, new functionality
FLAG_SET_CMDLINE(bool, ReduceSignalUsage, true);
- } else if (match_option(option, "-Xusealtsigs", &tail)) {
+ } else if (match_option(option, "-Xusealtsigs")) {
// change default internal VM signals used - lower case for back compat
FLAG_SET_CMDLINE(bool, UseAltSigs, true);
// -Xoptimize
- } else if (match_option(option, "-Xoptimize", &tail)) {
+ } else if (match_option(option, "-Xoptimize")) {
// EVM option, ignore silently for compatibility
// -Xprof
- } else if (match_option(option, "-Xprof", &tail)) {
+ } else if (match_option(option, "-Xprof")) {
#if INCLUDE_FPROF
_has_profile = true;
#else // INCLUDE_FPROF
@@ -2966,7 +2977,7 @@
return JNI_ERR;
#endif // INCLUDE_FPROF
// -Xconcurrentio
- } else if (match_option(option, "-Xconcurrentio", &tail)) {
+ } else if (match_option(option, "-Xconcurrentio")) {
FLAG_SET_CMDLINE(bool, UseLWPSynchronization, true);
FLAG_SET_CMDLINE(bool, BackgroundCompilation, false);
FLAG_SET_CMDLINE(intx, DeferThrSuspendLoopCount, 1);
@@ -2974,13 +2985,13 @@
FLAG_SET_CMDLINE(uintx, NewSizeThreadIncrease, 16 * K); // 20Kb per thread added to new generation
// -Xinternalversion
- } else if (match_option(option, "-Xinternalversion", &tail)) {
+ } else if (match_option(option, "-Xinternalversion")) {
jio_fprintf(defaultStream::output_stream(), "%s\n",
VM_Version::internal_vm_info_string());
vm_exit(0);
#ifndef PRODUCT
// -Xprintflags
- } else if (match_option(option, "-Xprintflags", &tail)) {
+ } else if (match_option(option, "-Xprintflags")) {
CommandLineFlags::printFlags(tty, false);
vm_exit(0);
#endif
@@ -3014,29 +3025,29 @@
#endif
}
// -Xint
- } else if (match_option(option, "-Xint", &tail)) {
+ } else if (match_option(option, "-Xint")) {
set_mode_flags(_int);
// -Xmixed
- } else if (match_option(option, "-Xmixed", &tail)) {
+ } else if (match_option(option, "-Xmixed")) {
set_mode_flags(_mixed);
// -Xcomp
- } else if (match_option(option, "-Xcomp", &tail)) {
+ } else if (match_option(option, "-Xcomp")) {
// for testing the compiler; turn off all flags that inhibit compilation
set_mode_flags(_comp);
// -Xshare:dump
- } else if (match_option(option, "-Xshare:dump", &tail)) {
+ } else if (match_option(option, "-Xshare:dump")) {
FLAG_SET_CMDLINE(bool, DumpSharedSpaces, true);
set_mode_flags(_int); // Prevent compilation, which creates objects
// -Xshare:on
- } else if (match_option(option, "-Xshare:on", &tail)) {
+ } else if (match_option(option, "-Xshare:on")) {
FLAG_SET_CMDLINE(bool, UseSharedSpaces, true);
FLAG_SET_CMDLINE(bool, RequireSharedSpaces, true);
// -Xshare:auto
- } else if (match_option(option, "-Xshare:auto", &tail)) {
+ } else if (match_option(option, "-Xshare:auto")) {
FLAG_SET_CMDLINE(bool, UseSharedSpaces, true);
FLAG_SET_CMDLINE(bool, RequireSharedSpaces, false);
// -Xshare:off
- } else if (match_option(option, "-Xshare:off", &tail)) {
+ } else if (match_option(option, "-Xshare:off")) {
FLAG_SET_CMDLINE(bool, UseSharedSpaces, false);
FLAG_SET_CMDLINE(bool, RequireSharedSpaces, false);
// -Xverify
@@ -3054,13 +3065,13 @@
return JNI_EINVAL;
}
// -Xdebug
- } else if (match_option(option, "-Xdebug", &tail)) {
+ } else if (match_option(option, "-Xdebug")) {
// note this flag has been used, then ignore
set_xdebug_mode(true);
// -Xnoagent
- } else if (match_option(option, "-Xnoagent", &tail)) {
+ } else if (match_option(option, "-Xnoagent")) {
// For compatibility with classic. HotSpot refuses to load the old style agent.dll.
- } else if (match_option(option, "-Xboundthreads", &tail)) {
+ } else if (match_option(option, "-Xboundthreads")) {
// Bind user level threads to kernel threads (Solaris only)
FLAG_SET_CMDLINE(bool, UseBoundThreads, true);
} else if (match_option(option, "-Xloggc:", &tail)) {
@@ -3090,14 +3101,14 @@
"check")) {
return JNI_EINVAL;
}
- } else if (match_option(option, "vfprintf", &tail)) {
+ } else if (match_option(option, "vfprintf")) {
_vfprintf_hook = CAST_TO_FN_PTR(vfprintf_hook_t, option->extraInfo);
- } else if (match_option(option, "exit", &tail)) {
+ } else if (match_option(option, "exit")) {
_exit_hook = CAST_TO_FN_PTR(exit_hook_t, option->extraInfo);
- } else if (match_option(option, "abort", &tail)) {
+ } else if (match_option(option, "abort")) {
_abort_hook = CAST_TO_FN_PTR(abort_hook_t, option->extraInfo);
// -XX:+AggressiveHeap
- } else if (match_option(option, "-XX:+AggressiveHeap", &tail)) {
+ } else if (match_option(option, "-XX:+AggressiveHeap")) {
// This option inspects the machine and attempts to set various
// parameters to be optimal for long-running, memory allocation
@@ -3188,11 +3199,11 @@
// Need to keep consistency of MaxTenuringThreshold and AlwaysTenure/NeverTenure;
// and the last option wins.
- } else if (match_option(option, "-XX:+NeverTenure", &tail)) {
+ } else if (match_option(option, "-XX:+NeverTenure")) {
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)) {
+ } else if (match_option(option, "-XX:+AlwaysTenure")) {
FLAG_SET_CMDLINE(bool, NeverTenure, false);
FLAG_SET_CMDLINE(bool, AlwaysTenure, true);
FLAG_SET_CMDLINE(uintx, MaxTenuringThreshold, 0);
@@ -3211,17 +3222,17 @@
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)) {
+ } else if (match_option(option, "-XX:+CMSPermGenSweepingEnabled") ||
+ match_option(option, "-XX:-CMSPermGenSweepingEnabled")) {
jio_fprintf(defaultStream::error_stream(),
"Please use CMSClassUnloadingEnabled in place of "
"CMSPermGenSweepingEnabled in the future\n");
- } else if (match_option(option, "-XX:+UseGCTimeLimit", &tail)) {
+ } else if (match_option(option, "-XX:+UseGCTimeLimit")) {
FLAG_SET_CMDLINE(bool, UseGCOverheadLimit, true);
jio_fprintf(defaultStream::error_stream(),
"Please use -XX:+UseGCOverheadLimit in place of "
"-XX:+UseGCTimeLimit in the future\n");
- } else if (match_option(option, "-XX:-UseGCTimeLimit", &tail)) {
+ } else if (match_option(option, "-XX:-UseGCTimeLimit")) {
FLAG_SET_CMDLINE(bool, UseGCOverheadLimit, false);
jio_fprintf(defaultStream::error_stream(),
"Please use -XX:-UseGCOverheadLimit in place of "
@@ -3231,13 +3242,13 @@
// are not to be documented.
} else if (match_option(option, "-XX:MaxTLERatio=", &tail)) {
// No longer used.
- } else if (match_option(option, "-XX:+ResizeTLE", &tail)) {
+ } else if (match_option(option, "-XX:+ResizeTLE")) {
FLAG_SET_CMDLINE(bool, ResizeTLAB, true);
- } else if (match_option(option, "-XX:-ResizeTLE", &tail)) {
+ } else if (match_option(option, "-XX:-ResizeTLE")) {
FLAG_SET_CMDLINE(bool, ResizeTLAB, false);
- } else if (match_option(option, "-XX:+PrintTLE", &tail)) {
+ } else if (match_option(option, "-XX:+PrintTLE")) {
FLAG_SET_CMDLINE(bool, PrintTLAB, true);
- } else if (match_option(option, "-XX:-PrintTLE", &tail)) {
+ } else if (match_option(option, "-XX:-PrintTLE")) {
FLAG_SET_CMDLINE(bool, PrintTLAB, false);
} else if (match_option(option, "-XX:TLEFragmentationRatio=", &tail)) {
// No longer used.
@@ -3253,17 +3264,17 @@
FLAG_SET_CMDLINE(uintx, TLABSize, long_tlab_size);
} else if (match_option(option, "-XX:TLEThreadRatio=", &tail)) {
// No longer used.
- } else if (match_option(option, "-XX:+UseTLE", &tail)) {
+ } else if (match_option(option, "-XX:+UseTLE")) {
FLAG_SET_CMDLINE(bool, UseTLAB, true);
- } else if (match_option(option, "-XX:-UseTLE", &tail)) {
+ } else if (match_option(option, "-XX:-UseTLE")) {
FLAG_SET_CMDLINE(bool, UseTLAB, false);
- } else if (match_option(option, "-XX:+DisplayVMOutputToStderr", &tail)) {
+ } else if (match_option(option, "-XX:+DisplayVMOutputToStderr")) {
FLAG_SET_CMDLINE(bool, DisplayVMOutputToStdout, false);
FLAG_SET_CMDLINE(bool, DisplayVMOutputToStderr, true);
- } else if (match_option(option, "-XX:+DisplayVMOutputToStdout", &tail)) {
+ } else if (match_option(option, "-XX:+DisplayVMOutputToStdout")) {
FLAG_SET_CMDLINE(bool, DisplayVMOutputToStderr, false);
FLAG_SET_CMDLINE(bool, DisplayVMOutputToStdout, true);
- } else if (match_option(option, "-XX:+ExtendedDTraceProbes", &tail)) {
+ } else if (match_option(option, "-XX:+ExtendedDTraceProbes")) {
#if defined(DTRACE_ENABLED)
FLAG_SET_CMDLINE(bool, ExtendedDTraceProbes, true);
FLAG_SET_CMDLINE(bool, DTraceMethodProbes, true);
@@ -3275,7 +3286,7 @@
return JNI_EINVAL;
#endif // defined(DTRACE_ENABLED)
#ifdef ASSERT
- } else if (match_option(option, "-XX:+FullGCALot", &tail)) {
+ } else if (match_option(option, "-XX:+FullGCALot")) {
FLAG_SET_CMDLINE(bool, FullGCALot, true);
// disable scavenge before parallel mark-compact
FLAG_SET_CMDLINE(bool, ScavengeBeforeFullGC, false);
@@ -3361,7 +3372,7 @@
}
FLAG_SET_CMDLINE(uintx, MaxDirectMemorySize, max_direct_memory_size);
#if !INCLUDE_MANAGEMENT
- } else if (match_option(option, "-XX:+ManagementServer", &tail)) {
+ } else if (match_option(option, "-XX:+ManagementServer")) {
jio_fprintf(defaultStream::error_stream(),
"ManagementServer is not supported in this VM.\n");
return JNI_ERR;
@@ -3796,23 +3807,23 @@
settings_file_specified = true;
continue;
}
- if (match_option(option, "-XX:+PrintVMOptions", &tail)) {
+ if (match_option(option, "-XX:+PrintVMOptions")) {
PrintVMOptions = true;
continue;
}
- if (match_option(option, "-XX:-PrintVMOptions", &tail)) {
+ if (match_option(option, "-XX:-PrintVMOptions")) {
PrintVMOptions = false;
continue;
}
- if (match_option(option, "-XX:+IgnoreUnrecognizedVMOptions", &tail)) {
+ if (match_option(option, "-XX:+IgnoreUnrecognizedVMOptions")) {
IgnoreUnrecognizedVMOptions = true;
continue;
}
- if (match_option(option, "-XX:-IgnoreUnrecognizedVMOptions", &tail)) {
+ if (match_option(option, "-XX:-IgnoreUnrecognizedVMOptions")) {
IgnoreUnrecognizedVMOptions = false;
continue;
}
- if (match_option(option, "-XX:+PrintFlagsInitial", &tail)) {
+ if (match_option(option, "-XX:+PrintFlagsInitial")) {
CommandLineFlags::printFlags(tty, false);
vm_exit(0);
}
@@ -3838,7 +3849,7 @@
#ifndef PRODUCT
- if (match_option(option, "-XX:+PrintFlagsWithComments", &tail)) {
+ if (match_option(option, "-XX:+PrintFlagsWithComments")) {
CommandLineFlags::printFlags(tty, true);
vm_exit(0);
}
--- a/hotspot/src/share/vm/runtime/deoptimization.cpp Tue Dec 23 12:40:06 2014 -0800
+++ b/hotspot/src/share/vm/runtime/deoptimization.cpp Thu Dec 25 19:46:17 2014 -0800
@@ -176,6 +176,8 @@
assert(vf->is_compiled_frame(), "Wrong frame type");
chunk->push(compiledVFrame::cast(vf));
+ bool realloc_failures = false;
+
#ifdef COMPILER2
// Reallocate the non-escaping objects and restore their fields. Then
// relock objects if synchronization on them was eliminated.
@@ -206,19 +208,16 @@
tty->print_cr("SAVED OOP RESULT " INTPTR_FORMAT " in thread " INTPTR_FORMAT, (void *)result, thread);
}
}
- bool reallocated = false;
if (objects != NULL) {
JRT_BLOCK
- reallocated = realloc_objects(thread, &deoptee, objects, THREAD);
+ realloc_failures = realloc_objects(thread, &deoptee, objects, THREAD);
JRT_END
- }
- if (reallocated) {
- reassign_fields(&deoptee, &map, objects);
+ reassign_fields(&deoptee, &map, objects, realloc_failures);
#ifndef PRODUCT
if (TraceDeoptimization) {
ttyLocker ttyl;
tty->print_cr("REALLOC OBJECTS in thread " INTPTR_FORMAT, thread);
- print_objects(objects);
+ print_objects(objects, realloc_failures);
}
#endif
}
@@ -236,7 +235,7 @@
assert (cvf->scope() != NULL,"expect only compiled java frames");
GrowableArray<MonitorInfo*>* monitors = cvf->monitors();
if (monitors->is_nonempty()) {
- relock_objects(monitors, thread);
+ relock_objects(monitors, thread, realloc_failures);
#ifndef PRODUCT
if (TraceDeoptimization) {
ttyLocker ttyl;
@@ -247,7 +246,12 @@
first = false;
tty->print_cr("RELOCK OBJECTS in thread " INTPTR_FORMAT, thread);
}
- tty->print_cr(" object <" INTPTR_FORMAT "> locked", (void *)mi->owner());
+ if (mi->owner_is_scalar_replaced()) {
+ Klass* k = java_lang_Class::as_Klass(mi->owner_klass());
+ tty->print_cr(" failed reallocation for klass %s", k->external_name());
+ } else {
+ tty->print_cr(" object <" INTPTR_FORMAT "> locked", (void *)mi->owner());
+ }
}
}
}
@@ -262,9 +266,14 @@
// out the java state residing in the vframeArray will be missed.
No_Safepoint_Verifier no_safepoint;
- vframeArray* array = create_vframeArray(thread, deoptee, &map, chunk);
+ vframeArray* array = create_vframeArray(thread, deoptee, &map, chunk, realloc_failures);
+#ifdef COMPILER2
+ if (realloc_failures) {
+ pop_frames_failed_reallocs(thread, array);
+ }
+#endif
- assert(thread->vframe_array_head() == NULL, "Pending deopt!");;
+ assert(thread->vframe_array_head() == NULL, "Pending deopt!");
thread->set_vframe_array_head(array);
// Now that the vframeArray has been created if we have any deferred local writes
@@ -718,6 +727,8 @@
int exception_line = thread->exception_line();
thread->clear_pending_exception();
+ bool failures = false;
+
for (int i = 0; i < objects->length(); i++) {
assert(objects->at(i)->is_object(), "invalid debug information");
ObjectValue* sv = (ObjectValue*) objects->at(i);
@@ -727,27 +738,34 @@
if (k->oop_is_instance()) {
InstanceKlass* ik = InstanceKlass::cast(k());
- obj = ik->allocate_instance(CHECK_(false));
+ obj = ik->allocate_instance(THREAD);
} else if (k->oop_is_typeArray()) {
TypeArrayKlass* ak = TypeArrayKlass::cast(k());
assert(sv->field_size() % type2size[ak->element_type()] == 0, "non-integral array length");
int len = sv->field_size() / type2size[ak->element_type()];
- obj = ak->allocate(len, CHECK_(false));
+ obj = ak->allocate(len, THREAD);
} else if (k->oop_is_objArray()) {
ObjArrayKlass* ak = ObjArrayKlass::cast(k());
- obj = ak->allocate(sv->field_size(), CHECK_(false));
+ obj = ak->allocate(sv->field_size(), THREAD);
}
- assert(obj != NULL, "allocation failed");
+ if (obj == NULL) {
+ failures = true;
+ }
+
assert(sv->value().is_null(), "redundant reallocation");
+ assert(obj != NULL || HAS_PENDING_EXCEPTION, "allocation should succeed or we should get an exception");
+ CLEAR_PENDING_EXCEPTION;
sv->set_value(obj);
}
- if (pending_exception.not_null()) {
+ if (failures) {
+ THROW_OOP_(Universe::out_of_memory_error_realloc_objects(), failures);
+ } else if (pending_exception.not_null()) {
thread->set_pending_exception(pending_exception(), exception_file, exception_line);
}
- return true;
+ return failures;
}
// This assumes that the fields are stored in ObjectValue in the same order
@@ -885,12 +903,15 @@
// restore fields of all eliminated objects and arrays
-void Deoptimization::reassign_fields(frame* fr, RegisterMap* reg_map, GrowableArray<ScopeValue*>* objects) {
+void Deoptimization::reassign_fields(frame* fr, RegisterMap* reg_map, GrowableArray<ScopeValue*>* objects, bool realloc_failures) {
for (int i = 0; i < objects->length(); i++) {
ObjectValue* sv = (ObjectValue*) objects->at(i);
KlassHandle k(java_lang_Class::as_Klass(sv->klass()->as_ConstantOopReadValue()->value()()));
Handle obj = sv->value();
- assert(obj.not_null(), "reallocation was missed");
+ assert(obj.not_null() || realloc_failures, "reallocation was missed");
+ if (obj.is_null()) {
+ continue;
+ }
if (k->oop_is_instance()) {
InstanceKlass* ik = InstanceKlass::cast(k());
@@ -907,34 +928,36 @@
// relock objects for which synchronization was eliminated
-void Deoptimization::relock_objects(GrowableArray<MonitorInfo*>* monitors, JavaThread* thread) {
+void Deoptimization::relock_objects(GrowableArray<MonitorInfo*>* monitors, JavaThread* thread, bool realloc_failures) {
for (int i = 0; i < monitors->length(); i++) {
MonitorInfo* mon_info = monitors->at(i);
if (mon_info->eliminated()) {
- assert(mon_info->owner() != NULL, "reallocation was missed");
- Handle obj = Handle(mon_info->owner());
- markOop mark = obj->mark();
- if (UseBiasedLocking && mark->has_bias_pattern()) {
- // New allocated objects may have the mark set to anonymously biased.
- // Also the deoptimized method may called methods with synchronization
- // where the thread-local object is bias locked to the current thread.
- assert(mark->is_biased_anonymously() ||
- mark->biased_locker() == thread, "should be locked to current thread");
- // Reset mark word to unbiased prototype.
- markOop unbiased_prototype = markOopDesc::prototype()->set_age(mark->age());
- obj->set_mark(unbiased_prototype);
+ assert(!mon_info->owner_is_scalar_replaced() || realloc_failures, "reallocation was missed");
+ if (!mon_info->owner_is_scalar_replaced()) {
+ Handle obj = Handle(mon_info->owner());
+ markOop mark = obj->mark();
+ if (UseBiasedLocking && mark->has_bias_pattern()) {
+ // New allocated objects may have the mark set to anonymously biased.
+ // Also the deoptimized method may called methods with synchronization
+ // where the thread-local object is bias locked to the current thread.
+ assert(mark->is_biased_anonymously() ||
+ mark->biased_locker() == thread, "should be locked to current thread");
+ // Reset mark word to unbiased prototype.
+ markOop unbiased_prototype = markOopDesc::prototype()->set_age(mark->age());
+ obj->set_mark(unbiased_prototype);
+ }
+ BasicLock* lock = mon_info->lock();
+ ObjectSynchronizer::slow_enter(obj, lock, thread);
+ assert(mon_info->owner()->is_locked(), "object must be locked now");
}
- BasicLock* lock = mon_info->lock();
- ObjectSynchronizer::slow_enter(obj, lock, thread);
}
- assert(mon_info->owner()->is_locked(), "object must be locked now");
}
}
#ifndef PRODUCT
// print information about reallocated objects
-void Deoptimization::print_objects(GrowableArray<ScopeValue*>* objects) {
+void Deoptimization::print_objects(GrowableArray<ScopeValue*>* objects, bool realloc_failures) {
fieldDescriptor fd;
for (int i = 0; i < objects->length(); i++) {
@@ -944,10 +967,15 @@
tty->print(" object <" INTPTR_FORMAT "> of type ", (void *)sv->value()());
k->print_value();
- tty->print(" allocated (%d bytes)", obj->size() * HeapWordSize);
+ assert(obj.not_null() || realloc_failures, "reallocation was missed");
+ if (obj.is_null()) {
+ tty->print(" allocation failed");
+ } else {
+ tty->print(" allocated (%d bytes)", obj->size() * HeapWordSize);
+ }
tty->cr();
- if (Verbose) {
+ if (Verbose && !obj.is_null()) {
k->oop_print_on(obj(), tty);
}
}
@@ -955,7 +983,7 @@
#endif
#endif // COMPILER2
-vframeArray* Deoptimization::create_vframeArray(JavaThread* thread, frame fr, RegisterMap *reg_map, GrowableArray<compiledVFrame*>* chunk) {
+vframeArray* Deoptimization::create_vframeArray(JavaThread* thread, frame fr, RegisterMap *reg_map, GrowableArray<compiledVFrame*>* chunk, bool realloc_failures) {
Events::log(thread, "DEOPT PACKING pc=" INTPTR_FORMAT " sp=" INTPTR_FORMAT, fr.pc(), fr.sp());
#ifndef PRODUCT
@@ -998,7 +1026,7 @@
// Since the Java thread being deoptimized will eventually adjust it's own stack,
// the vframeArray containing the unpacking information is allocated in the C heap.
// For Compiler1, the caller of the deoptimized frame is saved for use by unpack_frames().
- vframeArray* array = vframeArray::allocate(thread, frame_size, chunk, reg_map, sender, caller, fr);
+ vframeArray* array = vframeArray::allocate(thread, frame_size, chunk, reg_map, sender, caller, fr, realloc_failures);
// Compare the vframeArray to the collected vframes
assert(array->structural_compare(thread, chunk), "just checking");
@@ -1013,6 +1041,33 @@
return array;
}
+#ifdef COMPILER2
+void Deoptimization::pop_frames_failed_reallocs(JavaThread* thread, vframeArray* array) {
+ // Reallocation of some scalar replaced objects failed. Record
+ // that we need to pop all the interpreter frames for the
+ // deoptimized compiled frame.
+ assert(thread->frames_to_pop_failed_realloc() == 0, "missed frames to pop?");
+ thread->set_frames_to_pop_failed_realloc(array->frames());
+ // Unlock all monitors here otherwise the interpreter will see a
+ // mix of locked and unlocked monitors (because of failed
+ // reallocations of synchronized objects) and be confused.
+ for (int i = 0; i < array->frames(); i++) {
+ MonitorChunk* monitors = array->element(i)->monitors();
+ if (monitors != NULL) {
+ for (int j = 0; j < monitors->number_of_monitors(); j++) {
+ BasicObjectLock* src = monitors->at(j);
+ if (src->obj() != NULL) {
+ ObjectSynchronizer::fast_exit(src->obj(), src->lock(), thread);
+ }
+ }
+ array->element(i)->free_monitors(thread);
+#ifdef ASSERT
+ array->element(i)->set_removed_monitors();
+#endif
+ }
+ }
+}
+#endif
static void collect_monitors(compiledVFrame* cvf, GrowableArray<Handle>* objects_to_revoke) {
GrowableArray<MonitorInfo*>* monitors = cvf->monitors();
--- a/hotspot/src/share/vm/runtime/deoptimization.hpp Tue Dec 23 12:40:06 2014 -0800
+++ b/hotspot/src/share/vm/runtime/deoptimization.hpp Thu Dec 25 19:46:17 2014 -0800
@@ -125,13 +125,14 @@
static bool realloc_objects(JavaThread* thread, frame* fr, GrowableArray<ScopeValue*>* objects, TRAPS);
static void reassign_type_array_elements(frame* fr, RegisterMap* reg_map, ObjectValue* sv, typeArrayOop obj, BasicType type);
static void reassign_object_array_elements(frame* fr, RegisterMap* reg_map, ObjectValue* sv, objArrayOop obj);
- static void reassign_fields(frame* fr, RegisterMap* reg_map, GrowableArray<ScopeValue*>* objects);
- static void relock_objects(GrowableArray<MonitorInfo*>* monitors, JavaThread* thread);
- NOT_PRODUCT(static void print_objects(GrowableArray<ScopeValue*>* objects);)
+ static void reassign_fields(frame* fr, RegisterMap* reg_map, GrowableArray<ScopeValue*>* objects, bool realloc_failures);
+ static void relock_objects(GrowableArray<MonitorInfo*>* monitors, JavaThread* thread, bool realloc_failures);
+ static void pop_frames_failed_reallocs(JavaThread* thread, vframeArray* array);
+ NOT_PRODUCT(static void print_objects(GrowableArray<ScopeValue*>* objects, bool realloc_failures);)
#endif // COMPILER2
public:
- static vframeArray* create_vframeArray(JavaThread* thread, frame fr, RegisterMap *reg_map, GrowableArray<compiledVFrame*>* chunk);
+ static vframeArray* create_vframeArray(JavaThread* thread, frame fr, RegisterMap *reg_map, GrowableArray<compiledVFrame*>* chunk, bool realloc_failures);
// Interface used for unpacking deoptimized frames
--- a/hotspot/src/share/vm/runtime/sharedRuntime.cpp Tue Dec 23 12:40:06 2014 -0800
+++ b/hotspot/src/share/vm/runtime/sharedRuntime.cpp Thu Dec 25 19:46:17 2014 -0800
@@ -456,6 +456,7 @@
address SharedRuntime::raw_exception_handler_for_return_address(JavaThread* thread, address return_address) {
assert(frame::verify_return_pc(return_address), err_msg("must be a return address: " INTPTR_FORMAT, return_address));
+ assert(thread->frames_to_pop_failed_realloc() == 0 || Interpreter::contains(return_address), "missed frames to pop?");
// Reset method handle flag.
thread->set_is_method_handle_return(false);
--- a/hotspot/src/share/vm/runtime/thread.cpp Tue Dec 23 12:40:06 2014 -0800
+++ b/hotspot/src/share/vm/runtime/thread.cpp Thu Dec 25 19:46:17 2014 -0800
@@ -1448,6 +1448,7 @@
_popframe_condition = popframe_inactive;
_popframe_preserved_args = NULL;
_popframe_preserved_args_size = 0;
+ _frames_to_pop_failed_realloc = 0;
pd_initialize();
}
--- a/hotspot/src/share/vm/runtime/thread.hpp Tue Dec 23 12:40:06 2014 -0800
+++ b/hotspot/src/share/vm/runtime/thread.hpp Thu Dec 25 19:46:17 2014 -0800
@@ -908,6 +908,12 @@
// This is set to popframe_pending to signal that top Java frame should be popped immediately
int _popframe_condition;
+ // If reallocation of scalar replaced objects fails, we throw OOM
+ // and during exception propagation, pop the top
+ // _frames_to_pop_failed_realloc frames, the ones that reference
+ // failed reallocations.
+ int _frames_to_pop_failed_realloc;
+
#ifndef PRODUCT
int _jmp_ring_index;
struct {
@@ -1567,6 +1573,10 @@
void clr_pop_frame_in_process(void) { _popframe_condition &= ~popframe_processing_bit; }
#endif
+ int frames_to_pop_failed_realloc() const { return _frames_to_pop_failed_realloc; }
+ void set_frames_to_pop_failed_realloc(int nb) { _frames_to_pop_failed_realloc = nb; }
+ void dec_frames_to_pop_failed_realloc() { _frames_to_pop_failed_realloc--; }
+
private:
// Saved incoming arguments to popped frame.
// Used only when popped interpreted frame returns to deoptimized frame.
--- a/hotspot/src/share/vm/runtime/vframeArray.cpp Tue Dec 23 12:40:06 2014 -0800
+++ b/hotspot/src/share/vm/runtime/vframeArray.cpp Thu Dec 25 19:46:17 2014 -0800
@@ -57,7 +57,7 @@
}
}
-void vframeArrayElement::fill_in(compiledVFrame* vf) {
+void vframeArrayElement::fill_in(compiledVFrame* vf, bool realloc_failures) {
// Copy the information from the compiled vframe to the
// interpreter frame we will be creating to replace vf
@@ -65,6 +65,9 @@
_method = vf->method();
_bci = vf->raw_bci();
_reexecute = vf->should_reexecute();
+#ifdef ASSERT
+ _removed_monitors = false;
+#endif
int index;
@@ -82,11 +85,15 @@
// Migrate the BasicLocks from the stack to the monitor chunk
for (index = 0; index < list->length(); index++) {
MonitorInfo* monitor = list->at(index);
- assert(!monitor->owner_is_scalar_replaced(), "object should be reallocated already");
- assert(monitor->owner() == NULL || (!monitor->owner()->is_unlocked() && !monitor->owner()->has_bias_pattern()), "object must be null or locked, and unbiased");
+ assert(!monitor->owner_is_scalar_replaced() || realloc_failures, "object should be reallocated already");
BasicObjectLock* dest = _monitors->at(index);
- dest->set_obj(monitor->owner());
- monitor->lock()->move_to(monitor->owner(), dest->lock());
+ if (monitor->owner_is_scalar_replaced()) {
+ dest->set_obj(NULL);
+ } else {
+ assert(monitor->owner() == NULL || (!monitor->owner()->is_unlocked() && !monitor->owner()->has_bias_pattern()), "object must be null or locked, and unbiased");
+ dest->set_obj(monitor->owner());
+ monitor->lock()->move_to(monitor->owner(), dest->lock());
+ }
}
}
@@ -111,7 +118,7 @@
StackValue* value = locs->at(index);
switch(value->type()) {
case T_OBJECT:
- assert(!value->obj_is_scalar_replaced(), "object should be reallocated already");
+ assert(!value->obj_is_scalar_replaced() || realloc_failures, "object should be reallocated already");
// preserve object type
_locals->add( new StackValue(cast_from_oop<intptr_t>((value->get_obj()())), T_OBJECT ));
break;
@@ -136,7 +143,7 @@
StackValue* value = exprs->at(index);
switch(value->type()) {
case T_OBJECT:
- assert(!value->obj_is_scalar_replaced(), "object should be reallocated already");
+ assert(!value->obj_is_scalar_replaced() || realloc_failures, "object should be reallocated already");
// preserve object type
_expressions->add( new StackValue(cast_from_oop<intptr_t>((value->get_obj()())), T_OBJECT ));
break;
@@ -287,7 +294,7 @@
_frame.patch_pc(thread, pc);
- assert (!method()->is_synchronized() || locks > 0, "synchronized methods must have monitors");
+ assert (!method()->is_synchronized() || locks > 0 || _removed_monitors, "synchronized methods must have monitors");
BasicObjectLock* top = iframe()->interpreter_frame_monitor_begin();
for (int index = 0; index < locks; index++) {
@@ -439,7 +446,8 @@
vframeArray* vframeArray::allocate(JavaThread* thread, int frame_size, GrowableArray<compiledVFrame*>* chunk,
- RegisterMap *reg_map, frame sender, frame caller, frame self) {
+ RegisterMap *reg_map, frame sender, frame caller, frame self,
+ bool realloc_failures) {
// Allocate the vframeArray
vframeArray * result = (vframeArray*) AllocateHeap(sizeof(vframeArray) + // fixed part
@@ -451,19 +459,20 @@
result->_caller = caller;
result->_original = self;
result->set_unroll_block(NULL); // initialize it
- result->fill_in(thread, frame_size, chunk, reg_map);
+ result->fill_in(thread, frame_size, chunk, reg_map, realloc_failures);
return result;
}
void vframeArray::fill_in(JavaThread* thread,
int frame_size,
GrowableArray<compiledVFrame*>* chunk,
- const RegisterMap *reg_map) {
+ const RegisterMap *reg_map,
+ bool realloc_failures) {
// Set owner first, it is used when adding monitor chunks
_frame_size = frame_size;
for(int i = 0; i < chunk->length(); i++) {
- element(i)->fill_in(chunk->at(i));
+ element(i)->fill_in(chunk->at(i), realloc_failures);
}
// Copy registers for callee-saved registers
--- a/hotspot/src/share/vm/runtime/vframeArray.hpp Tue Dec 23 12:40:06 2014 -0800
+++ b/hotspot/src/share/vm/runtime/vframeArray.hpp Thu Dec 25 19:46:17 2014 -0800
@@ -58,6 +58,9 @@
MonitorChunk* _monitors; // active monitors for this vframe
StackValueCollection* _locals;
StackValueCollection* _expressions;
+#ifdef ASSERT
+ bool _removed_monitors;
+#endif
public:
@@ -78,7 +81,7 @@
StackValueCollection* expressions(void) const { return _expressions; }
- void fill_in(compiledVFrame* vf);
+ void fill_in(compiledVFrame* vf, bool realloc_failures);
// Formerly part of deoptimizedVFrame
@@ -99,6 +102,12 @@
bool is_bottom_frame,
int exec_mode);
+#ifdef ASSERT
+ void set_removed_monitors() {
+ _removed_monitors = true;
+ }
+#endif
+
#ifndef PRODUCT
void print(outputStream* st);
#endif /* PRODUCT */
@@ -160,13 +169,14 @@
int frames() const { return _frames; }
static vframeArray* allocate(JavaThread* thread, int frame_size, GrowableArray<compiledVFrame*>* chunk,
- RegisterMap* reg_map, frame sender, frame caller, frame self);
+ RegisterMap* reg_map, frame sender, frame caller, frame self,
+ bool realloc_failures);
vframeArrayElement* element(int index) { assert(is_within_bounds(index), "Bad index"); return &_elements[index]; }
// Allocates a new vframe in the array and fills the array with vframe information in chunk
- void fill_in(JavaThread* thread, int frame_size, GrowableArray<compiledVFrame*>* chunk, const RegisterMap *reg_map);
+ void fill_in(JavaThread* thread, int frame_size, GrowableArray<compiledVFrame*>* chunk, const RegisterMap *reg_map, bool realloc_failures);
// Returns the owner of this vframeArray
JavaThread* owner_thread() const { return _owner_thread; }
--- a/hotspot/src/share/vm/runtime/vmStructs.cpp Tue Dec 23 12:40:06 2014 -0800
+++ b/hotspot/src/share/vm/runtime/vmStructs.cpp Thu Dec 25 19:46:17 2014 -0800
@@ -556,9 +556,6 @@
\
nonstatic_field(TenuredGeneration, _min_heap_delta_bytes, size_t) \
nonstatic_field(TenuredGeneration, _the_space, ContiguousSpace*) \
- nonstatic_field(TenuredGeneration, _last_gc, WaterMark) \
- \
- \
\
nonstatic_field(Space, _bottom, HeapWord*) \
nonstatic_field(Space, _end, HeapWord*) \
--- a/hotspot/src/share/vm/trace/trace.xml Tue Dec 23 12:40:06 2014 -0800
+++ b/hotspot/src/share/vm/trace/trace.xml Thu Dec 25 19:46:17 2014 -0800
@@ -314,6 +314,28 @@
<value type="BYTES64" field="totalSize" label="Total Size" />
</event>
+ <!-- Promotion events, Supported GCs are Parallel Scavange, G1 and CMS with Parallel New. -->
+ <event id="PromoteObjectInNewPLAB" path="vm/gc/detailed/object_promotion_in_new_PLAB" label="Promotion in new PLAB"
+ description="Object survived scavenge and was copied to a new Promotion Local Allocation Buffer (PLAB). Supported GCs are Parallel Scavange, G1 and CMS with Parallel New. Due to promotion being done in parallel an object might be reported multiple times as the GC threads race to copy all objects."
+ has_thread="true" has_stacktrace="false" is_instant="true">
+ <value type="UINT" field="gcId" label="GC ID" relation="GC_ID" description="ID of GC during which the object was promoted"/>
+ <value type="CLASS" field="class" label="Class" description="Class of promoted object"/>
+ <value type="BYTES64" field="objectSize" label="Object Size" description="Size of promoted object"/>
+ <value type="UINT" field="tenuringAge" label="Object Tenuring Age" description="Tenuring age of a surviving object before being copied. The tenuring age of an object is a value between 0-15 and is incremented each scavange the object survives. Newly allocated objects have tenuring age 0."/>
+ <value type="BOOLEAN" field="tenured" label="Tenured" description="True if object was promoted to Old space, otherwise the object was aged and copied to a Survivor space"/>
+ <value type="BYTES64" field="plabSize" label="PLAB Size" description="Size of the allocated PLAB to which the object was copied"/>
+ </event>
+
+ <event id="PromoteObjectOutsidePLAB" path="vm/gc/detailed/object_promotion_outside_PLAB" label="Promotion outside PLAB"
+ description="Object survived scavenge and was copied directly to the heap. Supported GCs are Parallel Scavange, G1 and CMS with Parallel New. Due to promotion being done in parallel an object might be reported multiple times as the GC threads race to copy all objects."
+ has_thread="true" has_stacktrace="false" is_instant="true">
+ <value type="UINT" field="gcId" label="GC ID" relation="GC_ID" description="ID of GC during which the object was promoted"/>
+ <value type="CLASS" field="class" label="Class" description="Class of promoted object"/>
+ <value type="BYTES64" field="objectSize" label="Object Size" description="Size of promoted object"/>
+ <value type="UINT" field="tenuringAge" label="Object Tenuring Age" description="Tenuring age of a surviving object before being copied. The tenuring age of an object is a value between 0-15 and is incremented each scavange the object survives. Newly allocated objects have tenuring age 0."/>
+ <value type="BOOLEAN" field="tenured" label="Tenured" description="True if object was promoted to Old space, otherwise the object was aged and copied to a Survivor space"/>
+ </event>
+
<event id="PromotionFailed" path="vm/gc/detailed/promotion_failed" label="Promotion Failed" is_instant="true"
description="Promotion of an object failed">
<value type="UINT" field="gcId" label="GC ID" relation="GC_ID"/>
--- a/hotspot/test/Makefile Tue Dec 23 12:40:06 2014 -0800
+++ b/hotspot/test/Makefile Thu Dec 25 19:46:17 2014 -0800
@@ -275,6 +275,9 @@
# Ignore tests are not run and completely silent about it
JTREG_IGNORE_OPTION = -ignore:quiet
JTREG_BASIC_OPTIONS += $(JTREG_IGNORE_OPTION)
+# Multiply by 4 the timeout factor
+JTREG_TIMEOUT_OPTION = -timeoutFactor:4
+JTREG_BASIC_OPTIONS += $(JTREG_TIMEOUT_OPTION)
# Add any extra options
JTREG_BASIC_OPTIONS += $(EXTRA_JTREG_OPTIONS)
# Set other vm and test options
--- a/hotspot/test/compiler/dependencies/MonomorphicObjectCall/TestMonomorphicObjectCall.java Tue Dec 23 12:40:06 2014 -0800
+++ b/hotspot/test/compiler/dependencies/MonomorphicObjectCall/TestMonomorphicObjectCall.java Thu Dec 25 19:46:17 2014 -0800
@@ -61,6 +61,7 @@
String[] vmOpts = new String[] {
"-Xbootclasspath/p:" + testClasses,
"-Xcomp",
+ "-XX:+IgnoreUnrecognizedVMOptions",
"-XX:-VerifyDependencies",
"-XX:CompileOnly=TestMonomorphicObjectCall::callFinalize",
"-XX:CompileOnly=Object::finalizeObject",
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/compiler/exceptions/SumTest.java Thu Dec 25 19:46:17 2014 -0800
@@ -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 8066900
+ * @summary FP registers are not properly restored by C1 when handling exceptions
+ * @run main/othervm -Xbatch SumTest
+ *
+ */
+public class SumTest {
+ private static class Sum {
+
+ double[] sums;
+
+ /**
+ * Construct empty Sum
+ */
+ public Sum() {
+ sums = new double[0];
+ }
+
+ /**
+ * Return the sum of all numbers added to this Sum
+ *
+ * @return the sum
+ */
+ final public double getSum() {
+ double sum = 0;
+ for (final double s : sums) {
+ sum += s;
+ }
+
+ return sum;
+ }
+
+ /**
+ * Add a new number to this Sum
+ *
+ * @param a number to be added.
+ */
+ final public void add(double a) {
+ try {
+ sums[sums.length] = -1; // Cause IndexOutOfBoundsException
+ } catch (final IndexOutOfBoundsException e) {
+ final double[] oldSums = sums;
+ sums = new double[oldSums.length + 1]; // Extend sums
+ System.arraycopy(oldSums, 0, sums, 0, oldSums.length);
+ sums[oldSums.length] = a; // Append a
+ }
+ }
+ }
+
+ public static void main(String[] args) throws Exception {
+ final Sum sum = new Sum();
+ for (int i = 1; i <= 10000; ++i) {
+ sum.add(1);
+ double ii = sum.getSum();
+ if (i != ii) {
+ throw new Exception("Failure: computed = " + ii + ", expected = " + i);
+ }
+ }
+ }
+
+}
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/compiler/rangechecks/TestRangeCheckSmearing.java Thu Dec 25 19:46:17 2014 -0800
@@ -0,0 +1,436 @@
+/*
+ * 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 8066103
+ * @summary C2's range check smearing allows out of bound array accesses
+ * @library /testlibrary /testlibrary/whitebox /compiler/whitebox /testlibrary/com/oracle/java/testlibrary
+ * @build TestRangeCheckSmearing
+ * @run main ClassFileInstaller sun.hotspot.WhiteBox
+ * @run main ClassFileInstaller com.oracle.java.testlibrary.Platform
+ * @run main/othervm -ea -Xmixed -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI
+ * -XX:-BackgroundCompilation -XX:-UseOnStackReplacement TestRangeCheckSmearing
+ *
+ */
+
+import java.lang.annotation.*;
+import java.lang.reflect.*;
+import java.util.*;
+import sun.hotspot.WhiteBox;
+import sun.hotspot.code.NMethod;
+import com.oracle.java.testlibrary.Platform;
+
+public class TestRangeCheckSmearing {
+ private static final WhiteBox WHITE_BOX = WhiteBox.getWhiteBox();
+
+ @Retention(RetentionPolicy.RUNTIME)
+ @interface Args { int[] value(); }
+
+ // first range check is i + max of all constants
+ @Args({0, 8})
+ static int m1(int[] array, int i, boolean allaccesses) {
+ int res = 0;
+ res += array[i+9];
+ if (allaccesses) {
+ res += array[i+8];
+ res += array[i+7];
+ res += array[i+6];
+ res += array[i+5];
+ res += array[i+4];
+ res += array[i+3];
+ res += array[i+2];
+ res += array[i+1];
+ }
+ return res;
+ }
+
+ // first range check is i + min of all constants
+ @Args({0, -9})
+ static int m2(int[] array, int i, boolean allaccesses) {
+ int res = 0;
+ res += array[i+1];
+ if (allaccesses) {
+ res += array[i+2];
+ res += array[i+3];
+ res += array[i+4];
+ res += array[i+5];
+ res += array[i+6];
+ res += array[i+7];
+ res += array[i+8];
+ res += array[i+9];
+ }
+ return res;
+ }
+
+ // first range check is not i + min/max of all constants
+ @Args({0, 8})
+ static int m3(int[] array, int i, boolean allaccesses) {
+ int res = 0;
+ res += array[i+3];
+ if (allaccesses) {
+ res += array[i+2];
+ res += array[i+1];
+ res += array[i+4];
+ res += array[i+5];
+ res += array[i+6];
+ res += array[i+7];
+ res += array[i+8];
+ res += array[i+9];
+ }
+ return res;
+ }
+
+ @Args({0, -9})
+ static int m4(int[] array, int i, boolean allaccesses) {
+ int res = 0;
+ res += array[i+3];
+ if (allaccesses) {
+ res += array[i+4];
+ res += array[i+1];
+ res += array[i+2];
+ res += array[i+5];
+ res += array[i+6];
+ res += array[i+7];
+ res += array[i+8];
+ res += array[i+9];
+ }
+ return res;
+ }
+
+ @Args({0, -3})
+ static int m5(int[] array, int i, boolean allaccesses) {
+ int res = 0;
+ res += array[i+3];
+ res += array[i+2];
+ if (allaccesses) {
+ res += array[i+1];
+ res += array[i+4];
+ res += array[i+5];
+ res += array[i+6];
+ res += array[i+7];
+ res += array[i+8];
+ res += array[i+9];
+ }
+ return res;
+ }
+
+ @Args({0, 6})
+ static int m6(int[] array, int i, boolean allaccesses) {
+ int res = 0;
+ res += array[i+3];
+ res += array[i+4];
+ if (allaccesses) {
+ res += array[i+2];
+ res += array[i+1];
+ res += array[i+5];
+ res += array[i+6];
+ res += array[i+7];
+ res += array[i+8];
+ res += array[i+9];
+ }
+ return res;
+ }
+
+ @Args({0, 6})
+ static int m7(int[] array, int i, boolean allaccesses) {
+ int res = 0;
+ res += array[i+3];
+ res += array[i+2];
+ res += array[i+4];
+ if (allaccesses) {
+ res += array[i+1];
+ res += array[i+5];
+ res += array[i+6];
+ res += array[i+7];
+ res += array[i+8];
+ res += array[i+9];
+ }
+ return res;
+ }
+
+ @Args({0, -3})
+ static int m8(int[] array, int i, boolean allaccesses) {
+ int res = 0;
+ res += array[i+3];
+ res += array[i+4];
+ res += array[i+2];
+ if (allaccesses) {
+ res += array[i+1];
+ res += array[i+5];
+ res += array[i+6];
+ res += array[i+7];
+ res += array[i+8];
+ res += array[i+9];
+ }
+ return res;
+ }
+
+ @Args({6, 15})
+ static int m9(int[] array, int i, boolean allaccesses) {
+ int res = 0;
+ res += array[i+3];
+ if (allaccesses) {
+ res += array[i-2];
+ res += array[i-1];
+ res += array[i-4];
+ res += array[i-5];
+ res += array[i-6];
+ }
+ return res;
+ }
+
+ @Args({3, 12})
+ static int m10(int[] array, int i, boolean allaccesses) {
+ int res = 0;
+ res += array[i+3];
+ if (allaccesses) {
+ res += array[i-2];
+ res += array[i-1];
+ res += array[i-3];
+ res += array[i+4];
+ res += array[i+5];
+ res += array[i+6];
+ }
+ return res;
+ }
+
+ @Args({3, -3})
+ static int m11(int[] array, int i, boolean allaccesses) {
+ int res = 0;
+ res += array[i+3];
+ res += array[i-2];
+ if (allaccesses) {
+ res += array[i+5];
+ res += array[i+6];
+ }
+ return res;
+ }
+
+ @Args({3, 6})
+ static int m12(int[] array, int i, boolean allaccesses) {
+ int res = 0;
+ res += array[i+3];
+ res += array[i+6];
+ if (allaccesses) {
+ res += array[i-2];
+ res += array[i-3];
+ }
+ return res;
+ }
+
+ // check that identical range check is replaced by dominating one
+ // only when correct
+ @Args({0})
+ static int m13(int[] array, int i, boolean ignore) {
+ int res = 0;
+ res += array[i+3];
+ res += array[i+3];
+ return res;
+ }
+
+ @Args({2, 0})
+ static int m14(int[] array, int i, boolean ignore) {
+ int res = 0;
+
+ res += array[i];
+ res += array[i-2];
+ res += array[i]; // If range check below were to be removed first this cannot be considered identical to first range check
+ res += array[i-1]; // range check removed so i-1 array access depends on previous check
+
+ return res;
+ }
+
+ static int[] m15_dummy = new int[10];
+ @Args({2, 0})
+ static int m15(int[] array, int i, boolean ignore) {
+ int res = 0;
+ res += array[i];
+
+ // When the loop is optimized out we don't want the
+ // array[i-1] access which is dependent on array[i]'s
+ // range check to become dependent on the identical range
+ // check above.
+
+ int[] array2 = m15_dummy;
+ int j = 0;
+ for (; j < 10; j++);
+ if (j == 10) {
+ array2 = array;
+ }
+
+ res += array2[i-2];
+ res += array2[i];
+ res += array2[i-1]; // range check removed so i-1 array access depends on previous check
+
+ return res;
+ }
+
+ @Args({2, 0})
+ static int m16(int[] array, int i, boolean ignore) {
+ int res = 0;
+
+ res += array[i];
+ res += array[i-1];
+ res += array[i-1];
+ res += array[i-2];
+
+ return res;
+ }
+
+ @Args({2, 0})
+ static int m17(int[] array, int i, boolean ignore) {
+ int res = 0;
+
+ res += array[i];
+ res += array[i-2];
+ res += array[i-2];
+ res += array[i+2];
+ res += array[i+2];
+ res += array[i-1];
+ res += array[i-1];
+
+ return res;
+ }
+
+ static public void main(String[] args) {
+ if (WHITE_BOX.getBooleanVMFlag("BackgroundCompilation")) {
+ throw new AssertionError("Background compilation enabled");
+ }
+ new TestRangeCheckSmearing().doTests();
+ }
+ boolean success = true;
+ boolean exception = false;
+ final int[] array = new int[10];
+ final HashMap<String,Method> tests = new HashMap<>();
+ {
+ final Class<?> TEST_PARAM_TYPES[] = { int[].class, int.class, boolean.class };
+ for (Method m : this.getClass().getDeclaredMethods()) {
+ if (m.getName().matches("m[0-9]+")) {
+ assert(Modifier.isStatic(m.getModifiers())) : m;
+ assert(m.getReturnType() == int.class) : m;
+ assert(Arrays.equals(m.getParameterTypes(), TEST_PARAM_TYPES)) : m;
+ tests.put(m.getName(), m);
+ }
+ }
+ }
+
+ void invokeTest(Method m, int[] array, int index, boolean z) {
+ try {
+ m.invoke(null, array, index, z);
+ } catch (ReflectiveOperationException roe) {
+ Throwable ex = roe.getCause();
+ if (ex instanceof ArrayIndexOutOfBoundsException)
+ throw (ArrayIndexOutOfBoundsException) ex;
+ throw new AssertionError(roe);
+ }
+ }
+
+ void doTest(String name) {
+ Method m = tests.get(name);
+ tests.remove(name);
+ int[] args = m.getAnnotation(Args.class).value();
+ int index0 = args[0], index1;
+ boolean exceptionRequired = true;
+ if (args.length == 2) {
+ index1 = args[1];
+ } else {
+ // no negative test for this one
+ assert(args.length == 1);
+ assert(name.equals("m13"));
+ exceptionRequired = false;
+ index1 = index0;
+ }
+ // Get the method compiled.
+ if (!WHITE_BOX.isMethodCompiled(m)) {
+ // If not, try to compile it with C2
+ if(!WHITE_BOX.enqueueMethodForCompilation(m, CompilerWhiteBoxTest.COMP_LEVEL_FULL_OPTIMIZATION)) {
+ // C2 compiler not available, try to compile with C1
+ WHITE_BOX.enqueueMethodForCompilation(m, CompilerWhiteBoxTest.COMP_LEVEL_SIMPLE);
+ }
+ }
+ if (!WHITE_BOX.isMethodCompiled(m)) {
+ throw new RuntimeException(m + " not compiled");
+ }
+
+ // valid access
+ invokeTest(m, array, index0, true);
+
+ if (!WHITE_BOX.isMethodCompiled(m)) {
+ throw new RuntimeException(m + " deoptimized on valid array access");
+ }
+
+ exception = false;
+ boolean test_success = true;
+ try {
+ invokeTest(m, array, index1, false);
+ } catch(ArrayIndexOutOfBoundsException aioob) {
+ exception = true;
+ System.out.println("ArrayIndexOutOfBoundsException thrown in "+name);
+ }
+ if (!exception) {
+ System.out.println("ArrayIndexOutOfBoundsException was not thrown in "+name);
+ }
+
+ if (Platform.isServer()) {
+ if (exceptionRequired == WHITE_BOX.isMethodCompiled(m)) {
+ System.out.println((exceptionRequired?"Didn't deoptimized":"deoptimized") + " in "+name);
+ test_success = false;
+ }
+ }
+
+ if (exception != exceptionRequired) {
+ System.out.println((exceptionRequired?"exception required but not thrown":"not exception required but thrown") + " in "+name);
+ test_success = false;
+ }
+
+ if (!test_success) {
+ success = false;
+ System.out.println("TEST FAILED: "+name);
+ }
+
+ }
+ void doTests() {
+ doTest("m1");
+ doTest("m2");
+ doTest("m3");
+ doTest("m4");
+ doTest("m5");
+ doTest("m6");
+ doTest("m7");
+ doTest("m8");
+ doTest("m9");
+ doTest("m10");
+ doTest("m11");
+ doTest("m12");
+ doTest("m13");
+ doTest("m14");
+ doTest("m15");
+ doTest("m16");
+ doTest("m17");
+ if (!success) {
+ throw new RuntimeException("Some tests failed");
+ }
+ assert(tests.isEmpty()) : tests;
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/compiler/rangechecks/TestRangeCheckSmearingLoopOpts.java Thu Dec 25 19:46:17 2014 -0800
@@ -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 8048170
+ * @summary Following range check smearing, range check cannot be replaced by dominating identical test.
+ * @run main/othervm -XX:-BackgroundCompilation -XX:-UseOnStackReplacement TestRangeCheckSmearingLoopOpts
+ *
+ */
+public class TestRangeCheckSmearingLoopOpts {
+
+ static int dummy;
+
+ static int m1(int[] array, int i) {
+ for (;;) {
+ for (;;) {
+ if (array[i] < 0) { // range check (i+0) dominates equivalent check below
+ break;
+ }
+ i++;
+ }
+
+ // A control flow that stops IfNode::up_one_dom()
+ if ((i % 2)== 0) {
+ if ((array[i] % 2) == 0) {
+ dummy = i;
+ }
+ }
+
+ // IfNode::Ideal will rewrite some range checks if Compile::allow_range_check_smearing
+ if (array[i-1] == 9) { // range check (i-1) unchanged
+ int res = array[i-3]; // range check (i-3) unchanged
+ res += array[i]; // range check (i+0) unchanged
+ res += array[i-2]; // removed redundant range check
+ // the previous access might be hoisted by
+ // PhaseIdealLoop::split_if_with_blocks_post because
+ // it appears to have the same guard, but it also
+ // depends on the previous guards
+ return res;
+ }
+ i++;
+ }
+ }
+
+ static public void main(String[] args) {
+ int[] array = { 0, 1, 2, -3, 4, 5, -2, 7, 8, 9, -1 };
+ for (int i = 0; i < 20000; i++) {
+ m1(array, 0);
+ }
+ array[0] = -1;
+ try {
+ m1(array, 0);
+ } catch(ArrayIndexOutOfBoundsException aioobe) {}
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/compiler/uncommontrap/TestDeoptOOM.java Thu Dec 25 19:46:17 2014 -0800
@@ -0,0 +1,426 @@
+/*
+ * 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 6898462
+ * @summary failed reallocations of scalar replaced objects during deoptimization causes crash
+ * @run main/othervm -XX:-BackgroundCompilation -XX:CompileCommand=exclude,TestDeoptOOM::main -XX:CompileCommand=exclude,TestDeoptOOM::m9_1 -Xmx128M TestDeoptOOM
+ *
+ */
+
+public class TestDeoptOOM {
+
+ long f1;
+ long f2;
+ long f3;
+ long f4;
+ long f5;
+
+ static class LinkedList {
+ LinkedList l;
+ long[] array;
+ LinkedList(LinkedList l, int size) {
+ array = new long[size];
+ this.l = l;
+ }
+ }
+
+ static LinkedList ll;
+
+ static void consume_all_memory() {
+ int size = 128 * 1024 * 1024;
+ while(size > 0) {
+ try {
+ while(true) {
+ ll = new LinkedList(ll, size);
+ }
+ } catch(OutOfMemoryError oom) {
+ }
+ size = size / 2;
+ }
+ }
+
+ static void free_memory() {
+ ll = null;
+ }
+
+ static TestDeoptOOM m1(boolean deopt) {
+ try {
+ TestDeoptOOM tdoom = new TestDeoptOOM();
+ if (deopt) {
+ return tdoom;
+ }
+ } catch(OutOfMemoryError oom) {
+ free_memory();
+ System.out.println("OOM caught in m1");
+ }
+ return null;
+ }
+
+ static TestDeoptOOM m2_1(boolean deopt) {
+ try {
+ TestDeoptOOM tdoom = new TestDeoptOOM();
+ if (deopt) {
+ return tdoom;
+ }
+ } catch(OutOfMemoryError oom) {
+ free_memory();
+ System.out.println("OOM caught in m2_1");
+ }
+ return null;
+ }
+
+ static TestDeoptOOM m2(boolean deopt) {
+ try {
+ return m2_1(deopt);
+ } catch(OutOfMemoryError oom) {
+ free_memory();
+ System.out.println("OOM caught in m2");
+ }
+ return null;
+ }
+
+ static TestDeoptOOM m3_3(boolean deopt) {
+ try {
+ TestDeoptOOM tdoom = new TestDeoptOOM();
+ if (deopt) {
+ return tdoom;
+ }
+ } catch(OutOfMemoryError oom) {
+ free_memory();
+ System.out.println("OOM caught in m3_3");
+ }
+ return null;
+ }
+
+ static boolean m3_2(boolean deopt) {
+ try {
+ return m3_3(deopt) != null;
+ } catch(OutOfMemoryError oom) {
+ free_memory();
+ System.out.println("OOM caught in m3_2");
+ }
+ return false;
+ }
+
+ static TestDeoptOOM m3_1(boolean deopt) {
+ try {
+ TestDeoptOOM tdoom = new TestDeoptOOM();
+ if (m3_2(deopt)) {
+ return tdoom;
+ }
+ } catch(OutOfMemoryError oom) {
+ free_memory();
+ System.out.println("OOM caught in m3_1");
+ }
+ return null;
+ }
+
+ static TestDeoptOOM m3(boolean deopt) {
+ try {
+ return m3_1(deopt);
+ } catch(OutOfMemoryError oom) {
+ free_memory();
+ System.out.println("OOM caught in m3");
+ }
+ return null;
+ }
+
+ static TestDeoptOOM m4(boolean deopt) {
+ try {
+ TestDeoptOOM tdoom = new TestDeoptOOM();
+ if (deopt) {
+ tdoom.f1 = 1l;
+ tdoom.f2 = 2l;
+ tdoom.f3 = 3l;
+ return tdoom;
+ }
+ } catch(OutOfMemoryError oom) {
+ free_memory();
+ System.out.println("OOM caught in m4");
+ }
+ return null;
+ }
+
+ static TestDeoptOOM m5(boolean deopt) {
+ try {
+ TestDeoptOOM tdoom = new TestDeoptOOM();
+ synchronized(tdoom) {
+ if (deopt) {
+ return tdoom;
+ }
+ }
+ } catch(OutOfMemoryError oom) {
+ free_memory();
+ System.out.println("OOM caught in m5");
+ }
+ return null;
+ }
+
+ synchronized TestDeoptOOM m6_1(boolean deopt) {
+ if (deopt) {
+ return this;
+ }
+ return null;
+ }
+
+ static TestDeoptOOM m6(boolean deopt) {
+ try {
+ TestDeoptOOM tdoom = new TestDeoptOOM();
+ return tdoom.m6_1(deopt);
+ } catch(OutOfMemoryError oom) {
+ free_memory();
+ System.out.println("OOM caught in m6");
+ }
+ return null;
+ }
+
+ static TestDeoptOOM m7_1(boolean deopt, Object lock) {
+ try {
+ synchronized(lock) {
+ TestDeoptOOM tdoom = new TestDeoptOOM();
+ if (deopt) {
+ return tdoom;
+ }
+ }
+ } catch(OutOfMemoryError oom) {
+ free_memory();
+ System.out.println("OOM caught in m7_1");
+ }
+ return null;
+ }
+
+ static TestDeoptOOM m7(boolean deopt, Object lock) {
+ try {
+ return m7_1(deopt, lock);
+ } catch(OutOfMemoryError oom) {
+ free_memory();
+ System.out.println("OOM caught in m7");
+ }
+ return null;
+ }
+
+ static class A {
+ long f1;
+ long f2;
+ long f3;
+ long f4;
+ long f5;
+ }
+
+ static class B {
+ long f1;
+ long f2;
+ long f3;
+ long f4;
+ long f5;
+
+ A a;
+ }
+
+ static B m8(boolean deopt) {
+ try {
+ A a = new A();
+ B b = new B();
+ b.a = a;
+ if (deopt) {
+ return b;
+ }
+ } catch(OutOfMemoryError oom) {
+ free_memory();
+ System.out.println("OOM caught in m8");
+ }
+ return null;
+ }
+
+ static void m9_1(int i) {
+ if (i > 90000) {
+ consume_all_memory();
+ }
+ }
+
+ static TestDeoptOOM m9() {
+ try {
+ for (int i = 0; i < 100000; i++) {
+ TestDeoptOOM tdoom = new TestDeoptOOM();
+ m9_1(i);
+ if (i > 90000) {
+ return tdoom;
+ }
+ }
+ } catch(OutOfMemoryError oom) {
+ free_memory();
+ System.out.println("OOM caught in m1");
+ }
+ return null;
+ }
+
+ public static void main(String[] args) {
+ for (int i = 0; i < 20000; i++) {
+ m1(false);
+ }
+
+ consume_all_memory();
+
+ try {
+ m1(true);
+ } catch(OutOfMemoryError oom) {
+ free_memory();
+ System.out.println("OOM caught in main " + oom.getMessage());
+ }
+
+ free_memory();
+
+ for (int i = 0; i < 20000; i++) {
+ m2(false);
+ }
+
+ consume_all_memory();
+
+ try {
+ m2(true);
+ } catch(OutOfMemoryError oom) {
+ free_memory();
+ System.out.println("OOM caught in main");
+ }
+
+ free_memory();
+
+ for (int i = 0; i < 20000; i++) {
+ m3(false);
+ }
+
+ consume_all_memory();
+
+ try {
+ m3(true);
+ } catch(OutOfMemoryError oom) {
+ free_memory();
+ System.out.println("OOM caught in main");
+ }
+
+ free_memory();
+
+ for (int i = 0; i < 20000; i++) {
+ m4(false);
+ }
+
+ consume_all_memory();
+
+ try {
+ m4(true);
+ } catch(OutOfMemoryError oom) {
+ free_memory();
+ System.out.println("OOM caught in main");
+ }
+
+ free_memory();
+
+ for (int i = 0; i < 20000; i++) {
+ m5(false);
+ }
+
+ consume_all_memory();
+
+ try {
+ m5(true);
+ } catch(OutOfMemoryError oom) {
+ free_memory();
+ System.out.println("OOM caught in main");
+ }
+
+ free_memory();
+
+ for (int i = 0; i < 20000; i++) {
+ m6(false);
+ }
+
+ consume_all_memory();
+
+ try {
+ m6(true);
+ } catch(OutOfMemoryError oom) {
+ free_memory();
+ System.out.println("OOM caught in main");
+ }
+
+ free_memory();
+
+ final Object lock = new Object();
+
+ for (int i = 0; i < 20000; i++) {
+ m7(false, lock);
+ }
+
+ consume_all_memory();
+
+ try {
+ m7(true, lock);
+ } catch(OutOfMemoryError oom) {
+ free_memory();
+ System.out.println("OOM caught in main");
+ }
+
+ free_memory();
+
+ Thread thread = new Thread() {
+ public void run() {
+ System.out.println("Acquiring lock");
+ synchronized(lock) {
+ System.out.println("Lock acquired");
+ }
+ System.out.println("Lock released");
+ }
+ };
+ thread.start();
+ try {
+ thread.join();
+ } catch(InterruptedException ie) {
+ }
+
+ for (int i = 0; i < 20000; i++) {
+ m8(false);
+ }
+
+ consume_all_memory();
+
+ try {
+ m8(true);
+ } catch(OutOfMemoryError oom) {
+ free_memory();
+ System.out.println("OOM caught in main");
+ }
+
+ free_memory();
+
+ try {
+ m9();
+ } catch(OutOfMemoryError oom) {
+ free_memory();
+ System.out.println("OOM caught in main");
+ }
+
+ free_memory();
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/compiler/uncommontrap/TraceDeoptimizationNoRealloc.java Thu Dec 25 19:46:17 2014 -0800
@@ -0,0 +1,47 @@
+/*
+ * 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 8067144
+ * @summary -XX:+TraceDeoptimization tries to print realloc'ed objects even when there are none
+ * @run main/othervm -XX:-BackgroundCompilation -XX:-UseOnStackReplacement -XX:+IgnoreUnrecognizedVMOptions -XX:+TraceDeoptimization TraceDeoptimizationNoRealloc
+ *
+ */
+
+public class TraceDeoptimizationNoRealloc {
+
+ static void m(boolean some_condition) {
+ if (some_condition) {
+ return;
+ }
+ }
+
+
+ static public void main(String[] args) {
+ for (int i = 0; i < 20000; i++) {
+ m(false);
+ }
+ m(true);
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/gc/TestCardTablePageCommits.java Thu Dec 25 19:46:17 2014 -0800
@@ -0,0 +1,49 @@
+/*
+* 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.JDKToolFinder;
+import com.oracle.java.testlibrary.OutputAnalyzer;
+import com.oracle.java.testlibrary.ProcessTools;
+import com.oracle.java.testlibrary.Platform;
+
+/*
+ * @test TestCardTablePageCommits
+ * @key gc
+ * @bug 8059066
+ * @summary Tests that the card table does not commit the same page twice
+ * @library /testlibrary
+ * @run driver TestCardTablePageCommits
+ */
+public class TestCardTablePageCommits {
+ public static void main(String args[]) throws Exception {
+ // The test is run with a small heap to make sure all pages in the card
+ // table gets committed. Need 8 MB heap to trigger the bug on SPARC
+ // because of 8kB pages, assume 4 KB pages for all other CPUs.
+ String Xmx = Platform.isSparc() ? "-Xmx8m" : "-Xmx4m";
+
+ String[] opts = {Xmx, "-XX:NativeMemoryTracking=detail", "-XX:+UseParallelGC", "-version"};
+ ProcessBuilder pb = ProcessTools.createJavaProcessBuilder(opts);
+ OutputAnalyzer output = new OutputAnalyzer(pb.start());
+ output.shouldHaveExitValue(0);
+ }
+}
--- a/hotspot/test/runtime/SharedArchiveFile/LimitSharedSizes.java Tue Dec 23 12:40:06 2014 -0800
+++ b/hotspot/test/runtime/SharedArchiveFile/LimitSharedSizes.java Thu Dec 25 19:46:17 2014 -0800
@@ -30,40 +30,96 @@
import com.oracle.java.testlibrary.*;
public class LimitSharedSizes {
+ static enum Region {
+ RO, RW, MD, MC
+ }
+
private static class SharedSizeTestData {
public String optionName;
public String optionValue;
public String expectedErrorMsg;
- public SharedSizeTestData(String name, String value, String msg) {
- optionName = name;
+ public SharedSizeTestData(Region region, String value, String msg) {
+ optionName = getName(region);
optionValue = value;
expectedErrorMsg = msg;
}
+
+ public SharedSizeTestData(Region region, String msg) {
+ optionName = getName(region);
+ optionValue = getValue(region);
+ expectedErrorMsg = msg;
+ }
+
+ private String getName(Region region) {
+ String name;
+ switch (region) {
+ case RO:
+ name = "-XX:SharedReadOnlySize";
+ break;
+ case RW:
+ name = "-XX:SharedReadWriteSize";
+ break;
+ case MD:
+ name = "-XX:SharedMiscDataSize";
+ break;
+ case MC:
+ name = "-XX:SharedMiscCodeSize";
+ break;
+ default:
+ name = "Unknown";
+ break;
+ }
+ return name;
+ }
+
+ private String getValue(Region region) {
+ String value;
+ switch (region) {
+ case RO:
+ value = Platform.is64bit() ? "9M" : "8M";
+ break;
+ case RW:
+ value = Platform.is64bit() ? "12M" : "7M";
+ break;
+ case MD:
+ value = Platform.is64bit() ? "4M" : "2M";
+ break;
+ case MC:
+ value = "120k";
+ break;
+ default:
+ value = "0M";
+ break;
+ }
+ return value;
+ }
}
private static final SharedSizeTestData[] testTable = {
- // values in this part of the test table should cause failure
- // (shared space sizes are deliberately too small)
- new SharedSizeTestData("-XX:SharedReadOnlySize", "4M", "read only"),
- new SharedSizeTestData("-XX:SharedReadWriteSize","4M", "read write"),
-
- // Known issue, JDK-8038422 (assert() on Windows)
- // new SharedSizeTestData("-XX:SharedMiscDataSize", "500k", "miscellaneous data"),
-
- // Too small of a misc code size should not cause a vm crash.
- // It should result in the following error message:
+ // Too small of a region size should not cause a vm crash.
+ // It should result in an error message like the following:
// The shared miscellaneous code space is not large enough
// to preload requested classes. Use -XX:SharedMiscCodeSize=
// to increase the initial size of shared miscellaneous code space.
- new SharedSizeTestData("-XX:SharedMiscCodeSize", "20k", "miscellaneous code"),
+ new SharedSizeTestData(Region.RO, "4M", "read only"),
+ new SharedSizeTestData(Region.RW, "4M", "read write"),
+ new SharedSizeTestData(Region.MD, "50k", "miscellaneous data"),
+ new SharedSizeTestData(Region.MC, "20k", "miscellaneous code"),
// these values are larger than default ones, but should
// be acceptable and not cause failure
- new SharedSizeTestData("-XX:SharedReadOnlySize", "20M", null),
- new SharedSizeTestData("-XX:SharedReadWriteSize", "20M", null),
- new SharedSizeTestData("-XX:SharedMiscDataSize", "20M", null),
- new SharedSizeTestData("-XX:SharedMiscCodeSize", "20M", null)
+ new SharedSizeTestData(Region.RO, "20M", null),
+ new SharedSizeTestData(Region.RW, "20M", null),
+ new SharedSizeTestData(Region.MD, "20M", null),
+ new SharedSizeTestData(Region.MC, "20M", null),
+
+ // test with sizes which just meet the minimum required sizes
+ // the following tests also attempt to use the shared archive
+ new SharedSizeTestData(Region.RO, "UseArchive"),
+ new SharedSizeTestData(Region.RW, "UseArchive"),
+ new SharedSizeTestData(Region.MD, "UseArchive"),
+ new SharedSizeTestData(Region.MC, "UseArchive")
};
public static void main(String[] args) throws Exception {
@@ -82,10 +138,39 @@
OutputAnalyzer output = new OutputAnalyzer(pb.start());
if (td.expectedErrorMsg != null) {
- output.shouldContain("The shared " + td.expectedErrorMsg
- + " space is not large enough");
+ if (!td.expectedErrorMsg.equals("UseArchive")) {
+ output.shouldContain("The shared " + td.expectedErrorMsg
+ + " space is not large enough");
+
+ output.shouldHaveExitValue(2);
+ } else {
+ output.shouldNotContain("space is not large enough");
+ output.shouldHaveExitValue(0);
+
+ // try to use the archive
+ pb = ProcessTools.createJavaProcessBuilder(
+ "-XX:+UnlockDiagnosticVMOptions",
+ "-XX:SharedArchiveFile=./" + fileName,
+ "-XX:+PrintSharedArchiveAndExit",
+ "-version");
- output.shouldHaveExitValue(2);
+ try {
+ output = new OutputAnalyzer(pb.start());
+ output.shouldContain("archive is valid");
+ } catch (RuntimeException e) {
+ // if sharing failed due to ASLR or similar reasons,
+ // check whether sharing was attempted at all (UseSharedSpaces)
+ if ((output.getOutput().contains("Unable to use shared archive") ||
+ output.getOutput().contains("Unable to map ReadOnly shared space at required address.") ||
+ output.getOutput().contains("Unable to map ReadWrite shared space at required address.") ||
+ output.getOutput().contains("Unable to reserve shared space at required address")) &&
+ output.getExitValue() == 1) {
+ System.out.println("Unable to use shared archive: test not executed; assumed passed");
+ return;
+ }
+ }
+ output.shouldHaveExitValue(0);
+ }
} else {
output.shouldNotContain("space is not large enough");
output.shouldHaveExitValue(0);
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/runtime/SharedArchiveFile/PrintSharedArchiveAndExit.java Thu Dec 25 19:46:17 2014 -0800
@@ -0,0 +1,83 @@
+/*
+ * 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 8066670
+ * @summary Testing -XX:+PrintSharedArchiveAndExit option
+ * @library /testlibrary
+ */
+
+import com.oracle.java.testlibrary.*;
+
+public class PrintSharedArchiveAndExit {
+ public static void main(String[] args) throws Exception {
+ ProcessBuilder pb = ProcessTools.createJavaProcessBuilder(
+ "-XX:+UnlockDiagnosticVMOptions", "-XX:SharedArchiveFile=./sample.jsa", "-Xshare:dump");
+ OutputAnalyzer output = new OutputAnalyzer(pb.start());
+ try {
+ output.shouldContain("Loading classes to share");
+ output.shouldHaveExitValue(0);
+
+ // (1) With a valid archive
+ pb = ProcessTools.createJavaProcessBuilder(
+ "-XX:+UnlockDiagnosticVMOptions", "-XX:SharedArchiveFile=./sample.jsa",
+ "-XX:+PrintSharedArchiveAndExit", "-version");
+ output = new OutputAnalyzer(pb.start());
+ output.shouldContain("archive is valid");
+ output.shouldNotContain("java version"); // Should not print JVM version
+ output.shouldHaveExitValue(0); // Should report success in error code.
+
+ pb = ProcessTools.createJavaProcessBuilder(
+ "-XX:+UnlockDiagnosticVMOptions", "-XX:SharedArchiveFile=./sample.jsa",
+ "-XX:+PrintSharedArchiveAndExit");
+ output = new OutputAnalyzer(pb.start());
+ output.shouldContain("archive is valid");
+ output.shouldNotContain("Usage:"); // Should not print JVM help message
+ output.shouldHaveExitValue(0); // Should report success in error code.
+
+ // (2) With an invalid archive (boot class path has been prepended)
+ pb = ProcessTools.createJavaProcessBuilder(
+ "-Xbootclasspath/p:foo.jar",
+ "-XX:+UnlockDiagnosticVMOptions", "-XX:SharedArchiveFile=./sample.jsa",
+ "-XX:+PrintSharedArchiveAndExit", "-version");
+ output = new OutputAnalyzer(pb.start());
+ output.shouldContain("archive is invalid");
+ output.shouldNotContain("java version"); // Should not print JVM version
+ output.shouldHaveExitValue(1); // Should report failure in error code.
+
+ pb = ProcessTools.createJavaProcessBuilder(
+ "-Xbootclasspath/p:foo.jar",
+ "-XX:+UnlockDiagnosticVMOptions", "-XX:SharedArchiveFile=./sample.jsa",
+ "-XX:+PrintSharedArchiveAndExit");
+ output = new OutputAnalyzer(pb.start());
+ output.shouldContain("archive is invalid");
+ output.shouldNotContain("Usage:"); // Should not print JVM help message
+ output.shouldHaveExitValue(1); // Should report failure in error code.
+ } catch (RuntimeException e) {
+ e.printStackTrace();
+ output.shouldContain("Unable to use shared archive");
+ output.shouldHaveExitValue(1);
+ }
+ }
+}
--- a/hotspot/test/serviceability/sa/jmap-hashcode/Test8028623.java Tue Dec 23 12:40:06 2014 -0800
+++ b/hotspot/test/serviceability/sa/jmap-hashcode/Test8028623.java Thu Dec 25 19:46:17 2014 -0800
@@ -41,12 +41,12 @@
public class Test8028623 {
- public static int à = 1;
+ public static int \u00CB = 1;
public static String dumpFile = "heap.out";
public static void main (String[] args) {
- System.out.println(Ã);
+ System.out.println(\u00CB);
try {
if (!Platform.shouldSAAttach()) {
--- a/hotspot/test/testlibrary/whitebox/sun/hotspot/WhiteBox.java Tue Dec 23 12:40:06 2014 -0800
+++ b/hotspot/test/testlibrary/whitebox/sun/hotspot/WhiteBox.java Thu Dec 25 19:46:17 2014 -0800
@@ -153,6 +153,14 @@
public native int getMethodEntryBci(Executable method);
public native Object[] getNMethod(Executable method, boolean isOsr);
public native long allocateCodeBlob(int size, int type);
+ public long allocateCodeBlob(long size, int type) {
+ int intSize = (int) size;
+ if ((long) intSize != size || size < 0) {
+ throw new IllegalArgumentException(
+ "size argument has illegal value " + size);
+ }
+ return allocateCodeBlob( intSize, type);
+ }
public native void freeCodeBlob(long addr);
public void forceNMethodSweep() {
try {
--- a/jaxp/.hgtags Tue Dec 23 12:40:06 2014 -0800
+++ b/jaxp/.hgtags Thu Dec 25 19:46:17 2014 -0800
@@ -285,3 +285,4 @@
3f46e2196498de33e7c65efa7b372e46f1faba01 jdk9-b40
71dd8f7649428efd3a56ca5fefc80e59d37b8434 jdk9-b41
47b0d3fa4118b9d56870cf4004987438c501f5c0 jdk9-b42
+40b242363040229a05224fbc5dc203a3f46a8f8f jdk9-b43
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jaxp/test/Makefile Thu Dec 25 19:46:17 2014 -0800
@@ -0,0 +1,325 @@
+#
+# Copyright (c) 1995, 2014, Oracle and/or its affiliates. All rights reserved.
+# 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.
+#
+
+#
+# Makefile to run various JAXP tests
+#
+
+.DEFAULT : all
+
+# Empty these to get rid of some default rules
+.SUFFIXES:
+.SUFFIXES: .java
+CO=
+GET=
+
+# Utilities used
+AWK = awk
+CAT = cat
+CD = cd
+CHMOD = chmod
+CP = cp
+CUT = cut
+DIRNAME = dirname
+ECHO = echo
+EGREP = egrep
+EXPAND = expand
+FIND = find
+MKDIR = mkdir
+PWD = pwd
+SED = sed
+SORT = sort
+TEE = tee
+UNAME = uname
+UNIQ = uniq
+WC = wc
+ZIP = zip
+
+# Get OS name from uname (Cygwin inexplicably adds _NT-5.1)
+UNAME_S := $(shell $(UNAME) -s | $(CUT) -f1 -d_)
+
+# Commands to run on paths to make mixed paths for java on windows
+ifeq ($(UNAME_S), CYGWIN)
+ # Location of developer shared files
+ SLASH_JAVA = J:
+ GETMIXEDPATH = cygpath -m
+else
+ # Location of developer shared files
+ SLASH_JAVA = /java
+
+ GETMIXEDPATH=$(ECHO)
+endif
+
+# Root of this test area (important to use full paths in some places)
+TEST_ROOT := $(shell $(PWD))
+
+# Root of all test results
+ifdef ALT_OUTPUTDIR
+ ABS_OUTPUTDIR = $(shell $(CD) $(ALT_OUTPUTDIR) && $(PWD))
+else
+ ABS_OUTPUTDIR = $(shell $(CD) $(TEST_ROOT)/.. && $(PWD))
+endif
+
+ABS_PLATFORM_BUILD_ROOT = $(ABS_OUTPUTDIR)
+ABS_TEST_OUTPUT_DIR := $(ABS_PLATFORM_BUILD_ROOT)/testoutput/$(UNIQUE_DIR)
+
+# Expect JPRT to set PRODUCT_HOME (the product or jdk in this case to test)
+ifndef PRODUCT_HOME
+ # Try to use j2sdk-image if it exists
+ ABS_JDK_IMAGE = $(ABS_PLATFORM_BUILD_ROOT)/images/j2sdk-image
+ PRODUCT_HOME := \
+ $(shell \
+ if [ -d $(ABS_JDK_IMAGE) ] ; then \
+ $(ECHO) "$(ABS_JDK_IMAGE)"; \
+ else \
+ $(ECHO) "$(ABS_PLATFORM_BUILD_ROOT)"; \
+ fi)
+ PRODUCT_HOME := $(PRODUCT_HOME)
+endif
+
+# Expect JPRT to set JPRT_PRODUCT_ARGS (e.g. -server etc.)
+# Should be passed into 'java' only.
+# Could include: -d64 -server -client OR any java option
+ifdef JPRT_PRODUCT_ARGS
+ JAVA_ARGS = $(JPRT_PRODUCT_ARGS)
+endif
+
+# Expect JPRT to set JPRT_PRODUCT_VM_ARGS (e.g. -Xcomp etc.)
+# Should be passed into anything running the vm (java, javac, javadoc, ...).
+ifdef JPRT_PRODUCT_VM_ARGS
+ JAVA_VM_ARGS = $(JPRT_PRODUCT_VM_ARGS)
+endif
+
+# Expect JPRT to set JPRT_ARCHIVE_BUNDLE (path to zip bundle for results)
+ifdef JPRT_ARCHIVE_BUNDLE
+ ARCHIVE_BUNDLE = $(JPRT_ARCHIVE_BUNDLE)
+else
+ ARCHIVE_BUNDLE = $(ABS_TEST_OUTPUT_DIR)/ARCHIVE_BUNDLE.zip
+endif
+
+# How to create the test bundle (pass or fail, we want to create this)
+# Follow command with ";$(BUNDLE_UP_AND_EXIT)", so it always gets executed.
+ZIP_UP_RESULTS = ( $(MKDIR) -p `$(DIRNAME) $(ARCHIVE_BUNDLE)` \
+ && $(CD) $(ABS_TEST_OUTPUT_DIR) \
+ && $(CHMOD) -R a+r . \
+ && $(ZIP) -q -r $(ARCHIVE_BUNDLE) . )
+
+# important results files
+SUMMARY_TXT = $(shell $(GETMIXEDPATH) "$(ABS_TEST_OUTPUT_DIR)/JTreport/text/summary.txt")
+STATS_TXT_NAME = Stats.txt
+STATS_TXT = $(shell $(GETMIXEDPATH) "$(ABS_TEST_OUTPUT_DIR)/$(STATS_TXT_NAME)")
+RUNLIST = $(shell $(GETMIXEDPATH) "$(ABS_TEST_OUTPUT_DIR)/runlist.txt")
+PASSLIST = $(shell $(GETMIXEDPATH) "$(ABS_TEST_OUTPUT_DIR)/passlist.txt")
+FAILLIST = $(shell $(GETMIXEDPATH) "$(ABS_TEST_OUTPUT_DIR)/faillist.txt")
+EXITCODE = $(shell $(GETMIXEDPATH) "$(ABS_TEST_OUTPUT_DIR)/exitcode.txt")
+
+TESTEXIT = \
+ if [ ! -s $(EXITCODE) ] ; then \
+ $(ECHO) "ERROR: EXITCODE file not filled in."; \
+ $(ECHO) "1" > $(EXITCODE); \
+ fi ; \
+ testExitCode=`$(CAT) $(EXITCODE)`; \
+ $(ECHO) "EXIT CODE: $${testExitCode}"; \
+ exit $${testExitCode}
+
+BUNDLE_UP_AND_EXIT = \
+( \
+ jtregExitCode=$$? && \
+ _summary="$(SUMMARY_TXT)"; \
+ $(RM) -f $(STATS_TXT) $(RUNLIST) $(PASSLIST) $(FAILLIST) $(EXITCODE); \
+ $(ECHO) "$${jtregExitCode}" > $(EXITCODE); \
+ if [ -r "$${_summary}" ] ; then \
+ $(ECHO) "Summary: $(UNIQUE_DIR)" > $(STATS_TXT); \
+ $(EXPAND) $${_summary} | $(EGREP) -v ' Not run\.' > $(RUNLIST); \
+ $(EGREP) ' Passed\.' $(RUNLIST) \
+ | $(EGREP) -v ' Error\.' \
+ | $(EGREP) -v ' Failed\.' > $(PASSLIST); \
+ ( $(EGREP) ' Failed\.' $(RUNLIST); \
+ $(EGREP) ' Error\.' $(RUNLIST); \
+ $(EGREP) -v ' Passed\.' $(RUNLIST) ) \
+ | $(SORT) | $(UNIQ) > $(FAILLIST); \
+ if [ $${jtregExitCode} != 0 -o -s $(FAILLIST) ] ; then \
+ $(EXPAND) $(FAILLIST) \
+ | $(CUT) -d' ' -f1 \
+ | $(SED) -e 's@^@FAILED: @' >> $(STATS_TXT); \
+ if [ $${jtregExitCode} = 0 ] ; then \
+ jtregExitCode=1; \
+ fi; \
+ fi; \
+ runc="`$(CAT) $(RUNLIST) | $(WC) -l | $(AWK) '{print $$1;}'`"; \
+ passc="`$(CAT) $(PASSLIST) | $(WC) -l | $(AWK) '{print $$1;}'`"; \
+ failc="`$(CAT) $(FAILLIST) | $(WC) -l | $(AWK) '{print $$1;}'`"; \
+ exclc="FIXME CODETOOLS-7900176"; \
+ $(ECHO) "TEST STATS: name=$(UNIQUE_DIR) run=$${runc} pass=$${passc} fail=$${failc}" \
+ >> $(STATS_TXT); \
+ else \
+ $(ECHO) "Missing file: $${_summary}" >> $(STATS_TXT); \
+ fi; \
+ if [ -f $(STATS_TXT) ] ; then \
+ $(CAT) $(STATS_TXT); \
+ fi; \
+ $(ZIP_UP_RESULTS) ; \
+ $(TESTEXIT) \
+)
+
+################################################################
+
+# Default make rule (runs default JAXP tests)
+all: jaxp_all
+ @$(ECHO) "Testing completed successfully"
+
+# Prep for output
+# Change execute permissions on shared library files.
+# Files in repositories should never have execute permissions, but
+# there are some tests that have pre-built shared libraries, and these
+# windows dll files must have execute permission. Adding execute
+# permission may happen automatically on windows when using certain
+# versions of mercurial but it cannot be guaranteed. And blindly
+# adding execute permission might be seen as a mercurial 'change', so
+# we avoid adding execute permission to repository files. But testing
+# from a plain source tree needs the chmod a+rx. Applying the chmod to
+# all shared libraries not just dll files. And with CYGWIN and sshd
+# service, you may need CYGWIN=ntsec for this to work.
+prep:
+ @$(MKDIR) -p $(ABS_TEST_OUTPUT_DIR)
+ @$(MKDIR) -p `$(DIRNAME) $(ARCHIVE_BUNDLE)`
+ @if [ ! -d $(TEST_ROOT)/../.hg ] ; then \
+ $(FIND) $(TEST_ROOT) \( -name \*.dll -o -name \*.DLL -o -name \*.so \) \
+ -exec $(CHMOD) a+rx {} \; ; \
+ fi
+
+# Cleanup
+clean:
+ @$(RM) -r $(ABS_TEST_OUTPUT_DIR)
+ @$(RM) $(ARCHIVE_BUNDLE)
+
+################################################################
+
+# jtreg tests
+
+# Expect JT_HOME to be set for jtreg tests. (home for jtreg)
+ifndef JT_HOME
+ JT_HOME = $(SLASH_JAVA)/re/jtreg/4.1/promoted/latest/binaries/jtreg
+ ifdef JPRT_JTREG_HOME
+ JT_HOME = $(JPRT_JTREG_HOME)
+ endif
+endif
+
+# Problematic tests to be excluded
+PROBLEM_LISTS=$(call MixedDirs,$(wildcard ProblemList.txt closed/ProblemList.txt))
+
+# Create exclude list for this platform and arch
+ifdef NO_EXCLUDES
+ JTREG_EXCLUSIONS =
+else
+ JTREG_EXCLUSIONS = $(PROBLEM_LISTS:%=-exclude:%)
+endif
+
+# convert list of directories to dos paths
+define MixedDirs
+$(foreach i,$1,$(shell $(GETMIXEDPATH) "${i}"))
+endef
+
+define SummaryInfo
+$(ECHO) "########################################################"
+$(CAT) $(?:%=$(ABS_TEST_OUTPUT_DIR)/%/$(STATS_TXT_NAME))
+$(ECHO) "########################################################"
+endef
+
+# ------------------------------------------------------------------
+
+jaxp_%:
+ $(ECHO) "Running tests: $@"
+ for each in $@; do \
+ $(MAKE) -j 1 TEST_SELECTION=":$$each" UNIQUE_DIR=$$each jtreg_tests; \
+ done
+
+# ------------------------------------------------------------------
+
+ifdef CONCURRENCY
+ EXTRA_JTREG_OPTIONS += -concurrency:$(CONCURRENCY)
+endif
+
+# Default JTREG to run (win32 script works for everybody)
+JTREG = $(JT_HOME)/win32/bin/jtreg
+# run in agentvm mode
+JTREG_BASIC_OPTIONS += -agentvm
+# Only run automatic tests
+JTREG_BASIC_OPTIONS += -a
+# Always turn on assertions
+JTREG_ASSERT_OPTION = -ea -esa
+JTREG_BASIC_OPTIONS += $(JTREG_ASSERT_OPTION)
+# Report details on all failed or error tests, times too
+JTREG_BASIC_OPTIONS += -v:fail,error,time
+# Retain all files for failing tests
+JTREG_BASIC_OPTIONS += -retain:fail,error
+# Ignore tests are not run and completely silent about it
+JTREG_IGNORE_OPTION = -ignore:quiet
+JTREG_BASIC_OPTIONS += $(JTREG_IGNORE_OPTION)
+# Multiple by 4 the timeout numbers
+JTREG_TIMEOUT_OPTION = -timeoutFactor:4
+JTREG_BASIC_OPTIONS += $(JTREG_TIMEOUT_OPTION)
+# Set the max memory for jtreg control vm
+JTREG_MEMORY_OPTION = -J-Xmx512m
+JTREG_BASIC_OPTIONS += $(JTREG_MEMORY_OPTION)
+# Add any extra options
+JTREG_BASIC_OPTIONS += $(EXTRA_JTREG_OPTIONS)
+# Set other vm and test options
+JTREG_TEST_OPTIONS = $(JAVA_ARGS:%=-javaoptions:%) $(JAVA_VM_ARGS:%=-vmoption:%)
+# Set the GC options for test vms
+#JTREG_GC_OPTION = -vmoption:-XX:+UseSerialGC
+#JTREG_TEST_OPTIONS += $(JTREG_GC_OPTION)
+# Set the max memory for jtreg target test vms
+JTREG_TESTVM_MEMORY_OPTION = -vmoption:-Xmx512m
+JTREG_TEST_OPTIONS += $(JTREG_TESTVM_MEMORY_OPTION)
+
+# Make sure jtreg exists
+$(JTREG): $(JT_HOME)
+
+# Run jtreg
+jtreg_tests: prep $(PRODUCT_HOME) $(JTREG)
+ ( \
+ ( JT_HOME=$(shell $(GETMIXEDPATH) "$(JT_HOME)"); \
+ export JT_HOME; \
+ $(shell $(GETMIXEDPATH) "$(JTREG)") \
+ $(JTREG_BASIC_OPTIONS) \
+ -r:$(shell $(GETMIXEDPATH) "$(ABS_TEST_OUTPUT_DIR)/JTreport") \
+ -w:$(shell $(GETMIXEDPATH) "$(ABS_TEST_OUTPUT_DIR)/JTwork") \
+ -jdk:$(shell $(GETMIXEDPATH) "$(PRODUCT_HOME)") \
+ $(JTREG_EXCLUSIONS) \
+ $(JTREG_TEST_OPTIONS) \
+ $(TEST_SELECTION) \
+ ) ; \
+ $(BUNDLE_UP_AND_EXIT) \
+ ) 2>&1 | $(TEE) $(ABS_TEST_OUTPUT_DIR)/output.txt ; $(TESTEXIT)
+
+PHONY_LIST += jtreg_tests
+
+################################################################
+
+# Phony targets (e.g. these are not filenames)
+.PHONY: all clean prep $(PHONY_LIST)
+
+################################################################
--- a/jaxp/test/TEST.ROOT Tue Dec 23 12:40:06 2014 -0800
+++ b/jaxp/test/TEST.ROOT Thu Dec 25 19:46:17 2014 -0800
@@ -2,5 +2,7 @@
# It also contains test-suite configuration information.
# Tests that must run in othervm mode
-othervm.dirs=javax/xml/jaxp/unittest
+othervm.dirs=javax/xml/jaxp
+# Group definitions
+groups=TEST.groups
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jaxp/test/TEST.groups Thu Dec 25 19:46:17 2014 -0800
@@ -0,0 +1,24 @@
+# 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
+# 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.
+#
+
+jaxp_all = \
+ javax/xml/jaxp
--- a/jaxws/.hgtags Tue Dec 23 12:40:06 2014 -0800
+++ b/jaxws/.hgtags Thu Dec 25 19:46:17 2014 -0800
@@ -288,3 +288,4 @@
5455969de31f3083bcfd779b7acc3ab758ecb308 jdk9-b40
4f785187377fe4c7ff388a7026dd72fcccdcfe7a jdk9-b41
301ddb4478fb36d1f025d14e7e48c2a434e9e6ff jdk9-b42
+edc13d27dc871be57d7ca77eef77e6d04972fee2 jdk9-b43
--- a/jdk/.hgtags Tue Dec 23 12:40:06 2014 -0800
+++ b/jdk/.hgtags Thu Dec 25 19:46:17 2014 -0800
@@ -285,3 +285,4 @@
f1ed1540da70a066527fd043413107e47721edbf jdk9-b40
e336cbd8b15e959e70ed02f0f5e93fa76ebd4c07 jdk9-b41
6b2314173433467245261364a52fb8e347fe6342 jdk9-b42
+8c6ad41974f9ab6c33d544b088648314963f2a50 jdk9-b43
--- a/langtools/.hgtags Tue Dec 23 12:40:06 2014 -0800
+++ b/langtools/.hgtags Thu Dec 25 19:46:17 2014 -0800
@@ -285,3 +285,4 @@
c286272a81dd8f6005e22fed0238c4a3f75188c7 jdk9-b40
f7ce2cfa4cdbec0ae0f46080484eace66be7987a jdk9-b41
23a3a063a906a91ba696d792f0eeabf157cd2f86 jdk9-b42
+6a06008aec10d32898ca665685f531c681b28f5f jdk9-b43
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Analyzer.java Thu Dec 25 19:46:17 2014 -0800
@@ -0,0 +1,509 @@
+/*
+ * 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.tools.javac.comp;
+
+import com.sun.source.tree.LambdaExpressionTree;
+import com.sun.tools.javac.code.Source;
+import com.sun.tools.javac.code.Type;
+import com.sun.tools.javac.code.Types;
+import com.sun.tools.javac.tree.JCTree;
+import com.sun.tools.javac.tree.JCTree.JCBlock;
+import com.sun.tools.javac.tree.JCTree.JCClassDecl;
+import com.sun.tools.javac.tree.JCTree.JCDoWhileLoop;
+import com.sun.tools.javac.tree.JCTree.JCEnhancedForLoop;
+import com.sun.tools.javac.tree.JCTree.JCForLoop;
+import com.sun.tools.javac.tree.JCTree.JCIf;
+import com.sun.tools.javac.tree.JCTree.JCLambda;
+import com.sun.tools.javac.tree.JCTree.JCLambda.ParameterKind;
+import com.sun.tools.javac.tree.JCTree.JCMethodDecl;
+import com.sun.tools.javac.tree.JCTree.JCMethodInvocation;
+import com.sun.tools.javac.tree.JCTree.JCNewClass;
+import com.sun.tools.javac.tree.JCTree.JCStatement;
+import com.sun.tools.javac.tree.JCTree.JCSwitch;
+import com.sun.tools.javac.tree.JCTree.JCTypeApply;
+import com.sun.tools.javac.tree.JCTree.JCVariableDecl;
+import com.sun.tools.javac.tree.JCTree.JCWhileLoop;
+import com.sun.tools.javac.tree.JCTree.Tag;
+import com.sun.tools.javac.tree.TreeCopier;
+import com.sun.tools.javac.tree.TreeInfo;
+import com.sun.tools.javac.tree.TreeMaker;
+import com.sun.tools.javac.tree.TreeScanner;
+import com.sun.tools.javac.util.Context;
+import com.sun.tools.javac.util.DefinedBy;
+import com.sun.tools.javac.util.DefinedBy.Api;
+import com.sun.tools.javac.util.Filter;
+import com.sun.tools.javac.util.JCDiagnostic;
+import com.sun.tools.javac.util.JCDiagnostic.DiagnosticType;
+import com.sun.tools.javac.util.List;
+import com.sun.tools.javac.util.ListBuffer;
+import com.sun.tools.javac.util.Log;
+import com.sun.tools.javac.util.Names;
+import com.sun.tools.javac.util.Options;
+
+import java.util.EnumSet;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.function.Predicate;
+
+import static com.sun.tools.javac.code.Flags.GENERATEDCONSTR;
+import static com.sun.tools.javac.code.Flags.SYNTHETIC;
+import static com.sun.tools.javac.code.TypeTag.CLASS;
+import static com.sun.tools.javac.tree.JCTree.Tag.APPLY;
+import static com.sun.tools.javac.tree.JCTree.Tag.CLASSDEF;
+import static com.sun.tools.javac.tree.JCTree.Tag.METHODDEF;
+import static com.sun.tools.javac.tree.JCTree.Tag.NEWCLASS;
+import static com.sun.tools.javac.tree.JCTree.Tag.TYPEAPPLY;
+
+/**
+ * Helper class for defining custom code analysis, such as finding instance creation expression
+ * that can benefit from diamond syntax.
+ */
+public class Analyzer {
+ protected static final Context.Key<Analyzer> analyzerKey = new Context.Key<>();
+
+ final Types types;
+ final Log log;
+ final Attr attr;
+ final DeferredAttr deferredAttr;
+ final TreeMaker make;
+ final Names names;
+
+ final EnumSet<AnalyzerMode> analyzerModes;
+
+ public static Analyzer instance(Context context) {
+ Analyzer instance = context.get(analyzerKey);
+ if (instance == null)
+ instance = new Analyzer(context);
+ return instance;
+ }
+
+ protected Analyzer(Context context) {
+ context.put(analyzerKey, this);
+ types = Types.instance(context);
+ log = Log.instance(context);
+ attr = Attr.instance(context);
+ deferredAttr = DeferredAttr.instance(context);
+ make = TreeMaker.instance(context);
+ names = Names.instance(context);
+ Options options = Options.instance(context);
+ String findOpt = options.get("find");
+ //parse modes
+ Source source = Source.instance(context);
+ analyzerModes = AnalyzerMode.getAnalyzerModes(findOpt, source);
+ }
+
+ /**
+ * This enum defines supported analyzer modes, as well as defining the logic for decoding
+ * the {@code -XDfind} option.
+ */
+ enum AnalyzerMode {
+ DIAMOND("diamond", Source::allowDiamond),
+ LAMBDA("lambda", Source::allowLambda),
+ METHOD("method", Source::allowGraphInference);
+
+ final String opt;
+ final Predicate<Source> sourceFilter;
+
+ AnalyzerMode(String opt, Predicate<Source> sourceFilter) {
+ this.opt = opt;
+ this.sourceFilter = sourceFilter;
+ }
+
+ /**
+ * This method is used to parse the {@code find} option.
+ * Possible modes are separated by colon; a mode can be excluded by
+ * prepending '-' to its name. Finally, the special mode 'all' can be used to
+ * add all modes to the resulting enum.
+ */
+ static EnumSet<AnalyzerMode> getAnalyzerModes(String opt, Source source) {
+ if (opt == null) {
+ return EnumSet.noneOf(AnalyzerMode.class);
+ }
+ List<String> modes = List.from(opt.split(","));
+ EnumSet<AnalyzerMode> res = EnumSet.noneOf(AnalyzerMode.class);
+ if (modes.contains("all")) {
+ res = EnumSet.allOf(AnalyzerMode.class);
+ }
+ for (AnalyzerMode mode : values()) {
+ if (modes.contains(mode.opt)) {
+ res.add(mode);
+ } else if (modes.contains("-" + mode.opt) || !mode.sourceFilter.test(source)) {
+ res.remove(mode);
+ }
+ }
+ return res;
+ }
+ }
+
+ /**
+ * A statement analyzer is a work-unit that matches certain AST nodes (of given type {@code S}),
+ * rewrites them to different AST nodes (of type {@code T}) and then generates some meaningful
+ * messages in case the analysis has been successful.
+ */
+ abstract class StatementAnalyzer<S extends JCTree, T extends JCTree> {
+
+ AnalyzerMode mode;
+ JCTree.Tag tag;
+
+ StatementAnalyzer(AnalyzerMode mode, Tag tag) {
+ this.mode = mode;
+ this.tag = tag;
+ }
+
+ /**
+ * Is this analyzer allowed to run?
+ */
+ boolean isEnabled() {
+ return analyzerModes.contains(mode);
+ }
+
+ /**
+ * Should this analyzer be rewriting the given tree?
+ */
+ abstract boolean match(S tree);
+
+ /**
+ * Rewrite a given AST node into a new one
+ */
+ abstract T map(S oldTree, S newTree);
+
+ /**
+ * Entry-point for comparing results and generating diagnostics.
+ */
+ abstract void process(S oldTree, T newTree, boolean hasErrors);
+
+ }
+
+ /**
+ * This analyzer checks if generic instance creation expression can use diamond syntax.
+ */
+ class DiamondInitializer extends StatementAnalyzer<JCNewClass, JCNewClass> {
+
+ DiamondInitializer() {
+ super(AnalyzerMode.DIAMOND, NEWCLASS);
+ }
+
+ @Override
+ boolean match(JCNewClass tree) {
+ return tree.clazz.hasTag(TYPEAPPLY) &&
+ !TreeInfo.isDiamond(tree) &&
+ tree.def == null;
+ }
+
+ @Override
+ JCNewClass map(JCNewClass oldTree, JCNewClass newTree) {
+ if (newTree.clazz.hasTag(TYPEAPPLY)) {
+ ((JCTypeApply)newTree.clazz).arguments = List.nil();
+ }
+ return newTree;
+ }
+
+ @Override
+ void process(JCNewClass oldTree, JCNewClass newTree, boolean hasErrors) {
+ if (!hasErrors) {
+ List<Type> inferredArgs = newTree.type.getTypeArguments();
+ List<Type> explicitArgs = oldTree.type.getTypeArguments();
+ for (Type t : inferredArgs) {
+ if (!types.isSameType(t, explicitArgs.head)) {
+ log.warning(oldTree.clazz, "diamond.redundant.args.1",
+ oldTree.clazz.type, newTree.clazz.type);
+ return;
+ }
+ explicitArgs = explicitArgs.tail;
+ }
+ //exact match
+ log.warning(oldTree.clazz, "diamond.redundant.args");
+ }
+ }
+ }
+
+ /**
+ * This analyzer checks if anonymous instance creation expression can replaced by lambda.
+ */
+ class LambdaAnalyzer extends StatementAnalyzer<JCNewClass, JCLambda> {
+
+ LambdaAnalyzer() {
+ super(AnalyzerMode.LAMBDA, NEWCLASS);
+ }
+
+ @Override
+ boolean match (JCNewClass tree){
+ Type clazztype = tree.clazz.type;
+ return tree.def != null &&
+ clazztype.hasTag(CLASS) &&
+ types.isFunctionalInterface(clazztype.tsym) &&
+ decls(tree.def).length() == 1;
+ }
+ //where
+ private List<JCTree> decls(JCClassDecl decl) {
+ ListBuffer<JCTree> decls = new ListBuffer<>();
+ for (JCTree t : decl.defs) {
+ if (t.hasTag(METHODDEF)) {
+ JCMethodDecl md = (JCMethodDecl)t;
+ if ((md.getModifiers().flags & GENERATEDCONSTR) == 0) {
+ decls.add(md);
+ }
+ } else {
+ decls.add(t);
+ }
+ }
+ return decls.toList();
+ }
+
+ @Override
+ JCLambda map (JCNewClass oldTree, JCNewClass newTree){
+ JCMethodDecl md = (JCMethodDecl)decls(newTree.def).head;
+ List<JCVariableDecl> params = md.params;
+ JCBlock body = md.body;
+ return make.Lambda(params, body);
+ }
+ @Override
+ void process (JCNewClass oldTree, JCLambda newTree, boolean hasErrors){
+ if (!hasErrors) {
+ log.warning(oldTree.def, "potential.lambda.found");
+ }
+ }
+ }
+
+ /**
+ * This analyzer checks if generic method call has redundant type arguments.
+ */
+ class RedundantTypeArgAnalyzer extends StatementAnalyzer<JCMethodInvocation, JCMethodInvocation> {
+
+ RedundantTypeArgAnalyzer() {
+ super(AnalyzerMode.METHOD, APPLY);
+ }
+
+ @Override
+ boolean match (JCMethodInvocation tree){
+ return tree.typeargs != null &&
+ tree.typeargs.nonEmpty();
+ }
+ @Override
+ JCMethodInvocation map (JCMethodInvocation oldTree, JCMethodInvocation newTree){
+ newTree.typeargs = List.nil();
+ return newTree;
+ }
+ @Override
+ void process (JCMethodInvocation oldTree, JCMethodInvocation newTree, boolean hasErrors){
+ if (!hasErrors) {
+ //exact match
+ log.warning(oldTree, "method.redundant.typeargs");
+ }
+ }
+ }
+
+ @SuppressWarnings({"unchecked", "rawtypes"})
+ StatementAnalyzer<JCTree, JCTree>[] analyzers = new StatementAnalyzer[] {
+ new DiamondInitializer(),
+ new LambdaAnalyzer(),
+ new RedundantTypeArgAnalyzer()
+ };
+
+ /**
+ * Analyze an AST node if needed.
+ */
+ void analyzeIfNeeded(JCTree tree, Env<AttrContext> env) {
+ if (!analyzerModes.isEmpty() &&
+ !env.info.isSpeculative &&
+ TreeInfo.isStatement(tree)) {
+ JCStatement stmt = (JCStatement)tree;
+ analyze(stmt, env);
+ }
+ }
+
+ /**
+ * Analyze an AST node; this involves collecting a list of all the nodes that needs rewriting,
+ * and speculatively type-check the rewritten code to compare results against previously attributed code.
+ */
+ void analyze(JCStatement statement, Env<AttrContext> env) {
+ AnalysisContext context = new AnalysisContext();
+ StatementScanner statementScanner = new StatementScanner(context);
+ statementScanner.scan(statement);
+
+ if (!context.treesToAnalyzer.isEmpty()) {
+
+ //add a block to hoist potential dangling variable declarations
+ JCBlock fakeBlock = make.Block(SYNTHETIC, List.of(statement));
+
+ TreeMapper treeMapper = new TreeMapper(context);
+ //TODO: to further refine the analysis, try all rewriting combinations
+ deferredAttr.attribSpeculative(fakeBlock, env, attr.statInfo, treeMapper,
+ t -> new AnalyzeDeferredDiagHandler(context));
+
+ context.treeMap.entrySet().forEach(e -> {
+ context.treesToAnalyzer.get(e.getKey())
+ .process(e.getKey(), e.getValue(), context.errors.nonEmpty());
+ });
+ }
+ }
+
+ /**
+ * Simple deferred diagnostic handler which filters out all messages and keep track of errors.
+ */
+ class AnalyzeDeferredDiagHandler extends Log.DeferredDiagnosticHandler {
+ AnalysisContext context;
+
+ public AnalyzeDeferredDiagHandler(AnalysisContext context) {
+ super(log, d -> {
+ if (d.getType() == DiagnosticType.ERROR) {
+ context.errors.add(d);
+ }
+ return true;
+ });
+ this.context = context;
+ }
+ }
+
+ /**
+ * This class is used to pass around contextual information bewteen analyzer classes, such as
+ * trees to be rewritten, errors occurred during the speculative attribution step, etc.
+ */
+ class AnalysisContext {
+ /** Map from trees to analyzers. */
+ Map<JCTree, StatementAnalyzer<JCTree, JCTree>> treesToAnalyzer = new HashMap<>();
+
+ /** Map from original AST nodes to rewritten AST nodes */
+ Map<JCTree, JCTree> treeMap = new HashMap<>();
+
+ /** Errors in rewritten tree */
+ ListBuffer<JCDiagnostic> errors = new ListBuffer<>();
+ }
+
+ /**
+ * Subclass of {@link com.sun.tools.javac.tree.TreeScanner} which visit AST-nodes w/o crossing
+ * statement boundaries.
+ */
+ class StatementScanner extends TreeScanner {
+
+ /** context */
+ AnalysisContext context;
+
+ StatementScanner(AnalysisContext context) {
+ this.context = context;
+ }
+
+ @Override
+ @SuppressWarnings("unchecked")
+ public void scan(JCTree tree) {
+ if (tree != null) {
+ for (StatementAnalyzer<JCTree, JCTree> analyzer : analyzers) {
+ if (analyzer.isEnabled() &&
+ tree.hasTag(analyzer.tag) &&
+ analyzer.match(tree)) {
+ context.treesToAnalyzer.put(tree, analyzer);
+ break; //TODO: cover cases where multiple matching analyzers are found
+ }
+ }
+ }
+ super.scan(tree);
+ }
+
+ @Override
+ public void visitClassDef(JCClassDecl tree) {
+ //do nothing (prevents seeing same stuff twice
+ }
+
+ @Override
+ public void visitMethodDef(JCMethodDecl tree) {
+ //do nothing (prevents seeing same stuff twice
+ }
+
+ @Override
+ public void visitBlock(JCBlock tree) {
+ //do nothing (prevents seeing same stuff twice
+ }
+
+ @Override
+ public void visitSwitch(JCSwitch tree) {
+ scan(tree.getExpression());
+ }
+
+ @Override
+ public void visitForLoop(JCForLoop tree) {
+ scan(tree.getInitializer());
+ scan(tree.getCondition());
+ scan(tree.getUpdate());
+ }
+
+ @Override
+ public void visitForeachLoop(JCEnhancedForLoop tree) {
+ scan(tree.getExpression());
+ }
+
+ @Override
+ public void visitWhileLoop(JCWhileLoop tree) {
+ scan(tree.getCondition());
+ }
+
+ @Override
+ public void visitDoLoop(JCDoWhileLoop tree) {
+ scan(tree.getCondition());
+ }
+
+ @Override
+ public void visitIf(JCIf tree) {
+ scan(tree.getCondition());
+ }
+ }
+
+ /**
+ * Subclass of TreeCopier that maps nodes matched by analyzers onto new AST nodes.
+ */
+ class TreeMapper extends TreeCopier<Void> {
+
+ AnalysisContext context;
+
+ TreeMapper(AnalysisContext context) {
+ super(make);
+ this.context = context;
+ }
+
+ @Override
+ @SuppressWarnings("unchecked")
+ public <Z extends JCTree> Z copy(Z tree, Void _unused) {
+ Z newTree = super.copy(tree, _unused);
+ StatementAnalyzer<JCTree, JCTree> analyzer = context.treesToAnalyzer.get(tree);
+ if (analyzer != null) {
+ newTree = (Z)analyzer.map(tree, newTree);
+ context.treeMap.put(tree, newTree);
+ }
+ return newTree;
+ }
+
+ @Override @DefinedBy(Api.COMPILER_TREE)
+ public JCTree visitLambdaExpression(LambdaExpressionTree node, Void _unused) {
+ JCLambda oldLambda = (JCLambda)node;
+ JCLambda newLambda = (JCLambda)super.visitLambdaExpression(node, _unused);
+ if (oldLambda.paramKind == ParameterKind.IMPLICIT) {
+ //reset implicit lambda parameters (whose type might have been set during attr)
+ newLambda.paramKind = ParameterKind.IMPLICIT;
+ newLambda.params.forEach(p -> p.vartype = null);
+ }
+ return newLambda;
+ }
+ }
+}
--- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Attr.java Tue Dec 23 12:40:06 2014 -0800
+++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Attr.java Thu Dec 25 19:46:17 2014 -0800
@@ -83,6 +83,7 @@
final Symtab syms;
final Resolve rs;
final Infer infer;
+ final Analyzer analyzer;
final DeferredAttr deferredAttr;
final Check chk;
final Flow flow;
@@ -121,6 +122,7 @@
make = TreeMaker.instance(context);
enter = Enter.instance(context);
infer = Infer.instance(context);
+ analyzer = Analyzer.instance(context);
deferredAttr = DeferredAttr.instance(context);
cfolder = ConstFold.instance(context);
target = Target.instance(context);
@@ -143,11 +145,8 @@
allowStaticInterfaceMethods = source.allowStaticInterfaceMethods();
sourceName = source.name;
relax = (options.isSet("-retrofit") ||
- options.isSet("-relax"));
- findDiamonds = options.get("findDiamond") != null &&
- source.allowDiamond();
+ options.isSet("-relax"));
useBeforeDeclarationWarning = options.isSet("useBeforeDeclarationWarning");
- identifyLambdaCandidate = options.getBoolean("identifyLambdaCandidate", false);
statInfo = new ResultInfo(KindSelector.NIL, Type.noType);
varAssignmentInfo = new ResultInfo(KindSelector.ASG, Type.noType);
@@ -156,6 +155,8 @@
unknownTypeInfo = new ResultInfo(KindSelector.TYP, Type.noType);
unknownTypeExprInfo = new ResultInfo(KindSelector.VAL_TYP, Type.noType);
recoveryInfo = new RecoveryInfo(deferredAttr.emptyDeferredAttrContext);
+
+ noCheckTree = make.at(-1).Skip();
}
/** Switch: relax some constraints for retrofit mode.
@@ -182,16 +183,6 @@
*/
boolean allowStaticInterfaceMethods;
- /** Switch: generates a warning if diamond can be safely applied
- * to a given new expression
- */
- boolean findDiamonds;
-
- /**
- * Internally enables/disables diamond finder feature
- */
- static final boolean allowDiamondFinder = true;
-
/**
* Switch: warn about use of variable before declaration?
* RFE: 6425594
@@ -199,12 +190,6 @@
boolean useBeforeDeclarationWarning;
/**
- * Switch: generate warnings whenever an anonymous inner class that is convertible
- * to a lambda expression is found
- */
- boolean identifyLambdaCandidate;
-
- /**
* Switch: allow strings in switch?
*/
boolean allowStringsInSwitch;
@@ -231,31 +216,32 @@
final ResultInfo resultInfo) {
InferenceContext inferenceContext = resultInfo.checkContext.inferenceContext();
Type owntype;
- if (!found.hasTag(ERROR) && !resultInfo.pt.hasTag(METHOD) && !resultInfo.pt.hasTag(FORALL)) {
- if (!ownkind.subset(resultInfo.pkind)) {
- log.error(tree.pos(), "unexpected.type",
- resultInfo.pkind.kindNames(),
- ownkind.kindNames());
- owntype = types.createErrorType(found);
- } else if (allowPoly && inferenceContext.free(found)) {
- //delay the check if there are inference variables in the found type
- //this means we are dealing with a partially inferred poly expression
- owntype = resultInfo.pt;
- inferenceContext.addFreeTypeListener(List.of(found, resultInfo.pt), new FreeTypeListener() {
- @Override
- public void typesInferred(InferenceContext inferenceContext) {
+ boolean shouldCheck = !found.hasTag(ERROR) &&
+ !resultInfo.pt.hasTag(METHOD) &&
+ !resultInfo.pt.hasTag(FORALL);
+ if (shouldCheck && !ownkind.subset(resultInfo.pkind)) {
+ log.error(tree.pos(), "unexpected.type",
+ resultInfo.pkind.kindNames(),
+ ownkind.kindNames());
+ owntype = types.createErrorType(found);
+ } else if (allowPoly && inferenceContext.free(found)) {
+ //delay the check if there are inference variables in the found type
+ //this means we are dealing with a partially inferred poly expression
+ owntype = shouldCheck ? resultInfo.pt : found;
+ inferenceContext.addFreeTypeListener(List.of(found, resultInfo.pt),
+ instantiatedContext -> {
ResultInfo pendingResult =
resultInfo.dup(inferenceContext.asInstType(resultInfo.pt));
check(tree, inferenceContext.asInstType(found), ownkind, pendingResult);
- }
- });
- } else {
- owntype = resultInfo.check(tree, found);
- }
+ });
} else {
- owntype = found;
+ owntype = shouldCheck ?
+ resultInfo.check(tree, found) :
+ found;
}
- tree.type = owntype;
+ if (tree != noCheckTree) {
+ tree.type = owntype;
+ }
return owntype;
}
@@ -531,6 +517,10 @@
*/
Type result;
+ /** Synthetic tree to be used during 'fake' checks.
+ */
+ JCTree noCheckTree;
+
/** Visitor method: attribute a tree, catching any completion failure
* exceptions. Return the tree's type.
*
@@ -610,7 +600,13 @@
/** Derived visitor method: attribute a statement or definition tree.
*/
public Type attribStat(JCTree tree, Env<AttrContext> env) {
- return attribTree(tree, env, statInfo);
+ Env<AttrContext> analyzeEnv =
+ env.dup(tree, env.info.dup(env.info.scope.dupUnshared(env.info.scope.owner)));
+ try {
+ return attribTree(tree, env, statInfo);
+ } finally {
+ analyzer.analyzeIfNeeded(tree, analyzeEnv);
+ }
}
/** Attribute a list of expressions, returning a list of types.
@@ -792,8 +788,8 @@
Type attribIdentAsEnumType(Env<AttrContext> env, JCIdent id) {
Assert.check((env.enclClass.sym.flags() & ENUM) != 0);
- id.type = env.info.scope.owner.type;
- id.sym = env.info.scope.owner;
+ id.type = env.info.scope.owner.enclClass().type;
+ id.sym = env.info.scope.owner.enclClass();
return id.type;
}
@@ -2018,7 +2014,7 @@
}
});
Type constructorType = tree.constructorType = types.createErrorType(clazztype);
- constructorType = checkId(tree, site,
+ constructorType = checkId(noCheckTree, site,
constructor,
diamondEnv,
diamondResult);
@@ -2044,7 +2040,7 @@
tree.constructor = rs.resolveConstructor(
tree.pos(), rsEnv, clazztype, argtypes, typeargtypes);
if (cdef == null) { //do not check twice!
- tree.constructorType = checkId(tree,
+ tree.constructorType = checkId(noCheckTree,
clazztype,
tree.constructor,
rsEnv,
@@ -2052,12 +2048,6 @@
if (rsEnv.info.lastResolveVarargs())
Assert.check(tree.constructorType.isErroneous() || tree.varargsElement != null);
}
- if (cdef == null &&
- !clazztype.isErroneous() &&
- clazztype.getTypeArguments().nonEmpty() &&
- findDiamonds) {
- findDiamond(localEnv, tree, clazztype);
- }
}
if (cdef != null) {
@@ -2105,8 +2095,6 @@
attribStat(cdef, localEnv);
- checkLambdaCandidate(tree, cdef.sym, clazztype);
-
// If an outer instance is given,
// prefix it to the constructor arguments
// and delete it from the new expression
@@ -2122,7 +2110,7 @@
tree.pos(), localEnv, clazztype, argtypes, typeargtypes);
Assert.check(!sym.kind.isOverloadError());
tree.constructor = sym;
- tree.constructorType = checkId(tree,
+ tree.constructorType = checkId(noCheckTree,
clazztype,
tree.constructor,
localEnv,
@@ -2133,60 +2121,16 @@
owntype = clazztype;
}
result = check(tree, owntype, KindSelector.VAL, resultInfo);
+ InferenceContext inferenceContext = resultInfo.checkContext.inferenceContext();
+ if (tree.constructorType != null && inferenceContext.free(tree.constructorType)) {
+ //we need to wait for inference to finish and then replace inference vars in the constructor type
+ inferenceContext.addFreeTypeListener(List.of(tree.constructorType),
+ instantiatedContext -> {
+ tree.constructorType = instantiatedContext.asInstType(tree.constructorType);
+ });
+ }
chk.validate(tree.typeargs, localEnv);
}
- //where
- void findDiamond(Env<AttrContext> env, JCNewClass tree, Type clazztype) {
- JCTypeApply ta = (JCTypeApply)tree.clazz;
- List<JCExpression> prevTypeargs = ta.arguments;
- try {
- //create a 'fake' diamond AST node by removing type-argument trees
- ta.arguments = List.nil();
- ResultInfo findDiamondResult = new ResultInfo(KindSelector.VAL,
- resultInfo.checkContext.inferenceContext().free(resultInfo.pt) ? Type.noType : pt());
- Type inferred = deferredAttr.attribSpeculative(tree, env, findDiamondResult).type;
- Type polyPt = allowPoly ?
- syms.objectType :
- clazztype;
- if (!inferred.isErroneous() &&
- (allowPoly && pt() == Infer.anyPoly ?
- types.isSameType(inferred, clazztype) :
- types.isAssignable(inferred, pt().hasTag(NONE) ? polyPt : pt(), types.noWarnings))) {
- String key = types.isSameType(clazztype, inferred) ?
- "diamond.redundant.args" :
- "diamond.redundant.args.1";
- log.warning(tree.clazz.pos(), key, clazztype, inferred);
- }
- } finally {
- ta.arguments = prevTypeargs;
- }
- }
-
- private void checkLambdaCandidate(JCNewClass tree, ClassSymbol csym, Type clazztype) {
- if (allowLambda &&
- identifyLambdaCandidate &&
- clazztype.hasTag(CLASS) &&
- !pt().hasTag(NONE) &&
- types.isFunctionalInterface(clazztype.tsym)) {
- Symbol descriptor = types.findDescriptorSymbol(clazztype.tsym);
- int count = 0;
- boolean found = false;
- for (Symbol sym : csym.members().getSymbols()) {
- if ((sym.flags() & SYNTHETIC) != 0 ||
- sym.isConstructor()) continue;
- count++;
- if (sym.kind != MTH ||
- !sym.name.equals(descriptor.name)) continue;
- Type mtype = types.memberType(clazztype, sym);
- if (types.overrideEquivalent(mtype, types.memberType(clazztype, descriptor))) {
- found = true;
- }
- }
- if (found && count == 1) {
- log.note(tree.def, "potential.lambda.found");
- }
- }
- }
/** Make an attributed null check tree.
*/
@@ -2361,6 +2305,7 @@
preFlow(that);
flow.analyzeLambda(env, that, make, isSpeculativeRound);
+ that.type = currentTarget; //avoids recovery at this stage
checkLambdaCompatible(that, lambdaType, resultInfo.checkContext);
if (!isSpeculativeRound) {
@@ -2801,7 +2746,7 @@
that.kind.isUnbound() ? argtypes.tail : argtypes, typeargtypes),
new FunctionalReturnContext(resultInfo.checkContext));
- Type refType = checkId(that, lookupHelper.site, refSym, localEnv, checkInfo);
+ Type refType = checkId(noCheckTree, lookupHelper.site, refSym, localEnv, checkInfo);
if (that.kind.isUnbound() &&
resultInfo.checkContext.inferenceContext().free(argtypes.head)) {
@@ -2823,6 +2768,8 @@
//is a no-op (as this has been taken care during method applicability)
boolean isSpeculativeRound =
resultInfo.checkContext.deferredAttrContext().mode == DeferredAttr.AttrMode.SPECULATIVE;
+
+ that.type = currentTarget; //avoids recovery at this stage
checkReferenceCompatible(that, desc, refType, resultInfo.checkContext, isSpeculativeRound);
if (!isSpeculativeRound) {
checkAccessibleTypes(that, localEnv, resultInfo.checkContext.inferenceContext(), desc, currentTarget);
@@ -3953,7 +3900,7 @@
all_multicatchTypes.append(ctype);
}
}
- Type t = check(tree, types.lub(multicatchTypes.toList()),
+ Type t = check(noCheckTree, types.lub(multicatchTypes.toList()),
KindSelector.TYP, resultInfo);
if (t.hasTag(CLASS)) {
List<Type> alternatives =
--- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/AttrContext.java Tue Dec 23 12:40:06 2014 -0800
+++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/AttrContext.java Thu Dec 25 19:46:17 2014 -0800
@@ -59,6 +59,10 @@
*/
boolean isSerializable = false;
+ /** Is this a speculative attribution environment?
+ */
+ boolean isSpeculative = false;
+
/** Are arguments to current function applications boxed into an array for varargs?
*/
Resolve.MethodResolutionPhase pendingResolutionPhase = null;
@@ -95,6 +99,7 @@
info.returnResult = returnResult;
info.defaultSuperCallSite = defaultSuperCallSite;
info.isSerializable = isSerializable;
+ info.isSpeculative = isSpeculative;
return info;
}
--- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/DeferredAttr.java Tue Dec 23 12:40:06 2014 -0800
+++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/DeferredAttr.java Thu Dec 25 19:46:17 2014 -0800
@@ -37,6 +37,7 @@
import com.sun.tools.javac.comp.Infer.InferenceContext;
import com.sun.tools.javac.comp.Resolve.MethodResolutionPhase;
import com.sun.tools.javac.tree.JCTree.*;
+import com.sun.tools.javac.util.Log.DeferredDiagnosticHandler;
import java.util.ArrayList;
import java.util.Collections;
@@ -46,6 +47,7 @@
import java.util.Map;
import java.util.Set;
import java.util.WeakHashMap;
+import java.util.function.Function;
import static com.sun.tools.javac.code.TypeTag.*;
import static com.sun.tools.javac.tree.JCTree.Tag.*;
@@ -364,28 +366,16 @@
* disabled during speculative type-checking.
*/
JCTree attribSpeculative(JCTree tree, Env<AttrContext> env, ResultInfo resultInfo) {
- final JCTree newTree = new TreeCopier<>(make).copy(tree);
- Env<AttrContext> speculativeEnv = env.dup(newTree, env.info.dup(env.info.scope.dupUnshared(env.info.scope.owner)));
- Log.DeferredDiagnosticHandler deferredDiagnosticHandler =
- new Log.DeferredDiagnosticHandler(log, new Filter<JCDiagnostic>() {
- public boolean accepts(final JCDiagnostic d) {
- class PosScanner extends TreeScanner {
- boolean found = false;
+ return attribSpeculative(tree, env, resultInfo, new TreeCopier<>(make),
+ (newTree)->new DeferredAttrDiagHandler(log, newTree));
+ }
- @Override
- public void scan(JCTree tree) {
- if (tree != null &&
- tree.pos() == d.getDiagnosticPosition()) {
- found = true;
- }
- super.scan(tree);
- }
- }
- PosScanner posScanner = new PosScanner();
- posScanner.scan(newTree);
- return posScanner.found;
- }
- });
+ <Z> JCTree attribSpeculative(JCTree tree, Env<AttrContext> env, ResultInfo resultInfo, TreeCopier<Z> deferredCopier,
+ Function<JCTree, DeferredDiagnosticHandler> diagHandlerCreator) {
+ final JCTree newTree = deferredCopier.copy(tree);
+ Env<AttrContext> speculativeEnv = env.dup(newTree, env.info.dup(env.info.scope.dupUnshared(env.info.scope.owner)));
+ speculativeEnv.info.isSpeculative = true;
+ Log.DeferredDiagnosticHandler deferredDiagnosticHandler = diagHandlerCreator.apply(newTree);
try {
attr.attribTree(newTree, speculativeEnv, resultInfo);
unenterScanner.scan(newTree);
@@ -413,6 +403,37 @@
}
}
+ static class DeferredAttrDiagHandler extends Log.DeferredDiagnosticHandler {
+
+ static class PosScanner extends TreeScanner {
+ DiagnosticPosition pos;
+ boolean found = false;
+
+ PosScanner(DiagnosticPosition pos) {
+ this.pos = pos;
+ }
+
+ @Override
+ public void scan(JCTree tree) {
+ if (tree != null &&
+ tree.pos() == pos) {
+ found = true;
+ }
+ super.scan(tree);
+ }
+ }
+
+ DeferredAttrDiagHandler(Log log, JCTree newTree) {
+ super(log, new Filter<JCDiagnostic>() {
+ public boolean accepts(JCDiagnostic d) {
+ PosScanner posScanner = new PosScanner(d.getDiagnosticPosition());
+ posScanner.scan(newTree);
+ return posScanner.found;
+ }
+ });
+ }
+ }
+
/**
* A deferred context is created on each method check. A deferred context is
* used to keep track of information associated with the method check, such as
@@ -1221,7 +1242,7 @@
@Override
public void visitNewClass(JCNewClass tree) {
- result = (TreeInfo.isDiamond(tree) || attr.findDiamonds) ?
+ result = TreeInfo.isDiamond(tree) ?
ArgumentExpressionKind.POLY : ArgumentExpressionKind.NO_POLY;
}
--- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/LambdaToMethod.java Tue Dec 23 12:40:06 2014 -0800
+++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/LambdaToMethod.java Thu Dec 25 19:46:17 2014 -0800
@@ -1176,12 +1176,14 @@
@Override
public void visitClassDef(JCClassDecl tree) {
List<Frame> prevStack = frameStack;
+ int prevLambdaCount = lambdaCount;
SyntheticMethodNameCounter prevSyntheticMethodNameCounts =
syntheticMethodNameCounts;
Map<ClassSymbol, Symbol> prevClinits = clinits;
DiagnosticSource prevSource = log.currentSource();
try {
log.useSource(tree.sym.sourcefile);
+ lambdaCount = 0;
syntheticMethodNameCounts = new SyntheticMethodNameCounter();
prevClinits = new HashMap<>();
if (tree.sym.owner.kind == MTH) {
@@ -1208,6 +1210,7 @@
finally {
log.useSource(prevSource.getFile());
frameStack = prevStack;
+ lambdaCount = prevLambdaCount;
syntheticMethodNameCounts = prevSyntheticMethodNameCounts;
clinits = prevClinits;
}
--- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/JavacParser.java Tue Dec 23 12:40:06 2014 -0800
+++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/JavacParser.java Thu Dec 25 19:46:17 2014 -0800
@@ -251,19 +251,19 @@
* mode = NOPARAMS : no parameters allowed for type
* mode = TYPEARG : type argument
*/
- static final int EXPR = 0x1;
- static final int TYPE = 0x2;
- static final int NOPARAMS = 0x4;
- static final int TYPEARG = 0x8;
- static final int DIAMOND = 0x10;
+ protected static final int EXPR = 0x1;
+ protected static final int TYPE = 0x2;
+ protected static final int NOPARAMS = 0x4;
+ protected static final int TYPEARG = 0x8;
+ protected static final int DIAMOND = 0x10;
/** The current mode.
*/
- private int mode = 0;
+ protected int mode = 0;
/** The mode of the term that was parsed last.
*/
- private int lastmode = 0;
+ protected int lastmode = 0;
/* ---------- token management -------------- */
@@ -326,7 +326,7 @@
/** Skip forward until a suitable stop token is found.
*/
- private void skip(boolean stopAtImport, boolean stopAtMemberDecl, boolean stopAtIdentifier, boolean stopAtStatement) {
+ protected void skip(boolean stopAtImport, boolean stopAtMemberDecl, boolean stopAtIdentifier, boolean stopAtStatement) {
while (true) {
switch (token.kind) {
case SEMI:
@@ -403,11 +403,11 @@
}
}
- private JCErroneous syntaxError(int pos, String key, TokenKind... args) {
+ protected JCErroneous syntaxError(int pos, String key, TokenKind... args) {
return syntaxError(pos, List.<JCTree>nil(), key, args);
}
- private JCErroneous syntaxError(int pos, List<JCTree> errs, String key, TokenKind... args) {
+ protected JCErroneous syntaxError(int pos, List<JCTree> errs, String key, TokenKind... args) {
setErrorEndPos(pos);
JCErroneous err = F.at(pos).Erroneous(errs);
reportSyntaxError(err, key, (Object[])args);
@@ -427,7 +427,7 @@
* Report a syntax using the given the position parameter and arguments,
* unless one was already reported at the same position.
*/
- private void reportSyntaxError(int pos, String key, Object... args) {
+ protected void reportSyntaxError(int pos, String key, Object... args) {
JCDiagnostic.DiagnosticPosition diag = new JCDiagnostic.SimpleDiagnosticPosition(pos);
reportSyntaxError(diag, key, args);
}
@@ -436,7 +436,7 @@
* Report a syntax error using the given DiagnosticPosition object and
* arguments, unless one was already reported at the same position.
*/
- private void reportSyntaxError(JCDiagnostic.DiagnosticPosition diagPos, String key, Object... args) {
+ protected void reportSyntaxError(JCDiagnostic.DiagnosticPosition diagPos, String key, Object... args) {
int pos = diagPos.getPreferredPosition();
if (pos > S.errPos() || pos == Position.NOPOS) {
if (token.kind == EOF) {
@@ -459,14 +459,14 @@
/** Generate a syntax error at current position unless one was already
* reported at the same position.
*/
- private JCErroneous syntaxError(String key) {
+ protected JCErroneous syntaxError(String key) {
return syntaxError(token.pos, key);
}
/** Generate a syntax error at current position unless one was
* already reported at the same position.
*/
- private JCErroneous syntaxError(String key, TokenKind arg) {
+ protected JCErroneous syntaxError(String key, TokenKind arg) {
return syntaxError(token.pos, key, arg);
}
@@ -500,7 +500,7 @@
}
/** Diagnose a modifier flag from the set, if any. */
- void checkNoMods(long mods) {
+ protected void checkNoMods(long mods) {
if (mods != 0) {
long lowestMod = mods & -mods;
error(token.pos, "mod.not.allowed.here",
@@ -521,7 +521,7 @@
* @param tree The tree to be used as index in the hashtable
* @param dc The doc comment to associate with the tree, or null.
*/
- void attach(JCTree tree, Comment dc) {
+ protected void attach(JCTree tree, Comment dc) {
if (keepDocComments && dc != null) {
// System.out.println("doc comment = ");System.out.println(dc);//DEBUG
docComments.putComment(tree, dc);
@@ -530,19 +530,19 @@
/* -------- source positions ------- */
- private void setErrorEndPos(int errPos) {
+ protected void setErrorEndPos(int errPos) {
endPosTable.setErrorEndPos(errPos);
}
- private void storeEnd(JCTree tree, int endpos) {
+ protected void storeEnd(JCTree tree, int endpos) {
endPosTable.storeEnd(tree, endpos);
}
- private <T extends JCTree> T to(T t) {
+ protected <T extends JCTree> T to(T t) {
return endPosTable.to(t);
}
- private <T extends JCTree> T toP(T t) {
+ protected <T extends JCTree> T toP(T t) {
return endPosTable.toP(t);
}
@@ -574,7 +574,7 @@
/**
* Ident = IDENTIFIER
*/
- Name ident() {
+ protected Name ident() {
if (token.kind == IDENTIFIER) {
Name name = token.name();
nextToken();
@@ -789,7 +789,7 @@
return term(TYPE);
}
- JCExpression term(int newmode) {
+ protected JCExpression term(int newmode) {
int prevmode = mode;
mode = newmode;
JCExpression t = term();
@@ -1669,7 +1669,7 @@
}
/** Accepts all identifier-like tokens */
- Filter<TokenKind> LAX_IDENTIFIER = new Filter<TokenKind>() {
+ protected Filter<TokenKind> LAX_IDENTIFIER = new Filter<TokenKind>() {
public boolean accepts(TokenKind t) {
return t == IDENTIFIER || t == UNDERSCORE || t == ASSERT || t == ENUM;
}
@@ -2408,7 +2408,7 @@
* | ASSERT Expression [ ":" Expression ] ";"
* | ";"
*/
- JCStatement parseSimpleStatement() {
+ public JCStatement parseSimpleStatement() {
int pos = token.pos;
switch (token.kind) {
case LBRACE:
@@ -2706,7 +2706,7 @@
*
* @param kind Whether to parse an ANNOTATION or TYPE_ANNOTATION
*/
- List<JCAnnotation> annotationsOpt(Tag kind) {
+ protected List<JCAnnotation> annotationsOpt(Tag kind) {
if (token.kind != MONKEYS_AT) return List.nil(); // optimization
ListBuffer<JCAnnotation> buf = new ListBuffer<>();
int prevmode = mode;
@@ -2732,7 +2732,7 @@
* | NATIVE | SYNCHRONIZED | TRANSIENT | VOLATILE | "@"
* | "@" Annotation
*/
- JCModifiers modifiersOpt() {
+ protected JCModifiers modifiersOpt() {
return modifiersOpt(null);
}
protected JCModifiers modifiersOpt(JCModifiers partial) {
@@ -2914,7 +2914,7 @@
* @param reqInit Is an initializer always required?
* @param dc The documentation comment for the variable declarations, or null.
*/
- <T extends ListBuffer<? super JCVariableDecl>> T variableDeclaratorsRest(int pos,
+ protected <T extends ListBuffer<? super JCVariableDecl>> T variableDeclaratorsRest(int pos,
JCModifiers mods,
JCExpression type,
Name name,
@@ -3117,7 +3117,7 @@
/** ImportDeclaration = IMPORT [ STATIC ] Ident { "." Ident } [ "." "*" ] ";"
*/
- JCTree importDeclaration() {
+ protected JCTree importDeclaration() {
int pos = token.pos;
nextToken();
boolean importStatic = false;
@@ -3159,7 +3159,7 @@
* @param mods Any modifiers starting the class or interface declaration
* @param dc The documentation comment for the class, or null.
*/
- JCStatement classOrInterfaceOrEnumDeclaration(JCModifiers mods, Comment dc) {
+ protected JCStatement classOrInterfaceOrEnumDeclaration(JCModifiers mods, Comment dc) {
if (token.kind == CLASS) {
return classDeclaration(mods, dc);
} else if (token.kind == INTERFACE) {
@@ -3569,7 +3569,7 @@
* TypeParametersOpt = ["<" TypeParameter {"," TypeParameter} ">"]
* }
*/
- List<JCTypeParameter> typeParametersOpt() {
+ protected List<JCTypeParameter> typeParametersOpt() {
if (token.kind == LT) {
ListBuffer<JCTypeParameter> typarams = new ListBuffer<>();
nextToken();
@@ -4004,7 +4004,7 @@
allowTypeAnnotations = true;
}
}
- void checkAnnotationsAfterTypeParams(int pos) {
+ protected void checkAnnotationsAfterTypeParams(int pos) {
if (!allowAnnotationsAfterTypeParams) {
log.error(pos, "annotations.after.type.params.not.supported.in.source", source.name);
allowAnnotationsAfterTypeParams = true;
@@ -4092,7 +4092,7 @@
/**
* Store the last error position.
*/
- protected int errorEndPos = Position.NOPOS;
+ public int errorEndPos = Position.NOPOS;
public AbstractEndPosTable(JavacParser parser) {
this.parser = parser;
@@ -4119,13 +4119,13 @@
* will be set only if it is greater than the last stored error position.
* @param errPos The error position
*/
- protected void setErrorEndPos(int errPos) {
+ public void setErrorEndPos(int errPos) {
if (errPos > errorEndPos) {
errorEndPos = errPos;
}
}
- protected void setParser(JavacParser parser) {
+ public void setParser(JavacParser parser) {
this.parser = parser;
}
}
--- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/resources/compiler.properties Tue Dec 23 12:40:06 2014 -0800
+++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/resources/compiler.properties Thu Dec 25 19:46:17 2014 -0800
@@ -1196,9 +1196,6 @@
compiler.note.compressed.diags=\
Some messages have been simplified; recompile with -Xdiags:verbose to get full output
-compiler.note.potential.lambda.found=\
- This anonymous inner class creation can be turned into a lambda expression.
-
# 0: boolean, 1: symbol
compiler.note.lambda.stat=\
Translating lambda expression\n\
@@ -1640,14 +1637,20 @@
# 0: unused, 1: unused
compiler.warn.diamond.redundant.args=\
- redundant type arguments in new expression (use diamond operator instead).
-
-# 0: type, 1: type
+ Redundant type arguments in new expression (use diamond operator instead).
+
+# 0: type, 1: list of type
compiler.warn.diamond.redundant.args.1=\
- redundant type arguments in new expression (use diamond operator instead).\n\
+ Redundant type arguments in new expression (use diamond operator instead).\n\
explicit: {0}\n\
inferred: {1}
+compiler.warn.potential.lambda.found=\
+ This anonymous inner class creation can be turned into a lambda expression.
+
+compiler.warn.method.redundant.typeargs=\
+ Redundant type arguments in method call.
+
# 0: symbol, 1: message segment
compiler.warn.varargs.redundant.trustme.anno=\
Redundant {0} annotation. {1}
--- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/TreeInfo.java Tue Dec 23 12:40:06 2014 -0800
+++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/TreeInfo.java Thu Dec 25 19:46:17 2014 -0800
@@ -313,6 +313,14 @@
}
}
+ /** Return true if the tree corresponds to a statement */
+ public static boolean isStatement(JCTree tree) {
+ return (tree instanceof JCStatement) &&
+ !tree.hasTag(CLASSDEF) &&
+ !tree.hasTag(Tag.BLOCK) &&
+ !tree.hasTag(METHODDEF);
+ }
+
/**
* Return true if the AST corresponds to a static select of the kind A.B
*/
--- a/langtools/src/jdk.dev/share/classes/com/sun/tools/jdeps/JdepsTask.java Tue Dec 23 12:40:06 2014 -0800
+++ b/langtools/src/jdk.dev/share/classes/com/sun/tools/jdeps/JdepsTask.java Thu Dec 25 19:46:17 2014 -0800
@@ -554,8 +554,9 @@
classpaths.addAll(PlatformClassPath.getModules(options.mpath));
if (options.mpath != null) {
initialArchives.addAll(PlatformClassPath.getModules(options.mpath));
+ } else {
+ classpaths.addAll(PlatformClassPath.getJarFiles());
}
- classpaths.addAll(PlatformClassPath.getJarFiles());
// add all classpath archives to the source locations for reporting
sourceLocations.addAll(classpaths);
}
--- a/langtools/test/Makefile Tue Dec 23 12:40:06 2014 -0800
+++ b/langtools/test/Makefile Thu Dec 25 19:46:17 2014 -0800
@@ -21,7 +21,6 @@
ifeq ($(OSNAME), SunOS)
SLASH_JAVA = /java
PLATFORM = solaris
- JT_PLATFORM = solaris
ARCH = $(shell uname -p)
ifeq ($(ARCH), i386)
ARCH=i586
@@ -30,7 +29,6 @@
ifeq ($(OSNAME), Linux)
SLASH_JAVA = /java
PLATFORM = linux
- JT_PLATFORM = linux
ARCH = $(shell uname -m)
ifeq ($(ARCH), i386)
ARCH=i586
@@ -38,7 +36,6 @@
endif
ifeq ($(OSNAME), Darwin)
PLATFORM = bsd
- JT_PLATFORM = linux
ARCH = $(shell uname -m)
ifeq ($(ARCH), i386)
ARCH=i586
@@ -55,7 +52,6 @@
ifeq ($(PLATFORM), windows)
SLASH_JAVA = J:
- JT_PLATFORM = win32
ifeq ($(word 1, $(PROCESSOR_IDENTIFIER)),ia64)
ARCH=ia64
else
@@ -93,8 +89,8 @@
else
JTREG_HOME = $(SLASH_JAVA)/re/jtreg/4.1/promoted/latest/binaries/jtreg
endif
-JTREG = $(JTREG_HOME)/$(JT_PLATFORM)/bin/jtreg
-JTDIFF = $(JTREG_HOME)/$(JT_PLATFORM)/bin/jtdiff
+JTREG = $(JTREG_HOME)/bin/jtreg
+JTDIFF = $(JTREG_HOME)/bin/jtdiff
# Default JCK to run
ifdef JPRT_JCK_HOME
@@ -105,21 +101,19 @@
# Default JDK for JTREG and JCK
#
-# JT_JAVA is the version of java used to run jtreg/JCK. Since it is now
-# standard to execute tests in sameVM mode, it should normally be set the
-# same as TESTJAVA (although not necessarily so.)
+# JT_JAVA is the version of java used to run jtreg/JCK.
#
ifdef JPRT_JAVA_HOME
JT_JAVA = $(JPRT_JAVA_HOME)
else
- JT_JAVA = $(SLASH_JAVA)/re/jdk/1.7.0/archive/fcs/binaries/$(PLATFORM)-$(ARCH)
+ JT_JAVA = $(SLASH_JAVA)/re/jdk/1.9.0/archive/fcs/binaries/$(PLATFORM)-$(ARCH)
endif
# Default JDK to test
ifdef JPRT_IMPORT_PRODUCT_HOME
TESTJAVA = $(JPRT_IMPORT_PRODUCT_HOME)
else
- TESTJAVA = $(SLASH_JAVA)/re/jdk/1.7.0/promoted/latest/binaries/$(PLATFORM)-$(ARCH)
+ TESTJAVA = $(SLASH_JAVA)/re/jdk/1.9.0/promoted/latest/binaries/$(PLATFORM)-$(ARCH)
endif
# PRODUCT_HOME is a JPRT variable pointing to a directory containing the output from
@@ -152,7 +146,7 @@
ifdef CONCURRENCY
JTREG_OPTIONS += -agentvm -concurrency:$(CONCURRENCY)
else
- JTREG_OPTIONS += -samevm
+ JTREG_OPTIONS += -agentvm
endif
ifdef JCK_CONCURRENCY
--- a/langtools/test/tools/javac/diags/examples/DiamondRedundantArgs.java Tue Dec 23 12:40:06 2014 -0800
+++ b/langtools/test/tools/javac/diags/examples/DiamondRedundantArgs.java Thu Dec 25 19:46:17 2014 -0800
@@ -22,8 +22,8 @@
*/
// key: compiler.warn.diamond.redundant.args
-// options: -XDfindDiamond
+// options: -XDfind=diamond
-class Foo<X> {
- Foo<String> fs = new Foo<String>();
+class DiamondRedundantArgs<X> {
+ DiamondRedundantArgs<String> fs = new DiamondRedundantArgs<String>();
}
--- a/langtools/test/tools/javac/diags/examples/DiamondRedundantArgs1.java Tue Dec 23 12:40:06 2014 -0800
+++ b/langtools/test/tools/javac/diags/examples/DiamondRedundantArgs1.java Thu Dec 25 19:46:17 2014 -0800
@@ -22,8 +22,8 @@
*/
// key: compiler.warn.diamond.redundant.args.1
-// options: -XDfindDiamond
+// options: -XDfind=diamond
-class Foo<X> {
- Foo<?> fs = new Foo<String>();
+class DiamondRedundantArgs1<X> {
+ DiamondRedundantArgs1<?> fs = new DiamondRedundantArgs1<String>();
}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/diags/examples/MethodRedundantTypeargs.java Thu Dec 25 19:46:17 2014 -0800
@@ -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. 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.
+ */
+
+// key: compiler.warn.method.redundant.typeargs
+// options: -XDfind=method
+
+class MethodRedundantTypeargs {
+ <Z> Z id(Z z) { return z; }
+
+ void test() {
+ String s = this.<String>id("");
+ }
+}
--- a/langtools/test/tools/javac/diags/examples/PotentialLambdaFound.java Tue Dec 23 12:40:06 2014 -0800
+++ b/langtools/test/tools/javac/diags/examples/PotentialLambdaFound.java Thu Dec 25 19:46:17 2014 -0800
@@ -21,8 +21,8 @@
* questions.
*/
-// key: compiler.note.potential.lambda.found
-// options: -XDidentifyLambdaCandidate=true
+// key: compiler.warn.potential.lambda.found
+// options: -XDfind=lambda
class PotentialLambdaFound {
--- a/langtools/test/tools/javac/generics/diamond/6939780/T6939780.java Tue Dec 23 12:40:06 2014 -0800
+++ b/langtools/test/tools/javac/generics/diamond/6939780/T6939780.java Thu Dec 25 19:46:17 2014 -0800
@@ -1,11 +1,11 @@
/*
* @test /nodynamiccopyright/
- * @bug 6939780 7020044 8009459 8021338
+ * @bug 6939780 7020044 8009459 8021338 8064365
*
* @summary add a warning to detect diamond sites
* @author mcimadamore
- * @compile/ref=T6939780_7.out -Xlint:-options -source 7 T6939780.java -XDrawDiagnostics -XDfindDiamond
- * @compile/ref=T6939780_8.out T6939780.java -XDrawDiagnostics -XDfindDiamond
+ * @compile/ref=T6939780_7.out -Xlint:-options -source 7 T6939780.java -XDrawDiagnostics -XDfind=diamond
+ * @compile/ref=T6939780_8.out T6939780.java -XDrawDiagnostics -XDfind=diamond
*
*/
--- a/langtools/test/tools/javac/generics/diamond/6939780/T6939780_7.out Tue Dec 23 12:40:06 2014 -0800
+++ b/langtools/test/tools/javac/generics/diamond/6939780/T6939780_7.out Thu Dec 25 19:46:17 2014 -0800
@@ -1,4 +1,5 @@
-T6939780.java:21:28: compiler.warn.diamond.redundant.args: T6939780.Foo<java.lang.Number>, T6939780.Foo<java.lang.Number>
+T6939780.java:21:28: compiler.warn.diamond.redundant.args
T6939780.java:22:28: compiler.warn.diamond.redundant.args.1: T6939780.Foo<java.lang.Integer>, T6939780.Foo<java.lang.Number>
-T6939780.java:30:19: compiler.warn.diamond.redundant.args: T6939780.Foo<java.lang.Number>, T6939780.Foo<java.lang.Number>
-3 warnings
+T6939780.java:30:19: compiler.warn.diamond.redundant.args
+T6939780.java:31:19: compiler.warn.diamond.redundant.args.1: T6939780.Foo<java.lang.Integer>, T6939780.Foo<java.lang.Number>
+4 warnings
--- a/langtools/test/tools/javac/generics/diamond/6939780/T6939780_8.out Tue Dec 23 12:40:06 2014 -0800
+++ b/langtools/test/tools/javac/generics/diamond/6939780/T6939780_8.out Thu Dec 25 19:46:17 2014 -0800
@@ -1,7 +1,7 @@
-T6939780.java:20:33: compiler.warn.diamond.redundant.args: T6939780.Foo<java.lang.Number>, T6939780.Foo<java.lang.Number>
-T6939780.java:21:28: compiler.warn.diamond.redundant.args: T6939780.Foo<java.lang.Number>, T6939780.Foo<java.lang.Number>
+T6939780.java:20:33: compiler.warn.diamond.redundant.args
+T6939780.java:21:28: compiler.warn.diamond.redundant.args
T6939780.java:22:28: compiler.warn.diamond.redundant.args.1: T6939780.Foo<java.lang.Integer>, T6939780.Foo<java.lang.Number>
-T6939780.java:29:19: compiler.warn.diamond.redundant.args: T6939780.Foo<java.lang.Number>, T6939780.Foo<java.lang.Number>
-T6939780.java:30:19: compiler.warn.diamond.redundant.args: T6939780.Foo<java.lang.Number>, T6939780.Foo<java.lang.Number>
+T6939780.java:29:19: compiler.warn.diamond.redundant.args
+T6939780.java:30:19: compiler.warn.diamond.redundant.args
T6939780.java:31:19: compiler.warn.diamond.redundant.args.1: T6939780.Foo<java.lang.Integer>, T6939780.Foo<java.lang.Number>
6 warnings
--- a/langtools/test/tools/javac/generics/diamond/7002837/T7002837.java Tue Dec 23 12:40:06 2014 -0800
+++ b/langtools/test/tools/javac/generics/diamond/7002837/T7002837.java Thu Dec 25 19:46:17 2014 -0800
@@ -1,10 +1,10 @@
/*
* @test /nodynamiccopyright/
- * @bug 7002837
+ * @bug 7002837 8064365
*
* @summary Diamond: javac generates diamond inference errors when in 'finder' mode
* @author mcimadamore
- * @compile/fail/ref=T7002837.out -Werror -XDrawDiagnostics -XDfindDiamond T7002837.java
+ * @compile/fail/ref=T7002837.out -Werror -XDrawDiagnostics -XDfind=diamond T7002837.java
*
*/
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/lambda/8066974/T8066974.java Thu Dec 25 19:46:17 2014 -0800
@@ -0,0 +1,44 @@
+/*
+ * @test /nodynamiccopyright/
+ * @bug 8066974
+ * @summary Compiler doesn't infer method's generic type information in lambda body
+ * @compile/fail/ref=T8066974.out -XDrawDiagnostics T8066974.java
+ */
+class T8066974 {
+ static class Throwing<E extends Throwable> { }
+ static class RuntimeThrowing extends Throwing<RuntimeException> { }
+ static class CheckedThrowing extends Throwing<Exception> { }
+
+ interface Parameter {
+ <E extends Throwable> Object m(Throwing<E> tw) throws E;
+ }
+
+ interface Mapper<R> {
+ R m(Parameter p);
+ }
+
+ <Z> Z map(Mapper<Z> mz) { return null; }
+
+ <Z extends Throwable> Mapper<Throwing<Z>> mapper(Throwing<Z> tz) throws Z { return null; }
+
+ static class ThrowingMapper<X extends Throwable> implements Mapper<Throwing<X>> {
+ ThrowingMapper(Throwing<X> arg) throws X { }
+
+ @Override
+ public Throwing<X> m(Parameter p) {
+ return null;
+ }
+ }
+
+ void testRuntime(RuntimeThrowing rt) {
+ map(p->p.m(rt));
+ map(mapper(rt));
+ map(new ThrowingMapper<>(rt));
+ }
+
+ void testChecked(CheckedThrowing ct) {
+ map(p->p.m(ct));
+ map(mapper(ct));
+ map(new ThrowingMapper<>(ct));
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/lambda/8066974/T8066974.out Thu Dec 25 19:46:17 2014 -0800
@@ -0,0 +1,4 @@
+T8066974.java:40:19: compiler.err.unreported.exception.need.to.catch.or.throw: java.lang.Exception
+T8066974.java:41:19: compiler.err.unreported.exception.need.to.catch.or.throw: java.lang.Exception
+T8066974.java:42:13: compiler.err.unreported.exception.need.to.catch.or.throw: java.lang.Exception
+3 errors
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/lambda/8067792/T8067792.java Thu Dec 25 19:46:17 2014 -0800
@@ -0,0 +1,19 @@
+/*
+ * @test /nodynamiccopyright/
+ * @bug 8067792
+ * @summary Javac crashes in finder mode with nested implicit lambdas
+ * @compile/fail/ref=T8067792.out -XDrawDiagnostics -Werror -XDfind=lambda T8067792.java
+ */
+
+import java.util.stream.*;
+import java.util.*;
+
+class T8067792 {
+ void test(Stream<List<?>> sl) {
+ Runnable r = new Runnable() {
+ public void run() {
+ Stream<List<?>> constructor = sl.filter(c -> true);
+ }
+ };
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/lambda/8067792/T8067792.out Thu Dec 25 19:46:17 2014 -0800
@@ -0,0 +1,4 @@
+T8067792.java:13:37: compiler.warn.potential.lambda.found
+- compiler.err.warnings.and.werror
+1 error
+1 warning
--- a/langtools/test/tools/javac/lambda/LambdaConv18.java Tue Dec 23 12:40:06 2014 -0800
+++ b/langtools/test/tools/javac/lambda/LambdaConv18.java Thu Dec 25 19:46:17 2014 -0800
@@ -1,9 +1,9 @@
/*
* @test /nodynamiccopyright/
- * @bug 8003280
+ * @bug 8003280 8064365
* @summary Add lambda tests
* simple test for lambda candidate check
- * @compile/fail/ref=LambdaConv18.out -XDrawDiagnostics -XDidentifyLambdaCandidate=true LambdaConv18.java
+ * @compile/fail/ref=LambdaConv18.out -XDrawDiagnostics -XDfind=lambda LambdaConv18.java
*/
class LambdaConv18 {
--- a/langtools/test/tools/javac/lambda/LambdaConv18.out Tue Dec 23 12:40:06 2014 -0800
+++ b/langtools/test/tools/javac/lambda/LambdaConv18.out Thu Dec 25 19:46:17 2014 -0800
@@ -1,4 +1,5 @@
LambdaConv18.java:23:5: compiler.err.cant.resolve.location: kindname.class, NonExistent, , , (compiler.misc.location: kindname.class, LambdaConv18, null)
-LambdaConv18.java:20:24: compiler.note.potential.lambda.found
+LambdaConv18.java:20:24: compiler.warn.potential.lambda.found
LambdaConv18.java:23:26: compiler.err.cant.resolve.location: kindname.class, NonExistent, , , (compiler.misc.location: kindname.class, LambdaConv18, null)
2 errors
+1 warning
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/lambda/lambdaNaming/TestNonSerializableLambdaNameStability.java Thu Dec 25 19:46:17 2014 -0800
@@ -0,0 +1,100 @@
+/*
+ * 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 8067422
+ * @summary Check that the lambda names are not unnecessarily unstable
+ * @library /tools/lib
+ * @build ToolBox
+ * @run main TestNonSerializableLambdaNameStability
+ */
+
+import com.sun.tools.classfile.ClassFile;
+import com.sun.tools.classfile.Method;
+import java.io.ByteArrayInputStream;
+import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.List;
+import javax.tools.StandardLocation;
+
+public class TestNonSerializableLambdaNameStability {
+
+ public static void main(String... args) throws Exception {
+ new TestNonSerializableLambdaNameStability().run();
+ }
+
+ String lambdaSource = "public class L%d {\n" +
+ " public static class A {\n" +
+ " private Runnable r = () -> { };\n" +
+ " }\n" +
+ " public static class B {\n" +
+ " private Runnable r = () -> { };\n" +
+ " }\n" +
+ " private Runnable r = () -> { };\n" +
+ "}\n";
+
+ String expectedLambdaMethodName = "lambda$new$0";
+
+ void run() throws Exception {
+ List<String> sources = new ArrayList<>();
+
+ for (int i = 0; i < 3; i++) {
+ sources.add(String.format(lambdaSource, i));
+ }
+
+ ToolBox tb = new ToolBox();
+
+ try (ToolBox.MemoryFileManager fm = new ToolBox.MemoryFileManager()) {
+ tb.new JavacTask()
+ .sources(sources.toArray(new String[sources.size()]))
+ .fileManager(fm)
+ .run();
+
+ for (String file : fm.files.get(StandardLocation.CLASS_OUTPUT).keySet()) {
+ byte[] fileBytes = fm.getFileBytes(StandardLocation.CLASS_OUTPUT, file);
+ try (InputStream in = new ByteArrayInputStream(fileBytes)) {
+ boolean foundLambdaMethod = false;
+ ClassFile cf = ClassFile.read(in);
+ StringBuilder seenMethods = new StringBuilder();
+ String sep = "";
+ for (Method m : cf.methods) {
+ String methodName = m.getName(cf.constant_pool);
+ if (expectedLambdaMethodName.equals(methodName)) {
+ foundLambdaMethod = true;
+ break;
+ }
+ seenMethods.append(sep);
+ seenMethods.append(methodName);
+ sep = ", ";
+ }
+
+ if (!foundLambdaMethod) {
+ throw new AbstractMethodError("Did not find the lambda method, " +
+ "found methods: " + seenMethods.toString());
+ }
+ }
+ }
+ }
+ }
+}
--- a/langtools/test/tools/javac/lambda/speculative/DiamondFinder.java Tue Dec 23 12:40:06 2014 -0800
+++ b/langtools/test/tools/javac/lambda/speculative/DiamondFinder.java Thu Dec 25 19:46:17 2014 -0800
@@ -23,10 +23,10 @@
/*
* @test
- * @bug 8003280
+ * @bug 8003280 8064365
* @summary Add lambda tests
* spurious crashes when running in 'diamond finder' mode
- * @compile -XDfindDiamond DiamondFinder.java
+ * @compile -XDfind=diamond DiamondFinder.java
*/
import java.util.*;
--- a/make/Javadoc.gmk Tue Dec 23 12:40:06 2014 -0800
+++ b/make/Javadoc.gmk Thu Dec 25 19:46:17 2014 -0800
@@ -53,8 +53,7 @@
JAVADOC_CMD = $(JAVA) \
-Djava.awt.headless=true \
- $(NEW_JAVADOC) \
- -bootclasspath $(JDK_OUTPUTDIR)/classes
+ $(NEW_JAVADOC)
# Copyright year for beginning of Java and some of the apis
# (Needed when creating the javadocs)
@@ -231,17 +230,17 @@
# Common echo of option
define OptionOnly # opt
- if [ "$1" != "" ] ; then \
- $(PRINTF) "%s\n" "$1"; \
+ if [ "$(strip $1)" != "" ] ; then \
+ $(PRINTF) "%s\n" "$(strip $1)"; \
fi
endef
define OptionPair # opt arg
- $(PRINTF) "%s '%s'\n" "$1" '$2'
+ $(PRINTF) "%s '%s'\n" "$(strip $1)" '$(strip $2)'
endef
define OptionTrip # opt arg arg
- $(PRINTF) "%s '%s' '%s'\n" "$1" '$2' '$3'
+ $(PRINTF) "%s '%s' '%s'\n" "$(strip $1)" '$(strip $2)' '$(strip $3)'
endef
# Core api bottom argument (with special sauce)
--- a/make/Main.gmk Tue Dec 23 12:40:06 2014 -0800
+++ b/make/Main.gmk Thu Dec 25 19:46:17 2014 -0800
@@ -257,7 +257,7 @@
test:
($(CD) $(SRC_ROOT)/test && $(MAKE) $(MAKE_ARGS) -j1 -k MAKEFLAGS= \
- JT_HOME=$(JT_HOME) PRODUCT_HOME=$(JDK_OUTPUTDIR) \
+ JT_HOME=$(JT_HOME) PRODUCT_HOME=$(JDK_IMAGE_DIR) \
ALT_OUTPUTDIR=$(OUTPUT_ROOT) CONCURRENCY=$(JOBS) $(TEST)) || true
test-make:
@@ -394,7 +394,7 @@
docs-jvmtidoc: hotspot
- test: exploded-image
+ test: jimages
verify-modules: exploded-image
--- a/make/StripBinaries.gmk Tue Dec 23 12:40:06 2014 -0800
+++ b/make/StripBinaries.gmk Thu Dec 25 19:46:17 2014 -0800
@@ -66,11 +66,6 @@
$(shell $(FIND) $(SUPPORT_OUTPUTDIR)/modules_libs \
-name '*$(SHARED_LIBRARY_SUFFIX)' -type f)
-# On Windows, don't include debug info for libs either.
-ifeq ($(OPENJDK_TARGET_OS), windows)
- COPY_LIBS_SRC := $(filter-out %.diz %.map %.pdb, $(COPY_LIBS_SRC))
-endif
-
$(eval $(call SetupCopyFiles,STRIP_MODULES_CMDS, \
SRC := $(SUPPORT_OUTPUTDIR)/modules_cmds, \
DEST := $(MODULES_CMDS_STRIPPED), \
--- a/make/jprt.properties Tue Dec 23 12:40:06 2014 -0800
+++ b/make/jprt.properties Thu Dec 25 19:46:17 2014 -0800
@@ -188,6 +188,13 @@
${my.test.target.set:TESTNAME=svc_tools}, \
${my.make.rule.test.targets.svc.extra}
+# JAXP vm test targets (testset=jaxp)
+my.test.targets.jaxp=
+
+# JAXP test targets (testset=jaxp)
+my.make.rule.test.targets.jaxp= \
+ ${my.test.target.set:TESTNAME=jaxp_all}
+
# All vm test targets (testset=all)
my.test.targets.all= \
${my.test.targets.default}, \
@@ -211,7 +218,8 @@
my.make.rule.test.targets.pit= \
${my.test.target.set:TESTNAME=langtools_jtreg}, \
${my.make.rule.test.targets.core}, \
- ${my.make.rule.test.targets.svc}
+ ${my.make.rule.test.targets.svc} \
+ ${my.make.rule.test.targets.jaxp}
# JCK test targets in test/Makefile (no windows)
my.test.target.set.jck= \
--- a/nashorn/.hgtags Tue Dec 23 12:40:06 2014 -0800
+++ b/nashorn/.hgtags Thu Dec 25 19:46:17 2014 -0800
@@ -276,3 +276,4 @@
74dcd8dbef252938d6deb032aefb46b8f452dd9e jdk9-b40
52340a35aec9955d4aeaaf01d6337284f179b31c jdk9-b41
498d1d6c4219086143b764b3bf61afe65dcece47 jdk9-b42
+8ae8dff2a28f3b8831cce97ae0c7a957c5dc650a jdk9-b43
--- a/nashorn/make/build.xml Tue Dec 23 12:40:06 2014 -0800
+++ b/nashorn/make/build.xml Thu Dec 25 19:46:17 2014 -0800
@@ -209,7 +209,7 @@
</target>
<target name="javadoc" depends="jar">
- <javadoc destdir="${dist.javadoc.dir}" use="yes" overview="src/overview.html"
+ <javadoc destdir="${dist.javadoc.dir}" use="yes" overview="${src.dir}/overview.html"
extdirs="${nashorn.ext.path}" windowtitle="${nashorn.product.name} ${nashorn.version}"
additionalparam="-quiet" failonerror="true">
<classpath>
--- a/nashorn/make/nbproject/ide-targets.xml Tue Dec 23 12:40:06 2014 -0800
+++ b/nashorn/make/nbproject/ide-targets.xml Thu Dec 25 19:46:17 2014 -0800
@@ -32,9 +32,8 @@
</nbjpdastart>
<java classname="jdk.nashorn.tools.Shell" classpath="${run.test.classpath}" dir="samples" fork="true">
<jvmarg line="-Dnashorn.optimistic"/>
- <jvmarg line="${ext.class.path}"/>
+ <jvmarg line="${boot.class.path}"/>
<jvmarg line="${run.test.jvmargs}"/>
- <arg value="../samples/test.js"/>
<jvmarg value="-Xdebug"/>
<jvmarg value="-Xrunjdwp:transport=dt_socket,address=${jpda.address}"/>
</java>
--- a/nashorn/make/nbproject/project.xml Tue Dec 23 12:40:06 2014 -0800
+++ b/nashorn/make/nbproject/project.xml Thu Dec 25 19:46:17 2014 -0800
@@ -38,10 +38,6 @@
<encoding>UTF-8</encoding>
</source-folder>
<source-folder>
- <label>../src</label>
- <location>../src</location>
- </source-folder>
- <source-folder>
<label>../test/src</label>
<location>../test/src</location>
</source-folder>
@@ -50,21 +46,25 @@
<location>../buildtools/nasgen/src</location>
</source-folder>
<source-folder>
+ <label>../src/jdk.scripting.nashorn/share/classes</label>
+ <location>../src/jdk.scripting.nashorn/share/classes</location>
+ </source-folder>
+ <source-folder>
<label>../test/src</label>
<type>java</type>
<location>../test/src</location>
<encoding>UTF-8</encoding>
</source-folder>
<source-folder>
- <label>../src</label>
+ <label>../buildtools/nasgen/src</label>
<type>java</type>
- <location>../src</location>
+ <location>../buildtools/nasgen/src</location>
<encoding>UTF-8</encoding>
</source-folder>
<source-folder>
- <label>../buildtools/nasgen/src</label>
+ <label>../src/jdk.scripting.nashorn/share/classes</label>
<type>java</type>
- <location>../buildtools/nasgen/src</location>
+ <location>../src/jdk.scripting.nashorn/share/classes</location>
<encoding>UTF-8</encoding>
</source-folder>
</folders>
@@ -132,12 +132,12 @@
<location>../test/src</location>
</source-folder>
<source-folder style="packages">
- <label>../src</label>
- <location>../src</location>
+ <label>../buildtools/nasgen/src</label>
+ <location>../buildtools/nasgen/src</location>
</source-folder>
<source-folder style="packages">
- <label>../buildtools/nasgen/src</label>
- <location>../buildtools/nasgen/src</location>
+ <label>../src/jdk.scripting.nashorn/share/classes</label>
+ <location>../src/jdk.scripting.nashorn/share/classes</location>
</source-folder>
<source-file>
<location>build.xml</location>
@@ -159,11 +159,7 @@
<compilation-unit>
<package-root>../test/src</package-root>
<unit-tests/>
- <classpath mode="compile">../test/lib/testng.jar:../build/classes:../src</classpath>
- <source-level>1.7</source-level>
- </compilation-unit>
- <compilation-unit>
- <package-root>../src</package-root>
+ <classpath mode="compile">../test/lib/testng.jar:../build/classes:../src/jdk.scripting.nashorn/share/classes</classpath>
<source-level>1.7</source-level>
</compilation-unit>
<compilation-unit>
@@ -171,6 +167,10 @@
<classpath mode="compile">../build/classes:../src</classpath>
<source-level>1.7</source-level>
</compilation-unit>
+ <compilation-unit>
+ <package-root>../src/jdk.scripting.nashorn/share/classes</package-root>
+ <source-level>1.7</source-level>
+ </compilation-unit>
</java-data>
</configuration>
</project>
--- a/nashorn/make/project.properties Tue Dec 23 12:40:06 2014 -0800
+++ b/nashorn/make/project.properties Thu Dec 25 19:46:17 2014 -0800
@@ -24,7 +24,7 @@
application.title=nashorn
# location of JDK embedded ASM sources
-jdk.asm.src.dir=../jdk/src/share/classes/jdk/internal/org/objectweb/asm
+jdk.asm.src.dir=../jdk/src/java.base/share/classes/jdk/internal/org/objectweb/asm
# source and target levels
build.compiler=modern
--- a/nashorn/samples/browser_dom.js Tue Dec 23 12:40:06 2014 -0800
+++ b/nashorn/samples/browser_dom.js Thu Dec 25 19:46:17 2014 -0800
@@ -1,4 +1,4 @@
-#// Usage: jjs -fx browser.js
+#// Usage: jjs -fx browser_dom.js
/*
* Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
@@ -32,7 +32,7 @@
*/
if (!$OPTIONS._fx) {
- print("Usage: jjs -fx browser.js");
+ print("Usage: jjs -fx browser_dom.js");
exit(1);
}
@@ -40,7 +40,6 @@
var ChangeListener = Java.type("javafx.beans.value.ChangeListener");
var Scene = Java.type("javafx.scene.Scene");
var WebView = Java.type("javafx.scene.web.WebView");
-var EventListener = Java.type("org.w3c.dom.events.EventListener");
// JavaFX start method
function start(stage) {
@@ -74,10 +73,10 @@
var btn = document.createElement("button");
var n = 0;
// attach a button handler - nashorn function!
- btn.onclick = new EventListener(function() {
+ btn.onclick = function() {
n++; print("You clicked " + n + " time(s)");
print("you clicked OK " + wv.engine.executeScript("okCount"));
- });
+ };
// attach text to button
var t = document.createTextNode("Click Me!");
btn.appendChild(t);
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/samples/time_color.fx Thu Dec 25 19:46:17 2014 -0800
@@ -0,0 +1,89 @@
+#// Usage: jjs -fx time_color.js [-- true/false]
+
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * - Neither the name of Oracle nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+// A simple javafx program that changes background color
+// of scene based on current time value (once per sec).
+// inspired by http://whatcolourisit.scn9a.org/
+
+if (!$OPTIONS._fx) {
+ print("Usage: jjs -fx time_color.js");
+ print(" jjs -fx time_color.js -- true");
+ exit(1);
+}
+
+// JavaFX classes used
+var Color = Java.type("javafx.scene.paint.Color");
+var Group = Java.type("javafx.scene.Group");
+var Label = Java.type("javafx.scene.control.Label");
+var Platform = Java.type("javafx.application.Platform");
+var Scene = Java.type("javafx.scene.Scene");
+var Timer = Java.type("java.util.Timer");
+
+// execute function periodically once per given time in millisec
+function setInterval(func, ms) {
+ // New timer, run as daemon so the application can quit
+ var timer = new Timer("setInterval", true);
+ timer.schedule(function() Platform.runLater(func), ms, ms);
+ return timer;
+}
+
+// do you want to flip hour/min/sec for RGB?
+var flip = arguments.length > 0? "true".equals(arguments[0]) : false;
+
+// JavaFX start method
+function start(stage) {
+ start.title = "Time Color";
+ var root = new Group();
+ var label = new Label("time");
+ label.textFill = Color.WHITE;
+ root.children.add(label);
+ stage.scene = new Scene(root, 700, 500);
+
+ setInterval(function() {
+ var d = new Date();
+ var hours = d.getHours();
+ var mins = d.getMinutes();
+ var secs = d.getSeconds();
+
+ if (hours < 10) hours = "0" + hours;
+ if (mins < 10) mins = "0" + mins;
+ if (secs < 10) secs = "0" + secs;
+
+ var hex = flip?
+ "#" + secs + mins + hours : "#" + hours + mins + secs;
+ label.text = "Color: " + hex;
+ stage.scene.fill = Color.web(hex);
+ }, 1000);
+
+ stage.show();
+}
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/LocalVariableTypesCalculator.java Tue Dec 23 12:40:06 2014 -0800
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/LocalVariableTypesCalculator.java Thu Dec 25 19:46:17 2014 -0800
@@ -40,21 +40,22 @@
import java.util.List;
import java.util.Map;
import java.util.Set;
-import java.util.function.Function;
import jdk.nashorn.internal.codegen.types.Type;
import jdk.nashorn.internal.ir.AccessNode;
-import jdk.nashorn.internal.ir.BaseNode;
import jdk.nashorn.internal.ir.BinaryNode;
import jdk.nashorn.internal.ir.Block;
import jdk.nashorn.internal.ir.BreakNode;
import jdk.nashorn.internal.ir.BreakableNode;
+import jdk.nashorn.internal.ir.CallNode;
import jdk.nashorn.internal.ir.CaseNode;
import jdk.nashorn.internal.ir.CatchNode;
import jdk.nashorn.internal.ir.ContinueNode;
import jdk.nashorn.internal.ir.Expression;
+import jdk.nashorn.internal.ir.ExpressionStatement;
import jdk.nashorn.internal.ir.ForNode;
import jdk.nashorn.internal.ir.FunctionNode;
import jdk.nashorn.internal.ir.FunctionNode.CompilationState;
+import jdk.nashorn.internal.ir.GetSplitState;
import jdk.nashorn.internal.ir.IdentNode;
import jdk.nashorn.internal.ir.IfNode;
import jdk.nashorn.internal.ir.IndexNode;
@@ -65,9 +66,11 @@
import jdk.nashorn.internal.ir.LexicalContext;
import jdk.nashorn.internal.ir.LexicalContextNode;
import jdk.nashorn.internal.ir.LiteralNode;
+import jdk.nashorn.internal.ir.LiteralNode.ArrayLiteralNode;
import jdk.nashorn.internal.ir.LocalVariableConversion;
import jdk.nashorn.internal.ir.LoopNode;
import jdk.nashorn.internal.ir.Node;
+import jdk.nashorn.internal.ir.ObjectNode;
import jdk.nashorn.internal.ir.PropertyNode;
import jdk.nashorn.internal.ir.ReturnNode;
import jdk.nashorn.internal.ir.RuntimeNode;
@@ -82,6 +85,7 @@
import jdk.nashorn.internal.ir.UnaryNode;
import jdk.nashorn.internal.ir.VarNode;
import jdk.nashorn.internal.ir.WhileNode;
+import jdk.nashorn.internal.ir.WithNode;
import jdk.nashorn.internal.ir.visitor.NodeVisitor;
import jdk.nashorn.internal.parser.TokenType;
@@ -131,8 +135,44 @@
OBJECT(Type.OBJECT);
private final Type type;
+ private final TypeHolderExpression typeExpression;
+
private LvarType(final Type type) {
this.type = type;
+ this.typeExpression = new TypeHolderExpression(type);
+ }
+ }
+
+ /**
+ * A bogus Expression subclass that only reports its type. Used to interrogate BinaryNode and UnaryNode about their
+ * types by creating temporary copies of them and replacing their operands with instances of these. An alternative
+ * solution would be to add BinaryNode.getType(Type lhsType, Type rhsType) and UnaryNode.getType(Type exprType)
+ * methods. For the time being though, this is easier to implement and is in fact fairly clean. It does result in
+ * generation of higher number of temporary short lived nodes, though.
+ */
+ private static class TypeHolderExpression extends Expression {
+ private static final long serialVersionUID = 1L;
+
+ private final Type type;
+
+ TypeHolderExpression(final Type type) {
+ super(0L, 0, 0);
+ this.type = type;
+ }
+
+ @Override
+ public Node accept(final NodeVisitor<? extends LexicalContext> visitor) {
+ throw new AssertionError();
+ }
+
+ @Override
+ public Type getType() {
+ return type;
+ }
+
+ @Override
+ public void toString(final StringBuilder sb, final boolean printType) {
+ throw new AssertionError();
}
}
@@ -359,6 +399,8 @@
// allocates a new map. Immutability of maps allows for cheap snapshots by just keeping the reference to the current
// value.
private Map<Symbol, LvarType> localVariableTypes = new IdentityHashMap<>();
+ // Stack for evaluated expression types.
+ private final Deque<LvarType> typeStack = new ArrayDeque<>();
// Whether the current point in the AST is reachable code
private boolean reachable = true;
@@ -375,8 +417,6 @@
private final Map<IdentNode, LvarType> identifierLvarTypes = new IdentityHashMap<>();
private final Map<Symbol, SymbolConversions> symbolConversions = new IdentityHashMap<>();
- private SymbolToType symbolToType = new SymbolToType();
-
// Stack of open labels for starts of catch blocks, one for every currently traversed try block; for inserting
// control flow edges to them. Note that we currently don't insert actual control flow edges, but instead edges that
// help us with type calculations. This means that some operations that can result in an exception being thrown
@@ -400,62 +440,56 @@
private void doesNotContinueSequentially() {
reachable = false;
localVariableTypes = Collections.emptyMap();
+ assertTypeStackIsEmpty();
}
+ private boolean pushExpressionType(final Expression expr) {
+ typeStack.push(toLvarType(expr.getType()));
+ return false;
+ }
+
+ @Override
+ public boolean enterAccessNode(final AccessNode accessNode) {
+ visitExpression(accessNode.getBase());
+ return pushExpressionType(accessNode);
+ }
@Override
public boolean enterBinaryNode(final BinaryNode binaryNode) {
// NOTE: regardless of operator's lexical associativity, lhs is always evaluated first.
final Expression lhs = binaryNode.lhs();
- final boolean isAssignment = binaryNode.isAssignment();
- LvarType lhsTypeOnLoad = null;
- if(isAssignment) {
- if(lhs instanceof BaseNode) {
- ((BaseNode)lhs).getBase().accept(this);
- if(lhs instanceof IndexNode) {
- ((IndexNode)lhs).getIndex().accept(this);
- } else {
- assert lhs instanceof AccessNode;
- }
- } else {
- assert lhs instanceof IdentNode;
- if(binaryNode.isSelfModifying()) {
- final IdentNode ident = ((IdentNode)lhs);
- ident.accept(this);
- // Self-assignment can cause a change in the type of the variable. For purposes of evaluating
- // the type of the operation, we must use its type as it was when it was loaded. If we didn't
- // do this, some awkward expressions would end up being calculated incorrectly, e.g.
- // "var x; x += x = 0;". In this case we have undefined+int so the result type is double (NaN).
- // However, if we used the type of "x" on LHS after we evaluated RHS, we'd see int+int, so the
- // result type would be either optimistic int or pessimistic long, which would be wrong.
- lhsTypeOnLoad = getLocalVariableTypeIfBytecode(ident.getSymbol());
- }
- }
+ final LvarType lhsType;
+ if (!(lhs instanceof IdentNode && binaryNode.tokenType() == TokenType.ASSIGN)) {
+ lhsType = visitExpression(lhs);
} else {
- lhs.accept(this);
+ // Can't visit IdentNode on LHS of a simple assignment, as visits imply use, and this is def.
+ // The type is irrelevant, as only RHS is used to determine the type anyway.
+ lhsType = LvarType.UNDEFINED;
}
final boolean isLogical = binaryNode.isLogical();
- assert !(isAssignment && isLogical); // there are no logical assignment operators in JS
final Label joinLabel = isLogical ? new Label("") : null;
if(isLogical) {
jumpToLabel((JoinPredecessor)lhs, joinLabel);
}
final Expression rhs = binaryNode.rhs();
- rhs.accept(this);
+ final LvarType rhsType = visitExpression(rhs);
if(isLogical) {
jumpToLabel((JoinPredecessor)rhs, joinLabel);
}
joinOnLabel(joinLabel);
- if(isAssignment && lhs instanceof IdentNode) {
+ final LvarType type = toLvarType(binaryNode.setOperands(lhsType.typeExpression, rhsType.typeExpression).getType());
+
+ if(binaryNode.isAssignment() && lhs instanceof IdentNode) {
if(binaryNode.isSelfModifying()) {
- onSelfAssignment((IdentNode)lhs, binaryNode, lhsTypeOnLoad);
+ onSelfAssignment((IdentNode)lhs, type);
} else {
- onAssignment((IdentNode)lhs, rhs);
+ onAssignment((IdentNode)lhs, type);
}
}
+ typeStack.push(type);
return false;
}
@@ -475,6 +509,17 @@
}
@Override
+ public boolean enterCallNode(final CallNode callNode) {
+ visitExpression(callNode.getFunction());
+ visitExpressions(callNode.getArgs());
+ final CallNode.EvalArgs evalArgs = callNode.getEvalArgs();
+ if (evalArgs != null) {
+ visitExpressions(evalArgs.getArgs());
+ }
+ return pushExpressionType(callNode);
+ }
+
+ @Override
public boolean enterContinueNode(final ContinueNode continueNode) {
return enterJumpStatement(continueNode);
}
@@ -483,6 +528,7 @@
if(!reachable) {
return false;
}
+ assertTypeStackIsEmpty();
final BreakableNode target = jump.getTarget(lc);
jumpToLabel(jump, jump.getTargetLabel(target), getBreakTargetTypes(target));
doesNotContinueSequentially();
@@ -495,6 +541,7 @@
}
private void enterDoWhileLoop(final WhileNode loopNode) {
+ assertTypeStackIsEmpty();
final JoinPredecessorExpression test = loopNode.getTest();
final Block body = loopNode.getBody();
final Label continueLabel = loopNode.getContinueLabel();
@@ -512,7 +559,7 @@
if(!reachable) {
break;
}
- test.accept(this);
+ visitExpressionOnEmptyStack(test);
jumpToLabel(test, breakLabel);
if(isAlwaysFalse(test)) {
break;
@@ -535,6 +582,45 @@
}
@Override
+ public boolean enterExpressionStatement(final ExpressionStatement expressionStatement) {
+ if (reachable) {
+ visitExpressionOnEmptyStack(expressionStatement.getExpression());
+ }
+ return false;
+ }
+
+ private void assertTypeStackIsEmpty() {
+ assert typeStack.isEmpty();
+ }
+
+ @Override
+ protected Node leaveDefault(final Node node) {
+ assert !(node instanceof Expression); // All expressions were handled
+ assert !(node instanceof Statement) || typeStack.isEmpty(); // No statements leave with a non-empty stack
+ return node;
+ }
+
+ private LvarType visitExpressionOnEmptyStack(final Expression expr) {
+ assertTypeStackIsEmpty();
+ return visitExpression(expr);
+ }
+
+ private LvarType visitExpression(final Expression expr) {
+ final int stackSize = typeStack.size();
+ expr.accept(this);
+ assert typeStack.size() == stackSize + 1;
+ return typeStack.pop();
+ }
+
+ private void visitExpressions(final List<Expression> exprs) {
+ for(final Expression expr: exprs) {
+ if (expr != null) {
+ visitExpression(expr);
+ }
+ }
+ }
+
+ @Override
public boolean enterForNode(final ForNode forNode) {
if(!reachable) {
return false;
@@ -543,7 +629,7 @@
final Expression init = forNode.getInit();
if(forNode.isForIn()) {
final JoinPredecessorExpression iterable = forNode.getModify();
- iterable.accept(this);
+ visitExpression(iterable);
enterTestFirstLoop(forNode, null, init,
// If we're iterating over property names, and we can discern from the runtime environment
// of the compilation that the object being iterated over must use strings for property
@@ -552,16 +638,18 @@
!compiler.useOptimisticTypes() || (!forNode.isForEach() && compiler.hasStringPropertyIterator(iterable.getExpression())));
} else {
if(init != null) {
- init.accept(this);
+ visitExpressionOnEmptyStack(init);
}
enterTestFirstLoop(forNode, forNode.getModify(), null, false);
}
+ assertTypeStackIsEmpty();
return false;
}
@Override
public boolean enterFunctionNode(final FunctionNode functionNode) {
if(alreadyEnteredTopLevelFunction) {
+ typeStack.push(LvarType.OBJECT);
return false;
}
int pos = 0;
@@ -603,11 +691,20 @@
}
@Override
+ public boolean enterGetSplitState(final GetSplitState getSplitState) {
+ return pushExpressionType(getSplitState);
+ }
+
+ @Override
public boolean enterIdentNode(final IdentNode identNode) {
final Symbol symbol = identNode.getSymbol();
if(symbol.isBytecodeLocal()) {
symbolIsUsed(symbol);
- setIdentifierLvarType(identNode, getLocalVariableType(symbol));
+ final LvarType type = getLocalVariableType(symbol);
+ setIdentifierLvarType(identNode, type);
+ typeStack.push(type);
+ } else {
+ pushExpressionType(identNode);
}
return false;
}
@@ -622,11 +719,12 @@
final Block pass = ifNode.getPass();
final Block fail = ifNode.getFail();
- test.accept(this);
+ visitExpressionOnEmptyStack(test);
final Map<Symbol, LvarType> afterTestLvarTypes = localVariableTypes;
if(!isAlwaysFalse(test)) {
pass.accept(this);
+ assertTypeStackIsEmpty();
}
final Map<Symbol, LvarType> passLvarTypes = localVariableTypes;
final boolean reachableFromPass = reachable;
@@ -635,6 +733,7 @@
localVariableTypes = afterTestLvarTypes;
if(!isAlwaysTrue(test) && fail != null) {
fail.accept(this);
+ assertTypeStackIsEmpty();
final boolean reachableFromFail = reachable;
reachable |= reachableFromPass;
if(!reachable) {
@@ -667,15 +766,54 @@
}
@Override
- public boolean enterPropertyNode(final PropertyNode propertyNode) {
- // Avoid falsely adding property keys to the control flow graph
- if(propertyNode.getValue() != null) {
- propertyNode.getValue().accept(this);
+ public boolean enterIndexNode(final IndexNode indexNode) {
+ visitExpression(indexNode.getBase());
+ visitExpression(indexNode.getIndex());
+ return pushExpressionType(indexNode);
+ }
+
+ @Override
+ public boolean enterJoinPredecessorExpression(final JoinPredecessorExpression joinExpr) {
+ final Expression expr = joinExpr.getExpression();
+ if (expr != null) {
+ expr.accept(this);
+ } else {
+ typeStack.push(LvarType.UNDEFINED);
}
return false;
}
@Override
+ public boolean enterLiteralNode(final LiteralNode<?> literalNode) {
+ if (literalNode instanceof ArrayLiteralNode) {
+ final List<Expression> expressions = ((ArrayLiteralNode)literalNode).getElementExpressions();
+ if (expressions != null) {
+ visitExpressions(expressions);
+ }
+ }
+ pushExpressionType(literalNode);
+ return false;
+ }
+
+ @Override
+ public boolean enterObjectNode(final ObjectNode objectNode) {
+ for(final PropertyNode propertyNode: objectNode.getElements()) {
+ // Avoid falsely adding property keys to the control flow graph
+ final Expression value = propertyNode.getValue();
+ if (value != null) {
+ visitExpression(value);
+ }
+ }
+ return pushExpressionType(objectNode);
+ }
+
+ @Override
+ public boolean enterPropertyNode(final PropertyNode propertyNode) {
+ // Property nodes are only accessible through object literals, and we handled that case above
+ throw new AssertionError();
+ }
+
+ @Override
public boolean enterReturnNode(final ReturnNode returnNode) {
if(!reachable) {
return false;
@@ -684,9 +822,9 @@
final Expression returnExpr = returnNode.getExpression();
final Type returnExprType;
if(returnExpr != null) {
- returnExpr.accept(this);
- returnExprType = getType(returnExpr);
+ returnExprType = visitExpressionOnEmptyStack(returnExpr).type;
} else {
+ assertTypeStackIsEmpty();
returnExprType = Type.UNDEFINED;
}
returnType = Type.widestReturnType(returnType, returnExprType);
@@ -695,6 +833,12 @@
}
@Override
+ public boolean enterRuntimeNode(final RuntimeNode runtimeNode) {
+ visitExpressions(runtimeNode.getArgs());
+ return pushExpressionType(runtimeNode);
+ }
+
+ @Override
public boolean enterSplitReturn(final SplitReturn splitReturn) {
doesNotContinueSequentially();
return false;
@@ -706,8 +850,7 @@
return false;
}
- final Expression expr = switchNode.getExpression();
- expr.accept(this);
+ visitExpressionOnEmptyStack(switchNode.getExpression());
final List<CaseNode> cases = switchNode.getCases();
if(cases.isEmpty()) {
@@ -724,7 +867,7 @@
for(final CaseNode caseNode: cases) {
final Expression test = caseNode.getTest();
if(!isInteger && test != null) {
- test.accept(this);
+ visitExpressionOnEmptyStack(test);
if(!tagUsed) {
symbolIsUsed(switchNode.getTag(), LvarType.OBJECT);
tagUsed = true;
@@ -769,29 +912,42 @@
final Expression trueExpr = ternaryNode.getTrueExpression();
final Expression falseExpr = ternaryNode.getFalseExpression();
- test.accept(this);
+ visitExpression(test);
final Map<Symbol, LvarType> testExitLvarTypes = localVariableTypes;
+ final LvarType trueType;
if(!isAlwaysFalse(test)) {
- trueExpr.accept(this);
+ trueType = visitExpression(trueExpr);
+ } else {
+ trueType = null;
}
final Map<Symbol, LvarType> trueExitLvarTypes = localVariableTypes;
localVariableTypes = testExitLvarTypes;
+ final LvarType falseType;
if(!isAlwaysTrue(test)) {
- falseExpr.accept(this);
+ falseType = visitExpression(falseExpr);
+ } else {
+ falseType = null;
}
final Map<Symbol, LvarType> falseExitLvarTypes = localVariableTypes;
localVariableTypes = getUnionTypes(trueExitLvarTypes, falseExitLvarTypes);
setConversion((JoinPredecessor)trueExpr, trueExitLvarTypes, localVariableTypes);
setConversion((JoinPredecessor)falseExpr, falseExitLvarTypes, localVariableTypes);
+
+ typeStack.push(trueType != null ? falseType != null ? widestLvarType(trueType, falseType) : trueType : assertNotNull(falseType));
return false;
}
+ private static <T> T assertNotNull(final T t) {
+ assert t != null;
+ return t;
+ }
+
private void enterTestFirstLoop(final LoopNode loopNode, final JoinPredecessorExpression modify,
final Expression iteratorValues, final boolean iteratorValuesAreObject) {
final JoinPredecessorExpression test = loopNode.getTest();
if(isAlwaysFalse(test)) {
- test.accept(this);
+ visitExpressionOnEmptyStack(test);
return;
}
@@ -804,7 +960,7 @@
jumpToLabel(loopNode, repeatLabel, beforeLoopTypes);
final Map<Symbol, LvarType> beforeRepeatTypes = localVariableTypes;
if(test != null) {
- test.accept(this);
+ visitExpressionOnEmptyStack(test);
}
if(!isAlwaysTrue(test)) {
jumpToLabel(test, breakLabel);
@@ -827,7 +983,7 @@
break;
}
if(modify != null) {
- modify.accept(this);
+ visitExpressionOnEmptyStack(modify);
jumpToLabel(modify, repeatLabel);
joinOnLabel(repeatLabel);
}
@@ -853,7 +1009,7 @@
return false;
}
- throwNode.getExpression().accept(this);
+ visitExpressionOnEmptyStack(throwNode.getExpression());
jumpToCatchBlock(throwNode);
doesNotContinueSequentially();
return false;
@@ -892,7 +1048,7 @@
onAssignment(exception, LvarType.OBJECT);
final Expression condition = catchNode.getExceptionCondition();
if(condition != null) {
- condition.accept(this);
+ visitExpression(condition);
}
final Map<Symbol, LvarType> afterConditionTypes = localVariableTypes;
final Block catchBody = catchNode.getBody();
@@ -927,14 +1083,11 @@
@Override
public boolean enterUnaryNode(final UnaryNode unaryNode) {
final Expression expr = unaryNode.getExpression();
- expr.accept(this);
-
- if(unaryNode.isSelfModifying()) {
- if(expr instanceof IdentNode) {
- final IdentNode ident = (IdentNode)expr;
- onSelfAssignment(ident, unaryNode, getLocalVariableTypeIfBytecode(ident.getSymbol()));
- }
+ final LvarType unaryType = toLvarType(unaryNode.setExpression(visitExpression(expr).typeExpression).getType());
+ if(unaryNode.isSelfModifying() && expr instanceof IdentNode) {
+ onSelfAssignment((IdentNode)expr, unaryType);
}
+ typeStack.push(unaryType);
return false;
}
@@ -945,8 +1098,7 @@
}
final Expression init = varNode.getInit();
if(init != null) {
- init.accept(this);
- onAssignment(varNode.getName(), init);
+ onAssignment(varNode.getName(), visitExpression(init));
}
return false;
}
@@ -964,6 +1116,15 @@
return false;
}
+ @Override
+ public boolean enterWithNode(final WithNode withNode) {
+ if (reachable) {
+ visitExpression(withNode.getExpression());
+ withNode.getBody().accept(this);
+ }
+ return false;
+ };
+
private Map<Symbol, LvarType> getBreakTargetTypes(final BreakableNode target) {
// Remove symbols defined in the the blocks that are being broken out of.
Map<Symbol, LvarType> types = localVariableTypes;
@@ -1002,18 +1163,6 @@
}
/**
- * Gets the type for a local variable if it is a bytecode local, otherwise null. Can be used in circumstances where
- * the type is irrelevant if the symbol is not a bytecode local. Note that for bytecode locals, it delegates to
- * {@link #getLocalVariableType(Symbol)}, so it will still assert that the type for such variable is already
- * defined (that is, not null).
- * @param symbol the symbol representing the variable.
- * @return the current variable type, if it is a bytecode local, otherwise null.
- */
- private LvarType getLocalVariableTypeIfBytecode(final Symbol symbol) {
- return symbol.isBytecodeLocal() ? getLocalVariableType(symbol) : null;
- }
-
- /**
* Gets the type for a variable represented by a symbol, or null if the type is not know. This is the least strict
* of all local variable type getters, and as such its use is discouraged except in initialization scenarios (where
* a just-defined symbol might still be null).
@@ -1154,6 +1303,7 @@
*/
private void leaveBreakable(final BreakableNode breakable) {
joinOnLabel(breakable.getBreakLabel());
+ assertTypeStackIsEmpty();
}
@Override
@@ -1329,10 +1479,6 @@
return conv == null || !conv.isLive();
}
- private void onAssignment(final IdentNode identNode, final Expression rhs) {
- onAssignment(identNode, toLvarType(getType(rhs)));
- }
-
private void onAssignment(final IdentNode identNode, final LvarType type) {
final Symbol symbol = identNode.getSymbol();
assert symbol != null : identNode.getName();
@@ -1400,13 +1546,12 @@
jumpToCatchBlock(identNode);
}
- private void onSelfAssignment(final IdentNode identNode, final Expression assignment, final LvarType typeOnLoad) {
+ private void onSelfAssignment(final IdentNode identNode, final LvarType type) {
final Symbol symbol = identNode.getSymbol();
assert symbol != null : identNode.getName();
if(!symbol.isBytecodeLocal()) {
return;
}
- final LvarType type = toLvarType(getType(assignment, symbol, typeOnLoad.type));
// Self-assignment never produce either a boolean or undefined
assert type != null && type != LvarType.UNDEFINED && type != LvarType.BOOLEAN;
setType(symbol, type);
@@ -1466,7 +1611,6 @@
* @param symbol the symbol representing the variable
* @param type the type
*/
- @SuppressWarnings("unused")
private void setType(final Symbol symbol, final LvarType type) {
if(getLocalVariableTypeOrNull(symbol) == type) {
return;
@@ -1486,77 +1630,4 @@
private void symbolIsUsed(final Symbol symbol) {
symbolIsUsed(symbol, getLocalVariableType(symbol));
}
-
- /**
- * Gets the type of the expression, dependent on the current types of the local variables.
- *
- * @param expr the expression
- * @return the current type of the expression dependent on the current types of the local variables.
- */
- private Type getType(final Expression expr) {
- return expr.getType(getSymbolToType());
- }
-
- /**
- * Returns a function object from symbols to their types, used by the expressions to evaluate their type.
- * {@link BinaryNode} specifically uses identity of the function to cache type calculations. This method makes
- * sure to return the same function object while the local variable types don't change, and create a new function
- * object if the local variable types have been changed.
- * @return a function object representing a mapping from symbols to their types.
- */
- private Function<Symbol, Type> getSymbolToType() {
- if(symbolToType.isStale()) {
- symbolToType = new SymbolToType();
- }
- return symbolToType;
- }
-
- private class SymbolToType implements Function<Symbol, Type> {
- private final Object boundTypes = localVariableTypes;
- @Override
- public Type apply(final Symbol t) {
- return getLocalVariableType(t).type;
- }
-
- boolean isStale() {
- return boundTypes != localVariableTypes;
- }
- }
-
- /**
- * Gets the type of the expression, dependent on the current types of the local variables and a single overridden
- * symbol type. Used by type calculation on compound operators to ensure the type of the LHS at the time it was
- * loaded (which can potentially be different after RHS evaluation, e.g. "var x; x += x = 0;") is preserved for
- * the calculation.
- *
- * @param expr the expression
- * @param overriddenSymbol the overridden symbol
- * @param overriddenType the overridden type
- * @return the current type of the expression dependent on the current types of the local variables and the single
- * potentially overridden type.
- */
- private Type getType(final Expression expr, final Symbol overriddenSymbol, final Type overriddenType) {
- return expr.getType(getSymbolToType(overriddenSymbol, overriddenType));
- }
-
- private Function<Symbol, Type> getSymbolToType(final Symbol overriddenSymbol, final Type overriddenType) {
- return getLocalVariableType(overriddenSymbol).type == overriddenType ? getSymbolToType() :
- new SymbolToTypeOverride(overriddenSymbol, overriddenType);
- }
-
- private class SymbolToTypeOverride implements Function<Symbol, Type> {
- private final Function<Symbol, Type> originalSymbolToType = getSymbolToType();
- private final Symbol overriddenSymbol;
- private final Type overriddenType;
-
- SymbolToTypeOverride(final Symbol overriddenSymbol, final Type overriddenType) {
- this.overriddenSymbol = overriddenSymbol;
- this.overriddenType = overriddenType;
- }
-
- @Override
- public Type apply(final Symbol symbol) {
- return symbol == overriddenSymbol ? overriddenType : originalSymbolToType.apply(symbol);
- }
- }
}
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/OptimisticTypesPersistence.java Tue Dec 23 12:40:06 2014 -0800
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/OptimisticTypesPersistence.java Thu Dec 25 19:46:17 2014 -0800
@@ -67,7 +67,7 @@
import jdk.nashorn.internal.runtime.options.Options;
/**
- * Static utility that encapsulates persistence of type information for functions compiled with optimistic
+ * <p>Static utility that encapsulates persistence of type information for functions compiled with optimistic
* typing. With this feature enabled, when a JavaScript function is recompiled because it gets deoptimized,
* the type information for deoptimization is stored in a cache file. If the same function is compiled in a
* subsequent JVM invocation, the type information is used for initial compilation, thus allowing the system
@@ -83,6 +83,7 @@
* {@code nashorn.typeInfo.cleanupDelaySeconds} system property. You can also specify the word
* {@code unlimited} as the value for {@code nashorn.typeInfo.maxFiles} in which case the type info cache is
* allowed to grow without limits.
+ * </p>
*/
public final class OptimisticTypesPersistence {
// Default is 0, for disabling the feature when not specified. A reasonable default when enabled is
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/BaseNode.java Tue Dec 23 12:40:06 2014 -0800
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/BaseNode.java Thu Dec 25 19:46:17 2014 -0800
@@ -27,7 +27,6 @@
import static jdk.nashorn.internal.runtime.UnwarrantedOptimismException.INVALID_PROGRAM_POINT;
-import java.util.function.Function;
import jdk.nashorn.internal.codegen.types.Type;
import jdk.nashorn.internal.ir.annotations.Immutable;
@@ -98,7 +97,7 @@
}
@Override
- public Type getType(final Function<Symbol, Type> localVariableTypes) {
+ public Type getType() {
return type == null ? getMostPessimisticType() : type;
}
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/BinaryNode.java Tue Dec 23 12:40:06 2014 -0800
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/BinaryNode.java Thu Dec 25 19:46:17 2014 -0800
@@ -31,7 +31,6 @@
import java.util.Collections;
import java.util.HashSet;
import java.util.Set;
-import java.util.function.Function;
import jdk.nashorn.internal.codegen.types.Type;
import jdk.nashorn.internal.ir.annotations.Ignore;
import jdk.nashorn.internal.ir.annotations.Immutable;
@@ -57,9 +56,7 @@
private final int programPoint;
private final Type type;
-
private transient Type cachedType;
- private transient Object cachedTypeFunction;
@Ignore
private static final Set<TokenType> CAN_OVERFLOW =
@@ -143,24 +140,6 @@
}
}
- private static final Function<Symbol, Type> UNKNOWN_LOCALS = new Function<Symbol, Type>() {
- @Override
- public Type apply(final Symbol t) {
- return null;
- }
- };
-
- /**
- * Return the widest possible type for this operation. This is used for compile time
- * static type inference
- *
- * @return Type
- */
- @Override
- public Type getWidestOperationType() {
- return getWidestOperationType(UNKNOWN_LOCALS);
- }
-
/**
* Return the widest possible operand type for this operation.
*
@@ -181,14 +160,15 @@
}
}
- private Type getWidestOperationType(final Function<Symbol, Type> localVariableTypes) {
+ @Override
+ public Type getWidestOperationType() {
switch (tokenType()) {
case ADD:
case ASSIGN_ADD: {
// Compare this logic to decideType(Type, Type); it's similar, but it handles the optimistic type
// calculation case while this handles the conservative case.
- final Type lhsType = lhs.getType(localVariableTypes);
- final Type rhsType = rhs.getType(localVariableTypes);
+ final Type lhsType = lhs.getType();
+ final Type rhsType = rhs.getType();
if(lhsType == Type.BOOLEAN && rhsType == Type.BOOLEAN) {
// Will always fit in an int, as the value range is [0, 1, 2]. If we didn't treat them specially here,
// they'd end up being treated as generic INT operands and their sum would be conservatively considered
@@ -238,8 +218,8 @@
case SUB:
case ASSIGN_MUL:
case ASSIGN_SUB: {
- final Type lhsType = lhs.getType(localVariableTypes);
- final Type rhsType = rhs.getType(localVariableTypes);
+ final Type lhsType = lhs.getType();
+ final Type rhsType = rhs.getType();
if(lhsType == Type.BOOLEAN && rhsType == Type.BOOLEAN) {
return Type.INT;
}
@@ -253,20 +233,20 @@
return Type.UNDEFINED;
}
case ASSIGN: {
- return rhs.getType(localVariableTypes);
+ return rhs.getType();
}
case INSTANCEOF: {
return Type.BOOLEAN;
}
case COMMALEFT: {
- return lhs.getType(localVariableTypes);
+ return lhs.getType();
}
case COMMARIGHT: {
- return rhs.getType(localVariableTypes);
+ return rhs.getType();
}
case AND:
case OR:{
- return Type.widestReturnType(lhs.getType(localVariableTypes), rhs.getType(localVariableTypes));
+ return Type.widestReturnType(lhs.getType(), rhs.getType());
}
default:
if (isComparison()) {
@@ -487,7 +467,7 @@
/**
* Set the right hand side expression for this node
- * @param rhs new left hand side expression
+ * @param rhs new right hand side expression
* @return a node equivalent to this one except for the requested change.
*/
public BinaryNode setRHS(final Expression rhs) {
@@ -497,6 +477,19 @@
return new BinaryNode(this, lhs, rhs, type, programPoint);
}
+ /**
+ * Set both the left and the right hand side expression for this node
+ * @param lhs new left hand side expression
+ * @param rhs new left hand side expression
+ * @return a node equivalent to this one except for the requested change.
+ */
+ public BinaryNode setOperands(final Expression lhs, final Expression rhs) {
+ if (this.lhs == lhs && this.rhs == rhs) {
+ return this;
+ }
+ return new BinaryNode(this, lhs, rhs, type, programPoint);
+ }
+
@Override
public int getProgramPoint() {
return programPoint;
@@ -541,24 +534,22 @@
}
@Override
- public Type getType(final Function<Symbol, Type> localVariableTypes) {
- if(localVariableTypes == cachedTypeFunction) {
- return cachedType;
+ public Type getType() {
+ if (cachedType == null) {
+ cachedType = getTypeUncached();
}
- cachedType = getTypeUncached(localVariableTypes);
- cachedTypeFunction = localVariableTypes;
return cachedType;
}
- private Type getTypeUncached(final Function<Symbol, Type> localVariableTypes) {
+ private Type getTypeUncached() {
if(type == OPTIMISTIC_UNDECIDED_TYPE) {
- return decideType(lhs.getType(localVariableTypes), rhs.getType(localVariableTypes));
+ return decideType(lhs.getType(), rhs.getType());
}
- final Type widest = getWidestOperationType(localVariableTypes);
+ final Type widest = getWidestOperationType();
if(type == null) {
return widest;
}
- return Type.narrowest(widest, Type.widest(type, Type.widest(lhs.getType(localVariableTypes), rhs.getType(localVariableTypes))));
+ return Type.narrowest(widest, Type.widest(type, Type.widest(lhs.getType(), rhs.getType())));
}
private static Type decideType(final Type lhsType, final Type rhsType) {
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/CallNode.java Tue Dec 23 12:40:06 2014 -0800
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/CallNode.java Thu Dec 25 19:46:17 2014 -0800
@@ -30,7 +30,6 @@
import java.io.Serializable;
import java.util.Collections;
import java.util.List;
-import java.util.function.Function;
import jdk.nashorn.internal.codegen.types.Type;
import jdk.nashorn.internal.ir.annotations.Ignore;
import jdk.nashorn.internal.ir.annotations.Immutable;
@@ -154,7 +153,7 @@
}
@Override
- public Type getType(final Function<Symbol, Type> localVariableTypes) {
+ public Type getType() {
return optimisticType == null ? Type.OBJECT : optimisticType;
}
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/Expression.java Tue Dec 23 12:40:06 2014 -0800
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/Expression.java Thu Dec 25 19:46:17 2014 -0800
@@ -25,7 +25,6 @@
package jdk.nashorn.internal.ir;
-import java.util.function.Function;
import jdk.nashorn.internal.codegen.types.Type;
import jdk.nashorn.internal.runtime.UnwarrantedOptimismException;
@@ -39,14 +38,7 @@
static final String OPT_IDENTIFIER = "%";
- private static final Function<Symbol, Type> UNKNOWN_LOCALS = new Function<Symbol, Type>() {
- @Override
- public Type apply(final Symbol t) {
- return null;
- }
- };
-
- Expression(final long token, final int start, final int finish) {
+ protected Expression(final long token, final int start, final int finish) {
super(token, start, finish);
}
@@ -63,18 +55,7 @@
*
* @return the type of the expression.
*/
- public final Type getType() {
- return getType(UNKNOWN_LOCALS);
- }
-
- /**
- * Returns the type of the expression under the specified symbol-to-type mapping. By default delegates to
- * {@link #getType()} but expressions whose type depends on their subexpressions' types and expressions whose type
- * depends on symbol type ({@link IdentNode}) will have a special implementation.
- * @param localVariableTypes a mapping from symbols to their types, used for type calculation.
- * @return the type of the expression under the specified symbol-to-type mapping.
- */
- public abstract Type getType(final Function<Symbol, Type> localVariableTypes);
+ public abstract Type getType();
/**
* Returns {@code true} if this expression depends exclusively on state that is constant
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/FunctionNode.java Tue Dec 23 12:40:06 2014 -0800
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/FunctionNode.java Thu Dec 25 19:46:17 2014 -0800
@@ -36,7 +36,6 @@
import java.util.EnumSet;
import java.util.Iterator;
import java.util.List;
-import java.util.function.Function;
import jdk.nashorn.internal.AssertsEnabled;
import jdk.nashorn.internal.codegen.CompileUnit;
import jdk.nashorn.internal.codegen.Compiler;
@@ -1101,7 +1100,7 @@
}
@Override
- public Type getType(final Function<Symbol, Type> localVariableTypes) {
+ public Type getType() {
return FUNCTION_TYPE;
}
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/GetSplitState.java Tue Dec 23 12:40:06 2014 -0800
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/GetSplitState.java Thu Dec 25 19:46:17 2014 -0800
@@ -25,7 +25,6 @@
package jdk.nashorn.internal.ir;
-import java.util.function.Function;
import jdk.nashorn.internal.codegen.CompilerConstants;
import jdk.nashorn.internal.codegen.types.Type;
import jdk.nashorn.internal.ir.visitor.NodeVisitor;
@@ -47,7 +46,7 @@
}
@Override
- public Type getType(final Function<Symbol, Type> localVariableTypes) {
+ public Type getType() {
return Type.INT;
}
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/IdentNode.java Tue Dec 23 12:40:06 2014 -0800
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/IdentNode.java Thu Dec 25 19:46:17 2014 -0800
@@ -30,7 +30,6 @@
import static jdk.nashorn.internal.codegen.CompilerConstants.__LINE__;
import static jdk.nashorn.internal.runtime.UnwarrantedOptimismException.INVALID_PROGRAM_POINT;
-import java.util.function.Function;
import jdk.nashorn.internal.codegen.types.Type;
import jdk.nashorn.internal.ir.annotations.Immutable;
import jdk.nashorn.internal.ir.visitor.NodeVisitor;
@@ -118,14 +117,13 @@
}
@Override
- public Type getType(final Function<Symbol, Type> localVariableTypes) {
+ public Type getType() {
if(type != null) {
return type;
} else if(symbol != null && symbol.isScope()) {
return Type.OBJECT;
}
- final Type symbolType = localVariableTypes.apply(symbol);
- return symbolType == null ? Type.UNDEFINED : symbolType;
+ return Type.UNDEFINED;
}
/**
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/JoinPredecessorExpression.java Tue Dec 23 12:40:06 2014 -0800
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/JoinPredecessorExpression.java Thu Dec 25 19:46:17 2014 -0800
@@ -25,7 +25,6 @@
package jdk.nashorn.internal.ir;
-import java.util.function.Function;
import jdk.nashorn.internal.codegen.types.Type;
import jdk.nashorn.internal.ir.visitor.NodeVisitor;
@@ -71,8 +70,8 @@
}
@Override
- public Type getType(final Function<Symbol, Type> localVariableTypes) {
- return expression.getType(localVariableTypes);
+ public Type getType() {
+ return expression.getType();
}
@Override
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/LiteralNode.java Tue Dec 23 12:40:06 2014 -0800
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/LiteralNode.java Thu Dec 25 19:46:17 2014 -0800
@@ -29,7 +29,6 @@
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
-import java.util.function.Function;
import jdk.nashorn.internal.codegen.CompileUnit;
import jdk.nashorn.internal.codegen.types.ArrayType;
import jdk.nashorn.internal.codegen.types.Type;
@@ -109,7 +108,7 @@
}
@Override
- public Type getType(final Function<Symbol, Type> localVariableTypes) {
+ public Type getType() {
return Type.typeFor(value.getClass());
}
@@ -164,16 +163,6 @@
}
/**
- * Get the array value of the node
- *
- * @return the array value
- */
- public Node[] getArray() {
- assert false : "not an array node";
- return null;
- }
-
- /**
* Fetch String value of node.
*
* @return String value of node.
@@ -325,7 +314,7 @@
}
@Override
- public Type getType(final Function<Symbol, Type> localVariableTypes) {
+ public Type getType() {
return Type.BOOLEAN;
}
@@ -389,7 +378,7 @@
}
@Override
- public Type getType(final Function<Symbol, Type> localVariableTypes) {
+ public Type getType() {
return type;
}
@@ -519,7 +508,7 @@
}
@Override
- public Type getType(final Function<Symbol, Type> localVariableTypes) {
+ public Type getType() {
return Type.OBJECT;
}
@@ -589,7 +578,7 @@
}
@Override
- public Type getType(final Function<Symbol, Type> localVariableTypes) {
+ public Type getType() {
return Type.OBJECT;
}
@@ -840,9 +829,13 @@
this.units = units;
}
- @Override
- public Node[] getArray() {
- return value;
+ /**
+ * Returns a list of array element expressions. Note that empty array elements manifest themselves as
+ * null.
+ * @return a list of array element expressions.
+ */
+ public List<Expression> getElementExpressions() {
+ return Collections.unmodifiableList(Arrays.asList(value));
}
/**
@@ -879,7 +872,7 @@
}
@Override
- public Type getType(final Function<Symbol, Type> localVariableTypes) {
+ public Type getType() {
return Type.typeFor(NativeArray.class);
}
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/ObjectNode.java Tue Dec 23 12:40:06 2014 -0800
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/ObjectNode.java Thu Dec 25 19:46:17 2014 -0800
@@ -27,7 +27,6 @@
import java.util.Collections;
import java.util.List;
-import java.util.function.Function;
import jdk.nashorn.internal.codegen.types.Type;
import jdk.nashorn.internal.ir.annotations.Immutable;
import jdk.nashorn.internal.ir.visitor.NodeVisitor;
@@ -69,7 +68,7 @@
}
@Override
- public Type getType(final Function<Symbol, Type> localVariableTypes) {
+ public Type getType() {
return Type.OBJECT;
}
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/RuntimeNode.java Tue Dec 23 12:40:06 2014 -0800
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/RuntimeNode.java Thu Dec 25 19:46:17 2014 -0800
@@ -30,7 +30,6 @@
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
-import java.util.function.Function;
import jdk.nashorn.internal.codegen.types.Type;
import jdk.nashorn.internal.ir.annotations.Immutable;
import jdk.nashorn.internal.ir.visitor.NodeVisitor;
@@ -460,7 +459,7 @@
* Return type for the ReferenceNode
*/
@Override
- public Type getType(final Function<Symbol, Type> localVariableTypes) {
+ public Type getType() {
return request.getReturnType();
}
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/TernaryNode.java Tue Dec 23 12:40:06 2014 -0800
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/TernaryNode.java Thu Dec 25 19:46:17 2014 -0800
@@ -25,7 +25,6 @@
package jdk.nashorn.internal.ir;
-import java.util.function.Function;
import jdk.nashorn.internal.codegen.types.Type;
import jdk.nashorn.internal.ir.annotations.Immutable;
import jdk.nashorn.internal.ir.visitor.NodeVisitor;
@@ -122,8 +121,8 @@
}
@Override
- public Type getType(final Function<Symbol, Type> localVariableTypes) {
- return Type.widestReturnType(getTrueExpression().getType(localVariableTypes), getFalseExpression().getType(localVariableTypes));
+ public Type getType() {
+ return Type.widestReturnType(getTrueExpression().getType(), getFalseExpression().getType());
}
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/UnaryNode.java Tue Dec 23 12:40:06 2014 -0800
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/UnaryNode.java Thu Dec 25 19:46:17 2014 -0800
@@ -33,7 +33,6 @@
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
-import java.util.function.Function;
import jdk.nashorn.internal.codegen.types.Type;
import jdk.nashorn.internal.ir.annotations.Ignore;
import jdk.nashorn.internal.ir.annotations.Immutable;
@@ -123,23 +122,11 @@
return isAssignment();
}
- private static final Function<Symbol, Type> UNKNOWN_LOCALS = new Function<Symbol, Type>() {
- @Override
- public Type apply(final Symbol t) {
- return null;
- }
- };
-
-
@Override
public Type getWidestOperationType() {
- return getWidestOperationType(UNKNOWN_LOCALS);
- }
-
- private Type getWidestOperationType(final Function<Symbol, Type> localVariableTypes) {
switch (tokenType()) {
case ADD:
- final Type operandType = getExpression().getType(localVariableTypes);
+ final Type operandType = getExpression().getType();
if(operandType == Type.BOOLEAN) {
return Type.INT;
} else if(operandType.isObject()) {
@@ -326,12 +313,12 @@
}
@Override
- public Type getType(final Function<Symbol, Type> localVariableTypes) {
- final Type widest = getWidestOperationType(localVariableTypes);
+ public Type getType() {
+ final Type widest = getWidestOperationType();
if(type == null) {
return widest;
}
- return Type.narrowest(widest, Type.widest(type, expression.getType(localVariableTypes)));
+ return Type.narrowest(widest, Type.widest(type, expression.getType()));
}
@Override
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/debug/JSONWriter.java Tue Dec 23 12:40:06 2014 -0800
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/debug/JSONWriter.java Thu Dec 25 19:46:17 2014 -0800
@@ -28,7 +28,6 @@
import static jdk.nashorn.internal.runtime.Source.sourceFor;
import java.util.ArrayList;
-import java.util.Arrays;
import java.util.List;
import jdk.nashorn.internal.ir.AccessNode;
import jdk.nashorn.internal.ir.BinaryNode;
@@ -553,8 +552,7 @@
type("ArrayExpression");
comma();
- final Node[] value = literalNode.getArray();
- array("elements", Arrays.asList(value));
+ array("elements", ((LiteralNode.ArrayLiteralNode)literalNode).getElementExpressions());
} else {
type("Literal");
comma();
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeArray.java Tue Dec 23 12:40:06 2014 -0800
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeArray.java Thu Dec 25 19:46:17 2014 -0800
@@ -275,7 +275,7 @@
final PropertyDescriptor newLenDesc = desc;
// Step 3c and 3d - get new length and convert to long
- final long newLen = NativeArray.validLength(newLenDesc.getValue(), true);
+ final long newLen = NativeArray.validLength(newLenDesc.getValue());
// Step 3e
newLenDesc.setValue(newLen);
@@ -348,8 +348,8 @@
final PropertyDescriptor oldLenDesc = (PropertyDescriptor) super.getOwnPropertyDescriptor("length");
// Step 2
- // get old length and convert to long
- final long oldLen = NativeArray.validLength(oldLenDesc.getValue(), true);
+ // get old length and convert to long. Always a Long/Uint32 but we take the safe road.
+ final long oldLen = JSType.toUint32(oldLenDesc.getValue());
// Step 3
if ("length".equals(key)) {
@@ -471,7 +471,7 @@
@Setter(attributes = Attribute.NOT_ENUMERABLE | Attribute.NOT_CONFIGURABLE)
public static void length(final Object self, final Object length) {
if (isArray(self)) {
- ((ScriptObject)self).setLength(validLength(length, true));
+ ((ScriptObject)self).setLength(validLength(length));
}
}
@@ -495,18 +495,13 @@
length(self, length); // Same as instance setter but we can't make nasgen use the same method for prototype
}
- static long validLength(final Object length, final boolean reject) {
+ static long validLength(final Object length) {
+ // ES5 15.4.5.1, steps 3.c and 3.d require two ToNumber conversions here
final double doubleLength = JSType.toNumber(length);
- if (!Double.isNaN(doubleLength) && JSType.isRepresentableAsLong(doubleLength)) {
- final long len = (long) doubleLength;
- if (len >= 0 && len <= JSType.MAX_UINT) {
- return len;
- }
- }
- if (reject) {
+ if (doubleLength != JSType.toUint32(length)) {
throw rangeError("inappropriate.array.length", ScriptRuntime.safeToString(length));
}
- return -1;
+ return (long) doubleLength;
}
/**
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeRegExpExecResult.java Tue Dec 23 12:40:06 2014 -0800
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeRegExpExecResult.java Thu Dec 25 19:46:17 2014 -0800
@@ -88,7 +88,7 @@
@Setter(attributes = Attribute.NOT_ENUMERABLE | Attribute.NOT_CONFIGURABLE)
public static void length(final Object self, final Object length) {
if (self instanceof ScriptObject) {
- ((ScriptObject)self).setLength(NativeArray.validLength(length, true));
+ ((ScriptObject)self).setLength(NativeArray.validLength(length));
}
}
}
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/CodeInstaller.java Tue Dec 23 12:40:06 2014 -0800
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/CodeInstaller.java Thu Dec 25 19:46:17 2014 -0800
@@ -86,7 +86,7 @@
* @param source the script source
* @param mainClassName the main class name
* @param classBytes map of class names to class bytes
- * @param initializers compilation id -> FunctionInitializer map
+ * @param initializers compilation id -> FunctionInitializer map
* @param constants constants array
* @param compilationId compilation id
*/
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/JSType.java Tue Dec 23 12:40:06 2014 -0800
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/JSType.java Thu Dec 25 19:46:17 2014 -0800
@@ -180,10 +180,10 @@
/** Div exact wrapper for potentially integer division that turns into float point */
public static final Call DIV_EXACT_LONG = staticCall(JSTYPE_LOOKUP, JSType.class, "divExact", long.class, long.class, long.class, int.class);
- /** Div zero wrapper for long division that handles (0/0) >>> 0 == 0 */
+ /** Div zero wrapper for long division that handles (0/0) >>> 0 == 0 */
public static final Call DIV_ZERO_LONG = staticCall(JSTYPE_LOOKUP, JSType.class, "divZero", long.class, long.class, long.class);
- /** Mod zero wrapper for long division that handles (0%0) >>> 0 == 0 */
+ /** Mod zero wrapper for long division that handles (0%0) >>> 0 == 0 */
public static final Call REM_ZERO_LONG = staticCall(JSTYPE_LOOKUP, JSType.class, "remZero", long.class, long.class, long.class);
/** Mod exact wrapper for potentially integer remainders that turns into float point */
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/StoredScript.java Tue Dec 23 12:40:06 2014 -0800
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/StoredScript.java Thu Dec 25 19:46:17 2014 -0800
@@ -58,7 +58,7 @@
* @param compilationId compilation id
* @param mainClassName main class name
* @param classBytes map of class names to class bytes
- * @param initializers initializer map, id -> FunctionInitializer
+ * @param initializers initializer map, id -> FunctionInitializer
* @param constants constants array
*/
public StoredScript(final int compilationId, final String mainClassName, final Map<String, byte[]> classBytes, final Map<Integer, FunctionInitializer> initializers, final Object[] constants) {
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/arrays/ArrayData.java Tue Dec 23 12:40:06 2014 -0800
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/arrays/ArrayData.java Thu Dec 25 19:46:17 2014 -0800
@@ -275,7 +275,7 @@
/**
* Align an array size up to the nearest array chunk size
* @param size size required
- * @return size given, always >= size
+ * @return size given, always >= size
*/
protected final static int alignUp(final int size) {
return size + CHUNK_SIZE - 1 & ~(CHUNK_SIZE - 1);
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/linker/BoundCallableLinker.java Tue Dec 23 12:40:06 2014 -0800
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/linker/BoundCallableLinker.java Thu Dec 25 19:46:17 2014 -0800
@@ -99,7 +99,7 @@
MethodType newMethodType = descriptor.getMethodType().changeParameterType(0, callable.getClass());
if (isCall) {
// R(callable.class, T1, ...) => R(callable.class, boundThis.class, ...)
- newMethodType = newMethodType.changeParameterType(1, boundThis.getClass());
+ newMethodType = newMethodType.changeParameterType(1, boundThis == null? Object.class : boundThis.getClass());
}
// R(callable.class[, boundThis.class], T2, ...) => R(callable.class[, boundThis.class], boundArg0.class, ..., boundArgn.class, T2, ...)
for(int i = boundArgs.length; i-- > 0;) {
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/linker/BrowserJSObjectLinker.java Tue Dec 23 12:40:06 2014 -0800
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/linker/BrowserJSObjectLinker.java Thu Dec 25 19:46:17 2014 -0800
@@ -40,6 +40,7 @@
import jdk.internal.dynalink.support.CallSiteDescriptorFactory;
import jdk.nashorn.internal.lookup.MethodHandleFactory;
import jdk.nashorn.internal.lookup.MethodHandleFunctionality;
+import jdk.nashorn.internal.runtime.ConsString;
import jdk.nashorn.internal.runtime.JSType;
/**
@@ -118,20 +119,21 @@
private GuardedInvocation lookup(final CallSiteDescriptor desc, final LinkRequest request, final LinkerServices linkerServices) throws Exception {
final String operator = CallSiteDescriptorFactory.tokenizeOperators(desc).get(0);
final int c = desc.getNameTokenCount();
+ GuardedInvocation inv;
+ try {
+ inv = nashornBeansLinker.getGuardedInvocation(request, linkerServices);
+ } catch (Throwable th) {
+ inv = null;
+ }
switch (operator) {
case "getProp":
case "getElem":
case "getMethod":
- if (c > 2) {
- return findGetMethod(desc);
- }
- // For indexed get, we want GuardedInvocation from beans linker and pass it.
- // BrowserJSObjectLinker.get uses this fallback getter for explicit signature method access.
- return findGetIndexMethod(nashornBeansLinker.getGuardedInvocation(request, linkerServices));
+ return c > 2? findGetMethod(desc, inv) : findGetIndexMethod(inv);
case "setProp":
case "setElem":
- return c > 2 ? findSetMethod(desc) : findSetIndexMethod();
+ return c > 2? findSetMethod(desc, inv) : findSetIndexMethod();
case "call":
return findCallMethod(desc);
default:
@@ -139,7 +141,10 @@
}
}
- private static GuardedInvocation findGetMethod(final CallSiteDescriptor desc) {
+ private static GuardedInvocation findGetMethod(final CallSiteDescriptor desc, final GuardedInvocation inv) {
+ if (inv != null) {
+ return inv;
+ }
final String name = desc.getNameToken(CallSiteDescriptor.NAME_OPERAND);
final MethodHandle getter = MH.insertArguments(JSOBJECT_GETMEMBER, 1, name);
return new GuardedInvocation(getter, IS_JSOBJECT_GUARD);
@@ -150,7 +155,10 @@
return inv.replaceMethods(getter, inv.getGuard());
}
- private static GuardedInvocation findSetMethod(final CallSiteDescriptor desc) {
+ private static GuardedInvocation findSetMethod(final CallSiteDescriptor desc, final GuardedInvocation inv) {
+ if (inv != null) {
+ return inv;
+ }
final MethodHandle getter = MH.insertArguments(JSOBJECT_SETMEMBER, 1, desc.getNameToken(2));
return new GuardedInvocation(getter, IS_JSOBJECT_GUARD);
}
@@ -178,12 +186,12 @@
if (index > -1) {
return JSOBJECT_GETSLOT.invokeExact(jsobj, index);
}
- } else if (key instanceof String) {
- final String name = (String)key;
+ } else if (key instanceof String || key instanceof ConsString) {
+ final String name = key.toString();
if (name.indexOf('(') != -1) {
- return fallback.invokeExact(jsobj, key);
+ return fallback.invokeExact(jsobj, (Object) name);
}
- return JSOBJECT_GETMEMBER.invokeExact(jsobj, (String)key);
+ return JSOBJECT_GETMEMBER.invokeExact(jsobj, name);
}
return null;
}
@@ -194,8 +202,8 @@
JSOBJECT_SETSLOT.invokeExact(jsobj, (int)key, value);
} else if (key instanceof Number) {
JSOBJECT_SETSLOT.invokeExact(jsobj, getIndex((Number)key), value);
- } else if (key instanceof String) {
- JSOBJECT_SETMEMBER.invokeExact(jsobj, (String)key, value);
+ } else if (key instanceof String || key instanceof ConsString) {
+ JSOBJECT_SETMEMBER.invokeExact(jsobj, key.toString(), value);
}
}
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/linker/JSObjectLinker.java Tue Dec 23 12:40:06 2014 -0800
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/linker/JSObjectLinker.java Thu Dec 25 19:46:17 2014 -0800
@@ -42,6 +42,7 @@
import jdk.nashorn.api.scripting.JSObject;
import jdk.nashorn.internal.lookup.MethodHandleFactory;
import jdk.nashorn.internal.lookup.MethodHandleFunctionality;
+import jdk.nashorn.internal.runtime.ConsString;
import jdk.nashorn.internal.runtime.JSType;
/**
@@ -185,11 +186,11 @@
if (index > -1) {
return ((JSObject)jsobj).getSlot(index);
}
- } else if (key instanceof String) {
- final String name = (String)key;
+ } else if (key instanceof String || key instanceof ConsString) {
+ final String name = key.toString();
// get with method name and signature. delegate it to beans linker!
if (name.indexOf('(') != -1) {
- return fallback.invokeExact(jsobj, key);
+ return fallback.invokeExact(jsobj, (Object) name);
}
return ((JSObject)jsobj).getMember(name);
}
@@ -202,8 +203,8 @@
((JSObject)jsobj).setSlot((Integer)key, value);
} else if (key instanceof Number) {
((JSObject)jsobj).setSlot(getIndex((Number)key), value);
- } else if (key instanceof String) {
- ((JSObject)jsobj).setMember((String)key, value);
+ } else if (key instanceof String || key instanceof ConsString) {
+ ((JSObject)jsobj).setMember(key.toString(), value);
}
}
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/linker/PrimitiveLookup.java Tue Dec 23 12:40:06 2014 -0800
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/linker/PrimitiveLookup.java Thu Dec 25 19:46:17 2014 -0800
@@ -26,17 +26,23 @@
package jdk.nashorn.internal.runtime.linker;
import static jdk.nashorn.internal.lookup.Lookup.MH;
+import static jdk.nashorn.internal.runtime.ECMAErrors.typeError;
+
import java.lang.invoke.MethodHandle;
+import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodType;
import java.lang.invoke.SwitchPoint;
import jdk.internal.dynalink.CallSiteDescriptor;
import jdk.internal.dynalink.linker.GuardedInvocation;
import jdk.internal.dynalink.linker.LinkRequest;
+import jdk.internal.dynalink.support.CallSiteDescriptorFactory;
import jdk.internal.dynalink.support.Guards;
import jdk.nashorn.internal.runtime.Context;
import jdk.nashorn.internal.runtime.FindProperty;
import jdk.nashorn.internal.runtime.GlobalConstants;
+import jdk.nashorn.internal.runtime.JSType;
import jdk.nashorn.internal.runtime.ScriptObject;
+import jdk.nashorn.internal.runtime.ScriptRuntime;
import jdk.nashorn.internal.runtime.UserAccessorProperty;
/**
@@ -46,6 +52,11 @@
*/
public final class PrimitiveLookup {
+ /** Method handle to link setters on primitive base. See ES5 8.7.2. */
+ private static final MethodHandle PRIMITIVE_SETTER = findOwnMH("primitiveSetter",
+ MH.type(void.class, ScriptObject.class, Object.class, Object.class, boolean.class, Object.class));
+
+
private PrimitiveLookup() {
}
@@ -87,40 +98,58 @@
final ScriptObject wrappedReceiver, final MethodHandle wrapFilter,
final MethodHandle protoFilter) {
final CallSiteDescriptor desc = request.getCallSiteDescriptor();
+ final String name;
+ final FindProperty find;
- //checks whether the property name is hard-coded in the call-site (i.e. a getProp vs a getElem, or setProp vs setElem)
- //if it is we can make assumptions on the property: that if it is not defined on primitive wrapper itself it never will be.
- //so in that case we can skip creation of primitive wrapper and start our search with the prototype.
if (desc.getNameTokenCount() > 2) {
- final String name = desc.getNameToken(CallSiteDescriptor.NAME_OPERAND);
- final FindProperty find = wrappedReceiver.findProperty(name, true);
+ name = desc.getNameToken(CallSiteDescriptor.NAME_OPERAND);
+ find = wrappedReceiver.findProperty(name, true);
+ } else {
+ name = null;
+ find = null;
+ }
- if (find == null) {
- // Give up early, give chance to BeanLinker and NashornBottomLinker to deal with it.
- return null;
- }
+ final String firstOp = CallSiteDescriptorFactory.tokenizeOperators(desc).get(0);
- final SwitchPoint sp = find.getProperty().getBuiltinSwitchPoint(); //can use this instead of proto filter
- if (sp instanceof Context.BuiltinSwitchPoint && !sp.hasBeenInvalidated()) {
- return new GuardedInvocation(GlobalConstants.staticConstantGetter(find.getObjectValue()), guard, sp, null);
- }
+ switch (firstOp) {
+ case "getProp":
+ case "getElem":
+ case "getMethod":
+ //checks whether the property name is hard-coded in the call-site (i.e. a getProp vs a getElem, or setProp vs setElem)
+ //if it is we can make assumptions on the property: that if it is not defined on primitive wrapper itself it never will be.
+ //so in that case we can skip creation of primitive wrapper and start our search with the prototype.
+ if (name != null) {
+ if (find == null) {
+ // Give up early, give chance to BeanLinker and NashornBottomLinker to deal with it.
+ return null;
+ }
- if (find.isInherited() && !(find.getProperty() instanceof UserAccessorProperty)) {
- // If property is found in the prototype object bind the method handle directly to
- // the proto filter instead of going through wrapper instantiation below.
- final ScriptObject proto = wrappedReceiver.getProto();
- final GuardedInvocation link = proto.lookup(desc, request);
+ final SwitchPoint sp = find.getProperty().getBuiltinSwitchPoint(); //can use this instead of proto filter
+ if (sp instanceof Context.BuiltinSwitchPoint && !sp.hasBeenInvalidated()) {
+ return new GuardedInvocation(GlobalConstants.staticConstantGetter(find.getObjectValue()), guard, sp, null);
+ }
- if (link != null) {
- final MethodHandle invocation = link.getInvocation(); //this contains the builtin switchpoint
+ if (find.isInherited() && !(find.getProperty() instanceof UserAccessorProperty)) {
+ // If property is found in the prototype object bind the method handle directly to
+ // the proto filter instead of going through wrapper instantiation below.
+ final ScriptObject proto = wrappedReceiver.getProto();
+ final GuardedInvocation link = proto.lookup(desc, request);
- final MethodHandle adaptedInvocation = MH.asType(invocation, invocation.type().changeParameterType(0, Object.class));
- final MethodHandle method = MH.filterArguments(adaptedInvocation, 0, protoFilter);
- final MethodHandle protoGuard = MH.filterArguments(link.getGuard(), 0, protoFilter);
-
- return new GuardedInvocation(method, NashornGuards.combineGuards(guard, protoGuard));
+ if (link != null) {
+ final MethodHandle invocation = link.getInvocation(); //this contains the builtin switchpoint
+ final MethodHandle adaptedInvocation = MH.asType(invocation, invocation.type().changeParameterType(0, Object.class));
+ final MethodHandle method = MH.filterArguments(adaptedInvocation, 0, protoFilter);
+ final MethodHandle protoGuard = MH.filterArguments(link.getGuard(), 0, protoFilter);
+ return new GuardedInvocation(method, NashornGuards.combineGuards(guard, protoGuard));
+ }
}
}
+ break;
+ case "setProp":
+ case "setElem":
+ return getPrimitiveSetter(name, guard, wrapFilter, NashornCallSiteDescriptor.isStrict(desc));
+ default:
+ break;
}
final GuardedInvocation link = wrappedReceiver.lookup(desc, request);
@@ -138,4 +167,41 @@
return null;
}
+
+ private static GuardedInvocation getPrimitiveSetter(final String name, final MethodHandle guard,
+ final MethodHandle wrapFilter, final boolean isStrict) {
+ MethodHandle filter = MH.asType(wrapFilter, wrapFilter.type().changeReturnType(ScriptObject.class));
+ final MethodHandle target;
+
+ if (name == null) {
+ filter = MH.dropArguments(filter, 1, Object.class, Object.class);
+ target = MH.insertArguments(PRIMITIVE_SETTER, 3, isStrict);
+ } else {
+ filter = MH.dropArguments(filter, 1, Object.class);
+ target = MH.insertArguments(PRIMITIVE_SETTER, 2, name, isStrict);
+ }
+
+ return new GuardedInvocation(MH.foldArguments(target, filter), guard);
+ }
+
+
+ @SuppressWarnings("unused")
+ private static void primitiveSetter(final ScriptObject wrappedSelf, final Object self, final Object key,
+ final boolean strict, final Object value) {
+ // See ES5.1 8.7.2 PutValue (V, W)
+ final String name = JSType.toString(key);
+ final FindProperty find = wrappedSelf.findProperty(name, true);
+ if (find == null || !(find.getProperty() instanceof UserAccessorProperty) || !find.getProperty().isWritable()) {
+ if (strict) {
+ throw typeError("property.not.writable", name, ScriptRuntime.safeToString(self));
+ }
+ return;
+ }
+ // property found and is a UserAccessorProperty
+ find.setValue(value, strict);
+ }
+
+ private static MethodHandle findOwnMH(final String name, final MethodType type) {
+ return MH.findStatic(MethodHandles.lookup(), PrimitiveLookup.class, name, type);
+ }
}
--- a/nashorn/test/script/basic/JDK-8055762.js Tue Dec 23 12:40:06 2014 -0800
+++ b/nashorn/test/script/basic/JDK-8055762.js Thu Dec 25 19:46:17 2014 -0800
@@ -74,9 +74,12 @@
}
};
+ var a = "a";
print(obj["foo"]);
+ print(obj[a + "bc"]);
print(obj[2]);
obj.bar = 23;
+ obj[a + "bc"] = 23;
obj[3] = 23;
obj.func("hello");
}
--- a/nashorn/test/script/basic/JDK-8055762.js.EXPECTED Tue Dec 23 12:40:06 2014 -0800
+++ b/nashorn/test/script/basic/JDK-8055762.js.EXPECTED Thu Dec 25 19:46:17 2014 -0800
@@ -1,5 +1,7 @@
FOO
+ABC
0
bar set to 23
+abc set to 23
[3] set to 23
func called with hello
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/test/script/basic/JDK-8066215.js Thu Dec 25 19:46:17 2014 -0800
@@ -0,0 +1,46 @@
+/*
+ * 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.
+ *
+ * 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-8066215: Fuzzing bug: length valueOf bug
+ *
+ * @test
+ * @run
+ */
+
+function defineLength(arr, length) {
+ Object.defineProperty(arr, "length", {
+ value: {
+ valueOf: function() {
+ print("value retrieved: " + length);
+ return length;
+ }
+ }
+ });
+ print("done: " + arr.length + ", " + typeof arr.length);
+}
+
+var a = [];
+defineLength(a, 3);
+defineLength(a, 6);
+defineLength(a, 3);
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/test/script/basic/JDK-8066215.js.EXPECTED Thu Dec 25 19:46:17 2014 -0800
@@ -0,0 +1,9 @@
+value retrieved: 3
+value retrieved: 3
+done: 3, number
+value retrieved: 6
+value retrieved: 6
+done: 6, number
+value retrieved: 3
+value retrieved: 3
+done: 3, number
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/test/script/basic/JDK-8066226.js Thu Dec 25 19:46:17 2014 -0800
@@ -0,0 +1,132 @@
+/*
+ * 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-8066226: Fuzzing bug: parameter counts differ in TypeConverterFactory
+ *
+ * @test
+ * @run
+ */
+
+Object.defineProperty(Object.prototype, "accessor", {
+ set: function(value) {
+ print("Setting accessor on " + this + " to " + value);
+ }
+});
+
+Object.defineProperty(Object.prototype, "getterOnly", {
+ get: function() {
+ return 1;
+ }
+});
+
+function set(o) {
+ print("set(" + o + ")");
+ o.foo = 1;
+ o.constructor = 1;
+ o.accessor = 1;
+ o.getterOnly = 1;
+ print();
+}
+
+function setStrict(o) {
+ "use strict";
+ print("setStrict(" + o + ")")
+ try {
+ o.foo = 1;
+ } catch (e) {
+ print(e);
+ }
+ try {
+ o.constructor = 1;
+ } catch (e) {
+ print(e);
+ }
+ try {
+ o.accessor = 1;
+ } catch (e) {
+ print(e);
+ }
+ try {
+ o.getterOnly = 1;
+ } catch (e) {
+ print(e);
+ }
+ print();
+}
+
+function setAttr(o, id) {
+ print("setAttr(" + o + ", " + id + ")")
+ o[id] = 1;
+ print();
+}
+
+function setAttrStrict(o, id) {
+ "use strict";
+ print("setAttrStrict(" + o + ", " + id + ")")
+ try {
+ o[id] = 1;
+ } catch (e) {
+ print(e);
+ }
+ print();
+}
+
+set(1);
+set("str");
+set(true);
+set({});
+set([]);
+
+setStrict(1);
+setStrict("str");
+setStrict(true);
+setStrict({});
+setStrict([]);
+
+setAttr(1, "foo");
+setAttr(1, "constructor");
+setAttr(1, "accessor");
+setAttr(1, "getterOnly");
+setAttr("str", "foo");
+setAttr("str", "constructor");
+setAttr("str", "accessor");
+setAttr("str", "getterOnly");
+setAttr(true, "foo");
+setAttr(true, "constructor");
+setAttr(true, "accessor");
+setAttr(true, "getterOnly");
+
+setAttrStrict(1, "foo");
+setAttrStrict(1, "constructor");
+setAttrStrict(1, "accessor");
+setAttrStrict(1, "getterOnly");
+setAttrStrict("str", "foo");
+setAttrStrict("str", "constructor");
+setAttrStrict("str", "accessor");
+setAttrStrict("str", "getterOnly");
+setAttrStrict(true, "foo");
+setAttrStrict(true, "constructor");
+setAttrStrict(true, "accessor");
+setAttrStrict(true, "getterOnly");
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/test/script/basic/JDK-8066226.js.EXPECTED Thu Dec 25 19:46:17 2014 -0800
@@ -0,0 +1,104 @@
+set(1)
+Setting accessor on 1 to 1
+
+set(str)
+Setting accessor on str to 1
+
+set(true)
+Setting accessor on true to 1
+
+set([object Object])
+Setting accessor on [object Object] to 1
+
+set()
+Setting accessor on to 1
+
+setStrict(1)
+TypeError: "foo" is not a writable property of 1
+TypeError: "constructor" is not a writable property of 1
+Setting accessor on 1 to 1
+TypeError: Cannot set property "getterOnly" of [object Object] that has only a getter
+
+setStrict(str)
+TypeError: "foo" is not a writable property of str
+TypeError: "constructor" is not a writable property of str
+Setting accessor on str to 1
+TypeError: Cannot set property "getterOnly" of [object Object] that has only a getter
+
+setStrict(true)
+TypeError: "foo" is not a writable property of true
+TypeError: "constructor" is not a writable property of true
+Setting accessor on true to 1
+TypeError: Cannot set property "getterOnly" of [object Object] that has only a getter
+
+setStrict([object Object])
+Setting accessor on [object Object] to 1
+TypeError: Cannot set property "getterOnly" of [object Object] that has only a getter
+
+setStrict()
+Setting accessor on to 1
+TypeError: Cannot set property "getterOnly" of [object Array] that has only a getter
+
+setAttr(1, foo)
+
+setAttr(1, constructor)
+
+setAttr(1, accessor)
+Setting accessor on 1 to 1
+
+setAttr(1, getterOnly)
+
+setAttr(str, foo)
+
+setAttr(str, constructor)
+
+setAttr(str, accessor)
+Setting accessor on str to 1
+
+setAttr(str, getterOnly)
+
+setAttr(true, foo)
+
+setAttr(true, constructor)
+
+setAttr(true, accessor)
+Setting accessor on true to 1
+
+setAttr(true, getterOnly)
+
+setAttrStrict(1, foo)
+TypeError: "foo" is not a writable property of 1
+
+setAttrStrict(1, constructor)
+TypeError: "constructor" is not a writable property of 1
+
+setAttrStrict(1, accessor)
+Setting accessor on 1 to 1
+
+setAttrStrict(1, getterOnly)
+TypeError: Cannot set property "getterOnly" of [object Object] that has only a getter
+
+setAttrStrict(str, foo)
+TypeError: "foo" is not a writable property of str
+
+setAttrStrict(str, constructor)
+TypeError: "constructor" is not a writable property of str
+
+setAttrStrict(str, accessor)
+Setting accessor on str to 1
+
+setAttrStrict(str, getterOnly)
+TypeError: Cannot set property "getterOnly" of [object Object] that has only a getter
+
+setAttrStrict(true, foo)
+TypeError: "foo" is not a writable property of true
+
+setAttrStrict(true, constructor)
+TypeError: "constructor" is not a writable property of true
+
+setAttrStrict(true, accessor)
+Setting accessor on true to 1
+
+setAttrStrict(true, getterOnly)
+TypeError: Cannot set property "getterOnly" of [object Object] that has only a getter
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/test/script/basic/JDK-8067774.js Thu Dec 25 19:46:17 2014 -0800
@@ -0,0 +1,37 @@
+/*
+ * 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-8067774: Use a stack of types when calculating local variable types
+ *
+ * @test
+ * @run
+ */
+
+print((function (p) {
+ var a, b;
+
+ a = p ? ((b = 1), b) : 0;
+
+ return a;
+})(true));
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/test/script/basic/JDK-8067774.js.EXPECTED Thu Dec 25 19:46:17 2014 -0800
@@ -0,0 +1,1 @@
+1
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/test/script/trusted/JDK-8067854.js Thu Dec 25 19:46:17 2014 -0800
@@ -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-8067854: bound java static method throws NPE when 'null' is used for this argument
+ *
+ * @test
+ * @run
+ */
+
+getProp = java.lang.System.getProperty;
+
+// bind this and an argument. "null" for this as getProperty is a
+// static method of java.lang.System
+getHome = Function.prototype.bind.call(getProp, null, "java.home");
+
+if (getHome() != getProp("java.home")) {
+ fail("getHome() failed to get java.home");
+}
--- a/nashorn/test/src/jdk/nashorn/api/scripting/PluggableJSObjectTest.java Tue Dec 23 12:40:06 2014 -0800
+++ b/nashorn/test/src/jdk/nashorn/api/scripting/PluggableJSObjectTest.java Thu Dec 25 19:46:17 2014 -0800
@@ -109,6 +109,35 @@
}
}
+ // @bug 8062030: Nashorn bug retrieving array property after key string concatenation
+ @Test
+ // ConsString attribute access on a JSObject
+ public void consStringTest() {
+ final ScriptEngineManager m = new ScriptEngineManager();
+ final ScriptEngine e = m.getEngineByName("nashorn");
+ try {
+ final MapWrapperObject obj = new MapWrapperObject();
+ e.put("obj", obj);
+ e.put("f", "f");
+ e.eval("obj[f + 'oo'] = 'bar';");
+
+ assertEquals(obj.getMap().get("foo"), "bar");
+ assertEquals(e.eval("obj[f + 'oo']"), "bar");
+ assertEquals(e.eval("obj['foo']"), "bar");
+ assertEquals(e.eval("f + 'oo' in obj"), Boolean.TRUE);
+ assertEquals(e.eval("'foo' in obj"), Boolean.TRUE);
+ e.eval("delete obj[f + 'oo']");
+ assertFalse(obj.getMap().containsKey("foo"));
+ assertEquals(e.eval("obj[f + 'oo']"), null);
+ assertEquals(e.eval("obj['foo']"), null);
+ assertEquals(e.eval("f + 'oo' in obj"), Boolean.FALSE);
+ assertEquals(e.eval("'foo' in obj"), Boolean.FALSE);
+ } catch (final Exception exp) {
+ exp.printStackTrace();
+ fail(exp.getMessage());
+ }
+ }
+
public static class BufferObject extends AbstractJSObject {
private final IntBuffer buf;
--- a/test/Makefile Tue Dec 23 12:40:06 2014 -0800
+++ b/test/Makefile Thu Dec 25 19:46:17 2014 -0800
@@ -33,6 +33,7 @@
# This makefile depends on the availability of sibling directories.
LANGTOOLS_DIR=$(TOPDIR)/langtools
JDK_DIR=$(TOPDIR)/jdk
+JAXP_DIR=$(TOPDIR)/jaxp
HOTSPOT_DIR=$(TOPDIR)/hotspot
# Macro to run a test target in a subdir
@@ -51,10 +52,10 @@
endef
# Default test target (core)
-default: jdk_core langtools_jtreg
+default: jdk_core langtools_jtreg jaxp_all
# All testing
-all: jdk_all langtools_all
+all: jdk_all langtools_all jaxp_all
# Test targets
langtools_% :
@@ -63,6 +64,9 @@
jdk_% core_%s svc_%:
@$(NO_STOPPING)$(call SUBDIR_TEST, $(JDK_DIR), TEST="$@" $@)
+jaxp_%:
+ @$(NO_STOPPING)$(call SUBDIR_TEST, $(JAXP_DIR), TEST="$@" $@)
+
hotspot_%:
@$(NO_STOPPING)$(call SUBDIR_TEST, $(HOTSPOT_DIR), TEST="$@" $@)