This commit is contained in:
Lana Steuck 2010-08-12 19:58:19 -07:00
commit f87e976a33
633 changed files with 18887 additions and 1040 deletions

View File

@ -77,3 +77,5 @@ c4c8a5bc54f66abc68cd185d9294042121922154 jdk7-b99
2d6ba7a221915bdf0311acc5641c7f3875cb793e jdk7-b100
2548ac036b8fca3326d058d758e6df8355a42469 jdk7-b101
88db80c8e49cea352c2900f689600dc410761c1f jdk7-b102
64770970865839b0443066370e7d476ef47e90cd jdk7-b103
10bc903a228d3a8efdf46fb8c3fcf82a59b88bc5 jdk7-b104

View File

@ -77,3 +77,5 @@ e7f18db469a3e947b7096bfd12e87380e5a042cd jdk7-b99
b218a53ec7d3d42be61d31d6917a6c5c037b6f56 jdk7-b100
4193eaf5f1b82794c6a0fb1a8d11af43d1b1d611 jdk7-b101
a136a51f5113da4dad3853b74a8536ab583ab112 jdk7-b102
be2aedc4e3b1751c1310f334242ba69e90867f38 jdk7-b103
f8be576feefce0c6695f188ef97ec16b73ad9cfd jdk7-b104

View File

@ -77,3 +77,5 @@ edc2a2659c77dabc55cb55bb617bad89e3a05bb3 jdk7-b96
a56d734a1e970e1a21a8f4feb13053e9a33674c7 jdk7-b100
86a239832646a74811695428984b6947c0bd6dc8 jdk7-b101
78561a95779090b5106c8d0f1a75360a027ef087 jdk7-b102
11e7678c3eb169b77d9a9892fe5e3dfa1d1a0d51 jdk7-b103
9607213481d400ac477183191cc080e1bef6f475 jdk7-b104

View File

@ -107,3 +107,6 @@ ad1977f08c4d69162a0775fe3f9576b9fd521d10 jdk7-b100
6c3a919105b68c15b7db923ec9a00006e9560910 jdk7-b101
ad1977f08c4d69162a0775fe3f9576b9fd521d10 hs19-b03
c5cadf1a07717955cf60dbaec16e35b529fd2cb0 jdk7-b102
cb4250ef73b21de6c487ea14e2b0b99eed67b4b6 jdk7-b103
e55900b5c1b865cac17e18abc639c7dc50de7fd8 hs19-b04
b4acf10eb134fe930802c97e36db65e7ccb544b5 jdk7-b104

View File

@ -297,6 +297,7 @@ public class ConstantPool extends Oop implements ClassConstants {
case JVM_CONSTANT_NameAndType: return "JVM_CONSTANT_NameAndType";
case JVM_CONSTANT_MethodHandle: return "JVM_CONSTANT_MethodHandle";
case JVM_CONSTANT_MethodType: return "JVM_CONSTANT_MethodType";
case JVM_CONSTANT_InvokeDynamic: return "JVM_CONSTANT_InvokeDynamic";
case JVM_CONSTANT_Invalid: return "JVM_CONSTANT_Invalid";
case JVM_CONSTANT_UnresolvedClass: return "JVM_CONSTANT_UnresolvedClass";
case JVM_CONSTANT_UnresolvedClassInError: return "JVM_CONSTANT_UnresolvedClassInError";
@ -355,6 +356,7 @@ public class ConstantPool extends Oop implements ClassConstants {
case JVM_CONSTANT_NameAndType:
case JVM_CONSTANT_MethodHandle:
case JVM_CONSTANT_MethodType:
case JVM_CONSTANT_InvokeDynamic:
visitor.doInt(new IntField(new NamedFieldIdentifier(nameForTag(ctag)), indexOffset(index), true), true);
break;
}
@ -517,6 +519,18 @@ public class ConstantPool extends Oop implements ClassConstants {
+ ", type = " + signatureIndex);
break;
}
case JVM_CONSTANT_InvokeDynamic: {
dos.writeByte(cpConstType);
int value = getIntAt(ci);
short bootstrapMethodIndex = (short) extractLowShortFromInt(value);
short nameAndTypeIndex = (short) extractHighShortFromInt(value);
dos.writeShort(bootstrapMethodIndex);
dos.writeShort(nameAndTypeIndex);
if (DEBUG) debugMessage("CP[" + ci + "] = indy BSM = " + bootstrapMethodIndex
+ ", N&T = " + nameAndTypeIndex);
break;
}
default:
throw new InternalError("unknown tag: " + cpConstType);
} // switch

View File

@ -42,6 +42,7 @@ public interface ClassConstants
public static final int JVM_CONSTANT_NameAndType = 12;
public static final int JVM_CONSTANT_MethodHandle = 15;
public static final int JVM_CONSTANT_MethodType = 16;
public static final int JVM_CONSTANT_InvokeDynamic = 17;
// JVM_CONSTANT_MethodHandle subtypes
public static final int JVM_REF_getField = 1;

View File

@ -303,12 +303,12 @@ public class ClassWriter implements /* imports */ ClassConstants
case JVM_CONSTANT_MethodHandle: {
dos.writeByte(cpConstType);
int value = cpool.getIntAt(ci);
short refIndex = (short) extractHighShortFromInt(value);
byte refKind = (byte) extractLowShortFromInt(value);
dos.writeByte(refKind);
dos.writeShort(refIndex);
if (DEBUG) debugMessage("CP[" + ci + "] = MH index = " + refIndex
+ ", kind = " + refKind);
short bootstrapMethodIndex = (short) extractLowShortFromInt(value);
short nameAndTypeIndex = (short) extractHighShortFromInt(value);
dos.writeShort(bootstrapMethodIndex);
dos.writeShort(nameAndTypeIndex);
if (DEBUG) debugMessage("CP[" + ci + "] = indy BSM = " +
bootstrapMethodIndex + ", N&T = " + nameAndTypeIndex);
break;
}
@ -321,6 +321,15 @@ public class ClassWriter implements /* imports */ ClassConstants
break;
}
case JVM_CONSTANT_InvokeDynamic: {
dos.writeByte(cpConstType);
int value = cpool.getIntAt(ci);
short refIndex = (short) value;
dos.writeShort(refIndex);
if (DEBUG) debugMessage("CP[" + ci + "] = MT index = " + refIndex);
break;
}
default:
throw new InternalError("Unknown tag: " + cpConstType);
} // switch

View File

@ -582,6 +582,11 @@ public class HTMLGenerator implements /* imports */ ClassConstants {
buf.cell(Integer.toString(cpool.getIntAt(index)));
break;
case JVM_CONSTANT_InvokeDynamic:
buf.cell("JVM_CONSTANT_InvokeDynamic");
buf.cell(genLowHighShort(cpool.getIntAt(index)));
break;
default:
throw new InternalError("unknown tag: " + ctag);
}

View File

@ -40,6 +40,7 @@ public class ConstantTag {
private static int JVM_CONSTANT_NameAndType = 12;
private static int JVM_CONSTANT_MethodHandle = 15; // JSR 292
private static int JVM_CONSTANT_MethodType = 16; // JSR 292
private static int JVM_CONSTANT_InvokeDynamic = 17; // JSR 292
private static int JVM_CONSTANT_Invalid = 0; // For bad value initialization
private static int JVM_CONSTANT_UnresolvedClass = 100; // Temporary tag until actual use
private static int JVM_CONSTANT_ClassIndex = 101; // Temporary tag while constructing constant pool
@ -78,6 +79,7 @@ public class ConstantTag {
public boolean isUtf8() { return tag == JVM_CONSTANT_Utf8; }
public boolean isMethodHandle() { return tag == JVM_CONSTANT_MethodHandle; }
public boolean isMethodType() { return tag == JVM_CONSTANT_MethodType; }
public boolean isInvokeDynamic() { return tag == JVM_CONSTANT_InvokeDynamic; }
public boolean isInvalid() { return tag == JVM_CONSTANT_Invalid; }

View File

@ -35,7 +35,7 @@ HOTSPOT_VM_COPYRIGHT=Copyright 2010
HS_MAJOR_VER=19
HS_MINOR_VER=0
HS_BUILD_NUMBER=04
HS_BUILD_NUMBER=05
JDK_MAJOR_VER=1
JDK_MINOR_VER=7

View File

@ -1007,9 +1007,9 @@ class StubGenerator: public StubCodeGenerator {
__ brx(Assembler::lessEqualUnsigned, false, Assembler::pt, (*NOLp));
__ delayed()->cmp(to_from, byte_count);
if (NOLp == NULL)
__ brx(Assembler::greaterEqual, false, Assembler::pt, no_overlap_target);
__ brx(Assembler::greaterEqualUnsigned, false, Assembler::pt, no_overlap_target);
else
__ brx(Assembler::greaterEqual, false, Assembler::pt, (*NOLp));
__ brx(Assembler::greaterEqualUnsigned, false, Assembler::pt, (*NOLp));
__ delayed()->nop();
}

View File

@ -728,8 +728,8 @@ ciMethod* ciEnv::get_fake_invokedynamic_method_impl(constantPoolHandle cpool,
}
// Get the invoker methodOop from the constant pool.
intptr_t f2_value = cpool->cache()->main_entry_at(index)->f2();
methodOop signature_invoker = methodOop(f2_value);
oop f1_value = cpool->cache()->main_entry_at(index)->f1();
methodOop signature_invoker = methodOop(f1_value);
assert(signature_invoker != NULL && signature_invoker->is_method() && signature_invoker->is_method_handle_invoke(),
"correct result from LinkResolver::resolve_invokedynamic");

View File

@ -694,30 +694,21 @@ int ciMethod::scale_count(int count, float prof_factor) {
// ------------------------------------------------------------------
// ciMethod::is_method_handle_invoke
//
// Return true if the method is a MethodHandle target.
// Return true if the method is an instance of one of the two
// signature-polymorphic MethodHandle methods, invokeExact or invokeGeneric.
bool ciMethod::is_method_handle_invoke() const {
bool flag = (holder()->name() == ciSymbol::java_dyn_MethodHandle() &&
methodOopDesc::is_method_handle_invoke_name(name()->sid()));
#ifdef ASSERT
if (is_loaded()) {
bool flag2 = ((flags().as_int() & JVM_MH_INVOKE_BITS) == JVM_MH_INVOKE_BITS);
{
VM_ENTRY_MARK;
bool flag3 = get_methodOop()->is_method_handle_invoke();
assert(flag2 == flag3, "consistent");
assert(flag == flag3, "consistent");
}
}
#endif //ASSERT
return flag;
if (!is_loaded()) return false;
VM_ENTRY_MARK;
return get_methodOop()->is_method_handle_invoke();
}
// ------------------------------------------------------------------
// ciMethod::is_method_handle_adapter
//
// Return true if the method is a generated MethodHandle adapter.
// These are built by MethodHandleCompiler.
bool ciMethod::is_method_handle_adapter() const {
check_is_loaded();
if (!is_loaded()) return false;
VM_ENTRY_MARK;
return get_methodOop()->is_method_handle_adapter();
}

View File

@ -122,7 +122,7 @@ void ClassFileParser::parse_constant_pool_entries(constantPoolHandle cp, int len
if (!EnableMethodHandles ||
_major_version < Verifier::INVOKEDYNAMIC_MAJOR_VERSION) {
classfile_parse_error(
(!EnableInvokeDynamic ?
(!EnableMethodHandles ?
"This JVM does not support constant tag %u in class file %s" :
"Class file version does not support constant tag %u in class file %s"),
tag, CHECK);
@ -140,6 +140,22 @@ void ClassFileParser::parse_constant_pool_entries(constantPoolHandle cp, int len
ShouldNotReachHere();
}
break;
case JVM_CONSTANT_InvokeDynamic :
{
if (!EnableInvokeDynamic ||
_major_version < Verifier::INVOKEDYNAMIC_MAJOR_VERSION) {
classfile_parse_error(
(!EnableInvokeDynamic ?
"This JVM does not support constant tag %u in class file %s" :
"Class file version does not support constant tag %u in class file %s"),
tag, CHECK);
}
cfs->guarantee_more(5, CHECK); // bsm_index, name_and_type_index, tag/access_flags
u2 bootstrap_method_index = cfs->get_u2_fast();
u2 name_and_type_index = cfs->get_u2_fast();
cp->invoke_dynamic_at_put(index, bootstrap_method_index, name_and_type_index);
}
break;
case JVM_CONSTANT_Integer :
{
cfs->guarantee_more(5, CHECK); // bytes, tag/access_flags
@ -414,6 +430,24 @@ constantPoolHandle ClassFileParser::parse_constant_pool(TRAPS) {
ref_index, CHECK_(nullHandle));
}
break;
case JVM_CONSTANT_InvokeDynamic :
{
int bootstrap_method_ref_index = cp->invoke_dynamic_bootstrap_method_ref_index_at(index);
int name_and_type_ref_index = cp->invoke_dynamic_name_and_type_ref_index_at(index);
check_property((bootstrap_method_ref_index == 0 && AllowTransitionalJSR292)
||
(valid_cp_range(bootstrap_method_ref_index, length) &&
cp->tag_at(bootstrap_method_ref_index).is_method_handle()),
"Invalid constant pool index %u in class file %s",
bootstrap_method_ref_index,
CHECK_(nullHandle));
check_property(valid_cp_range(name_and_type_ref_index, length) &&
cp->tag_at(name_and_type_ref_index).is_name_and_type(),
"Invalid constant pool index %u in class file %s",
name_and_type_ref_index,
CHECK_(nullHandle));
break;
}
default:
fatal(err_msg("bad constant pool tag value %u",
cp->tag_at(index).value()));

View File

@ -2507,6 +2507,10 @@ Handle SystemDictionary::make_dynamic_call_site(Handle bootstrap_method,
int caller_bci,
TRAPS) {
Handle empty;
guarantee(bootstrap_method.not_null() &&
java_dyn_MethodHandle::is_instance(bootstrap_method()),
"caller must supply a valid BSM");
Handle caller_mname = MethodHandles::new_MemberName(CHECK_(empty));
MethodHandles::init_MemberName(caller_mname(), caller_method());
@ -2537,20 +2541,61 @@ Handle SystemDictionary::make_dynamic_call_site(Handle bootstrap_method,
return call_site_oop;
}
Handle SystemDictionary::find_bootstrap_method(KlassHandle caller, TRAPS) {
Handle SystemDictionary::find_bootstrap_method(methodHandle caller_method, int caller_bci,
int cache_index, TRAPS) {
Handle empty;
if (!caller->oop_is_instance()) return empty;
instanceKlassHandle ik(THREAD, caller());
constantPoolHandle pool;
{
klassOop caller = caller_method->method_holder();
if (!Klass::cast(caller)->oop_is_instance()) return empty;
pool = constantPoolHandle(THREAD, instanceKlass::cast(caller)->constants());
}
oop boot_method_oop = ik->bootstrap_method();
if (boot_method_oop != NULL) {
if (TraceMethodHandles) {
tty->print_cr("bootstrap method for "PTR_FORMAT" cached as "PTR_FORMAT":", ik(), boot_method_oop);
int constant_pool_index = pool->cache()->entry_at(cache_index)->constant_pool_index();
constantTag tag = pool->tag_at(constant_pool_index);
if (tag.is_invoke_dynamic()) {
// JVM_CONSTANT_InvokeDynamic is an ordered pair of [bootm, name&type]
// The bootm, being a JVM_CONSTANT_MethodHandle, has its own cache entry.
int bsm_index = pool->invoke_dynamic_bootstrap_method_ref_index_at(constant_pool_index);
if (bsm_index != 0) {
int bsm_index_in_cache = pool->cache()->entry_at(cache_index)->bootstrap_method_index_in_cache();
DEBUG_ONLY(int bsm_index_2 = pool->cache()->entry_at(bsm_index_in_cache)->constant_pool_index());
assert(bsm_index == bsm_index_2, "BSM constant lifted to cache");
if (TraceMethodHandles) {
tty->print_cr("resolving bootstrap method for "PTR_FORMAT" at %d at cache[%d]CP[%d]...",
(intptr_t) caller_method(), caller_bci, cache_index, constant_pool_index);
}
oop bsm_oop = pool->resolve_cached_constant_at(bsm_index_in_cache, CHECK_(empty));
if (TraceMethodHandles) {
tty->print_cr("bootstrap method for "PTR_FORMAT" at %d retrieved as "PTR_FORMAT":",
(intptr_t) caller_method(), caller_bci, (intptr_t) bsm_oop);
}
assert(bsm_oop->is_oop()
&& java_dyn_MethodHandle::is_instance(bsm_oop), "must be sane");
return Handle(THREAD, bsm_oop);
}
assert(boot_method_oop->is_oop()
&& java_dyn_MethodHandle::is_instance(boot_method_oop), "must be sane");
return Handle(THREAD, boot_method_oop);
// else null BSM; fall through
} else if (tag.is_name_and_type()) {
// JSR 292 EDR does not have JVM_CONSTANT_InvokeDynamic
// a bare name&type defaults its BSM to null, so fall through...
} else {
ShouldNotReachHere(); // verifier does not allow this
}
// Fall through to pick up the per-class bootstrap method.
// This mechanism may go away in the PFD.
assert(AllowTransitionalJSR292, "else the verifier should have stopped us already");
oop bsm_oop = instanceKlass::cast(caller_method->method_holder())->bootstrap_method();
if (bsm_oop != NULL) {
if (TraceMethodHandles) {
tty->print_cr("bootstrap method for "PTR_FORMAT" registered as "PTR_FORMAT":",
(intptr_t) caller_method(), (intptr_t) bsm_oop);
}
assert(bsm_oop->is_oop()
&& java_dyn_MethodHandle::is_instance(bsm_oop), "must be sane");
return Handle(THREAD, bsm_oop);
}
return empty;

View File

@ -492,7 +492,10 @@ public:
TRAPS);
// coordinate with Java about bootstrap methods
static Handle find_bootstrap_method(KlassHandle caller, TRAPS);
static Handle find_bootstrap_method(methodHandle caller_method,
int caller_bci, // N.B. must be an invokedynamic
int cache_index, // must be corresponding main_entry
TRAPS);
// Utility for printing loader "name" as part of tracing constraints
static const char* loader_name(oop loader) {

View File

@ -1913,7 +1913,8 @@ void ClassVerifier::verify_invoke_instructions(
unsigned int types = (opcode == Bytecodes::_invokeinterface
? 1 << JVM_CONSTANT_InterfaceMethodref
: opcode == Bytecodes::_invokedynamic
? 1 << JVM_CONSTANT_NameAndType
? (1 << JVM_CONSTANT_NameAndType
|1 << JVM_CONSTANT_InvokeDynamic)
: 1 << JVM_CONSTANT_Methodref);
verify_cp_type(index, cp, types, CHECK_VERIFY(this));

View File

@ -202,6 +202,11 @@ void BufferBlob::free( BufferBlob *blob ) {
//----------------------------------------------------------------------------------------------------
// Implementation of AdapterBlob
AdapterBlob::AdapterBlob(int size, CodeBuffer* cb) :
BufferBlob("I2C/C2I adapters", size, cb) {
CodeCache::commit(this);
}
AdapterBlob* AdapterBlob::create(CodeBuffer* cb) {
ThreadInVMfromUnknown __tiv; // get to VM state in case we block on CodeCache_lock
@ -210,7 +215,6 @@ AdapterBlob* AdapterBlob::create(CodeBuffer* cb) {
{
MutexLockerEx mu(CodeCache_lock, Mutex::_no_safepoint_check_flag);
blob = new (size) AdapterBlob(size, cb);
CodeCache::commit(blob);
}
// Track memory usage statistic after releasing CodeCache_lock
MemoryService::track_code_cache_memory_usage();

View File

@ -219,8 +219,7 @@ class BufferBlob: public CodeBlob {
class AdapterBlob: public BufferBlob {
private:
AdapterBlob(int size) : BufferBlob("I2C/C2I adapters", size) {}
AdapterBlob(int size, CodeBuffer* cb) : BufferBlob("I2C/C2I adapters", size, cb) {}
AdapterBlob(int size, CodeBuffer* cb);
public:
// Creation

View File

@ -664,19 +664,14 @@ CMSCollector::CMSCollector(ConcurrentMarkSweepGeneration* cmsGen,
return;
}
// XXX use a global constant instead of 64!
typedef struct OopTaskQueuePadded {
OopTaskQueue work_queue;
char pad[64 - sizeof(OopTaskQueue)]; // prevent false sharing
} OopTaskQueuePadded;
typedef Padded<OopTaskQueue> PaddedOopTaskQueue;
for (i = 0; i < num_queues; i++) {
OopTaskQueuePadded *q_padded = new OopTaskQueuePadded();
if (q_padded == NULL) {
PaddedOopTaskQueue *q = new PaddedOopTaskQueue();
if (q == NULL) {
warning("work_queue allocation failure.");
return;
}
_task_queues->register_queue(i, &q_padded->work_queue);
_task_queues->register_queue(i, q);
}
for (i = 0; i < num_queues; i++) {
_task_queues->queue(i)->initialize();

View File

@ -234,6 +234,11 @@ void VM_GenCollectFullConcurrent::doit_epilogue() {
GenCollectedHeap* gch = GenCollectedHeap::heap();
if (_gc_cause != GCCause::_gc_locker &&
gch->total_full_collections_completed() <= _full_gc_count_before) {
// maybe we should change the condition to test _gc_cause ==
// GCCause::_java_lang_system_gc, instead of
// _gc_cause != GCCause::_gc_locker
assert(_gc_cause == GCCause::_java_lang_system_gc,
"the only way to get here if this was a System.gc()-induced GC");
assert(ExplicitGCInvokesConcurrent, "Error");
// Now, wait for witnessing concurrent gc cycle to complete,
// but do so in native mode, because we want to lock the

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2001, 2009, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2001, 2010, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -271,21 +271,16 @@ jbyte* ConcurrentG1Refine::add_card_count(jbyte* card_ptr, int* count, bool* def
if (cas_res == prev_epoch_entry) {
// We successfully updated the card num value in the epoch entry
count_ptr->_count = 0; // initialize counter for new card num
jbyte* old_card_ptr = card_num_2_ptr(old_card_num);
// Even though the region containg the card at old_card_num was not
// in the young list when old_card_num was recorded in the epoch
// cache it could have been added to the free list and subsequently
// added to the young list in the intervening time. If the evicted
// card is in a young region just return the card_ptr and the evicted
// card will not be cleaned. See CR 6817995.
jbyte* old_card_ptr = card_num_2_ptr(old_card_num);
if (is_young_card(old_card_ptr)) {
*count = 0;
// We can defer the processing of card_ptr
*defer = true;
return card_ptr;
}
// added to the young list in the intervening time. See CR 6817995.
// We do not deal with this case here - it will be handled in
// HeapRegion::oops_on_card_seq_iterate_careful after it has been
// determined that the region containing the card has been allocated
// to, and it's safe to check the young type of the region.
// We do not want to defer processing of card_ptr in this case
// (we need to refine old_card_ptr and card_ptr)
@ -301,22 +296,22 @@ jbyte* ConcurrentG1Refine::cache_insert(jbyte* card_ptr, bool* defer) {
jbyte* cached_ptr = add_card_count(card_ptr, &count, defer);
assert(cached_ptr != NULL, "bad cached card ptr");
if (is_young_card(cached_ptr)) {
// The region containing cached_ptr has been freed during a clean up
// pause, reallocated, and tagged as young.
assert(cached_ptr != card_ptr, "shouldn't be");
// We've just inserted a card pointer into the card count cache
// and got back the card that we just inserted or (evicted) the
// previous contents of that count slot.
// We've just inserted a new old-gen card pointer into the card count
// cache and evicted the previous contents of that count slot.
// The evicted card pointer has been determined to be in a young region
// and so cannot be the newly inserted card pointer (that will be
// in an old region).
// The count for newly inserted card will be set to zero during the
// insertion, so we don't want to defer the cleaning of the newly
// inserted card pointer.
assert(*defer == false, "deferring non-hot card");
return NULL;
}
// The card we got back could be in a young region. When the
// returned card (if evicted) was originally inserted, we had
// determined that its containing region was not young. However
// it is possible for the region to be freed during a cleanup
// pause, then reallocated and tagged as young which will result
// in the returned card residing in a young region.
//
// We do not deal with this case here - the change from non-young
// to young could be observed at any time - it will be handled in
// HeapRegion::oops_on_card_seq_iterate_careful after it has been
// determined that the region containing the card has been allocated
// to.
// The card pointer we obtained from card count cache is not hot
// so do not store it in the cache; return it for immediate
@ -325,7 +320,7 @@ jbyte* ConcurrentG1Refine::cache_insert(jbyte* card_ptr, bool* defer) {
return cached_ptr;
}
// Otherwise, the pointer we got from the _card_counts is hot.
// Otherwise, the pointer we got from the _card_counts cache is hot.
jbyte* res = NULL;
MutexLockerEx x(HotCardCache_lock, Mutex::_no_safepoint_check_flag);
if (_n_hot == _hot_cache_size) {
@ -338,17 +333,8 @@ jbyte* ConcurrentG1Refine::cache_insert(jbyte* card_ptr, bool* defer) {
if (_hot_cache_idx == _hot_cache_size) _hot_cache_idx = 0;
_n_hot++;
if (res != NULL) {
// Even though the region containg res was not in the young list
// when it was recorded in the hot cache it could have been added
// to the free list and subsequently added to the young list in
// the intervening time. If res is in a young region, return NULL
// so that res is not cleaned. See CR 6817995.
if (is_young_card(res)) {
res = NULL;
}
}
// The card obtained from the hot card cache could be in a young
// region. See above on how this can happen.
return res;
}

View File

@ -266,6 +266,12 @@ void ConcurrentMarkThread::run() {
_cm->clearNextBitmap();
_sts.leave();
}
// Update the number of full collections that have been
// completed. This will also notify the FullGCCount_lock in case a
// Java thread is waiting for a full GC to happen (e.g., it
// called System.gc() with +ExplicitGCInvokesConcurrent).
g1->increment_full_collections_completed(true /* outer */);
}
assert(_should_terminate, "just checking");

View File

@ -638,6 +638,11 @@ G1CollectedHeap::attempt_allocation_slow(size_t word_size,
// Now retry the allocation.
if (_cur_alloc_region != NULL) {
if (allocated_young_region != NULL) {
// We need to ensure that the store to top does not
// float above the setting of the young type.
OrderAccess::storestore();
}
res = _cur_alloc_region->allocate(word_size);
}
}
@ -809,7 +814,8 @@ public:
}
};
void G1CollectedHeap::do_collection(bool full, bool clear_all_soft_refs,
void G1CollectedHeap::do_collection(bool explicit_gc,
bool clear_all_soft_refs,
size_t word_size) {
if (GC_locker::check_active_before_gc()) {
return; // GC is disabled (e.g. JNI GetXXXCritical operation)
@ -821,10 +827,6 @@ void G1CollectedHeap::do_collection(bool full, bool clear_all_soft_refs,
Universe::print_heap_before_gc();
}
if (full && DisableExplicitGC) {
return;
}
assert(SafepointSynchronize::is_at_safepoint(), "should be at safepoint");
assert(Thread::current() == VMThread::vm_thread(), "should be in vm thread");
@ -837,9 +839,11 @@ void G1CollectedHeap::do_collection(bool full, bool clear_all_soft_refs,
IsGCActiveMark x;
// Timing
bool system_gc = (gc_cause() == GCCause::_java_lang_system_gc);
assert(!system_gc || explicit_gc, "invariant");
gclog_or_tty->date_stamp(PrintGC && PrintGCDateStamps);
TraceCPUTime tcpu(PrintGCDetails, true, gclog_or_tty);
TraceTime t(full ? "Full GC (System.gc())" : "Full GC",
TraceTime t(system_gc ? "Full GC (System.gc())" : "Full GC",
PrintGC, true, gclog_or_tty);
TraceMemoryManagerStats tms(true /* fullGC */);
@ -944,7 +948,7 @@ void G1CollectedHeap::do_collection(bool full, bool clear_all_soft_refs,
heap_region_iterate(&rs_clear);
// Resize the heap if necessary.
resize_if_necessary_after_full_collection(full ? 0 : word_size);
resize_if_necessary_after_full_collection(explicit_gc ? 0 : word_size);
if (_cg1r->use_cache()) {
_cg1r->clear_and_record_card_counts();
@ -1009,13 +1013,18 @@ void G1CollectedHeap::do_collection(bool full, bool clear_all_soft_refs,
"young list should be empty at this point");
}
// Update the number of full collections that have been completed.
increment_full_collections_completed(false /* outer */);
if (PrintHeapAtGC) {
Universe::print_heap_after_gc();
}
}
void G1CollectedHeap::do_full_collection(bool clear_all_soft_refs) {
do_collection(true, clear_all_soft_refs, 0);
do_collection(true, /* explicit_gc */
clear_all_soft_refs,
0 /* word_size */);
}
// This code is mostly copied from TenuredGeneration.
@ -1331,6 +1340,7 @@ G1CollectedHeap::G1CollectedHeap(G1CollectorPolicy* policy_) :
_young_list(new YoungList(this)),
_gc_time_stamp(0),
_surviving_young_words(NULL),
_full_collections_completed(0),
_in_cset_fast_test(NULL),
_in_cset_fast_test_base(NULL),
_dirty_cards_region_list(NULL) {
@ -1689,6 +1699,51 @@ size_t G1CollectedHeap::unsafe_max_alloc() {
return car->free();
}
bool G1CollectedHeap::should_do_concurrent_full_gc(GCCause::Cause cause) {
return
((cause == GCCause::_gc_locker && GCLockerInvokesConcurrent) ||
(cause == GCCause::_java_lang_system_gc && ExplicitGCInvokesConcurrent));
}
void G1CollectedHeap::increment_full_collections_completed(bool outer) {
MonitorLockerEx x(FullGCCount_lock, Mutex::_no_safepoint_check_flag);
// We have already incremented _total_full_collections at the start
// of the GC, so total_full_collections() represents how many full
// collections have been started.
unsigned int full_collections_started = total_full_collections();
// Given that this method is called at the end of a Full GC or of a
// concurrent cycle, and those can be nested (i.e., a Full GC can
// interrupt a concurrent cycle), the number of full collections
// completed should be either one (in the case where there was no
// nesting) or two (when a Full GC interrupted a concurrent cycle)
// behind the number of full collections started.
// This is the case for the inner caller, i.e. a Full GC.
assert(outer ||
(full_collections_started == _full_collections_completed + 1) ||
(full_collections_started == _full_collections_completed + 2),
err_msg("for inner caller: full_collections_started = %u "
"is inconsistent with _full_collections_completed = %u",
full_collections_started, _full_collections_completed));
// This is the case for the outer caller, i.e. the concurrent cycle.
assert(!outer ||
(full_collections_started == _full_collections_completed + 1),
err_msg("for outer caller: full_collections_started = %u "
"is inconsistent with _full_collections_completed = %u",
full_collections_started, _full_collections_completed));
_full_collections_completed += 1;
// This notify_all() will ensure that a thread that called
// System.gc() with (with ExplicitGCInvokesConcurrent set or not)
// and it's waiting for a full GC to finish will be woken up. It is
// waiting in VM_G1IncCollectionPause::doit_epilogue().
FullGCCount_lock->notify_all();
}
void G1CollectedHeap::collect_as_vm_thread(GCCause::Cause cause) {
assert(Thread::current()->is_VM_thread(), "Precondition#1");
assert(Heap_lock->is_locked(), "Precondition#2");
@ -1709,25 +1764,41 @@ void G1CollectedHeap::collect(GCCause::Cause cause) {
// The caller doesn't have the Heap_lock
assert(!Heap_lock->owned_by_self(), "this thread should not own the Heap_lock");
int gc_count_before;
unsigned int gc_count_before;
unsigned int full_gc_count_before;
{
MutexLocker ml(Heap_lock);
// Read the GC count while holding the Heap_lock
gc_count_before = SharedHeap::heap()->total_collections();
full_gc_count_before = SharedHeap::heap()->total_full_collections();
// Don't want to do a GC until cleanup is completed.
wait_for_cleanup_complete();
} // We give up heap lock; VMThread::execute gets it back below
switch (cause) {
case GCCause::_scavenge_alot: {
// Do an incremental pause, which might sometimes be abandoned.
VM_G1IncCollectionPause op(gc_count_before, cause);
// We give up heap lock; VMThread::execute gets it back below
}
if (should_do_concurrent_full_gc(cause)) {
// Schedule an initial-mark evacuation pause that will start a
// concurrent cycle.
VM_G1IncCollectionPause op(gc_count_before,
true, /* should_initiate_conc_mark */
g1_policy()->max_pause_time_ms(),
cause);
VMThread::execute(&op);
} else {
if (cause == GCCause::_gc_locker
DEBUG_ONLY(|| cause == GCCause::_scavenge_alot)) {
// Schedule a standard evacuation pause.
VM_G1IncCollectionPause op(gc_count_before,
false, /* should_initiate_conc_mark */
g1_policy()->max_pause_time_ms(),
cause);
VMThread::execute(&op);
break;
}
default: {
// In all other cases, we currently do a full gc.
VM_G1CollectFull op(gc_count_before, cause);
} else {
// Schedule a Full GC.
VM_G1CollectFull op(gc_count_before, full_gc_count_before, cause);
VMThread::execute(&op);
}
}
@ -1989,6 +2060,11 @@ void G1CollectedHeap::collection_set_iterate(HeapRegionClosure* cl) {
void G1CollectedHeap::collection_set_iterate_from(HeapRegion* r,
HeapRegionClosure *cl) {
if (r == NULL) {
// The CSet is empty so there's nothing to do.
return;
}
assert(r->in_collection_set(),
"Start region must be a member of the collection set.");
HeapRegion* cur = r;
@ -2481,11 +2557,13 @@ void G1CollectedHeap::gc_epilogue(bool full /* Ignored */) {
}
void G1CollectedHeap::do_collection_pause() {
assert(Heap_lock->owned_by_self(), "we assume we'reholding the Heap_lock");
// Read the GC count while holding the Heap_lock
// we need to do this _before_ wait_for_cleanup_complete(), to
// ensure that we do not give up the heap lock and potentially
// pick up the wrong count
int gc_count_before = SharedHeap::heap()->total_collections();
unsigned int gc_count_before = SharedHeap::heap()->total_collections();
// Don't want to do a GC pause while cleanup is being completed!
wait_for_cleanup_complete();
@ -2493,7 +2571,10 @@ void G1CollectedHeap::do_collection_pause() {
g1_policy()->record_stop_world_start();
{
MutexUnlocker mu(Heap_lock); // give up heap lock, execute gets it back
VM_G1IncCollectionPause op(gc_count_before);
VM_G1IncCollectionPause op(gc_count_before,
false, /* should_initiate_conc_mark */
g1_policy()->max_pause_time_ms(),
GCCause::_g1_inc_collection_pause);
VMThread::execute(&op);
}
}
@ -2612,7 +2693,7 @@ struct PrepareForRSScanningClosure : public HeapRegionClosure {
};
void
G1CollectedHeap::do_collection_pause_at_safepoint() {
G1CollectedHeap::do_collection_pause_at_safepoint(double target_pause_time_ms) {
if (GC_locker::check_active_before_gc()) {
return; // GC is disabled (e.g. JNI GetXXXCritical operation)
}
@ -2637,8 +2718,12 @@ G1CollectedHeap::do_collection_pause_at_safepoint() {
else
strcat(verbose_str, "(partial)");
}
if (g1_policy()->during_initial_mark_pause())
if (g1_policy()->during_initial_mark_pause()) {
strcat(verbose_str, " (initial-mark)");
// We are about to start a marking cycle, so we increment the
// full collection counter.
increment_total_full_collections();
}
// if PrintGCDetails is on, we'll print long statistics information
// in the collector policy code, so let's not print this as the output
@ -2661,7 +2746,6 @@ G1CollectedHeap::do_collection_pause_at_safepoint() {
"young list should be well formed");
}
bool abandoned = false;
{ // Call to jvmpi::post_class_unload_events must occur outside of active GC
IsGCActiveMark x;
@ -2743,7 +2827,7 @@ G1CollectedHeap::do_collection_pause_at_safepoint() {
// Now choose the CS. We may abandon a pause if we find no
// region that will fit in the MMU pause.
bool abandoned = g1_policy()->choose_collection_set();
bool abandoned = g1_policy()->choose_collection_set(target_pause_time_ms);
// Nothing to do if we were unable to choose a collection set.
if (!abandoned) {

View File

@ -277,6 +277,18 @@ private:
void update_surviving_young_words(size_t* surv_young_words);
void cleanup_surviving_young_words();
// It decides whether an explicit GC should start a concurrent cycle
// instead of doing a STW GC. Currently, a concurrent cycle is
// explicitly started if:
// (a) cause == _gc_locker and +GCLockerInvokesConcurrent, or
// (b) cause == _java_lang_system_gc and +ExplicitGCInvokesConcurrent.
bool should_do_concurrent_full_gc(GCCause::Cause cause);
// Keeps track of how many "full collections" (i.e., Full GCs or
// concurrent cycles) we have completed. The number of them we have
// started is maintained in _total_full_collections in CollectedHeap.
volatile unsigned int _full_collections_completed;
protected:
// Returns "true" iff none of the gc alloc regions have any allocations
@ -356,13 +368,14 @@ protected:
// GC pause.
void retire_alloc_region(HeapRegion* alloc_region, bool par);
// Helper function for two callbacks below.
// "full", if true, indicates that the GC is for a System.gc() request,
// and should collect the entire heap. If "clear_all_soft_refs" is true,
// all soft references are cleared during the GC. If "full" is false,
// "word_size" describes the allocation that the GC should
// attempt (at least) to satisfy.
void do_collection(bool full, bool clear_all_soft_refs,
// - if explicit_gc is true, the GC is for a System.gc() or a heap
// inspection request and should collect the entire heap
// - if clear_all_soft_refs is true, all soft references are cleared
// during the GC
// - if explicit_gc is false, word_size describes the allocation that
// the GC should attempt (at least) to satisfy
void do_collection(bool explicit_gc,
bool clear_all_soft_refs,
size_t word_size);
// Callback from VM_G1CollectFull operation.
@ -431,6 +444,26 @@ public:
_in_cset_fast_test_length * sizeof(bool));
}
// This is called at the end of either a concurrent cycle or a Full
// GC to update the number of full collections completed. Those two
// can happen in a nested fashion, i.e., we start a concurrent
// cycle, a Full GC happens half-way through it which ends first,
// and then the cycle notices that a Full GC happened and ends
// too. The outer parameter is a boolean to help us do a bit tighter
// consistency checking in the method. If outer is false, the caller
// is the inner caller in the nesting (i.e., the Full GC). If outer
// is true, the caller is the outer caller in this nesting (i.e.,
// the concurrent cycle). Further nesting is not currently
// supported. The end of the this call also notifies the
// FullGCCount_lock in case a Java thread is waiting for a full GC
// to happen (e.g., it called System.gc() with
// +ExplicitGCInvokesConcurrent).
void increment_full_collections_completed(bool outer);
unsigned int full_collections_completed() {
return _full_collections_completed;
}
protected:
// Shrink the garbage-first heap by at most the given size (in bytes!).
@ -444,7 +477,7 @@ protected:
// The guts of the incremental collection pause, executed by the vm
// thread.
virtual void do_collection_pause_at_safepoint();
virtual void do_collection_pause_at_safepoint(double target_pause_time_ms);
// Actually do the work of evacuating the collection set.
virtual void evacuate_collection_set();

View File

@ -154,7 +154,6 @@ G1CollectorPolicy::G1CollectorPolicy() :
_known_garbage_bytes(0),
_young_gc_eff_seq(new TruncatedSeq(TruncatedSeqLength)),
_target_pause_time_ms(-1.0),
_recent_prev_end_times_for_all_gcs_sec(new TruncatedSeq(NumPrevPausesForHeuristics)),
@ -1635,8 +1634,6 @@ void G1CollectorPolicy::record_collection_pause_end(bool abandoned) {
double update_rs_time_goal_ms = _mmu_tracker->max_gc_time() * MILLIUNITS * G1RSetUpdatingPauseTimePercent / 100.0;
adjust_concurrent_refinement(update_rs_time, update_rs_processed_buffers, update_rs_time_goal_ms);
// </NEW PREDICTION>
_target_pause_time_ms = -1.0;
}
// <NEW PREDICTION>
@ -2366,7 +2363,6 @@ G1CollectorPolicy_BestRegionsFirst::should_do_collection_pause(size_t
if (reached_target_length) {
assert( young_list_length > 0 && _g1->young_list()->length() > 0,
"invariant" );
_target_pause_time_ms = max_pause_time_ms;
return true;
}
} else {
@ -2398,6 +2394,17 @@ bool G1CollectorPolicy_BestRegionsFirst::assertMarkedBytesDataOK() {
}
#endif
bool
G1CollectorPolicy::force_initial_mark_if_outside_cycle() {
bool during_cycle = _g1->concurrent_mark()->cmThread()->during_cycle();
if (!during_cycle) {
set_initiate_conc_mark_if_possible();
return true;
} else {
return false;
}
}
void
G1CollectorPolicy::decide_on_conc_mark_initiation() {
// We are about to decide on whether this pause will be an
@ -2864,7 +2871,8 @@ void G1CollectorPolicy::print_collection_set(HeapRegion* list_head, outputStream
#endif // !PRODUCT
bool
G1CollectorPolicy_BestRegionsFirst::choose_collection_set() {
G1CollectorPolicy_BestRegionsFirst::choose_collection_set(
double target_pause_time_ms) {
// Set this here - in case we're not doing young collections.
double non_young_start_time_sec = os::elapsedTime();
@ -2877,26 +2885,19 @@ G1CollectorPolicy_BestRegionsFirst::choose_collection_set() {
start_recording_regions();
guarantee(_target_pause_time_ms > -1.0
NOT_PRODUCT(|| Universe::heap()->gc_cause() == GCCause::_scavenge_alot),
"_target_pause_time_ms should have been set!");
#ifndef PRODUCT
if (_target_pause_time_ms <= -1.0) {
assert(ScavengeALot && Universe::heap()->gc_cause() == GCCause::_scavenge_alot, "Error");
_target_pause_time_ms = _mmu_tracker->max_gc_time() * 1000.0;
}
#endif
assert(_collection_set == NULL, "Precondition");
guarantee(target_pause_time_ms > 0.0,
err_msg("target_pause_time_ms = %1.6lf should be positive",
target_pause_time_ms));
guarantee(_collection_set == NULL, "Precondition");
double base_time_ms = predict_base_elapsed_time_ms(_pending_cards);
double predicted_pause_time_ms = base_time_ms;
double target_time_ms = _target_pause_time_ms;
double time_remaining_ms = target_time_ms - base_time_ms;
double time_remaining_ms = target_pause_time_ms - base_time_ms;
// the 10% and 50% values are arbitrary...
if (time_remaining_ms < 0.10*target_time_ms) {
time_remaining_ms = 0.50 * target_time_ms;
if (time_remaining_ms < 0.10 * target_pause_time_ms) {
time_remaining_ms = 0.50 * target_pause_time_ms;
_within_target = false;
} else {
_within_target = true;
@ -3059,7 +3060,18 @@ choose_collection_set_end:
_recorded_non_young_cset_choice_time_ms =
(non_young_end_time_sec - non_young_start_time_sec) * 1000.0;
return abandon_collection;
// Here we are supposed to return whether the pause should be
// abandoned or not (i.e., whether the collection set is empty or
// not). However, this introduces a subtle issue when a pause is
// initiated explicitly with System.gc() and
// +ExplicitGCInvokesConcurrent (see Comment #2 in CR 6944166), it's
// supposed to start a marking cycle, and it's abandoned. So, by
// returning false here we are telling the caller never to consider
// a pause to be abandoned. We'll actually remove all the code
// associated with abandoned pauses as part of CR 6963209, but we are
// just disabling them this way for the moment to avoid increasing
// further the amount of changes for CR 6944166.
return false;
}
void G1CollectorPolicy_BestRegionsFirst::record_full_collection_end() {

View File

@ -199,8 +199,6 @@ protected:
size_t _young_cset_length;
bool _last_young_gc_full;
double _target_pause_time_ms;
unsigned _full_young_pause_num;
unsigned _partial_young_pause_num;
@ -526,6 +524,10 @@ public:
return _mmu_tracker;
}
double max_pause_time_ms() {
return _mmu_tracker->max_gc_time() * 1000.0;
}
double predict_init_time_ms() {
return get_new_prediction(_concurrent_mark_init_times_ms);
}
@ -1008,7 +1010,7 @@ public:
// Choose a new collection set. Marks the chosen regions as being
// "in_collection_set", and links them together. The head and number of
// the collection set are available via access methods.
virtual bool choose_collection_set() = 0;
virtual bool choose_collection_set(double target_pause_time_ms) = 0;
// The head of the list (via "next_in_collection_set()") representing the
// current collection set.
@ -1077,6 +1079,12 @@ public:
void set_during_initial_mark_pause() { _during_initial_mark_pause = true; }
void clear_during_initial_mark_pause(){ _during_initial_mark_pause = false; }
// This sets the initiate_conc_mark_if_possible() flag to start a
// new cycle, as long as we are not already in one. It's best if it
// is called during a safepoint when the test whether a cycle is in
// progress or not is stable.
bool force_initial_mark_if_outside_cycle();
// This is called at the very beginning of an evacuation pause (it
// has to be the first thing that the pause does). If
// initiate_conc_mark_if_possible() is true, and the concurrent
@ -1259,7 +1267,7 @@ class G1CollectorPolicy_BestRegionsFirst: public G1CollectorPolicy {
// If the estimated is less then desirable, resize if possible.
void expand_if_possible(size_t numRegions);
virtual bool choose_collection_set();
virtual bool choose_collection_set(double target_pause_time_ms);
virtual void record_collection_pause_start(double start_time_sec,
size_t start_used);
virtual void record_concurrent_mark_cleanup_end(size_t freed_bytes,

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2001, 2009, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2001, 2010, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -676,9 +676,27 @@ void HRInto_G1RemSet::concurrentRefineOneCard_impl(jbyte* card_ptr, int worker_i
// We must complete this write before we do any of the reads below.
OrderAccess::storeload();
// And process it, being careful of unallocated portions of TLAB's.
// The region for the current card may be a young region. The
// current card may have been a card that was evicted from the
// card cache. When the card was inserted into the cache, we had
// determined that its region was non-young. While in the cache,
// the region may have been freed during a cleanup pause, reallocated
// and tagged as young.
//
// We wish to filter out cards for such a region but the current
// thread, if we're running conucrrently, may "see" the young type
// change at any time (so an earlier "is_young" check may pass or
// fail arbitrarily). We tell the iteration code to perform this
// filtering when it has been determined that there has been an actual
// allocation in this region and making it safe to check the young type.
bool filter_young = true;
HeapWord* stop_point =
r->oops_on_card_seq_iterate_careful(dirtyRegion,
&filter_then_update_rs_oop_cl);
&filter_then_update_rs_oop_cl,
filter_young);
// If stop_point is non-null, then we encountered an unallocated region
// (perhaps the unfilled portion of a TLAB.) For now, we'll dirty the
// card and re-enqueue: if we put off the card until a GC pause, then the
@ -789,8 +807,14 @@ void HRInto_G1RemSet::concurrentRefineOneCard(jbyte* card_ptr, int worker_i) {
if (r == NULL) {
assert(_g1->is_in_permanent(start), "Or else where?");
} else {
guarantee(!r->is_young(), "It was evicted in the current minor cycle.");
// Process card pointer we get back from the hot card cache
// Checking whether the region we got back from the cache
// is young here is inappropriate. The region could have been
// freed, reallocated and tagged as young while in the cache.
// Hence we could see its young type change at any time.
//
// Process card pointer we get back from the hot card cache. This
// will check whether the region containing the card is young
// _after_ checking that the region has been allocated from.
concurrentRefineOneCard_impl(res, worker_i);
}
}

View File

@ -658,7 +658,8 @@ HeapRegion::object_iterate_mem_careful(MemRegion mr,
HeapWord*
HeapRegion::
oops_on_card_seq_iterate_careful(MemRegion mr,
FilterOutOfRegionClosure* cl) {
FilterOutOfRegionClosure* cl,
bool filter_young) {
G1CollectedHeap* g1h = G1CollectedHeap::heap();
// If we're within a stop-world GC, then we might look at a card in a
@ -672,6 +673,16 @@ oops_on_card_seq_iterate_careful(MemRegion mr,
if (mr.is_empty()) return NULL;
// Otherwise, find the obj that extends onto mr.start().
// The intersection of the incoming mr (for the card) and the
// allocated part of the region is non-empty. This implies that
// we have actually allocated into this region. The code in
// G1CollectedHeap.cpp that allocates a new region sets the
// is_young tag on the region before allocating. Thus we
// safely know if this region is young.
if (is_young() && filter_young) {
return NULL;
}
// We used to use "block_start_careful" here. But we're actually happy
// to update the BOT while we do this...
HeapWord* cur = block_start(mr.start());

View File

@ -252,7 +252,7 @@ class HeapRegion: public G1OffsetTableContigSpace {
// survivor
};
YoungType _young_type;
volatile YoungType _young_type;
int _young_index_in_cset;
SurvRateGroup* _surv_rate_group;
int _age_index;
@ -726,9 +726,12 @@ class HeapRegion: public G1OffsetTableContigSpace {
HeapWord*
object_iterate_mem_careful(MemRegion mr, ObjectClosure* cl);
// In this version - if filter_young is true and the region
// is a young region then we skip the iteration.
HeapWord*
oops_on_card_seq_iterate_careful(MemRegion mr,
FilterOutOfRegionClosure* cl);
FilterOutOfRegionClosure* cl,
bool filter_young);
// The region "mr" is entirely in "this", and starts and ends at block
// boundaries. The caller declares that all the contained blocks are

View File

@ -42,8 +42,65 @@ void VM_G1CollectFull::doit() {
void VM_G1IncCollectionPause::doit() {
JvmtiGCForAllocationMarker jgcm;
G1CollectedHeap* g1h = G1CollectedHeap::heap();
assert(!_should_initiate_conc_mark ||
((_gc_cause == GCCause::_gc_locker && GCLockerInvokesConcurrent) ||
(_gc_cause == GCCause::_java_lang_system_gc && ExplicitGCInvokesConcurrent)),
"only a GC locker or a System.gc() induced GC should start a cycle");
GCCauseSetter x(g1h, _gc_cause);
g1h->do_collection_pause_at_safepoint();
if (_should_initiate_conc_mark) {
// It's safer to read full_collections_completed() here, given
// that noone else will be updating it concurrently. Since we'll
// only need it if we're initiating a marking cycle, no point in
// setting it earlier.
_full_collections_completed_before = g1h->full_collections_completed();
// At this point we are supposed to start a concurrent cycle. We
// will do so if one is not already in progress.
bool res = g1h->g1_policy()->force_initial_mark_if_outside_cycle();
}
g1h->do_collection_pause_at_safepoint(_target_pause_time_ms);
}
void VM_G1IncCollectionPause::doit_epilogue() {
VM_GC_Operation::doit_epilogue();
// If the pause was initiated by a System.gc() and
// +ExplicitGCInvokesConcurrent, we have to wait here for the cycle
// that just started (or maybe one that was already in progress) to
// finish.
if (_gc_cause == GCCause::_java_lang_system_gc &&
_should_initiate_conc_mark) {
assert(ExplicitGCInvokesConcurrent,
"the only way to be here is if ExplicitGCInvokesConcurrent is set");
G1CollectedHeap* g1h = G1CollectedHeap::heap();
// In the doit() method we saved g1h->full_collections_completed()
// in the _full_collections_completed_before field. We have to
// wait until we observe that g1h->full_collections_completed()
// has increased by at least one. This can happen if a) we started
// a cycle and it completes, b) a cycle already in progress
// completes, or c) a Full GC happens.
// If the condition has already been reached, there's no point in
// actually taking the lock and doing the wait.
if (g1h->full_collections_completed() <=
_full_collections_completed_before) {
// The following is largely copied from CMS
Thread* thr = Thread::current();
assert(thr->is_Java_thread(), "invariant");
JavaThread* jt = (JavaThread*)thr;
ThreadToNativeFromVM native(jt);
MutexLockerEx x(FullGCCount_lock, Mutex::_no_safepoint_check_flag);
while (g1h->full_collections_completed() <=
_full_collections_completed_before) {
FullGCCount_lock->wait(Mutex::_no_safepoint_check_flag);
}
}
}
}
void VM_CGC_Operation::doit() {

View File

@ -31,13 +31,12 @@
// - VM_G1PopRegionCollectionPause
class VM_G1CollectFull: public VM_GC_Operation {
private:
public:
VM_G1CollectFull(int gc_count_before,
GCCause::Cause gc_cause)
: VM_GC_Operation(gc_count_before)
{
_gc_cause = gc_cause;
VM_G1CollectFull(unsigned int gc_count_before,
unsigned int full_gc_count_before,
GCCause::Cause cause)
: VM_GC_Operation(gc_count_before, full_gc_count_before) {
_gc_cause = cause;
}
~VM_G1CollectFull() {}
virtual VMOp_Type type() const { return VMOp_G1CollectFull; }
@ -67,12 +66,28 @@ class VM_G1CollectForAllocation: public VM_GC_Operation {
};
class VM_G1IncCollectionPause: public VM_GC_Operation {
public:
VM_G1IncCollectionPause(int gc_count_before,
GCCause::Cause gc_cause = GCCause::_g1_inc_collection_pause) :
VM_GC_Operation(gc_count_before) { _gc_cause = gc_cause; }
private:
bool _should_initiate_conc_mark;
double _target_pause_time_ms;
unsigned int _full_collections_completed_before;
public:
VM_G1IncCollectionPause(unsigned int gc_count_before,
bool should_initiate_conc_mark,
double target_pause_time_ms,
GCCause::Cause cause)
: VM_GC_Operation(gc_count_before),
_full_collections_completed_before(0),
_should_initiate_conc_mark(should_initiate_conc_mark),
_target_pause_time_ms(target_pause_time_ms) {
guarantee(target_pause_time_ms > 0.0,
err_msg("target_pause_time_ms = %1.6lf should be positive",
target_pause_time_ms));
_gc_cause = cause;
}
virtual VMOp_Type type() const { return VMOp_G1IncCollectionPause; }
virtual void doit();
virtual void doit_epilogue();
virtual const char* name() const {
return "garbage-first incremental collection pause";
}

View File

@ -367,4 +367,6 @@ vm_operations_g1.hpp vmGCOperations.hpp
vm_operations_g1.cpp vm_operations_g1.hpp
vm_operations_g1.cpp g1CollectedHeap.inline.hpp
vm_operations_g1.cpp g1CollectorPolicy.hpp
vm_operations_g1.cpp interfaceSupport.hpp
vm_operations_g1.cpp isGCActiveMark.hpp

View File

@ -539,10 +539,9 @@ ParNewGeneration(ReservedSpace rs, size_t initial_byte_size, int level)
guarantee(_task_queues != NULL, "task_queues allocation failure.");
for (uint i1 = 0; i1 < ParallelGCThreads; i1++) {
ObjToScanQueuePadded *q_padded = new ObjToScanQueuePadded();
guarantee(q_padded != NULL, "work_queue Allocation failure.");
_task_queues->register_queue(i1, &q_padded->work_queue);
ObjToScanQueue *q = new ObjToScanQueue();
guarantee(q != NULL, "work_queue Allocation failure.");
_task_queues->register_queue(i1, q);
}
for (uint i2 = 0; i2 < ParallelGCThreads; i2++)

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2001, 2009, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2001, 2010, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -33,8 +33,8 @@ class ParEvacuateFollowersClosure;
// but they must be here to allow ParScanClosure::do_oop_work to be defined
// in genOopClosures.inline.hpp.
typedef OopTaskQueue ObjToScanQueue;
typedef OopTaskQueueSet ObjToScanQueueSet;
typedef Padded<OopTaskQueue> ObjToScanQueue;
typedef GenericTaskQueueSet<ObjToScanQueue> ObjToScanQueueSet;
// Enable this to get push/pop/steal stats.
const int PAR_STATS_ENABLED = 0;
@ -304,12 +304,6 @@ class ParNewGeneration: public DefNewGeneration {
friend class ParEvacuateFollowersClosure;
private:
// XXX use a global constant instead of 64!
struct ObjToScanQueuePadded {
ObjToScanQueue work_queue;
char pad[64 - sizeof(ObjToScanQueue)]; // prevent false sharing
};
// The per-worker-thread work queues
ObjToScanQueueSet* _task_queues;

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2007, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -26,7 +26,8 @@
class ParScanThreadState;
class ParNewGeneration;
typedef OopTaskQueueSet ObjToScanQueueSet;
typedef Padded<OopTaskQueue> ObjToScanQueue;
typedef GenericTaskQueueSet<ObjToScanQueue> ObjToScanQueueSet;
class ParallelTaskTerminator;
class ParScanClosure: public OopsInGenClosure {

View File

@ -90,10 +90,7 @@ void PSPromotionManager::pre_scavenge() {
}
void PSPromotionManager::post_scavenge() {
#if PS_PM_STATS
print_stats();
#endif // PS_PM_STATS
TASKQUEUE_STATS_ONLY(if (PrintGCDetails && ParallelGCVerbose) print_stats());
for (uint i = 0; i < ParallelGCThreads + 1; i++) {
PSPromotionManager* manager = manager_array(i);
if (UseDepthFirstScavengeOrder) {
@ -105,37 +102,58 @@ void PSPromotionManager::post_scavenge() {
}
}
#if PS_PM_STATS
#if TASKQUEUE_STATS
void
PSPromotionManager::print_taskqueue_stats(uint i) const {
const TaskQueueStats& stats = depth_first() ?
_claimed_stack_depth.stats : _claimed_stack_breadth.stats;
tty->print("%3u ", i);
stats.print();
tty->cr();
}
void
PSPromotionManager::print_stats(uint i) {
tty->print_cr("---- GC Worker %2d Stats", i);
tty->print_cr(" total pushes %8d", _total_pushes);
tty->print_cr(" masked pushes %8d", _masked_pushes);
tty->print_cr(" overflow pushes %8d", _overflow_pushes);
tty->print_cr(" max overflow length %8d", _max_overflow_length);
tty->print_cr("");
tty->print_cr(" arrays chunked %8d", _arrays_chunked);
tty->print_cr(" array chunks processed %8d", _array_chunks_processed);
tty->print_cr("");
tty->print_cr(" total steals %8d", _total_steals);
tty->print_cr(" masked steals %8d", _masked_steals);
tty->print_cr("");
PSPromotionManager::print_local_stats(uint i) const {
#define FMT " " SIZE_FORMAT_W(10)
tty->print_cr("%3u" FMT FMT FMT FMT, i, _masked_pushes, _masked_steals,
_arrays_chunked, _array_chunks_processed);
#undef FMT
}
static const char* const pm_stats_hdr[] = {
" --------masked------- arrays array",
"thr push steal chunked chunks",
"--- ---------- ---------- ---------- ----------"
};
void
PSPromotionManager::print_stats() {
tty->print_cr("== GC Tasks Stats (%s), GC %3d",
(UseDepthFirstScavengeOrder) ? "Depth-First" : "Breadth-First",
const bool df = UseDepthFirstScavengeOrder;
tty->print_cr("== GC Task Stats (%s-First), GC %3d", df ? "Depth" : "Breadth",
Universe::heap()->total_collections());
for (uint i = 0; i < ParallelGCThreads+1; ++i) {
PSPromotionManager* manager = manager_array(i);
manager->print_stats(i);
tty->print("thr "); TaskQueueStats::print_header(1); tty->cr();
tty->print("--- "); TaskQueueStats::print_header(2); tty->cr();
for (uint i = 0; i < ParallelGCThreads + 1; ++i) {
manager_array(i)->print_taskqueue_stats(i);
}
const uint hlines = sizeof(pm_stats_hdr) / sizeof(pm_stats_hdr[0]);
for (uint i = 0; i < hlines; ++i) tty->print_cr(pm_stats_hdr[i]);
for (uint i = 0; i < ParallelGCThreads + 1; ++i) {
manager_array(i)->print_local_stats(i);
}
}
#endif // PS_PM_STATS
void
PSPromotionManager::reset_stats() {
TaskQueueStats& stats = depth_first() ?
claimed_stack_depth()->stats : claimed_stack_breadth()->stats;
stats.reset();
_masked_pushes = _masked_steals = 0;
_arrays_chunked = _array_chunks_processed = 0;
}
#endif // TASKQUEUE_STATS
PSPromotionManager::PSPromotionManager() {
ParallelScavengeHeap* heap = (ParallelScavengeHeap*)Universe::heap();
@ -189,16 +207,7 @@ void PSPromotionManager::reset() {
_prefetch_queue.clear();
#if PS_PM_STATS
_total_pushes = 0;
_masked_pushes = 0;
_overflow_pushes = 0;
_max_overflow_length = 0;
_arrays_chunked = 0;
_array_chunks_processed = 0;
_total_steals = 0;
_masked_steals = 0;
#endif // PS_PM_STATS
TASKQUEUE_STATS_ONLY(reset_stats());
}
@ -423,14 +432,9 @@ oop PSPromotionManager::copy_to_survivor_space(oop o, bool depth_first) {
new_obj->is_objArray() &&
PSChunkLargeArrays) {
// we'll chunk it
#if PS_PM_STATS
++_arrays_chunked;
#endif // PS_PM_STATS
oop* const masked_o = mask_chunked_array_oop(o);
push_depth(masked_o);
#if PS_PM_STATS
++_masked_pushes;
#endif // PS_PM_STATS
TASKQUEUE_STATS_ONLY(++_arrays_chunked; ++_masked_pushes);
} else {
// we'll just push its contents
new_obj->push_contents(this);
@ -494,9 +498,7 @@ void PSPromotionManager::process_array_chunk(oop old) {
assert(old->is_objArray(), "invariant");
assert(old->is_forwarded(), "invariant");
#if PS_PM_STATS
++_array_chunks_processed;
#endif // PS_PM_STATS
TASKQUEUE_STATS_ONLY(++_array_chunks_processed);
oop const obj = old->forwardee();
@ -508,9 +510,7 @@ void PSPromotionManager::process_array_chunk(oop old) {
assert(start > 0, "invariant");
arrayOop(old)->set_length(start);
push_depth(mask_chunked_array_oop(old));
#if PS_PM_STATS
++_masked_pushes;
#endif // PS_PM_STATS
TASKQUEUE_STATS_ONLY(++_masked_pushes);
} else {
// this is the final chunk for this array
start = 0;

View File

@ -42,8 +42,6 @@ class MutableSpace;
class PSOldGen;
class ParCompactionManager;
#define PS_PM_STATS 0
class PSPromotionManager : public CHeapObj {
friend class PSScavenge;
friend class PSRefProcTaskExecutor;
@ -54,22 +52,18 @@ class PSPromotionManager : public CHeapObj {
static PSOldGen* _old_gen;
static MutableSpace* _young_space;
#if PS_PM_STATS
uint _total_pushes;
uint _masked_pushes;
#if TASKQUEUE_STATS
size_t _masked_pushes;
size_t _masked_steals;
size_t _arrays_chunked;
size_t _array_chunks_processed;
uint _overflow_pushes;
uint _max_overflow_length;
uint _arrays_chunked;
uint _array_chunks_processed;
uint _total_steals;
uint _masked_steals;
void print_stats(uint i);
void print_taskqueue_stats(uint i) const;
void print_local_stats(uint i) const;
static void print_stats();
#endif // PS_PM_STATS
void reset_stats();
#endif // TASKQUEUE_STATS
PSYoungPromotionLAB _young_lab;
PSOldPromotionLAB _old_lab;
@ -143,42 +137,12 @@ class PSPromotionManager : public CHeapObj {
template <class T> void push_depth(T* p) {
assert(depth_first(), "pre-condition");
#if PS_PM_STATS
++_total_pushes;
int stack_length = claimed_stack_depth()->overflow_stack()->length();
#endif // PS_PM_STATS
claimed_stack_depth()->push(p);
#if PS_PM_STATS
if (claimed_stack_depth()->overflow_stack()->length() != stack_length) {
++_overflow_pushes;
if ((uint)stack_length + 1 > _max_overflow_length) {
_max_overflow_length = (uint)stack_length + 1;
}
}
#endif // PS_PM_STATS
}
void push_breadth(oop o) {
assert(!depth_first(), "pre-condition");
#if PS_PM_STATS
++_total_pushes;
int stack_length = claimed_stack_breadth()->overflow_stack()->length();
#endif // PS_PM_STATS
claimed_stack_breadth()->push(o);
#if PS_PM_STATS
if (claimed_stack_breadth()->overflow_stack()->length() != stack_length) {
++_overflow_pushes;
if ((uint)stack_length + 1 > _max_overflow_length) {
_max_overflow_length = (uint)stack_length + 1;
}
}
#endif // PS_PM_STATS
}
protected:
@ -256,12 +220,5 @@ class PSPromotionManager : public CHeapObj {
template <class T> inline void claim_or_forward_depth(T* p);
template <class T> inline void claim_or_forward_breadth(T* p);
#if PS_PM_STATS
void increment_steals(oop* p = NULL) {
_total_steals += 1;
if (p != NULL && is_oop_masked(p)) {
_masked_steals += 1;
}
}
#endif // PS_PM_STATS
TASKQUEUE_STATS_ONLY(inline void record_steal(StarTask& p);)
};

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2002, 2008, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2002, 2010, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -124,3 +124,11 @@ inline void PSPromotionManager::process_popped_location_depth(StarTask p) {
}
}
}
#if TASKQUEUE_STATS
void PSPromotionManager::record_steal(StarTask& p) {
if (is_oop_masked(p)) {
++_masked_steals;
}
}
#endif // TASKQUEUE_STATS

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2002, 2008, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2002, 2010, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -148,9 +148,7 @@ void StealTask::do_it(GCTaskManager* manager, uint which) {
while(true) {
StarTask p;
if (PSPromotionManager::steal_depth(which, &random_seed, p)) {
#if PS_PM_STATS
pm->increment_steals(p);
#endif // PS_PM_STATS
TASKQUEUE_STATS_ONLY(pm->record_steal(p));
pm->process_popped_location_depth(p);
pm->drain_stacks_depth(true);
} else {
@ -163,9 +161,6 @@ void StealTask::do_it(GCTaskManager* manager, uint which) {
while(true) {
oop obj;
if (PSPromotionManager::steal_breadth(which, &random_seed, obj)) {
#if PS_PM_STATS
pm->increment_steals();
#endif // PS_PM_STATS
obj->copy_contents(pm);
pm->drain_stacks_breadth(true);
} else {

View File

@ -86,9 +86,7 @@ class VM_GC_Operation: public VM_Operation {
_gc_locked = false;
if (full) {
_full_gc_count_before = full_gc_count_before;
}
_full_gc_count_before = full_gc_count_before;
// In ParallelScavengeHeap::mem_allocate() collections can be
// executed within a loop and _all_soft_refs_clear can be set
// true after they have been cleared by a collection and another

View File

@ -78,6 +78,9 @@ const char* GCCause::to_string(GCCause::Cause cause) {
case _old_generation_too_full_to_scavenge:
return "Old Generation Too Full To Scavenge";
case _g1_inc_collection_pause:
return "G1 Evacuation Pause";
case _last_ditch_collection:
return "Last ditch collection";

View File

@ -328,24 +328,35 @@ void BytecodePrinter::print_field_or_method(int orig_i, int i, outputStream* st)
constantPoolOop constants = method()->constants();
constantTag tag = constants->tag_at(i);
int nt_index = -1;
bool has_klass = true;
switch (tag.value()) {
case JVM_CONSTANT_InterfaceMethodref:
case JVM_CONSTANT_Methodref:
case JVM_CONSTANT_Fieldref:
break;
case JVM_CONSTANT_NameAndType:
case JVM_CONSTANT_InvokeDynamic:
has_klass = false;
break;
default:
st->print_cr(" bad tag=%d at %d", tag.value(), i);
return;
}
symbolOop klass = constants->klass_name_at(constants->uncached_klass_ref_index_at(i));
symbolOop name = constants->uncached_name_ref_at(i);
symbolOop signature = constants->uncached_signature_ref_at(i);
const char* sep = (tag.is_field() ? "/" : "");
st->print_cr(" %d <%s.%s%s%s> ", i, klass->as_C_string(), name->as_C_string(), sep, signature->as_C_string());
if (has_klass) {
symbolOop klass = constants->klass_name_at(constants->uncached_klass_ref_index_at(i));
st->print_cr(" %d <%s.%s%s%s> ", i, klass->as_C_string(), name->as_C_string(), sep, signature->as_C_string());
} else {
if (tag.is_invoke_dynamic()) {
int bsm = constants->invoke_dynamic_bootstrap_method_ref_index_at(i);
st->print(" bsm=%d", bsm);
}
st->print_cr(" %d <%s%s%s>", i, name->as_C_string(), sep, signature->as_C_string());
}
}

View File

@ -702,10 +702,6 @@ IRT_ENTRY(void, InterpreterRuntime::resolve_invokedynamic(JavaThread* thread)) {
methodHandle caller_method(thread, method(thread));
// first find the bootstrap method
KlassHandle caller_klass(thread, caller_method->method_holder());
Handle bootm = SystemDictionary::find_bootstrap_method(caller_klass, CHECK);
constantPoolHandle pool(thread, caller_method->constants());
pool->set_invokedynamic(); // mark header to flag active call sites
@ -726,7 +722,7 @@ IRT_ENTRY(void, InterpreterRuntime::resolve_invokedynamic(JavaThread* thread)) {
CallInfo info;
LinkResolver::resolve_invoke(info, Handle(), pool,
site_index, bytecode, CHECK);
// The main entry corresponds to a JVM_CONSTANT_NameAndType, and serves
// The main entry corresponds to a JVM_CONSTANT_InvokeDynamic, and serves
// as a common reference point for all invokedynamic call sites with
// that exact call descriptor. We will link it in the CP cache exactly
// as if it were an invokevirtual of MethodHandle.invoke.
@ -734,23 +730,30 @@ IRT_ENTRY(void, InterpreterRuntime::resolve_invokedynamic(JavaThread* thread)) {
bytecode,
info.resolved_method(),
info.vtable_index());
assert(pool->cache()->entry_at(main_index)->is_vfinal(), "f2 must be a methodOop");
}
// The method (f2 entry) of the main entry is the MH.invoke for the
// invokedynamic target call signature.
intptr_t f2_value = pool->cache()->entry_at(main_index)->f2();
methodHandle signature_invoker(THREAD, (methodOop) f2_value);
oop f1_value = pool->cache()->entry_at(main_index)->f1();
methodHandle signature_invoker(THREAD, (methodOop) f1_value);
assert(signature_invoker.not_null() && signature_invoker->is_method() && signature_invoker->is_method_handle_invoke(),
"correct result from LinkResolver::resolve_invokedynamic");
Handle bootm = SystemDictionary::find_bootstrap_method(caller_method, caller_bci,
main_index, CHECK);
if (bootm.is_null()) {
THROW_MSG(vmSymbols::java_lang_IllegalStateException(),
"no bootstrap method found for invokedynamic");
}
// Short circuit if CallSite has been bound already:
if (!pool->cache()->secondary_entry_at(site_index)->is_f1_null())
return;
symbolHandle call_site_name(THREAD, pool->name_ref_at(site_index));
Handle info; // NYI: Other metadata from a new kind of CP entry. (Annotations?)
// this is the index which gets stored on the CallSite object (as "callerPosition"):
int call_site_position = constantPoolCacheOopDesc::decode_secondary_index(site_index);
Handle call_site
= SystemDictionary::make_dynamic_call_site(bootm,
// Callee information:

View File

@ -67,6 +67,15 @@ void CallInfo::set_virtual(KlassHandle resolved_klass, KlassHandle selected_klas
set_common(resolved_klass, selected_klass, resolved_method, selected_method, vtable_index, CHECK);
}
void CallInfo::set_dynamic(methodHandle resolved_method, TRAPS) {
assert(resolved_method->is_method_handle_invoke(), "");
KlassHandle resolved_klass = SystemDictionaryHandles::MethodHandle_klass();
assert(resolved_klass == resolved_method->method_holder(), "");
int vtable_index = methodOopDesc::nonvirtual_vtable_index;
assert(resolved_method->vtable_index() == vtable_index, "");
set_common(resolved_klass, KlassHandle(), resolved_method, resolved_method, vtable_index, CHECK);
}
void CallInfo::set_common(KlassHandle resolved_klass, KlassHandle selected_klass, methodHandle resolved_method, methodHandle selected_method, int vtable_index, TRAPS) {
assert(resolved_method->signature() == selected_method->signature(), "signatures must correspond");
_resolved_klass = resolved_klass;
@ -176,9 +185,20 @@ void LinkResolver::lookup_implicit_method(methodHandle& result,
KlassHandle klass, symbolHandle name, symbolHandle signature,
KlassHandle current_klass,
TRAPS) {
if (EnableMethodHandles && MethodHandles::enabled() &&
if (EnableMethodHandles &&
klass() == SystemDictionary::MethodHandle_klass() &&
methodOopDesc::is_method_handle_invoke_name(name())) {
if (!MethodHandles::enabled()) {
// Make sure the Java part of the runtime has been booted up.
klassOop natives = SystemDictionary::MethodHandleNatives_klass();
if (natives == NULL || instanceKlass::cast(natives)->is_not_initialized()) {
SystemDictionary::resolve_or_fail(vmSymbolHandles::sun_dyn_MethodHandleNatives(),
Handle(),
Handle(),
true,
CHECK);
}
}
methodOop result_oop = SystemDictionary::find_method_handle_invoke(name,
signature,
current_klass,
@ -1065,7 +1085,7 @@ void LinkResolver::resolve_invokedynamic(CallInfo& result, constantPoolHandle po
if (resolved_method.is_null()) {
THROW(vmSymbols::java_lang_InternalError());
}
result.set_virtual(resolved_klass, KlassHandle(), resolved_method, resolved_method, resolved_method->vtable_index(), CHECK);
result.set_dynamic(resolved_method, CHECK);
}
//------------------------------------------------------------------------------------------------------------------------

View File

@ -73,6 +73,7 @@ class CallInfo: public LinkInfo {
void set_static( KlassHandle resolved_klass, methodHandle resolved_method , TRAPS);
void set_interface(KlassHandle resolved_klass, KlassHandle selected_klass, methodHandle resolved_method, methodHandle selected_method , TRAPS);
void set_virtual( KlassHandle resolved_klass, KlassHandle selected_klass, methodHandle resolved_method, methodHandle selected_method, int vtable_index, TRAPS);
void set_dynamic( methodHandle resolved_method, TRAPS);
void set_common( KlassHandle resolved_klass, KlassHandle selected_klass, methodHandle resolved_method, methodHandle selected_method, int vtable_index, TRAPS);
friend class LinkResolver;

View File

@ -32,14 +32,17 @@
void Rewriter::compute_index_maps() {
const int length = _pool->length();
init_cp_map(length);
jint tag_mask = 0;
for (int i = 0; i < length; i++) {
int tag = _pool->tag_at(i).value();
tag_mask |= (1 << tag);
switch (tag) {
case JVM_CONSTANT_InterfaceMethodref:
case JVM_CONSTANT_Fieldref : // fall through
case JVM_CONSTANT_Methodref : // fall through
case JVM_CONSTANT_MethodHandle : // fall through
case JVM_CONSTANT_MethodType : // fall through
case JVM_CONSTANT_InvokeDynamic : // fall through
add_cp_cache_entry(i);
break;
}
@ -47,6 +50,8 @@ void Rewriter::compute_index_maps() {
guarantee((int)_cp_cache_map.length()-1 <= (int)((u2)-1),
"all cp cache indexes fit in a u2");
_have_invoke_dynamic = ((tag_mask & (1 << JVM_CONSTANT_InvokeDynamic)) != 0);
}
@ -59,6 +64,28 @@ void Rewriter::make_constant_pool_cache(TRAPS) {
constantPoolCacheOop cache =
oopFactory::new_constantPoolCache(length, methodOopDesc::IsUnsafeConc, CHECK);
cache->initialize(_cp_cache_map);
// Don't bother to the next pass if there is no JVM_CONSTANT_InvokeDynamic.
if (_have_invoke_dynamic) {
for (int i = 0; i < length; i++) {
int pool_index = cp_cache_entry_pool_index(i);
if (pool_index >= 0 &&
_pool->tag_at(pool_index).is_invoke_dynamic()) {
int bsm_index = _pool->invoke_dynamic_bootstrap_method_ref_index_at(pool_index);
if (bsm_index != 0) {
assert(_pool->tag_at(bsm_index).is_method_handle(), "must be a MH constant");
// There is a CP cache entry holding the BSM for these calls.
int bsm_cache_index = cp_entry_to_cp_cache(bsm_index);
cache->entry_at(i)->initialize_bootstrap_method_index_in_cache(bsm_cache_index);
} else {
// There is no CP cache entry holding the BSM for these calls.
// We will need to look for a class-global BSM, later.
guarantee(AllowTransitionalJSR292, "");
}
}
}
}
_pool->set_cache(cache);
cache->set_constant_pool(_pool());
}

View File

@ -32,6 +32,7 @@ class Rewriter: public StackObj {
objArrayHandle _methods;
intArray _cp_map;
intStack _cp_cache_map;
bool _have_invoke_dynamic;
void init_cp_map(int length) {
_cp_map.initialize(length, -1);
@ -56,6 +57,22 @@ class Rewriter: public StackObj {
return cache_index;
}
// Access the contents of _cp_cache_map to determine CP cache layout.
int cp_cache_entry_pool_index(int cache_index) {
int cp_index = _cp_cache_map[cache_index];
if ((cp_index & _secondary_entry_tag) != 0)
return -1;
else
return cp_index;
}
int cp_cache_secondary_entry_main_index(int cache_index) {
int cp_index = _cp_cache_map[cache_index];
if ((cp_index & _secondary_entry_tag) == 0)
return -1;
else
return (cp_index - _secondary_entry_tag);
}
// All the work goes in here:
Rewriter(instanceKlassHandle klass, constantPoolHandle cpool, objArrayHandle methods, TRAPS);

View File

@ -379,6 +379,10 @@ void constantPoolKlass::oop_print_on(oop obj, outputStream* st) {
case JVM_CONSTANT_MethodType :
st->print("signature_index=%d", cp->method_type_index_at(index));
break;
case JVM_CONSTANT_InvokeDynamic :
st->print("bootstrap_method_index=%d", cp->invoke_dynamic_bootstrap_method_ref_index_at(index));
st->print(" name_and_type_index=%d", cp->invoke_dynamic_name_and_type_ref_index_at(index));
break;
default:
ShouldNotReachHere();
break;

View File

@ -264,10 +264,15 @@ symbolOop constantPoolOopDesc::impl_signature_ref_at(int which, bool uncached) {
int constantPoolOopDesc::impl_name_and_type_ref_index_at(int which, bool uncached) {
int i = which;
if (!uncached && cache() != NULL) {
if (constantPoolCacheOopDesc::is_secondary_index(which))
if (constantPoolCacheOopDesc::is_secondary_index(which)) {
// Invokedynamic indexes are always processed in native order
// so there is no question of reading a native u2 in Java order here.
return cache()->main_entry_at(which)->constant_pool_index();
int pool_index = cache()->main_entry_at(which)->constant_pool_index();
if (tag_at(pool_index).is_invoke_dynamic())
pool_index = invoke_dynamic_name_and_type_ref_index_at(pool_index);
assert(tag_at(pool_index).is_name_and_type(), "");
return pool_index;
}
// change byte-ordering and go via cache
i = remap_instruction_operand_from_cache(which);
} else {
@ -830,6 +835,19 @@ bool constantPoolOopDesc::compare_entry_to(int index1, constantPoolHandle cp2,
}
} break;
case JVM_CONSTANT_InvokeDynamic:
{
int k1 = invoke_dynamic_bootstrap_method_ref_index_at(index1);
int k2 = cp2->invoke_dynamic_bootstrap_method_ref_index_at(index2);
if (k1 == k2) {
int i1 = invoke_dynamic_name_and_type_ref_index_at(index1);
int i2 = cp2->invoke_dynamic_name_and_type_ref_index_at(index2);
if (i1 == i2) {
return true;
}
}
} break;
case JVM_CONSTANT_UnresolvedString:
{
symbolOop s1 = unresolved_string_at(index1);
@ -1016,6 +1034,13 @@ void constantPoolOopDesc::copy_entry_to(int from_i, constantPoolHandle to_cp,
to_cp->method_handle_index_at_put(to_i, k1, k2);
} break;
case JVM_CONSTANT_InvokeDynamic:
{
int k1 = invoke_dynamic_bootstrap_method_ref_index_at(from_i);
int k2 = invoke_dynamic_name_and_type_ref_index_at(from_i);
to_cp->invoke_dynamic_at_put(to_i, k1, k2);
} break;
// Invalid is used as the tag for the second constant pool entry
// occupied by JVM_CONSTANT_Double or JVM_CONSTANT_Long. It should
// not be seen by itself.
@ -1231,6 +1256,7 @@ jint constantPoolOopDesc::cpool_entry_size(jint idx) {
case JVM_CONSTANT_Methodref:
case JVM_CONSTANT_InterfaceMethodref:
case JVM_CONSTANT_NameAndType:
case JVM_CONSTANT_InvokeDynamic:
return 5;
case JVM_CONSTANT_Long:
@ -1444,6 +1470,15 @@ int constantPoolOopDesc::copy_cpool_bytes(int cpool_size,
DBG(printf("JVM_CONSTANT_MethodType: %hd", idx1));
break;
}
case JVM_CONSTANT_InvokeDynamic: {
*bytes = JVM_CONSTANT_InvokeDynamic;
idx1 = invoke_dynamic_bootstrap_method_ref_index_at(idx);
idx2 = invoke_dynamic_name_and_type_ref_index_at(idx);
Bytes::put_Java_u2((address) (bytes+1), idx1);
Bytes::put_Java_u2((address) (bytes+3), idx2);
DBG(printf("JVM_CONSTANT_InvokeDynamic: %hd %hd", idx1, idx2));
break;
}
}
DBG(printf("\n"));
bytes += ent_size;

View File

@ -156,6 +156,11 @@ class constantPoolOopDesc : public oopDesc {
*int_at_addr(which) = ref_index;
}
void invoke_dynamic_at_put(int which, int bootstrap_method_index, int name_and_type_index) {
tag_at_put(which, JVM_CONSTANT_InvokeDynamic);
*int_at_addr(which) = ((jint) name_and_type_index<<16) | bootstrap_method_index;
}
// Temporary until actual use
void unresolved_string_at_put(int which, symbolOop s) {
*obj_at_addr(which) = NULL;
@ -396,6 +401,16 @@ class constantPoolOopDesc : public oopDesc {
int sym = method_type_index_at(which);
return symbol_at(sym);
}
int invoke_dynamic_bootstrap_method_ref_index_at(int which) {
assert(tag_at(which).is_invoke_dynamic(), "Corrupted constant pool");
jint ref_index = *int_at_addr(which);
return extract_low_short_from_int(ref_index);
}
int invoke_dynamic_name_and_type_ref_index_at(int which) {
assert(tag_at(which).is_invoke_dynamic(), "Corrupted constant pool");
jint ref_index = *int_at_addr(which);
return extract_high_short_from_int(ref_index);
}
// The following methods (name/signature/klass_ref_at, klass_ref_at_noresolve,
// name_and_type_ref_index_at) all expect to be passed indices obtained

View File

@ -134,7 +134,7 @@ int ConstantPoolCacheEntry::field_index() const {
void ConstantPoolCacheEntry::set_method(Bytecodes::Code invoke_code,
methodHandle method,
int vtable_index) {
assert(!is_secondary_entry(), "");
assert(method->interpreter_entry() != NULL, "should have been set at this point");
assert(!method->is_obsolete(), "attempt to write obsolete method to cpCache");
bool change_to_virtual = (invoke_code == Bytecodes::_invokeinterface);
@ -142,7 +142,6 @@ void ConstantPoolCacheEntry::set_method(Bytecodes::Code invoke_code,
int byte_no = -1;
bool needs_vfinal_flag = false;
switch (invoke_code) {
case Bytecodes::_invokedynamic:
case Bytecodes::_invokevirtual:
case Bytecodes::_invokeinterface: {
if (method->can_be_statically_bound()) {
@ -155,6 +154,23 @@ void ConstantPoolCacheEntry::set_method(Bytecodes::Code invoke_code,
byte_no = 2;
break;
}
case Bytecodes::_invokedynamic: // similar to _invokevirtual
if (TraceInvokeDynamic) {
tty->print_cr("InvokeDynamic set_method%s method="PTR_FORMAT" index=%d",
(is_secondary_entry() ? " secondary" : ""),
(intptr_t)method(), vtable_index);
method->print();
this->print(tty, 0);
}
assert(method->can_be_statically_bound(), "must be a MH invoker method");
assert(AllowTransitionalJSR292 || _f2 >= constantPoolOopDesc::CPCACHE_INDEX_TAG, "BSM index initialized");
set_f1(method());
needs_vfinal_flag = false; // _f2 is not an oop
assert(!is_vfinal(), "f2 not an oop");
byte_no = 1; // coordinate this with bytecode_number & is_resolved
break;
case Bytecodes::_invokespecial:
// Preserve the value of the vfinal flag on invokevirtual bytecode
// which may be shared with this constant pool cache entry.
@ -209,6 +225,7 @@ void ConstantPoolCacheEntry::set_method(Bytecodes::Code invoke_code,
void ConstantPoolCacheEntry::set_interface_call(methodHandle method, int index) {
assert(!is_secondary_entry(), "");
klassOop interf = method->method_holder();
assert(instanceKlass::cast(interf)->is_interface(), "must be an interface");
set_f1(interf);
@ -218,8 +235,23 @@ void ConstantPoolCacheEntry::set_interface_call(methodHandle method, int index)
}
void ConstantPoolCacheEntry::initialize_bootstrap_method_index_in_cache(int bsm_cache_index) {
assert(!is_secondary_entry(), "only for JVM_CONSTANT_InvokeDynamic main entry");
assert(_f2 == 0, "initialize once");
assert(bsm_cache_index == (int)(u2)bsm_cache_index, "oob");
set_f2(bsm_cache_index + constantPoolOopDesc::CPCACHE_INDEX_TAG);
}
int ConstantPoolCacheEntry::bootstrap_method_index_in_cache() {
assert(!is_secondary_entry(), "only for JVM_CONSTANT_InvokeDynamic main entry");
intptr_t bsm_cache_index = (intptr_t) _f2 - constantPoolOopDesc::CPCACHE_INDEX_TAG;
assert(bsm_cache_index == (intptr_t)(u2)bsm_cache_index, "oob");
return (int) bsm_cache_index;
}
void ConstantPoolCacheEntry::set_dynamic_call(Handle call_site,
methodHandle signature_invoker) {
assert(is_secondary_entry(), "");
int param_size = signature_invoker->size_of_parameters();
assert(param_size >= 1, "method argument size must include MH.this");
param_size -= 1; // do not count MH.this; it is not stacked for invokedynamic
@ -227,7 +259,6 @@ void ConstantPoolCacheEntry::set_dynamic_call(Handle call_site,
// racing threads might be trying to install their own favorites
set_f1(call_site());
}
//set_f2(0);
bool is_final = true;
assert(signature_invoker->is_final_method(), "is_final");
set_flags(as_flags(as_TosState(signature_invoker->result_type()), is_final, false, false, false, true) | param_size);
@ -417,14 +448,14 @@ void ConstantPoolCacheEntry::print(outputStream* st, int index) const {
// print separator
if (index == 0) tty->print_cr(" -------------");
// print entry
tty->print_cr("%3d (%08x) ", index, this);
tty->print("%3d ("PTR_FORMAT") ", index, (intptr_t)this);
if (is_secondary_entry())
tty->print_cr("[%5d|secondary]", main_entry_index());
else
tty->print_cr("[%02x|%02x|%5d]", bytecode_2(), bytecode_1(), constant_pool_index());
tty->print_cr(" [ %08x]", (address)(oop)_f1);
tty->print_cr(" [ %08x]", _f2);
tty->print_cr(" [ %08x]", _flags);
tty->print_cr(" [ "PTR_FORMAT"]", (intptr_t)(oop)_f1);
tty->print_cr(" [ "PTR_FORMAT"]", (intptr_t)_f2);
tty->print_cr(" [ "PTR_FORMAT"]", (intptr_t)_flags);
tty->print_cr(" -------------");
}

View File

@ -185,6 +185,10 @@ class ConstantPoolCacheEntry VALUE_OBJ_CLASS_SPEC {
methodHandle signature_invoker // determines signature information
);
// For JVM_CONSTANT_InvokeDynamic cache entries:
void initialize_bootstrap_method_index_in_cache(int bsm_cache_index);
int bootstrap_method_index_in_cache();
void set_parameter_size(int value) {
assert(parameter_size() == 0 || parameter_size() == value,
"size must not change");
@ -207,6 +211,7 @@ class ConstantPoolCacheEntry VALUE_OBJ_CLASS_SPEC {
case Bytecodes::_getfield : // fall through
case Bytecodes::_invokespecial : // fall through
case Bytecodes::_invokestatic : // fall through
case Bytecodes::_invokedynamic : // fall through
case Bytecodes::_invokeinterface : return 1;
case Bytecodes::_putstatic : // fall through
case Bytecodes::_putfield : // fall through
@ -234,6 +239,7 @@ class ConstantPoolCacheEntry VALUE_OBJ_CLASS_SPEC {
Bytecodes::Code bytecode_1() const { return Bytecodes::cast((_indices >> 16) & 0xFF); }
Bytecodes::Code bytecode_2() const { return Bytecodes::cast((_indices >> 24) & 0xFF); }
volatile oop f1() const { return _f1; }
bool is_f1_null() const { return (oop)_f1 == NULL; } // classifies a CPC entry as unbound
intx f2() const { return _f2; }
int field_index() const;
int parameter_size() const { return _flags & 0xFF; }

View File

@ -851,9 +851,15 @@ jint* methodOopDesc::method_type_offsets_chain() {
// MethodHandleCompiler.
// Must be consistent with MethodHandleCompiler::get_method_oop().
bool methodOopDesc::is_method_handle_adapter() const {
return (is_method_handle_invoke_name(name()) &&
is_synthetic() &&
MethodHandleCompiler::klass_is_method_handle_adapter_holder(method_holder()));
if (is_synthetic() &&
!is_native() && // has code from MethodHandleCompiler
is_method_handle_invoke_name(name()) &&
MethodHandleCompiler::klass_is_method_handle_adapter_holder(method_holder())) {
assert(!is_method_handle_invoke(), "disjoint");
return true;
} else {
return false;
}
}
methodHandle methodOopDesc::make_invoke_method(KlassHandle holder,

View File

@ -1046,7 +1046,8 @@ enum {
JVM_CONSTANT_InterfaceMethodref,
JVM_CONSTANT_NameAndType,
JVM_CONSTANT_MethodHandle = 15, // JSR 292
JVM_CONSTANT_MethodType = 16 // JSR 292
JVM_CONSTANT_MethodType = 16, // JSR 292
JVM_CONSTANT_InvokeDynamic = 17 // JSR 292
};
/* JVM_CONSTANT_MethodHandle subtypes */

View File

@ -738,6 +738,12 @@ void MethodHandleCompiler::emit_bc(Bytecodes::Code op, int index) {
// bi
case Bytecodes::_ldc:
assert(Bytecodes::format_bits(op, false) == (Bytecodes::_fmt_b|Bytecodes::_fmt_has_k), "wrong bytecode format");
assert((char) index == index, "index does not fit in 8-bit");
_bytecode.push(op);
_bytecode.push(index);
break;
case Bytecodes::_iload:
case Bytecodes::_lload:
case Bytecodes::_fload:
@ -754,7 +760,8 @@ void MethodHandleCompiler::emit_bc(Bytecodes::Code op, int index) {
_bytecode.push(index);
break;
// bii
// bkk
case Bytecodes::_ldc_w:
case Bytecodes::_ldc2_w:
case Bytecodes::_checkcast:
assert(Bytecodes::format_bits(op, false) == Bytecodes::_fmt_bkk, "wrong bytecode format");

View File

@ -2475,6 +2475,10 @@ JVM_END
JVM_ENTRY(void, MHI_registerBootstrap(JNIEnv *env, jobject igcls, jclass caller_jh, jobject bsm_jh)) {
instanceKlassHandle ik = MethodHandles::resolve_instance_klass(caller_jh, THREAD);
if (!AllowTransitionalJSR292) {
THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(),
"registerBootstrapMethod is only supported in JSR 292 EDR");
}
ik->link_class(CHECK);
if (!java_dyn_MethodHandle::is_instance(JNIHandles::resolve(bsm_jh))) {
THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(), "method handle");

View File

@ -3517,6 +3517,9 @@ class CommandLineFlags {
experimental(bool, EnableInvokeDynamic, false, \
"recognize the invokedynamic instruction") \
\
experimental(bool, AllowTransitionalJSR292, true, \
"recognize pre-PFD formats of invokedynamic") \
\
develop(bool, TraceInvokeDynamic, false, \
"trace internal invoke dynamic operations") \
\

View File

@ -159,6 +159,8 @@ void mutex_init() {
def(STS_init_lock , Mutex, leaf, true );
if (UseConcMarkSweepGC) {
def(iCMS_lock , Monitor, special, true ); // CMS incremental mode start/stop notification
}
if (UseConcMarkSweepGC || UseG1GC) {
def(FullGCCount_lock , Monitor, leaf, true ); // in support of ExplicitGCInvokesConcurrent
}
if (UseG1GC) {

View File

@ -91,6 +91,8 @@ const char* constantTag::internal_name() const {
return "MethodHandle";
case JVM_CONSTANT_MethodType :
return "MethodType";
case JVM_CONSTANT_InvokeDynamic :
return "InvokeDynamic";
case JVM_CONSTANT_Object :
return "Object";
case JVM_CONSTANT_Utf8 :

View File

@ -80,13 +80,14 @@ class constantTag VALUE_OBJ_CLASS_SPEC {
bool is_method_type() const { return _tag == JVM_CONSTANT_MethodType; }
bool is_method_handle() const { return _tag == JVM_CONSTANT_MethodHandle; }
bool is_invoke_dynamic() const { return _tag == JVM_CONSTANT_InvokeDynamic; }
constantTag() {
_tag = JVM_CONSTANT_Invalid;
}
constantTag(jbyte tag) {
assert((tag >= 0 && tag <= JVM_CONSTANT_NameAndType) ||
(tag >= JVM_CONSTANT_MethodHandle && tag <= JVM_CONSTANT_MethodType) ||
(tag >= JVM_CONSTANT_MethodHandle && tag <= JVM_CONSTANT_InvokeDynamic) ||
(tag >= JVM_CONSTANT_InternalMin && tag <= JVM_CONSTANT_InternalMax), "Invalid constant tag");
_tag = tag;
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 1997, 2009, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -345,6 +345,35 @@ inline intptr_t align_object_offset(intptr_t offset) {
return align_size_up(offset, HeapWordsPerLong);
}
// The expected size in bytes of a cache line, used to pad data structures.
#define DEFAULT_CACHE_LINE_SIZE 64
// Bytes needed to pad type to avoid cache-line sharing; alignment should be the
// expected cache line size (a power of two). The first addend avoids sharing
// when the start address is not a multiple of alignment; the second maintains
// alignment of starting addresses that happen to be a multiple.
#define PADDING_SIZE(type, alignment) \
((alignment) + align_size_up_(sizeof(type), alignment))
// Templates to create a subclass padded to avoid cache line sharing. These are
// effective only when applied to derived-most (leaf) classes.
// When no args are passed to the base ctor.
template <class T, size_t alignment = DEFAULT_CACHE_LINE_SIZE>
class Padded: public T {
private:
char _pad_buf_[PADDING_SIZE(T, alignment)];
};
// When either 0 or 1 args may be passed to the base ctor.
template <class T, typename Arg1T, size_t alignment = DEFAULT_CACHE_LINE_SIZE>
class Padded01: public T {
public:
Padded01(): T() { }
Padded01(Arg1T arg1): T(arg1) { }
private:
char _pad_buf_[PADDING_SIZE(T, alignment)];
};
//----------------------------------------------------------------------------------------------------
// Utility macros for compilers

View File

@ -31,6 +31,48 @@ uint ParallelTaskTerminator::_total_spins = 0;
uint ParallelTaskTerminator::_total_peeks = 0;
#endif
#if TASKQUEUE_STATS
const char * const TaskQueueStats::_names[last_stat_id] = {
"qpush", "qpop", "qpop-s", "qattempt", "qsteal", "opush", "omax"
};
void TaskQueueStats::print_header(unsigned int line, outputStream* const stream,
unsigned int width)
{
// Use a width w: 1 <= w <= max_width
const unsigned int max_width = 40;
const unsigned int w = MAX2(MIN2(width, max_width), 1U);
if (line == 0) { // spaces equal in width to the header
const unsigned int hdr_width = w * last_stat_id + last_stat_id - 1;
stream->print("%*s", hdr_width, " ");
} else if (line == 1) { // labels
stream->print("%*s", w, _names[0]);
for (unsigned int i = 1; i < last_stat_id; ++i) {
stream->print(" %*s", w, _names[i]);
}
} else if (line == 2) { // dashed lines
char dashes[max_width + 1];
memset(dashes, '-', w);
dashes[w] = '\0';
stream->print("%s", dashes);
for (unsigned int i = 1; i < last_stat_id; ++i) {
stream->print(" %s", dashes);
}
}
}
void TaskQueueStats::print(outputStream* stream, unsigned int width) const
{
#define FMT SIZE_FORMAT_W(*)
stream->print(FMT, width, _stats[0]);
for (unsigned int i = 1; i < last_stat_id; ++i) {
stream->print(" " FMT, width, _stats[i]);
}
#undef FMT
}
#endif // TASKQUEUE_STATS
int TaskQueueSetSuper::randomParkAndMiller(int *seed0) {
const int a = 16807;
const int m = 2147483647;

View File

@ -22,6 +22,72 @@
*
*/
// Simple TaskQueue stats that are collected by default in debug builds.
#if !defined(TASKQUEUE_STATS) && defined(ASSERT)
#define TASKQUEUE_STATS 1
#elif !defined(TASKQUEUE_STATS)
#define TASKQUEUE_STATS 0
#endif
#if TASKQUEUE_STATS
#define TASKQUEUE_STATS_ONLY(code) code
#else
#define TASKQUEUE_STATS_ONLY(code)
#endif // TASKQUEUE_STATS
#if TASKQUEUE_STATS
class TaskQueueStats {
public:
enum StatId {
push, // number of taskqueue pushes
pop, // number of taskqueue pops
pop_slow, // subset of taskqueue pops that were done slow-path
steal_attempt, // number of taskqueue steal attempts
steal, // number of taskqueue steals
overflow, // number of overflow pushes
overflow_max_len, // max length of overflow stack
last_stat_id
};
public:
inline TaskQueueStats() { reset(); }
inline void record_push() { ++_stats[push]; }
inline void record_pop() { ++_stats[pop]; }
inline void record_pop_slow() { record_pop(); ++_stats[pop_slow]; }
inline void record_steal(bool success);
inline void record_overflow(size_t new_length);
inline size_t get(StatId id) const { return _stats[id]; }
inline const size_t* get() const { return _stats; }
inline void reset();
static void print_header(unsigned int line, outputStream* const stream = tty,
unsigned int width = 10);
void print(outputStream* const stream = tty, unsigned int width = 10) const;
private:
size_t _stats[last_stat_id];
static const char * const _names[last_stat_id];
};
void TaskQueueStats::record_steal(bool success) {
++_stats[steal_attempt];
if (success) ++_stats[steal];
}
void TaskQueueStats::record_overflow(size_t new_len) {
++_stats[overflow];
if (new_len > _stats[overflow_max_len]) _stats[overflow_max_len] = new_len;
}
void TaskQueueStats::reset() {
memset(_stats, 0, sizeof(_stats));
}
#endif // TASKQUEUE_STATS
template <unsigned int N>
class TaskQueueSuper: public CHeapObj {
protected:
@ -135,6 +201,8 @@ public:
// Total size of queue.
static const uint total_size() { return N; }
TASKQUEUE_STATS_ONLY(TaskQueueStats stats;)
};
template<class E, unsigned int N = TASKQUEUE_SIZE>
@ -152,6 +220,7 @@ protected:
public:
using TaskQueueSuper<N>::max_elems;
using TaskQueueSuper<N>::size;
TASKQUEUE_STATS_ONLY(using TaskQueueSuper<N>::stats;)
private:
// Slow paths for push, pop_local. (pop_global has no fast path.)
@ -224,14 +293,14 @@ bool GenericTaskQueue<E, N>::push_slow(E t, uint dirty_n_elems) {
// g++ complains if the volatile result of the assignment is unused.
const_cast<E&>(_elems[localBot] = t);
OrderAccess::release_store(&_bottom, increment_index(localBot));
TASKQUEUE_STATS_ONLY(stats.record_push());
return true;
}
return false;
}
template<class E, unsigned int N>
bool GenericTaskQueue<E, N>::
pop_local_slow(uint localBot, Age oldAge) {
bool GenericTaskQueue<E, N>::pop_local_slow(uint localBot, Age oldAge) {
// This queue was observed to contain exactly one element; either this
// thread will claim it, or a competing "pop_global". In either case,
// the queue will be logically empty afterwards. Create a new Age value
@ -251,6 +320,7 @@ pop_local_slow(uint localBot, Age oldAge) {
if (tempAge == oldAge) {
// We win.
assert(dirty_size(localBot, _age.top()) != N - 1, "sanity");
TASKQUEUE_STATS_ONLY(stats.record_pop_slow());
return true;
}
}
@ -306,6 +376,8 @@ public:
typedef GrowableArray<E> overflow_t;
typedef GenericTaskQueue<E, N> taskqueue_t;
TASKQUEUE_STATS_ONLY(using taskqueue_t::stats;)
OverflowTaskQueue();
~OverflowTaskQueue();
void initialize();
@ -356,6 +428,7 @@ bool OverflowTaskQueue<E, N>::push(E t)
{
if (!taskqueue_t::push(t)) {
overflow_stack()->push(t);
TASKQUEUE_STATS_ONLY(stats.record_overflow(overflow_stack()->length()));
}
return true;
}
@ -424,9 +497,13 @@ GenericTaskQueueSet<T>::queue(uint i) {
template<class T> bool
GenericTaskQueueSet<T>::steal(uint queue_num, int* seed, E& t) {
for (uint i = 0; i < 2 * _n; i++)
if (steal_best_of_2(queue_num, seed, t))
for (uint i = 0; i < 2 * _n; i++) {
if (steal_best_of_2(queue_num, seed, t)) {
TASKQUEUE_STATS_ONLY(queue(queue_num)->stats.record_steal(true));
return true;
}
}
TASKQUEUE_STATS_ONLY(queue(queue_num)->stats.record_steal(false));
return false;
}
@ -574,6 +651,7 @@ GenericTaskQueue<E, N>::push(E t) {
// g++ complains if the volatile result of the assignment is unused.
const_cast<E&>(_elems[localBot] = t);
OrderAccess::release_store(&_bottom, increment_index(localBot));
TASKQUEUE_STATS_ONLY(stats.record_push());
return true;
} else {
return push_slow(t, dirty_n_elems);
@ -603,6 +681,7 @@ GenericTaskQueue<E, N>::pop_local(E& t) {
idx_t tp = _age.top(); // XXX
if (size(localBot, tp) > 0) {
assert(dirty_size(localBot, tp) != N - 1, "sanity");
TASKQUEUE_STATS_ONLY(stats.record_pop());
return true;
} else {
// Otherwise, the queue contained exactly one element; we take the slow

View File

@ -77,3 +77,5 @@ d4adf4f2d14c7b79df0a81de884b6b57c6850802 jdk7-b98
d524be5ef62e8b8cb890c59a5d2c19ef0ab50d45 jdk7-b100
17f62a566a2020fd908e77106ed885e0c4e7c14d jdk7-b101
15573625af97d01c4e24549041cba7584da7fe88 jdk7-b102
b7722e8788644507c10bb69a137de422d0300b24 jdk7-b103
d42c4acb6424a094bdafe2ad9c8c1c7ca7fb7b7e jdk7-b104

View File

@ -77,3 +77,5 @@ dac23846092ad4956ed41b5278f8686476ae46ef jdk7-b97
bd26d0ce0c3cb43e58a8e2770cc03f26d96ffe5c jdk7-b100
b55ce274490082712f5e002b38d2eed505ca863d jdk7-b101
d8580443d1815d68e0035a0560634e50fa899288 jdk7-b102
267386d6b923f724309cab855a555e2d86a15c8f jdk7-b103
bbc4cce6c20aeca4862804a6e8315a2350d43633 jdk7-b104

View File

@ -77,3 +77,5 @@ b1903d7528d33b521df42bc9291bdcdd2f444a29 jdk7-b97
820b4e843d5168370a3bf166d19751a3271d8575 jdk7-b100
d58354a69011f3d3354765fa3167567c4c4a9612 jdk7-b101
13029a61b16bec06535d4f0aa98229b358684128 jdk7-b102
6488b70a23cc6dc4b7e00809bc503c2884bafb28 jdk7-b103
1a92820132a0221c5bdedd42d0888c57ce4cbb34 jdk7-b104

View File

@ -191,7 +191,7 @@ endif
# Generic
REQUIRED_ANT_VER = 1.6.3
REQUIRED_BOOT_VER = 1.5
REQUIRED_BOOT_VER = 1.6
REQUIRED_FREETYPE_VERSION = 2.3.0
REQUIRED_MAKE_VER = 3.78
REQUIRED_UNZIP_VER = 5.12

View File

@ -47,9 +47,9 @@ BUG_SUBMIT_LINE = <a href=\"$(BUG_SUBMIT_URL)\">Submit a bug or feature</a>
# Url to devdocs page
# Was: http://java.sun.com/javase/6/webnotes/devdocs-vs-specs.html
DEV_DOCS_URL-5 = http://java.sun.com/j2se/1.5.0/docs
DEV_DOCS_URL-6 = http://download.oracle.com/docs/cd/E17409_01/javase/6/docs
DEV_DOCS_URL-7 = http://download.oracle.com/docs/cd/E17409_01/javase/7/docs
DEV_DOCS_URL-5 = http://java.sun.com/j2se/1.5.0/docs/index.html
DEV_DOCS_URL-6 = http://download.oracle.com/javase/6/docs/index.html
DEV_DOCS_URL-7 = http://download.oracle.com/javase/7/docs/index.html
DEV_DOCS_URL = $(DEV_DOCS_URL-$(JDK_MINOR_VERSION))
# Url to Java Language Spec
@ -84,6 +84,11 @@ ALL_SOURCE_DIRS = $(SHARE_SRC)/classes \
$(SHARE_SRC)/../solaris/classes \
$(SHARE_SRC)/../windows/classes \
$(SHARE_SRC)/doc/stub
# List of directories that actually exist
ALL_EXISTING_SOURCE_DIRS := $(wildcard $(ALL_SOURCE_DIRS))
# List with classpath separator between them
EMPTY:=
SPACE:= $(EMPTY) $(EMPTY)
RELEASEDOCS_SOURCEPATH = \
@ -240,7 +245,8 @@ include NON_CORE_PKGS.gmk
# Default target is same as docs target, create core api and all others it can
#
all docs: coredocs otherdocs
all: docs
docs: coredocs otherdocs
#################################################################
# Production Targets -- USE THESE TARGETS WHEN:
@ -1178,9 +1184,9 @@ $(TRACING_PACKAGES_FILE): $(DIRECTORY_CACHE) $(call PackageDependencies,$(TRACIN
#
# Get a cache of all the directories
$(DIRECTORY_CACHE): $(ALL_SOURCE_DIRS)
$(DIRECTORY_CACHE): $(ALL_EXISTING_SOURCE_DIRS)
$(prep-target)
@for cp in $(ALL_SOURCE_DIRS) ; do \
@for cp in $(ALL_EXISTING_SOURCE_DIRS) ; do \
$(ECHO) "$(FIND) $${cp} -type f >> $@"; \
$(FIND) $${cp} -type f >> $@; \
done

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 1997, 2008, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -113,7 +113,6 @@ public class BasicColorChooserUI extends ColorChooserUI
previewPanelHolder.setBorder(new TitledBorder(previewString));
}
previewPanelHolder.setInheritsPopupMenu(true);
chooser.add(previewPanelHolder, BorderLayout.SOUTH);
installPreviewPanel();
chooser.applyComponentOrientation(c.getComponentOrientation());
@ -126,13 +125,9 @@ public class BasicColorChooserUI extends ColorChooserUI
uninstallDefaultChoosers();
uninstallListeners();
uninstallPreviewPanel();
uninstallDefaults();
previewPanelHolder.remove(previewPanel);
if (previewPanel instanceof UIResource) {
chooser.setPreviewPanel(null);
}
previewPanelHolder = null;
previewPanel = null;
defaultChoosers = null;
@ -143,29 +138,37 @@ public class BasicColorChooserUI extends ColorChooserUI
}
protected void installPreviewPanel() {
if (previewPanel != null) {
previewPanelHolder.remove(previewPanel);
previewPanel.removeMouseListener(getHandler());
JComponent previewPanel = this.chooser.getPreviewPanel();
if (previewPanel == null) {
previewPanel = ColorChooserComponentFactory.getPreviewPanel();
}
previewPanel = chooser.getPreviewPanel();
Dimension layoutSize = new Dimension(); // fix for bug 4759306
if (previewPanel != null) {
layoutSize = new BorderLayout().minimumLayoutSize(previewPanel);
if ((previewPanelHolder != null) && (chooser != null) &&
(layoutSize.getWidth() + layoutSize.getHeight() == 0)) {
chooser.remove(previewPanelHolder);
return;
else {
Dimension size = new BorderLayout().minimumLayoutSize(previewPanel);
if ((size.width == 0) && (size.height == 0)) {
previewPanel = null;
}
}
if (previewPanel == null || previewPanel instanceof UIResource) {
previewPanel = ColorChooserComponentFactory.getPreviewPanel(); // get from table?
chooser.setPreviewPanel(previewPanel);
this.previewPanel = previewPanel;
if (previewPanel != null) {
chooser.add(previewPanelHolder, BorderLayout.SOUTH);
previewPanel.setForeground(chooser.getColor());
previewPanelHolder.add(previewPanel);
previewPanel.addMouseListener(getHandler());
previewPanel.setInheritsPopupMenu(true);
}
previewPanel.setForeground(chooser.getColor());
previewPanelHolder.add(previewPanel);
previewPanel.addMouseListener(getHandler());
previewPanel.setInheritsPopupMenu(true);
}
/**
* Removes installed preview panel from the UI delegate.
*
* @since 1.7
*/
protected void uninstallPreviewPanel() {
if (this.previewPanel != null) {
this.previewPanel.removeMouseListener(getHandler());
this.previewPanelHolder.remove(this.previewPanel);
}
this.chooser.remove(this.previewPanelHolder);
}
protected void installDefaults() {
@ -209,7 +212,6 @@ public class BasicColorChooserUI extends ColorChooserUI
chooser.removePropertyChangeListener( propertyChangeListener );
chooser.getSelectionModel().removeChangeListener(previewListener);
previewListener = null;
previewPanel.removeMouseListener(getHandler());
}
private void selectionChanged(ColorSelectionModel model) {
@ -312,9 +314,8 @@ public class BasicColorChooserUI extends ColorChooserUI
}
}
else if (prop == JColorChooser.PREVIEW_PANEL_PROPERTY) {
if (evt.getNewValue() != previewPanel) {
installPreviewPanel();
}
uninstallPreviewPanel();
installPreviewPanel();
}
else if (prop == JColorChooser.SELECTION_MODEL_PROPERTY) {
ColorSelectionModel oldModel = (ColorSelectionModel) evt.getOldValue();
@ -352,5 +353,4 @@ public class BasicColorChooserUI extends ColorChooserUI
super("color");
}
}
}

View File

@ -202,8 +202,8 @@ public class BasicComboPopup extends JPopupMenu implements ComboPopup {
* Implementation of ComboPopup.show().
*/
public void show() {
comboBox.firePopupMenuWillBecomeVisible();
setListSelection(comboBox.getSelectedIndex());
Point location = getPopupLocation();
show( comboBox, location.x, location.y );
}
@ -344,7 +344,8 @@ public class BasicComboPopup extends JPopupMenu implements ComboPopup {
protected void firePopupMenuWillBecomeVisible() {
super.firePopupMenuWillBecomeVisible();
comboBox.firePopupMenuWillBecomeVisible();
// comboBox.firePopupMenuWillBecomeVisible() is called from BasicComboPopup.show() method
// to let the user change the popup menu from the PopupMenuListener.popupMenuWillBecomeVisible()
}
protected void firePopupMenuWillBecomeInvisible() {

View File

@ -570,7 +570,9 @@ public class DefaultFormatter extends JFormattedTextField.AbstractFormatter
direction = -1;
}
if (getOverwriteMode() && rh.text != null) {
if (getOverwriteMode() && rh.text != null &&
getFormattedTextField().getSelectedText() == null)
{
rh.length = Math.min(Math.max(rh.length, rh.text.length()),
rh.fb.getDocument().getLength() - rh.offset);
}

View File

@ -622,18 +622,8 @@ public class InternationalFormatter extends DefaultFormatter {
/**
* Overriden in an attempt to honor the literals.
* <p>
* If we do
* not allow invalid values and are in overwrite mode, this does the
* following for each character in the replacement range:
* <ol>
* <li>If the character is a literal, add it to the string to replace
* with. If there is text to insert and it doesn't match the
* literal, then insert the literal in the the middle of the insert
* text. This allows you to either paste in literals or not and
* get the same behavior.
* <li>If there is no text to insert, replace it with ' '.
* </ol>
* <p>If we do not allow invalid values and are in overwrite mode, this
* {@code rh.length} is corrected as to preserve trailing literals.
* If not in overwrite mode, and there is text to insert it is
* inserted at the next non literal index going forward. If there
* is only text to remove, it is removed from the next non literal
@ -643,61 +633,27 @@ public class InternationalFormatter extends DefaultFormatter {
if (!getAllowsInvalid()) {
String text = rh.text;
int tl = (text != null) ? text.length() : 0;
JTextComponent c = getFormattedTextField();
if (tl == 0 && rh.length == 1 && getFormattedTextField().
getSelectionStart() != rh.offset) {
if (tl == 0 && rh.length == 1 && c.getSelectionStart() != rh.offset) {
// Backspace, adjust to actually delete next non-literal.
rh.offset = getNextNonliteralIndex(rh.offset, -1);
}
if (getOverwriteMode()) {
StringBuffer replace = null;
} else if (getOverwriteMode()) {
int pos = rh.offset;
int textPos = pos;
boolean overflown = false;
for (int counter = 0, textIndex = 0,
max = Math.max(tl, rh.length); counter < max;
counter++) {
if (isLiteral(rh.offset + counter)) {
if (replace != null) {
replace.append(getLiteral(rh.offset +
counter));
}
if (textIndex < tl && text.charAt(textIndex) ==
getLiteral(rh.offset + counter)) {
textIndex++;
}
else if (textIndex == 0) {
rh.offset++;
rh.length--;
counter--;
max--;
}
else if (replace == null) {
replace = new StringBuffer(max);
replace.append(text.substring(0, textIndex));
replace.append(getLiteral(rh.offset +
counter));
}
}
else if (textIndex < tl) {
if (replace != null) {
replace.append(text.charAt(textIndex));
}
textIndex++;
}
else {
// Nothing to replace it with, assume ' '
if (replace == null) {
replace = new StringBuffer(max);
if (textIndex > 0) {
replace.append(text.substring(0, textIndex));
}
}
if (replace != null) {
replace.append(' ');
}
for (int i = 0; i < rh.length; i++) {
while (isLiteral(pos)) pos++;
if (pos >= string.length()) {
pos = textPos;
overflown = true;
break;
}
textPos = ++pos;
}
if (replace != null) {
rh.text = replace.toString();
if (overflown || c.getSelectedText() == null) {
rh.length = pos - rh.offset;
}
}
else if (tl > 0) {

View File

@ -310,24 +310,32 @@ typedef JLocalRef<jclass> JLClass;
* Class to encapsulate the extraction of the java string contents
* into a buffer and the cleanup of the buffer
*/
class JavaStringBuffer
class JavaStringBuffer
{
protected:
LPWSTR m_pStr;
jsize m_dwSize;
LPWSTR getNonEmptyString() {
return (NULL==m_pStr)
? L""
: m_pStr;
}
public:
JavaStringBuffer(jsize cbTCharCount) {
m_dwSize = cbTCharCount;
m_pStr = (LPWSTR)safe_Malloc( (m_dwSize+1)*sizeof(WCHAR) );
m_pStr = (0 == m_dwSize)
? NULL
: (LPWSTR)safe_Malloc( (m_dwSize+1)*sizeof(WCHAR) );
}
JavaStringBuffer(JNIEnv *env, jstring text) {
if (NULL == text) {
m_pStr = L"";
m_dwSize = 0;
m_dwSize = (NULL == text)
? 0
: env->GetStringLength(text);
if (0 == m_dwSize) {
m_pStr = NULL;
} else {
m_dwSize = env->GetStringLength(text);
m_pStr = (LPWSTR)safe_Malloc( (m_dwSize+1)*sizeof(WCHAR) );
env->GetStringRegion(text, 0, m_dwSize, reinterpret_cast<jchar *>(m_pStr));
m_pStr[m_dwSize] = 0;
@ -341,12 +349,16 @@ public:
void Resize(jsize cbTCharCount) {
m_dwSize = cbTCharCount;
//It is ok to have non-null terminated string here.
//The function is used only for space reservation in staff buffer for
//followed data copying process. And that is the reason why we ignore
//the special case m_dwSize==0 here.
m_pStr = (LPWSTR)safe_Realloc(m_pStr, (m_dwSize+1)*sizeof(WCHAR) );
}
//we are in UNICODE now, so LPWSTR:=:LPTSTR
operator LPWSTR() { return m_pStr; }
operator LPARAM() { return (LPARAM)m_pStr; }
void *GetData() { return (void *)m_pStr; }
operator LPWSTR() { return getNonEmptyString(); }
operator LPARAM() { return (LPARAM)getNonEmptyString(); }
void *GetData() { return (void *)getNonEmptyString(); }
jsize GetSize() { return m_dwSize; }
};

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2003, 2007, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -23,7 +23,7 @@
/*
* @test
* @bug 4631471
* @bug 4631471 6972468
* @summary Tests DefaultTreeModel encoding
* @author Sergey Malenkov, Mark Davidson
*/
@ -37,6 +37,12 @@ import javax.swing.tree.TreeNode;
public abstract class Test4631471 extends AbstractTest {
public static void main(String[] args) throws Exception {
main();
System.setSecurityManager(new SecurityManager());
main();
}
private static void main() throws Exception {
// the DefaultMutableTreeNode will archive correctly
new Test4631471() {
protected Object getObject() {

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2003, 2007, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -23,7 +23,7 @@
/*
* @test
* @bug 4903007
* @bug 4903007 6972468
* @summary Tests encoding of container with boxes and BoxLayout
* @author Sergey Malenkov, Mark Davidson
*/
@ -36,7 +36,7 @@ import javax.swing.JPanel;
public class Test4903007 extends AbstractTest<JPanel> {
public static void main(String[] args) throws Exception {
new Test4903007().test(false); // TODO: could not encode with security manager
new Test4903007().test(true);
}
protected JPanel getObject() {

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2007, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -23,7 +23,7 @@
/*
* @test
* @bug 5023552
* @bug 5023552 6972468
* @summary Tests JLayeredPane encoding
* @author Sergey Malenkov
*/
@ -35,7 +35,7 @@ import javax.swing.JPanel;
public final class javax_swing_JLayeredPane extends AbstractTest<JLayeredPane> {
public static void main(String[] args) {
new javax_swing_JLayeredPane().test(false); // TODO: could not encode with security manager
new javax_swing_JLayeredPane().test(true);
}
private static void init(JLayeredPane pane, int layer, int x, int y, int w, int h, Color color) {

View File

@ -0,0 +1,117 @@
/*
* Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* @test
* @bug 6199676
* @summary Tests preview panel after L&F changing
* @author Sergey Malenkov
*/
import java.awt.Component;
import java.awt.Container;
import javax.swing.JColorChooser;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
import javax.swing.UIManager;
import javax.swing.UIManager.LookAndFeelInfo;
public class Test6199676 implements Runnable {
public static void main(String[] args) {
SwingUtilities.invokeLater(new Test6199676());
}
private static void exit(String error) {
if (error != null) {
System.err.println(error);
System.exit(1);
}
else {
System.exit(0);
}
}
private static Component getPreview(Container container) {
String name = "ColorChooser.previewPanelHolder";
for (Component component : container.getComponents()) {
if (!name.equals(component.getName())) {
component = (component instanceof Container)
? getPreview((Container) component)
: null;
}
if (component instanceof Container) {
container = (Container) component;
return 1 == container.getComponentCount()
? container.getComponent(0)
: null;
}
}
return null;
}
private static boolean isShowing(Component component) {
return (component != null) && component.isShowing();
}
private int index;
private boolean updated;
private JColorChooser chooser;
public synchronized void run() {
if (this.chooser == null) {
this.chooser = new JColorChooser();
JFrame frame = new JFrame(getClass().getName());
frame.add(this.chooser);
frame.setVisible(true);
}
else if (this.updated) {
if (isShowing(this.chooser.getPreviewPanel())) {
exit("custom preview panel is showing");
}
exit(null);
}
else {
Component component = this.chooser.getPreviewPanel();
if (component == null) {
component = getPreview(this.chooser);
}
if (!isShowing(component)) {
exit("default preview panel is not showing");
}
this.updated = true;
this.chooser.setPreviewPanel(new JPanel());
}
LookAndFeelInfo[] infos = UIManager.getInstalledLookAndFeels();
LookAndFeelInfo info = infos[++this.index % infos.length];
try {
UIManager.setLookAndFeel(info.getClassName());
}
catch (Exception exception) {
exit("could not change L&F");
}
SwingUtilities.updateComponentTreeUI(this.chooser);
SwingUtilities.invokeLater(this);
}
}

View File

@ -0,0 +1,111 @@
/*
* Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/* @test
* @bug 4743225
* @summary Size of JComboBox list is wrong when list is populated via PopupMenuListener
* @author Alexander Potochkin
*/
import sun.awt.SunToolkit;
import javax.accessibility.AccessibleContext;
import javax.swing.JComboBox;
import javax.swing.JFrame;
import javax.swing.SwingUtilities;
import javax.swing.event.PopupMenuEvent;
import javax.swing.event.PopupMenuListener;
import javax.swing.plaf.basic.BasicComboPopup;
import java.awt.FlowLayout;
import java.awt.Point;
import java.awt.Robot;
import java.awt.Toolkit;
import java.awt.event.InputEvent;
public class bug4743225 extends JFrame {
private static JComboBox cb;
private static volatile boolean flag;
public bug4743225() {
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setLayout(new FlowLayout());
cb = new JComboBox(new Object[] {"one", "two", "three"});
cb.addPopupMenuListener(new PopupMenuListener() {
public void popupMenuWillBecomeVisible(PopupMenuEvent e) {
cb.addItem("Test");
}
public void popupMenuWillBecomeInvisible(PopupMenuEvent e) {
}
public void popupMenuCanceled(PopupMenuEvent e) {
}
});
add(cb);
pack();
}
public static BasicComboPopup getPopup() {
AccessibleContext c = cb.getAccessibleContext();
for(int i = 0; i < c.getAccessibleChildrenCount(); i ++) {
if (c.getAccessibleChild(i) instanceof BasicComboPopup) {
return (BasicComboPopup) c.getAccessibleChild(i);
}
}
throw new AssertionError("No BasicComboPopup found");
}
public static void main(String... args) throws Exception {
Robot robot = new Robot();
robot.setAutoDelay(20);
SunToolkit toolkit = (SunToolkit) Toolkit.getDefaultToolkit();
SwingUtilities.invokeAndWait(new Runnable() {
public void run() {
new bug4743225().setVisible(true);
}
});
toolkit.realSync();
// calling this method from main thread is ok
Point point = cb.getLocationOnScreen();
robot.mouseMove(point.x + 10, point.y + 10);
robot.mousePress(InputEvent.BUTTON1_MASK);
robot.mouseRelease(InputEvent.BUTTON1_MASK);
toolkit.realSync();
SwingUtilities.invokeAndWait(new Runnable() {
public void run() {
if(getPopup().getList().getLastVisibleIndex() == 3) {
flag = true;
}
}
});
if (!flag) {
throw new RuntimeException("The ComboBox popup wasn't correctly updated");
}
}
}

View File

@ -0,0 +1,360 @@
/*
* Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
* CA 95054 USA or visit www.sun.com if you need additional information or
* have any questions.
*/
/* @test
@bug 6462562
@summary Tests text input into JFormattedTextField
with an InternationalFormatter
@author Peter Zhelezniakov
@run main Test6462562
*/
import java.awt.event.ActionEvent;
import java.text.DateFormat;
import java.text.NumberFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Locale;
import javax.swing.Action;
import javax.swing.JFormattedTextField;
import javax.swing.SwingUtilities;
import javax.swing.text.Caret;
import javax.swing.text.DateFormatter;
import javax.swing.text.DefaultEditorKit;
import javax.swing.text.InternationalFormatter;
import javax.swing.text.NumberFormatter;
public class Test6462562
{
static final String BACKSPACE = new String("backspace");
static final String DELETE = new String("delete");
boolean failed = false;
void test() {
testPercentFormat();
testCurrencyFormat();
testIntegerFormat();
testDateFormat();
if (failed) {
throw new RuntimeException("Some testcases failed, see output above");
}
System.err.println("(-; All testcases passed ;-)");
}
TestFormattedTextField create(NumberFormat format) {
format.setMaximumFractionDigits(0);
NumberFormatter fmt = new NumberFormatter(format);
return new TestFormattedTextField(fmt);
}
TestFormattedTextField create(DateFormat format) {
DateFormatter fmt = new DateFormatter(format);
return new TestFormattedTextField(fmt);
}
public static void main(String[] args) throws Exception {
SwingUtilities.invokeAndWait(new Runnable() {
public void run() {
new Test6462562().test();
}
});
}
class TestFormattedTextField extends JFormattedTextField
{
final Action backspace;
final Action delete;
final Action insert;
final ActionEvent dummyEvent;
public TestFormattedTextField(InternationalFormatter fmt) {
super(fmt);
fmt.setAllowsInvalid(false);
fmt.setOverwriteMode(true);
backspace = getActionMap().get(DefaultEditorKit.deletePrevCharAction);
delete = getActionMap().get(DefaultEditorKit.deleteNextCharAction);
insert = getActionMap().get(DefaultEditorKit.insertContentAction);
dummyEvent = new ActionEvent(this, 0, null);
}
public boolean test(int pos, int selectionLength, String todo, Object expectedResult) {
Object v0 = getValue();
Caret caret = getCaret();
caret.setDot(pos);
if (selectionLength > 0) {
caret.moveDot(pos + selectionLength);
}
String desc = todo;
if (todo == BACKSPACE) {
backspace.actionPerformed(dummyEvent);
} else if (todo == DELETE) {
delete.actionPerformed(dummyEvent);
} else {
desc = "insert('" + todo + "')";
insert.actionPerformed(new ActionEvent(this, 0, todo));
}
try {
commitEdit();
} catch (ParseException e) {
e.printStackTrace();
failed = true;
return false;
}
Object v1 = getValue();
if (! v1.equals(expectedResult)) {
System.err.printf("Failure: value='%s', mark=%d, dot=%d, action=%s\n",
v0, pos, pos + selectionLength, desc);
System.err.printf(" Result: '%s', expected: '%s'\n", v1, expectedResult);
failed = true;
return false;
}
return true;
}
}
void testPercentFormat() {
NumberFormat format = NumberFormat.getPercentInstance(Locale.US);
TestFormattedTextField ftf = create(format);
ftf.setValue(.34);
System.err.println("Testing NumberFormat.getPercentInstance(Locale.US)");
// test inserting individual characters
ftf.test(0, 0, "1", .14);
ftf.test(2, 0, "2", 1.42);
ftf.test(1, 0, "0", 1.02);
// test inserting several characters at once - e.g. from clipboard
ftf.test(0, 0, "1024", 10.24);
ftf.test(3, 0, "333", 103.33);
ftf.test(6, 0, "77", 10333.77);
ftf.test(4, 0, "99", 10399.77);
ftf.test(6, 0, "00", 10390.07);
// test inserting strings that contain some formatting
ftf.test(0, 0, "2,2", 2290.07);
ftf.test(2, 0, "2,2", 222.27);
ftf.test(4, 0, "2,2", 222.22);
ftf.test(6, 0, "33,33", 2222233.33);
// test delete
ftf.test(0, 0, DELETE, 222233.33);
ftf.test(10, 0, DELETE, 222233.33);
ftf.test(5, 0, DELETE, 22223.33);
ftf.test(6, 0, DELETE, 2222.33);
// test backspace
ftf.test(0, 0, BACKSPACE, 2222.33);
ftf.test(7, 0, BACKSPACE, 222.23);
ftf.test(4, 0, BACKSPACE, 22.23);
ftf.test(2, 0, BACKSPACE, 2.23);
// test replacing selection
ftf.test(0, 1, "555", 555.23);
ftf.test(4, 2, "555", 5555.55);
ftf.test(2, 3, "1", 551.55);
ftf.test(3, 2, "6", 55.65);
ftf.test(4, 2, "12", 556.12);
ftf.test(3, 4, "0", 5.5);
ftf.test(0, 3, "111222333444555", 1112223334445.55);
// test deleting selection
ftf.test(0, 2, DELETE, 12223334445.55);
ftf.test(0, 3, BACKSPACE, 223334445.55);
ftf.test(12, 2, DELETE, 2233344.45);
ftf.test(9, 2, BACKSPACE, 22333.44);
ftf.test(4, 3, DELETE, 223.44);
ftf.test(1, 2, BACKSPACE, 23.44);
ftf.test(3, 3, DELETE, .23);
ftf.test(1, 2, BACKSPACE, .02);
}
void testCurrencyFormat() {
NumberFormat format = NumberFormat.getCurrencyInstance(Locale.US);
TestFormattedTextField ftf = create(format);
ftf.setValue(56L);
System.err.println("Testing NumberFormat.getCurrencyInstance(Locale.US)");
// test inserting individual characters
ftf.test(1, 0, "1", 16L);
ftf.test(3, 0, "2", 162L);
ftf.test(2, 0, "0", 102L);
// test inserting several characters at once - e.g. from clipboard
ftf.test(1, 0, "1024", 1024L);
ftf.test(4, 0, "333", 10333L);
ftf.test(7, 0, "77", 1033377L);
ftf.test(5, 0, "99", 1039977L);
ftf.test(7, 0, "00", 1039007L);
// test inserting strings that contain some formatting
ftf.test(1, 0, "2,2", 229007L);
ftf.test(3, 0, "2,2", 22227L);
ftf.test(4, 0, "2,2", 2222L);
ftf.test(6, 0, "33,33", 22223333L);
// test delete
ftf.test(1, 0, DELETE, 2223333L);
ftf.test(10, 0, DELETE, 2223333L);
ftf.test(5, 0, DELETE, 222333L);
ftf.test(5, 0, DELETE, 22233L);
// test backspace
ftf.test(1, 0, BACKSPACE, 22233L);
ftf.test(7, 0, BACKSPACE, 2223L);
ftf.test(4, 0, BACKSPACE, 223L);
ftf.test(2, 0, BACKSPACE, 23L);
// test replacing selection
ftf.test(1, 1, "555", 5553L);
ftf.test(4, 2, "555", 55555L);
ftf.test(2, 3, "1", 5155L);
ftf.test(3, 2, "6", 565L);
ftf.test(1, 3, "111222333444555", 111222333444555L);
// test deleting selection
ftf.test(1, 2, DELETE, 1222333444555L);
ftf.test(1, 3, BACKSPACE, 22333444555L);
ftf.test(13, 2, DELETE, 223334445L);
ftf.test(10, 2, BACKSPACE, 2233344L);
ftf.test(4, 4, DELETE, 2244L);
ftf.test(1, 4, BACKSPACE, 4L);
}
void testIntegerFormat() {
NumberFormat format = NumberFormat.getIntegerInstance(Locale.US);
TestFormattedTextField ftf = create(format);
ftf.setValue(56L);
System.err.println("Testing NumberFormat.getIntegerInstance(Locale.US)");
// test inserting individual characters
ftf.test(0, 0, "1", 16L);
ftf.test(2, 0, "2", 162L);
ftf.test(1, 0, "0", 102L);
// test inserting several characters at once - e.g. from clipboard
ftf.test(0, 0, "1024", 1024L);
ftf.test(3, 0, "333", 10333L);
ftf.test(6, 0, "77", 1033377L);
ftf.test(4, 0, "99", 1039977L);
ftf.test(6, 0, "00", 1039007L);
// test inserting strings that contain some formatting
ftf.test(0, 0, "2,2", 229007L);
ftf.test(2, 0, "2,2", 22227L);
ftf.test(3, 0, "2,2", 2222L);
ftf.test(5, 0, "33,33", 22223333L);
// test delete
ftf.test(0, 0, DELETE, 2223333L);
ftf.test(9, 0, DELETE, 2223333L);
ftf.test(4, 0, DELETE, 222333L);
ftf.test(4, 0, DELETE, 22233L);
// test backspace
ftf.test(0, 0, BACKSPACE, 22233L);
ftf.test(6, 0, BACKSPACE, 2223L);
ftf.test(2, 0, BACKSPACE, 223L);
ftf.test(2, 0, BACKSPACE, 23L);
// test replacing selection
ftf.test(0, 1, "555", 5553L);
ftf.test(3, 2, "555", 55555L);
ftf.test(1, 3, "1", 5155L);
ftf.test(2, 2, "6", 565L);
ftf.test(0, 3, "111222333444555", 111222333444555L);
// test deleting selection
ftf.test(0, 2, DELETE, 1222333444555L);
ftf.test(0, 3, BACKSPACE, 22333444555L);
ftf.test(12, 2, DELETE, 223334445L);
ftf.test(9, 2, BACKSPACE, 2233344L);
ftf.test(3, 4, DELETE, 2244L);
ftf.test(0, 4, BACKSPACE, 4L);
}
Date date(DateFormat format, String spec) {
try {
return format.parse(spec);
} catch (ParseException e) {
throw new Error("Error in test");
}
}
void testDateFormat() {
DateFormat format = new SimpleDateFormat("MM/dd/yyyy", Locale.US);
TestFormattedTextField ftf = create(format);
ftf.setValue(date(format, "12/05/2005"));
System.err.println("Testing SimpleDateFormat(\"MM/dd/yyyy\", Locale.US)");
// test inserting individual characters
ftf.test(0, 0, "0", date(format, "02/05/2005"));
ftf.test(4, 0, "4", date(format, "02/04/2005"));
ftf.test(6, 0, "1", date(format, "02/04/1005"));
ftf.test(9, 0, "9", date(format, "02/04/1009"));
// test inserting several characters at once - e.g. from clipboard
ftf.test(0, 0, "11", date(format, "11/04/1009"));
ftf.test(3, 0, "23", date(format, "11/23/1009"));
ftf.test(6, 0, "191", date(format, "11/23/1919"));
// test delete
ftf.test(0, 0, DELETE, date(format, "01/23/1919"));
ftf.test(3, 0, DELETE, date(format, "01/03/1919"));
ftf.test(10, 0, DELETE, date(format, "01/03/1919"));
ftf.test(1, 0, DELETE, date(format, "12/03/1918"));
ftf.test(4, 0, DELETE, date(format, "11/30/1918"));
// test backspace
ftf.test(0, 0, BACKSPACE, date(format, "11/30/1918"));
ftf.test(1, 0, BACKSPACE, date(format, "01/30/1918"));
ftf.test(4, 0, BACKSPACE, date(format, "12/31/1917"));
ftf.test(10, 0, BACKSPACE, date(format, "12/31/0191"));
ftf.test(3, 0, BACKSPACE, date(format, "01/31/0191"));
ftf.test(5, 0, BACKSPACE, date(format, "01/03/0191"));
// test replacing selection
ftf.test(0, 1, "1", date(format, "11/03/0191"));
ftf.test(3, 1, "2", date(format, "11/23/0191"));
ftf.test(6, 2, "20", date(format, "11/23/2091"));
// test deleting selection
ftf.test(0, 1, BACKSPACE, date(format, "01/23/2091"));
ftf.test(3, 1, DELETE, date(format, "01/03/2091"));
ftf.test(6, 2, BACKSPACE, date(format, "01/03/0091"));
ftf.test(8, 1, DELETE, date(format, "01/03/0001"));
}
}

View File

@ -77,3 +77,5 @@ c0a41294297ed397098dd92b647f481f0e1bb8fa jdk7-b97
d1d7595fa824925651f09b8ffcb86c9cf39807be jdk7-b100
20a8fe72ee7b673f59c319a5222fe0eebbd92082 jdk7-b101
ff9c0a0bf7edf637a7dac5062b920924536ed79c jdk7-b102
bd85271c580ce4600b1b2d5598daa19d02174cf7 jdk7-b103
fc7219517ec16b28d729d259020a25b05ffdf0b6 jdk7-b104

View File

@ -107,7 +107,8 @@ javac.includes = \
javax/annotation/processing/ \
javax/lang/model/ \
javax/tools/ \
com/sun/source/ com/sun/tools/javac/
com/sun/source/ \
com/sun/tools/javac/
javac.tests = \
tools/javac

View File

@ -322,6 +322,35 @@
datafile="${build.coverage.dir}/cobertura.ser"/>
</target>
<target name="diags-examples" depends="build-javac">
<!-- can override the following on the command line if desired. -->
<property name="diags.examples.out" location="${build.dir}/diag-examples/diags-examples.html"/>
<mkdir dir="${build.dir}/diag-examples/classes"/>
<javac fork="true"
executable="${dist.bin.dir}/javac"
srcdir="test/tools/javac/diags"
destdir="${build.dir}/diag-examples/classes"
includes="Example.java,FileManager.java,HTMLWriter.java,RunExamples.java"
sourcepath=""
classpath="${dist.lib.dir}/javac.jar"
includeAntRuntime="no"
debug="${javac.debug}"
debuglevel="${javac.debuglevel}"/>
<java fork="true"
jvm="${target.java.home}/bin/java"
dir="test/tools/javac/diags"
classpath="${build.dir}/diag-examples/classes;${dist.lib.dir}/javac.jar"
classname="RunExamples">
<arg value="-examples"/>
<arg value="examples"/>
<arg value="-o"/>
<arg file="${diags.examples.out}"/>
<arg value="-showFiles"/>
<arg value="-title"/>
<arg value="Examples of javac diagnostics"/>
</java>
</target>
<!--
**** Debugging/diagnostic targets.

View File

@ -49,4 +49,5 @@ public interface TryTree extends StatementTree {
BlockTree getBlock();
List<? extends CatchTree> getCatches();
BlockTree getFinallyBlock();
List<? extends Tree> getResources();
}

View File

@ -209,7 +209,8 @@ public class TreeScanner<R,P> implements TreeVisitor<R,P> {
}
public R visitTry(TryTree node, P p) {
R r = scan(node.getBlock(), p);
R r = scan(node.getResources(), p);
r = scanAndReduce(node.getBlock(), p, r);
r = scanAndReduce(node.getCatches(), p, r);
r = scanAndReduce(node.getFinallyBlock(), p, r);
return r;

View File

@ -119,6 +119,7 @@ public class Lint
this.suppressedValues = other.suppressedValues.clone();
}
@Override
public String toString() {
return "Lint:[values" + values + " suppressedValues" + suppressedValues + "]";
}
@ -208,7 +209,12 @@ public class Lint
/**
* Warn about potentially unsafe vararg methods
*/
VARARGS("varargs");
VARARGS("varargs"),
/**
* Warn about arm resources
*/
ARM("arm");
LintCategory(String option) {
this(option, false);

View File

@ -159,6 +159,9 @@ public enum Source {
public boolean enforceMandatoryWarnings() {
return compareTo(JDK1_5) >= 0;
}
public boolean allowTryWithResources() {
return compareTo(JDK1_7) >= 0;
}
public boolean allowTypeAnnotations() {
return compareTo(JDK1_7) >= 0;
}

View File

@ -993,12 +993,17 @@ public abstract class Symbol implements Element {
return data == ElementKind.EXCEPTION_PARAMETER;
}
public boolean isResourceVariable() {
return data == ElementKind.RESOURCE_VARIABLE;
}
public Object getConstValue() {
// TODO: Consider if getConstValue and getConstantValue can be collapsed
if (data == ElementKind.EXCEPTION_PARAMETER) {
if (data == ElementKind.EXCEPTION_PARAMETER ||
data == ElementKind.RESOURCE_VARIABLE) {
return null;
} else if (data instanceof Callable<?>) {
// In this case, this is final a variable, with an as
// In this case, this is a final variable, with an as
// yet unevaluated initializer.
Callable<?> eval = (Callable<?>)data;
data = null; // to make sure we don't evaluate this twice.

View File

@ -148,6 +148,7 @@ public class Symtab {
public final Type inheritedType;
public final Type proprietaryType;
public final Type systemType;
public final Type autoCloseableType;
/** The symbol representing the length field of an array.
*/
@ -159,6 +160,9 @@ public class Symtab {
/** The symbol representing the final finalize method on enums */
public final MethodSymbol enumFinalFinalize;
/** The symbol representing the close method on TWR AutoCloseable type */
public final MethodSymbol autoCloseableClose;
/** The predefined type that belongs to a tag.
*/
public final Type[] typeOfTag = new Type[TypeTags.TypeTagCount];
@ -444,6 +448,12 @@ public class Symtab {
suppressWarningsType = enterClass("java.lang.SuppressWarnings");
inheritedType = enterClass("java.lang.annotation.Inherited");
systemType = enterClass("java.lang.System");
autoCloseableType = enterClass("java.lang.AutoCloseable");
autoCloseableClose = new MethodSymbol(PUBLIC,
names.close,
new MethodType(List.<Type>nil(), voidType,
List.of(exceptionType), methodClass),
autoCloseableType.tsym);
synthesizeEmptyInterfaceIfMissing(cloneableType);
synthesizeEmptyInterfaceIfMissing(serializableType);

View File

@ -192,7 +192,7 @@ public class Attr extends JCTree.Visitor {
Type check(JCTree tree, Type owntype, int ownkind, int pkind, Type pt) {
if (owntype.tag != ERROR && pt.tag != METHOD && pt.tag != FORALL) {
if ((ownkind & ~pkind) == 0) {
owntype = chk.checkType(tree.pos(), owntype, pt);
owntype = chk.checkType(tree.pos(), owntype, pt, errKey);
} else {
log.error(tree.pos(), "unexpected.type",
kindNames(pkind),
@ -239,7 +239,11 @@ public class Attr extends JCTree.Visitor {
!((base == null ||
(base.getTag() == JCTree.IDENT && TreeInfo.name(base) == names._this)) &&
isAssignableAsBlankFinal(v, env)))) {
log.error(pos, "cant.assign.val.to.final.var", v);
if (v.isResourceVariable()) { //TWR resource
log.error(pos, "twr.resource.may.not.be.assigned", v);
} else {
log.error(pos, "cant.assign.val.to.final.var", v);
}
}
}
@ -372,6 +376,10 @@ public class Attr extends JCTree.Visitor {
*/
Type pt;
/** Visitor argument: the error key to be generated when a type error occurs
*/
String errKey;
/** Visitor result: the computed type.
*/
Type result;
@ -385,13 +393,19 @@ public class Attr extends JCTree.Visitor {
* @param pt The prototype visitor argument.
*/
Type attribTree(JCTree tree, Env<AttrContext> env, int pkind, Type pt) {
return attribTree(tree, env, pkind, pt, "incompatible.types");
}
Type attribTree(JCTree tree, Env<AttrContext> env, int pkind, Type pt, String errKey) {
Env<AttrContext> prevEnv = this.env;
int prevPkind = this.pkind;
Type prevPt = this.pt;
String prevErrKey = this.errKey;
try {
this.env = env;
this.pkind = pkind;
this.pt = pt;
this.errKey = errKey;
tree.accept(this);
if (tree == breakTree)
throw new BreakAttr(env);
@ -403,6 +417,7 @@ public class Attr extends JCTree.Visitor {
this.env = prevEnv;
this.pkind = prevPkind;
this.pt = prevPt;
this.errKey = prevErrKey;
}
}
@ -412,6 +427,10 @@ public class Attr extends JCTree.Visitor {
return attribTree(tree, env, VAL, pt.tag != ERROR ? pt : Type.noType);
}
public Type attribExpr(JCTree tree, Env<AttrContext> env, Type pt, String key) {
return attribTree(tree, env, VAL, pt.tag != ERROR ? pt : Type.noType, key);
}
/** Derived visitor method: attribute an expression tree with
* no constraints on the computed type.
*/
@ -976,14 +995,34 @@ public class Attr extends JCTree.Visitor {
}
public void visitTry(JCTry tree) {
// Create a new local environment with a local
Env<AttrContext> localEnv = env.dup(tree, env.info.dup(env.info.scope.dup()));
boolean isTryWithResource = tree.resources.nonEmpty();
// Create a nested environment for attributing the try block if needed
Env<AttrContext> tryEnv = isTryWithResource ?
env.dup(tree, localEnv.info.dup(localEnv.info.scope.dup())) :
localEnv;
// Attribute resource declarations
for (JCTree resource : tree.resources) {
if (resource.getTag() == JCTree.VARDEF) {
attribStat(resource, tryEnv);
chk.checkType(resource, resource.type, syms.autoCloseableType, "twr.not.applicable.to.type");
VarSymbol var = (VarSymbol)TreeInfo.symbolFor(resource);
var.setData(ElementKind.RESOURCE_VARIABLE);
} else {
attribExpr(resource, tryEnv, syms.autoCloseableType, "twr.not.applicable.to.type");
}
}
// Attribute body
attribStat(tree.body, env.dup(tree, env.info.dup()));
attribStat(tree.body, tryEnv);
if (isTryWithResource)
tryEnv.info.scope.leave();
// Attribute catch clauses
for (List<JCCatch> l = tree.catchers; l.nonEmpty(); l = l.tail) {
JCCatch c = l.head;
Env<AttrContext> catchEnv =
env.dup(c, env.info.dup(env.info.scope.dup()));
localEnv.dup(c, localEnv.info.dup(localEnv.info.scope.dup()));
Type ctype = attribStat(c.param, catchEnv);
if (TreeInfo.isMultiCatch(c)) {
//check that multi-catch parameter is marked as final
@ -1003,7 +1042,9 @@ public class Attr extends JCTree.Visitor {
}
// Attribute finalizer
if (tree.finalizer != null) attribStat(tree.finalizer, env);
if (tree.finalizer != null) attribStat(tree.finalizer, localEnv);
localEnv.info.scope.leave();
result = null;
}
@ -1653,8 +1694,22 @@ public class Attr extends JCTree.Visitor {
//if the type of the instance creation expression is an interface
//skip the method resolution step (JLS 15.12.2.7). The type to be
//inferred is of the kind <X1,X2, ... Xn>C<X1,X2, ... Xn>
clazztype = new ForAll(clazztype.tsym.type.allparams(),
clazztype.tsym.type);
clazztype = new ForAll(clazztype.tsym.type.allparams(), clazztype.tsym.type) {
@Override
public List<Type> getConstraints(TypeVar tv, ConstraintKind ck) {
switch (ck) {
case EXTENDS: return types.getBounds(tv);
default: return List.nil();
}
}
@Override
public Type inst(List<Type> inferred, Types types) throws Infer.NoInstanceException {
// check that inferred bounds conform to their bounds
infer.checkWithinBounds(tvars,
types.subst(tvars, tvars, inferred), Warner.noWarnings);
return super.inst(inferred, types);
}
};
} else {
//if the type of the instance creation expression is a class type
//apply method resolution inference (JLS 15.12.2.7). The return type
@ -2139,6 +2194,15 @@ public class Attr extends JCTree.Visitor {
checkAssignable(tree.pos(), v, tree.selected, env);
}
if (sitesym != null &&
sitesym.kind == VAR &&
((VarSymbol)sitesym).isResourceVariable() &&
sym.kind == MTH &&
sym.overrides(syms.autoCloseableClose, sitesym.type.tsym, types, true) &&
env.info.lint.isEnabled(Lint.LintCategory.ARM)) {
log.warning(tree, "twr.explicit.close.call");
}
// Disallow selecting a type from an expression
if (isType(sym) && (sitesym==null || (sitesym.kind&(TYP|PCK)) == 0)) {
tree.type = check(tree.selected, pt,
@ -3061,7 +3125,8 @@ public class Attr extends JCTree.Visitor {
Scope.Entry e = c.members().lookup(names.serialVersionUID);
while (e.scope != null && e.sym.kind != VAR) e = e.next();
if (e.scope == null) {
log.warning(tree.pos(), "missing.SVUID", c);
log.warning(Lint.LintCategory.SERIAL,
tree.pos(), "missing.SVUID", c);
return;
}
@ -3069,15 +3134,18 @@ public class Attr extends JCTree.Visitor {
VarSymbol svuid = (VarSymbol)e.sym;
if ((svuid.flags() & (STATIC | FINAL)) !=
(STATIC | FINAL))
log.warning(TreeInfo.diagnosticPositionFor(svuid, tree), "improper.SVUID", c);
log.warning(Lint.LintCategory.SERIAL,
TreeInfo.diagnosticPositionFor(svuid, tree), "improper.SVUID", c);
// check that it is long
else if (svuid.type.tag != TypeTags.LONG)
log.warning(TreeInfo.diagnosticPositionFor(svuid, tree), "long.SVUID", c);
log.warning(Lint.LintCategory.SERIAL,
TreeInfo.diagnosticPositionFor(svuid, tree), "long.SVUID", c);
// check constant
else if (svuid.getConstValue() == null)
log.warning(TreeInfo.diagnosticPositionFor(svuid, tree), "constant.SVUID", c);
log.warning(Lint.LintCategory.SERIAL,
TreeInfo.diagnosticPositionFor(svuid, tree), "constant.SVUID", c);
}
private Type capture(Type type) {

View File

@ -111,13 +111,13 @@ public class Check {
boolean enforceMandatoryWarnings = source.enforceMandatoryWarnings();
deprecationHandler = new MandatoryWarningHandler(log, verboseDeprecated,
enforceMandatoryWarnings, "deprecated");
enforceMandatoryWarnings, "deprecated", LintCategory.DEPRECATION);
uncheckedHandler = new MandatoryWarningHandler(log, verboseUnchecked,
enforceMandatoryWarnings, "unchecked");
enforceMandatoryWarnings, "unchecked", LintCategory.UNCHECKED);
unsafeVarargsHandler = new MandatoryWarningHandler(log, verboseVarargs,
enforceMandatoryWarnings, "varargs");
enforceMandatoryWarnings, "varargs", LintCategory.VARARGS);
sunApiHandler = new MandatoryWarningHandler(log, verboseSunApi,
enforceMandatoryWarnings, "sunapi");
enforceMandatoryWarnings, "sunapi", null);
}
/** Switch: generics enabled?
@ -209,7 +209,7 @@ public class Check {
public void warnStatic(DiagnosticPosition pos, String msg, Object... args) {
if (lint.isEnabled(LintCategory.STATIC))
log.warning(pos, msg, args);
log.warning(LintCategory.STATIC, pos, msg, args);
}
/**
@ -393,6 +393,10 @@ public class Check {
* @param req The type that was required.
*/
Type checkType(DiagnosticPosition pos, Type found, Type req) {
return checkType(pos, found, req, "incompatible.types");
}
Type checkType(DiagnosticPosition pos, Type found, Type req, String errKey) {
if (req.tag == ERROR)
return req;
if (found.tag == FORALL)
@ -411,7 +415,7 @@ public class Check {
log.error(pos, "assignment.to.extends-bound", req);
return types.createErrorType(found);
}
return typeError(pos, diags.fragment("incompatible.types"), found, req);
return typeError(pos, diags.fragment(errKey), found, req);
}
/** Instantiate polymorphic type to some prototype, unless
@ -925,7 +929,8 @@ public class Check {
!TreeInfo.isDiamond(tree) &&
!env.enclClass.name.isEmpty() && //anonymous or intersection
tree.type.isRaw()) {
log.warning(tree.pos(), "raw.class.use", tree.type, tree.type.tsym.type);
log.warning(Lint.LintCategory.RAW,
tree.pos(), "raw.class.use", tree.type, tree.type.tsym.type);
}
}
@ -1853,6 +1858,7 @@ public class Check {
types.isSameType(types.erasure(sym.type), types.erasure(e.sym.type)) &&
sym != e.sym &&
(sym.flags() & Flags.SYNTHETIC) != (e.sym.flags() & Flags.SYNTHETIC) &&
(sym.flags() & IPROXY) == 0 && (e.sym.flags() & IPROXY) == 0 &&
(sym.flags() & BRIDGE) == 0 && (e.sym.flags() & BRIDGE) == 0) {
syntheticError(pos, (e.sym.flags() & SYNTHETIC) == 0 ? e.sym : sym);
return;
@ -2151,7 +2157,8 @@ public class Check {
(s.flags() & DEPRECATED) != 0 &&
!syms.deprecatedType.isErroneous() &&
s.attribute(syms.deprecatedType.tsym) == null) {
log.warning(pos, "missing.deprecated.annotation");
log.warning(Lint.LintCategory.DEP_ANN,
pos, "missing.deprecated.annotation");
}
}
@ -2302,7 +2309,7 @@ public class Check {
int opc = ((OperatorSymbol)operator).opcode;
if (opc == ByteCodes.idiv || opc == ByteCodes.imod
|| opc == ByteCodes.ldiv || opc == ByteCodes.lmod) {
log.warning(pos, "div.zero");
log.warning(Lint.LintCategory.DIVZERO, pos, "div.zero");
}
}
}
@ -2312,7 +2319,7 @@ public class Check {
*/
void checkEmptyIf(JCIf tree) {
if (tree.thenpart.getTag() == JCTree.SKIP && tree.elsepart == null && lint.isEnabled(Lint.LintCategory.EMPTY))
log.warning(tree.thenpart.pos(), "empty.if");
log.warning(Lint.LintCategory.EMPTY, tree.thenpart.pos(), "empty.if");
}
/** Check that symbol is unique in given scope.

View File

@ -28,6 +28,8 @@
package com.sun.tools.javac.comp;
import java.util.HashMap;
import java.util.Map;
import java.util.LinkedHashMap;
import com.sun.tools.javac.code.*;
import com.sun.tools.javac.tree.*;
@ -35,6 +37,7 @@ import com.sun.tools.javac.util.*;
import com.sun.tools.javac.util.JCDiagnostic.DiagnosticPosition;
import com.sun.tools.javac.code.Symbol.*;
import com.sun.tools.javac.comp.Resolve;
import com.sun.tools.javac.tree.JCTree.*;
import static com.sun.tools.javac.code.Flags.*;
@ -185,6 +188,8 @@ public class Flow extends TreeScanner {
private final Types types;
private final Check chk;
private TreeMaker make;
private final Resolve rs;
private Env<AttrContext> attrEnv;
private Lint lint;
private final boolean allowRethrowAnalysis;
@ -203,6 +208,7 @@ public class Flow extends TreeScanner {
types = Types.instance(context);
chk = Check.instance(context);
lint = Lint.instance(context);
rs = Resolve.instance(context);
Source source = Source.instance(context);
allowRethrowAnalysis = source.allowMulticatch();
}
@ -265,6 +271,10 @@ public class Flow extends TreeScanner {
*/
List<Type> caught;
/** The list of unreferenced automatic resources.
*/
Map<VarSymbol, JCVariableDecl> unrefdResources;
/** Set when processing a loop body the second time for DU analysis. */
boolean loopPassTwo = false;
@ -936,7 +946,8 @@ public class Flow extends TreeScanner {
alive &&
lint.isEnabled(Lint.LintCategory.FALLTHROUGH) &&
c.stats.nonEmpty() && l.tail.nonEmpty())
log.warning(l.tail.head.pos(),
log.warning(Lint.LintCategory.FALLTHROUGH,
l.tail.head.pos(),
"possible.fall-through.into.case");
}
if (!hasDefault) {
@ -963,6 +974,7 @@ public class Flow extends TreeScanner {
public void visitTry(JCTry tree) {
List<Type> caughtPrev = caught;
List<Type> thrownPrev = thrown;
Map<VarSymbol, JCVariableDecl> unrefdResourcesPrev = unrefdResources;
thrown = List.nil();
for (List<JCCatch> l = tree.catchers; l.nonEmpty(); l = l.tail) {
List<JCExpression> subClauses = TreeInfo.isMultiCatch(l.head) ?
@ -977,6 +989,38 @@ public class Flow extends TreeScanner {
pendingExits = new ListBuffer<PendingExit>();
Bits initsTry = inits.dup();
uninitsTry = uninits.dup();
unrefdResources = new LinkedHashMap<VarSymbol, JCVariableDecl>();
for (JCTree resource : tree.resources) {
if (resource instanceof JCVariableDecl) {
JCVariableDecl vdecl = (JCVariableDecl) resource;
visitVarDef(vdecl);
unrefdResources.put(vdecl.sym, vdecl);
} else if (resource instanceof JCExpression) {
scanExpr((JCExpression) resource);
} else {
throw new AssertionError(tree); // parser error
}
}
for (JCTree resource : tree.resources) {
List<Type> closeableSupertypes = resource.type.isCompound() ?
types.interfaces(resource.type).prepend(types.supertype(resource.type)) :
List.of(resource.type);
for (Type sup : closeableSupertypes) {
if (types.asSuper(sup, syms.autoCloseableType.tsym) != null) {
Symbol closeMethod = rs.resolveInternalMethod(tree,
attrEnv,
sup,
names.close,
List.<Type>nil(),
List.<Type>nil());
if (closeMethod.kind == MTH) {
for (Type t : ((MethodSymbol)closeMethod).getThrownTypes()) {
markThrown(tree.body, t);
}
}
}
}
}
scanStat(tree.body);
List<Type> thrownInTry = thrown;
thrown = thrownPrev;
@ -987,6 +1031,14 @@ public class Flow extends TreeScanner {
Bits uninitsEnd = uninits;
int nextadrCatch = nextadr;
if (!unrefdResources.isEmpty() &&
lint.isEnabled(Lint.LintCategory.ARM)) {
for (Map.Entry<VarSymbol, JCVariableDecl> e : unrefdResources.entrySet()) {
log.warning(e.getValue().pos(),
"automatic.resource.not.referenced", e.getKey());
}
}
List<Type> caughtInTry = List.nil();
for (List<JCCatch> l = tree.catchers; l.nonEmpty(); l = l.tail) {
alive = true;
@ -1040,8 +1092,9 @@ public class Flow extends TreeScanner {
thrown = chk.union(thrown, thrownPrev);
if (!loopPassTwo &&
lint.isEnabled(Lint.LintCategory.FINALLY)) {
log.warning(TreeInfo.diagEndPos(tree.finalizer),
"finally.cannot.complete");
log.warning(Lint.LintCategory.FINALLY,
TreeInfo.diagEndPos(tree.finalizer),
"finally.cannot.complete");
}
} else {
thrown = chk.union(thrown, chk.diff(thrownInTry, caughtInTry));
@ -1070,6 +1123,7 @@ public class Flow extends TreeScanner {
while (exits.nonEmpty()) pendingExits.append(exits.next());
}
uninitsTry.andSet(uninitsTryPrev).andSet(uninits);
unrefdResources = unrefdResourcesPrev;
}
public void visitConditional(JCConditional tree) {
@ -1293,8 +1347,16 @@ public class Flow extends TreeScanner {
}
public void visitIdent(JCIdent tree) {
if (tree.sym.kind == VAR)
if (tree.sym.kind == VAR) {
checkInit(tree.pos(), (VarSymbol)tree.sym);
referenced(tree.sym);
}
}
void referenced(Symbol sym) {
if (unrefdResources != null && unrefdResources.containsKey(sym)) {
unrefdResources.remove(sym);
}
}
public void visitTypeCast(JCTypeCast tree) {
@ -1303,7 +1365,8 @@ public class Flow extends TreeScanner {
&& lint.isEnabled(Lint.LintCategory.CAST)
&& types.isSameType(tree.expr.type, tree.clazz.type)
&& !(ignoreAnnotatedCasts && containsTypeAnnotation(tree.clazz))) {
log.warning(tree.pos(), "redundant.cast", tree.expr.type);
log.warning(Lint.LintCategory.CAST,
tree.pos(), "redundant.cast", tree.expr.type);
}
}
@ -1334,8 +1397,10 @@ public class Flow extends TreeScanner {
/** Perform definite assignment/unassignment analysis on a tree.
*/
public void analyzeTree(JCTree tree, TreeMaker make) {
public void analyzeTree(Env<AttrContext> env, TreeMaker make) {
try {
attrEnv = env;
JCTree tree = env.tree;
this.make = make;
inits = new Bits();
uninits = new Bits();

View File

@ -256,7 +256,7 @@ public class Infer {
UndetVar uv = (UndetVar) l.head;
TypeVar tv = (TypeVar)uv.qtype;
ListBuffer<Type> hibounds = new ListBuffer<Type>();
for (Type t : that.getConstraints(tv, ConstraintKind.EXTENDS).prependList(types.getBounds(tv))) {
for (Type t : that.getConstraints(tv, ConstraintKind.EXTENDS)) {
if (!t.containsSome(that.tvars) && t.tag != BOT) {
hibounds.append(t);
}
@ -280,7 +280,6 @@ public class Infer {
// check bounds
List<Type> targs = Type.map(undetvars, getInstFun);
targs = types.subst(targs, that.tvars, targs);
checkWithinBounds(that.tvars, targs, warn);
return chk.checkType(warn.pos(), that.inst(targs, types), to);
}
@ -398,7 +397,7 @@ public class Infer {
UndetVar uv = (UndetVar)t;
if (uv.qtype == tv) {
switch (ck) {
case EXTENDS: return uv.hibounds;
case EXTENDS: return uv.hibounds.appendList(types.subst(types.getBounds(tv), all_tvars, inferredTypes));
case SUPER: return uv.lobounds;
case EQUAL: return uv.inst != null ? List.of(uv.inst) : List.<Type>nil();
}
@ -458,7 +457,7 @@ public class Infer {
/** check that type parameters are within their bounds.
*/
private void checkWithinBounds(List<Type> tvars,
void checkWithinBounds(List<Type> tvars,
List<Type> arguments,
Warner warn)
throws InvalidInstanceException {

View File

@ -605,6 +605,23 @@ public class Lower extends TreeTranslator {
s.enter(sym);
}
/** Create a fresh synthetic name within a given scope - the unique name is
* obtained by appending '$' chars at the end of the name until no match
* is found.
*
* @param name base name
* @param s scope in which the name has to be unique
* @return fresh synthetic name
*/
private Name makeSyntheticName(Name name, Scope s) {
do {
name = name.append(
target.syntheticNameChar(),
names.empty);
} while (lookupSynthetic(name, s) != null);
return name;
}
/** Check whether synthetic symbols generated during lowering conflict
* with user-defined symbols.
*
@ -1299,6 +1316,11 @@ public class Lower extends TreeTranslator {
*/
Scope proxies;
/** A scope containing all unnamed resource variables/saved
* exception variables for translated TWR blocks
*/
Scope twrVars;
/** A stack containing the this$n field of the currently translated
* classes (if needed) in innermost first order.
* Inside a constructor, proxies and any this$n symbol are duplicated
@ -1400,6 +1422,122 @@ public class Lower extends TreeTranslator {
}
}
/** Optionally replace a try statement with an automatic resource
* management (ARM) block.
* @param tree The try statement to inspect.
* @return An ARM block, or the original try block if there are no
* resources to manage.
*/
JCTree makeArmTry(JCTry tree) {
make_at(tree.pos());
twrVars = twrVars.dup();
JCBlock armBlock = makeArmBlock(tree.resources, tree.body, 0);
if (tree.catchers.isEmpty() && tree.finalizer == null)
result = translate(armBlock);
else
result = translate(make.Try(armBlock, tree.catchers, tree.finalizer));
twrVars = twrVars.leave();
return result;
}
private JCBlock makeArmBlock(List<JCTree> resources, JCBlock block, int depth) {
if (resources.isEmpty())
return block;
// Add resource declaration or expression to block statements
ListBuffer<JCStatement> stats = new ListBuffer<JCStatement>();
JCTree resource = resources.head;
JCExpression expr = null;
if (resource instanceof JCVariableDecl) {
JCVariableDecl var = (JCVariableDecl) resource;
expr = make.Ident(var.sym).setType(resource.type);
stats.add(var);
} else {
assert resource instanceof JCExpression;
VarSymbol syntheticTwrVar =
new VarSymbol(SYNTHETIC | FINAL,
makeSyntheticName(names.fromString("twrVar" +
depth), twrVars),
(resource.type.tag == TypeTags.BOT) ?
syms.autoCloseableType : resource.type,
currentMethodSym);
twrVars.enter(syntheticTwrVar);
JCVariableDecl syntheticTwrVarDecl =
make.VarDef(syntheticTwrVar, (JCExpression)resource);
expr = (JCExpression)make.Ident(syntheticTwrVar);
stats.add(syntheticTwrVarDecl);
}
// Add primaryException declaration
VarSymbol primaryException =
new VarSymbol(SYNTHETIC,
makeSyntheticName(names.fromString("primaryException" +
depth), twrVars),
syms.throwableType,
currentMethodSym);
twrVars.enter(primaryException);
JCVariableDecl primaryExceptionTreeDecl = make.VarDef(primaryException, makeNull());
stats.add(primaryExceptionTreeDecl);
// Create catch clause that saves exception and then rethrows it
VarSymbol param =
new VarSymbol(FINAL|SYNTHETIC,
names.fromString("t" +
target.syntheticNameChar()),
syms.throwableType,
currentMethodSym);
JCVariableDecl paramTree = make.VarDef(param, null);
JCStatement assign = make.Assignment(primaryException, make.Ident(param));
JCStatement rethrowStat = make.Throw(make.Ident(param));
JCBlock catchBlock = make.Block(0L, List.<JCStatement>of(assign, rethrowStat));
JCCatch catchClause = make.Catch(paramTree, catchBlock);
int oldPos = make.pos;
make.at(TreeInfo.endPos(block));
JCBlock finallyClause = makeArmFinallyClause(primaryException, expr);
make.at(oldPos);
JCTry outerTry = make.Try(makeArmBlock(resources.tail, block, depth + 1),
List.<JCCatch>of(catchClause),
finallyClause);
stats.add(outerTry);
return make.Block(0L, stats.toList());
}
private JCBlock makeArmFinallyClause(Symbol primaryException, JCExpression resource) {
// primaryException.addSuppressedException(catchException);
VarSymbol catchException =
new VarSymbol(0, make.paramName(2),
syms.throwableType,
currentMethodSym);
JCStatement addSuppressionStatement =
make.Exec(makeCall(make.Ident(primaryException),
names.fromString("addSuppressedException"),
List.<JCExpression>of(make.Ident(catchException))));
// try { resource.close(); } catch (e) { primaryException.addSuppressedException(e); }
JCBlock tryBlock =
make.Block(0L, List.<JCStatement>of(makeResourceCloseInvocation(resource)));
JCVariableDecl catchExceptionDecl = make.VarDef(catchException, null);
JCBlock catchBlock = make.Block(0L, List.<JCStatement>of(addSuppressionStatement));
List<JCCatch> catchClauses = List.<JCCatch>of(make.Catch(catchExceptionDecl, catchBlock));
JCTry tryTree = make.Try(tryBlock, catchClauses, null);
// if (resource != null) resourceClose;
JCExpression nullCheck = makeBinary(JCTree.NE,
make.Ident(primaryException),
makeNull());
JCIf closeIfStatement = make.If(nullCheck,
tryTree,
makeResourceCloseInvocation(resource));
return make.Block(0L, List.<JCStatement>of(closeIfStatement));
}
private JCStatement makeResourceCloseInvocation(JCExpression resource) {
// create resource.close() method invocation
JCExpression resourceClose = makeCall(resource, names.close, List.<JCExpression>nil());
return make.Exec(resourceClose);
}
/** Construct a tree that represents the outer instance
* <C.this>. Never pick the current `this'.
* @param pos The source code position to be used for the tree.
@ -3405,6 +3543,15 @@ public class Lower extends TreeTranslator {
result = tree;
}
@Override
public void visitTry(JCTry tree) {
if (tree.resources.isEmpty()) {
super.visitTry(tree);
} else {
result = makeArmTry(tree);
}
}
/**************************************************************************
* main method
*************************************************************************/
@ -3430,6 +3577,7 @@ public class Lower extends TreeTranslator {
actualSymbols = new HashMap<Symbol,Symbol>();
freevarCache = new HashMap<ClassSymbol,List<VarSymbol>>();
proxies = new Scope(syms.noSymbol);
twrVars = new Scope(syms.noSymbol);
outerThisStack = List.nil();
accessNums = new HashMap<Symbol,Integer>();
accessSyms = new HashMap<Symbol,MethodSymbol[]>();

View File

@ -1797,13 +1797,13 @@ public class Resolve {
return null;
if (isOperator(name)) {
return diags.create(dkind, false, log.currentSource(), pos,
return diags.create(dkind, log.currentSource(), pos,
"operator.cant.be.applied", name, argtypes);
}
boolean hasLocation = false;
if (!site.tsym.name.isEmpty()) {
if (site.tsym.kind == PCK && !site.tsym.exists()) {
return diags.create(dkind, false, log.currentSource(), pos,
return diags.create(dkind, log.currentSource(), pos,
"doesnt.exist", site.tsym);
}
hasLocation = true;
@ -1814,13 +1814,13 @@ public class Resolve {
Name idname = isConstructor ? site.tsym.name : name;
String errKey = getErrorKey(kindname, typeargtypes.nonEmpty(), hasLocation);
if (hasLocation) {
return diags.create(dkind, false, log.currentSource(), pos,
return diags.create(dkind, log.currentSource(), pos,
errKey, kindname, idname, //symbol kindname, name
typeargtypes, argtypes, //type parameters and arguments (if any)
typeKindName(site), site); //location kindname, type
}
else {
return diags.create(dkind, false, log.currentSource(), pos,
return diags.create(dkind, log.currentSource(), pos,
errKey, kindname, idname, //symbol kindname, name
typeargtypes, argtypes); //type parameters and arguments (if any)
}
@ -1886,12 +1886,12 @@ public class Resolve {
return null;
if (isOperator(name)) {
return diags.create(dkind, false, log.currentSource(),
return diags.create(dkind, log.currentSource(),
pos, "operator.cant.be.applied", name, argtypes);
}
else {
Symbol ws = sym.asMemberOf(site, types);
return diags.create(dkind, false, log.currentSource(), pos,
return diags.create(dkind, log.currentSource(), pos,
"cant.apply.symbol" + (explanation != null ? ".1" : ""),
kindName(ws),
ws.name == names.init ? ws.owner.name : ws.name,
@ -1974,18 +1974,18 @@ public class Resolve {
else if ((sym.flags() & PUBLIC) != 0
|| (env != null && this.site != null
&& !isAccessible(env, this.site))) {
return diags.create(dkind, false, log.currentSource(),
return diags.create(dkind, log.currentSource(),
pos, "not.def.access.class.intf.cant.access",
sym, sym.location());
}
else if ((sym.flags() & (PRIVATE | PROTECTED)) != 0) {
return diags.create(dkind, false, log.currentSource(),
return diags.create(dkind, log.currentSource(),
pos, "report.access", sym,
asFlagSet(sym.flags() & (PRIVATE | PROTECTED)),
sym.location());
}
else {
return diags.create(dkind, false, log.currentSource(),
return diags.create(dkind, log.currentSource(),
pos, "not.def.public.cant.access", sym, sym.location());
}
}
@ -2011,7 +2011,7 @@ public class Resolve {
Symbol errSym = ((sym.kind == TYP && sym.type.tag == CLASS)
? types.erasure(sym.type).tsym
: sym);
return diags.create(dkind, false, log.currentSource(), pos,
return diags.create(dkind, log.currentSource(), pos,
"non-static.cant.be.ref", kindName(sym), errSym);
}
}
@ -2048,7 +2048,7 @@ public class Resolve {
}
Name sname = pair.sym.name;
if (sname == names.init) sname = pair.sym.owner.name;
return diags.create(dkind, false, log.currentSource(),
return diags.create(dkind, log.currentSource(),
pos, "ref.ambiguous", sname,
kindName(pair.sym),
pair.sym,

View File

@ -535,6 +535,14 @@ public class TransTypes extends TreeTranslator {
result = tree;
}
public void visitTry(JCTry tree) {
tree.resources = translate(tree.resources, syms.autoCloseableType);
tree.body = translate(tree.body);
tree.catchers = translateCatchers(tree.catchers);
tree.finalizer = translate(tree.finalizer);
result = tree;
}
public void visitConditional(JCConditional tree) {
tree.cond = translate(tree.cond, syms.booleanType);
tree.truepart = translate(tree.truepart, erasure(tree.type));

View File

@ -246,7 +246,8 @@ public class Paths {
private void addDirectory(File dir, boolean warn) {
if (!dir.isDirectory()) {
if (warn)
log.warning("dir.path.element.not.found", dir);
log.warning(Lint.LintCategory.PATH,
"dir.path.element.not.found", dir);
return;
}
@ -280,8 +281,10 @@ public class Paths {
if (! fsInfo.exists(file)) {
/* No such file or directory exists */
if (warn)
log.warning("path.element.not.found", file);
if (warn) {
log.warning(Lint.LintCategory.PATH,
"path.element.not.found", file);
}
} else if (fsInfo.isFile(file)) {
/* File is an ordinary file. */
if (!isArchive(file)) {
@ -290,12 +293,16 @@ public class Paths {
try {
ZipFile z = new ZipFile(file);
z.close();
if (warn)
log.warning("unexpected.archive.file", file);
if (warn) {
log.warning(Lint.LintCategory.PATH,
"unexpected.archive.file", file);
}
} catch (IOException e) {
// FIXME: include e.getLocalizedMessage in warning
if (warn)
log.warning("invalid.archive.file", file);
if (warn) {
log.warning(Lint.LintCategory.PATH,
"invalid.archive.file", file);
}
return;
}
}

View File

@ -325,6 +325,7 @@ implements CRTFlags {
public void visitTry(JCTry tree) {
SourceRange sr = new SourceRange(startPos(tree), endPos(tree));
sr.mergeWith(csp(tree.resources));
sr.mergeWith(csp(tree.body));
sr.mergeWith(cspCatchers(tree.catchers));
sr.mergeWith(csp(tree.finalizer));

View File

@ -2628,7 +2628,7 @@ public class ClassReader implements Completer {
* @param arg An argument for substitution into the output string.
*/
private void printVerbose(String key, CharSequence arg) {
Log.printLines(log.noticeWriter, Log.getLocalizedString("verbose." + key, arg));
log.printNoteLines("verbose." + key, arg);
}
/** Output for "-checkclassfile" option.
@ -2636,7 +2636,7 @@ public class ClassReader implements Completer {
* @param arg An argument for substitution into the output string.
*/
private void printCCF(String key, Object arg) {
Log.printLines(log.noticeWriter, Log.getLocalizedString(key, arg));
log.printNoteLines(key, arg);
}

View File

@ -1604,7 +1604,7 @@ public class ClassWriter extends ClassFile {
try {
writeClassFile(out, c);
if (verbose)
log.errWriter.println(Log.getLocalizedString("verbose.wrote.file", outFile));
log.printErrLines("verbose.wrote.file", outFile);
out.close();
out = null;
} finally {

Some files were not shown because too many files have changed in this diff Show More