This commit is contained in:
Lana Steuck 2010-03-04 13:40:03 -08:00
commit 954fd4b4d9
120 changed files with 2045 additions and 737 deletions

View File

@ -58,3 +58,4 @@ e6abd38682d237306d6c147c17538ec9e7f8e3a7 jdk7-b80
dcc938ac40cc45f1ef454d76020b5db5d943001c jdk7-b81
a30062be6d9ca1d48579826f870f85974300004e jdk7-b82
34c8199936a1682aa8587857f44cfaf37c2b6381 jdk7-b83
b1e55627a6980b9508854ed0c0f21d4f981b4494 jdk7-b84

View File

@ -58,3 +58,4 @@ a3242906c7747b5d9bcc3d118c7c3c69aa40f4b7 jdk7-b80
8403096d1fe7ff5318df9708cfec84a3fd3e1cf9 jdk7-b81
e1176f86805fe07fd9fb9da065dc51b47712ce76 jdk7-b82
6880a3af9addb41541e80ebe8cde6f79ec402a58 jdk7-b83
2f3ea057d1ad56cf3b269cdc4de2741411151982 jdk7-b84

View File

@ -58,3 +58,4 @@ ec0421b5703b677e2226cf4bf7ae4eaafd8061c5 jdk7-b79
e08a42a2a94d97ea8eedb187a94dbff822c8fbba jdk7-b81
1e8c1bfad1abb4b81407a0f2645e0fb85764ca48 jdk7-b82
fde0df7a2384f7fe33204a79678989807d9c2b98 jdk7-b83
68c8961a82e4a3ad2a67991e5d834192a81eb4cd jdk7-b84

View File

@ -80,3 +80,4 @@ ac59d4e6dae51ac5fc31a9a4940d1857f91161b1 hs16-b08
9ab385cb0c42997e16a7761ebcd25c90560a2714 hs15-b04
fafab5d5349c7c066d677538db67a1ee0fb33bd2 hs15-b05
3f370a32906eb5ba993fabd7b4279be7f31052b9 jdk7-b83
ffc8d176b84bcfb5ac21302b4feb3b0c0d69b97c jdk7-b84

View File

@ -35,7 +35,7 @@ HOTSPOT_VM_COPYRIGHT=Copyright 2009
HS_MAJOR_VER=17
HS_MINOR_VER=0
HS_BUILD_NUMBER=09
HS_BUILD_NUMBER=10
JDK_MAJOR_VER=1
JDK_MINOR_VER=7

View File

@ -2730,9 +2730,6 @@ void LIR_Assembler::emit_profile_call(LIR_OpProfileCall* op) {
}
Address counter_addr(mdo, md->byte_offset_of_slot(data, CounterData::count_offset()) - mdo_offset_bias);
__ lduw(counter_addr, tmp1);
__ add(tmp1, DataLayout::counter_increment, tmp1);
__ stw(tmp1, counter_addr);
Bytecodes::Code bc = method->java_code_at_bci(bci);
// Perform additional virtual call profiling for invokevirtual and
// invokeinterface bytecodes
@ -2822,15 +2819,23 @@ void LIR_Assembler::emit_profile_call(LIR_OpProfileCall* op) {
__ set(DataLayout::counter_increment, tmp1);
__ st_ptr(tmp1, mdo, md->byte_offset_of_slot(data, VirtualCallData::receiver_count_offset(i)) -
mdo_offset_bias);
if (i < (VirtualCallData::row_limit() - 1)) {
__ br(Assembler::always, false, Assembler::pt, update_done);
__ delayed()->nop();
}
__ br(Assembler::always, false, Assembler::pt, update_done);
__ delayed()->nop();
__ bind(next_test);
}
// Receiver did not match any saved receiver and there is no empty row for it.
// Increment total counter to indicate polymorphic case.
__ lduw(counter_addr, tmp1);
__ add(tmp1, DataLayout::counter_increment, tmp1);
__ stw(tmp1, counter_addr);
__ bind(update_done);
}
} else {
// Static call
__ lduw(counter_addr, tmp1);
__ add(tmp1, DataLayout::counter_increment, tmp1);
__ stw(tmp1, counter_addr);
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright 1997-2009 Sun Microsystems, Inc. All Rights Reserved.
* Copyright 1997-2010 Sun Microsystems, Inc. All Rights Reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -1733,7 +1733,7 @@ void InterpreterMacroAssembler::record_klass_in_profile_helper(
brx(Assembler::zero, false, Assembler::pn, found_null);
delayed()->nop();
// Receiver did not match any saved receiver and there is no empty row for it.
// Increment total counter to indicate polimorphic case.
// Increment total counter to indicate polymorphic case.
increment_mdp_data_at(in_bytes(CounterData::count_offset()), scratch);
ba(false, done);
delayed()->nop();

View File

@ -851,10 +851,10 @@ void AdapterGenerator::gen_c2i_adapter(
__ set(reg2offset(r_1) + extraspace + bias, ld_off);
#else
int ld_off = reg2offset(r_1) + extraspace + bias;
#endif // _LP64
#ifdef ASSERT
G1_forced = true;
#endif // ASSERT
#endif // _LP64
r_1 = G1_scratch->as_VMReg();// as part of the load/store shuffle
if (!r_2->is_valid()) __ ld (base, ld_off, G1_scratch);
else __ ldx(base, ld_off, G1_scratch);
@ -865,9 +865,11 @@ void AdapterGenerator::gen_c2i_adapter(
if (sig_bt[i] == T_OBJECT || sig_bt[i] == T_ARRAY) {
store_c2i_object(r, base, st_off);
} else if (sig_bt[i] == T_LONG || sig_bt[i] == T_DOUBLE) {
#ifndef _LP64
if (TieredCompilation) {
assert(G1_forced || sig_bt[i] != T_LONG, "should not use register args for longs");
}
#endif // _LP64
store_c2i_long(r, base, st_off, r_2->is_stack());
} else {
store_c2i_int(r, base, st_off);

View File

@ -3279,7 +3279,7 @@ void LIR_Assembler::emit_profile_call(LIR_OpProfileCall* op) {
__ bind(next_test);
}
// Receiver did not match any saved receiver and there is no empty row for it.
// Increment total counter to indicate polimorphic case.
// Increment total counter to indicate polymorphic case.
__ addl(counter_addr, DataLayout::counter_increment);
__ bind(update_done);

View File

@ -233,7 +233,8 @@ inline intptr_t* frame::interpreter_frame_tos_address() const {
} else {
// sp() may have been extended or shrunk by an adapter. At least
// check that we don't fall behind the legal region.
assert(last_sp < (intptr_t*) interpreter_frame_monitor_begin(), "bad tos");
// For top deoptimized frame last_sp == interpreter_frame_monitor_end.
assert(last_sp <= (intptr_t*) interpreter_frame_monitor_end(), "bad tos");
return last_sp;
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright 1997-2009 Sun Microsystems, Inc. All Rights Reserved.
* Copyright 1997-2010 Sun Microsystems, Inc. All Rights Reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -1308,7 +1308,7 @@ void InterpreterMacroAssembler::record_klass_in_profile_helper(
if (is_virtual_call) {
jccb(Assembler::zero, found_null);
// Receiver did not match any saved receiver and there is no empty row for it.
// Increment total counter to indicate polimorphic case.
// Increment total counter to indicate polymorphic case.
increment_mdp_data_at(mdp, in_bytes(CounterData::count_offset()));
jmp(done);
bind(found_null);

View File

@ -1,5 +1,5 @@
/*
* Copyright 2003-2009 Sun Microsystems, Inc. All Rights Reserved.
* Copyright 2003-2010 Sun Microsystems, Inc. All Rights Reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -1341,7 +1341,7 @@ void InterpreterMacroAssembler::record_klass_in_profile_helper(
if (is_virtual_call) {
jccb(Assembler::zero, found_null);
// Receiver did not match any saved receiver and there is no empty row for it.
// Increment total counter to indicate polimorphic case.
// Increment total counter to indicate polymorphic case.
increment_mdp_data_at(mdp, in_bytes(CounterData::count_offset()));
jmp(done);
bind(found_null);

View File

@ -3238,17 +3238,19 @@ void TemplateTable::_new() {
__ xorl(rcx, rcx); // use zero reg to clear memory (shorter code)
__ store_klass_gap(rax, rcx); // zero klass gap for compressed oops
__ store_klass(rax, rsi); // store klass last
{
SkipIfEqual skip(_masm, &DTraceAllocProbes, false);
// Trigger dtrace event for fastpath
__ push(atos); // save the return value
__ call_VM_leaf(
CAST_FROM_FN_PTR(address, SharedRuntime::dtrace_object_alloc), rax);
__ pop(atos); // restore the return value
}
__ jmp(done);
}
{
SkipIfEqual skip(_masm, &DTraceAllocProbes, false);
// Trigger dtrace event for fastpath
__ push(atos); // save the return value
__ call_VM_leaf(
CAST_FROM_FN_PTR(address, SharedRuntime::dtrace_object_alloc), rax);
__ pop(atos); // restore the return value
}
// slow case
__ bind(slow_case);

View File

@ -1,6 +1,6 @@
/*
* Copyright 2003-2007 Sun Microsystems, Inc. All Rights Reserved.
* Copyright 2007, 2008, 2009 Red Hat, Inc.
* Copyright 2007, 2008, 2009, 2010 Red Hat, Inc.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -145,7 +145,7 @@ void CppInterpreter::main_loop(int recurse, TRAPS) {
}
else if (istate->msg() == BytecodeInterpreter::return_from_method) {
// Copy the result into the caller's frame
result_slots = type2size[method->result_type()];
result_slots = type2size[result_type_of(method)];
assert(result_slots >= 0 && result_slots <= 2, "what?");
result = istate->stack() + result_slots;
break;
@ -394,9 +394,10 @@ void CppInterpreter::native_entry(methodOop method, intptr_t UNUSED, TRAPS) {
// Push our result
if (!HAS_PENDING_EXCEPTION) {
stack->set_sp(stack->sp() - type2size[method->result_type()]);
BasicType type = result_type_of(method);
stack->set_sp(stack->sp() - type2size[type]);
switch (method->result_type()) {
switch (type) {
case T_VOID:
break;
@ -707,6 +708,26 @@ int AbstractInterpreter::BasicType_as_index(BasicType type) {
return i;
}
BasicType CppInterpreter::result_type_of(methodOop method) {
BasicType t;
switch (method->result_index()) {
case 0 : t = T_BOOLEAN; break;
case 1 : t = T_CHAR; break;
case 2 : t = T_BYTE; break;
case 3 : t = T_SHORT; break;
case 4 : t = T_INT; break;
case 5 : t = T_LONG; break;
case 6 : t = T_VOID; break;
case 7 : t = T_FLOAT; break;
case 8 : t = T_DOUBLE; break;
case 9 : t = T_OBJECT; break;
default: ShouldNotReachHere();
}
assert(AbstractInterpreter::BasicType_as_index(t) == method->result_index(),
"out of step with AbstractInterpreter::BasicType_as_index");
return t;
}
address InterpreterGenerator::generate_empty_entry() {
if (!UseFastEmptyMethods)
return NULL;

View File

@ -1,6 +1,6 @@
/*
* Copyright 1997-2007 Sun Microsystems, Inc. All Rights Reserved.
* Copyright 2007, 2008 Red Hat, Inc.
* Copyright 2007, 2008, 2010 Red Hat, Inc.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -41,3 +41,7 @@
private:
// Stack overflow checks
static bool stack_overflow_imminent(JavaThread *thread);
private:
// Fast result type determination
static BasicType result_type_of(methodOop method);

View File

@ -1,6 +1,6 @@
/*
* Copyright 2000-2006 Sun Microsystems, Inc. All Rights Reserved.
* Copyright 2007, 2008, 2009 Red Hat, Inc.
* Copyright 2007, 2008, 2009, 2010 Red Hat, Inc.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -40,7 +40,7 @@ define_pd_global(intx, PreInflateSpin, 10);
define_pd_global(intx, StackYellowPages, 2);
define_pd_global(intx, StackRedPages, 1);
define_pd_global(intx, StackShadowPages, 3 LP64_ONLY(+3) DEBUG_ONLY(+3));
define_pd_global(intx, StackShadowPages, 5 LP64_ONLY(+1) DEBUG_ONLY(+3));
define_pd_global(bool, RewriteBytecodes, true);
define_pd_global(bool, RewriteFrequentPairs, true);

View File

@ -1,6 +1,6 @@
/*
* Copyright 2003-2004 Sun Microsystems, Inc. All Rights Reserved.
* Copyright 2007, 2008 Red Hat, Inc.
* Copyright 2007, 2008, 2010 Red Hat, Inc.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -39,7 +39,13 @@
"stfd %0, 0(%2)\n"
: "=f"(tmp)
: "b"(src), "b"(dst));
#elif defined(S390) && !defined(_LP64)
double tmp;
asm volatile ("ld %0, 0(%1)\n"
"std %0, 0(%2)\n"
: "=r"(tmp)
: "a"(src), "a"(dst));
#else
*(jlong *) dst = *(jlong *) src;
#endif // PPC && !_LP64
#endif
}

View File

@ -1,5 +1,5 @@
/*
* Copyright 1999-2009 Sun Microsystems, Inc. All Rights Reserved.
* Copyright 1999-2010 Sun Microsystems, Inc. All Rights Reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -730,11 +730,12 @@ void os::print_context(outputStream *st, void *context) {
st->print(", RSI=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_RSI]);
st->print(", RDI=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_RDI]);
st->cr();
st->print(", R8=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_R8]);
st->print( "R8=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_R8]);
st->print(", R9=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_R9]);
st->print(", R10=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_R10]);
st->print(", R11=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_R11]);
st->print(", R12=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_R12]);
st->cr();
st->print( "R12=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_R12]);
st->print(", R13=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_R13]);
st->print(", R14=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_R14]);
st->print(", R15=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_R15]);

View File

@ -253,7 +253,8 @@ class IRScopeDebugInfo: public CompilationResourceObj {
// reexecute allowed only for the topmost frame
bool reexecute = topmost ? should_reexecute() : false;
bool is_method_handle_invoke = false;
recorder->describe_scope(pc_offset, scope()->method(), bci(), reexecute, is_method_handle_invoke, locvals, expvals, monvals);
bool return_oop = false; // This flag will be ignored since it used only for C2 with escape analysis.
recorder->describe_scope(pc_offset, scope()->method(), bci(), reexecute, is_method_handle_invoke, return_oop, locvals, expvals, monvals);
}
};

View File

@ -1075,6 +1075,7 @@ enum {
};
// Below length is the # elements copied.
template <class T> int obj_arraycopy_work(oopDesc* src, T* src_addr,
oopDesc* dst, T* dst_addr,
int length) {
@ -1083,22 +1084,22 @@ template <class T> int obj_arraycopy_work(oopDesc* src, T* src_addr,
// barrier. The assert will fail if this is not the case.
// Note that we use the non-virtual inlineable variant of write_ref_array.
BarrierSet* bs = Universe::heap()->barrier_set();
assert(bs->has_write_ref_array_opt(),
"Barrier set must have ref array opt");
assert(bs->has_write_ref_array_opt(), "Barrier set must have ref array opt");
assert(bs->has_write_ref_array_pre_opt(), "For pre-barrier as well.");
if (src == dst) {
// same object, no check
bs->write_ref_array_pre(dst_addr, length);
Copy::conjoint_oops_atomic(src_addr, dst_addr, length);
bs->write_ref_array(MemRegion((HeapWord*)dst_addr,
(HeapWord*)(dst_addr + length)));
bs->write_ref_array((HeapWord*)dst_addr, length);
return ac_ok;
} else {
klassOop bound = objArrayKlass::cast(dst->klass())->element_klass();
klassOop stype = objArrayKlass::cast(src->klass())->element_klass();
if (stype == bound || Klass::cast(stype)->is_subtype_of(bound)) {
// Elements are guaranteed to be subtypes, so no check necessary
bs->write_ref_array_pre(dst_addr, length);
Copy::conjoint_oops_atomic(src_addr, dst_addr, length);
bs->write_ref_array(MemRegion((HeapWord*)dst_addr,
(HeapWord*)(dst_addr + length)));
bs->write_ref_array((HeapWord*)dst_addr, length);
return ac_ok;
}
}
@ -1162,9 +1163,16 @@ JRT_LEAF(void, Runtime1::oop_arraycopy(HeapWord* src, HeapWord* dst, int num))
#endif
if (num == 0) return;
Copy::conjoint_oops_atomic((oop*) src, (oop*) dst, num);
BarrierSet* bs = Universe::heap()->barrier_set();
bs->write_ref_array(MemRegion(dst, dst + num));
assert(bs->has_write_ref_array_opt(), "Barrier set must have ref array opt");
assert(bs->has_write_ref_array_pre_opt(), "For pre-barrier as well.");
if (UseCompressedOops) {
bs->write_ref_array_pre((narrowOop*)dst, num);
} else {
bs->write_ref_array_pre((oop*)dst, num);
}
Copy::conjoint_oops_atomic((oop*) src, (oop*) dst, num);
bs->write_ref_array(dst, num);
JRT_END

View File

@ -445,7 +445,8 @@ ciCallProfile ciMethod::call_profile_at_bci(int bci) {
(morphism == ciCallProfile::MorphismLimit && count == 0)) {
#ifdef ASSERT
if (count > 0) {
tty->print_cr("bci: %d", bci);
this->print_short_name(tty);
tty->print_cr(" @ bci:%d", bci);
this->print_codes();
assert(false, "this call site should not be polymorphic");
}

View File

@ -1121,10 +1121,23 @@ class BacktraceBuilder: public StackObj {
}
void flush() {
// The following appears to have been an optimization to save from
// doing a barrier for each individual store into the _methods array,
// but rather to do it for the entire array after the series of writes.
// That optimization seems to have been lost when compressed oops was
// implemented. However, the extra card-marks below was left in place,
// but is now redundant because the individual stores into the
// _methods array already execute the barrier code. CR 6918185 has
// been filed so the original code may be restored by deferring the
// barriers until after the entire sequence of stores, thus re-enabling
// the intent of the original optimization. In the meantime the redundant
// card mark below is now disabled.
if (_dirty && _methods != NULL) {
#if 0
BarrierSet* bs = Universe::heap()->barrier_set();
assert(bs->has_write_ref_array_opt(), "Barrier set must have ref array opt");
bs->write_ref_array((HeapWord*)_methods->base(), _methods->length());
#endif
_dirty = false;
}
}
@ -1168,9 +1181,7 @@ class BacktraceBuilder: public StackObj {
method = mhandle();
}
_methods->obj_at_put(_index, method);
// bad for UseCompressedOops
// *_methods->obj_at_addr(_index) = method;
_methods->obj_at_put(_index, method);
_bcis->ushort_at_put(_index, bci);
_index++;
_dirty = true;

View File

@ -457,7 +457,8 @@ void LoaderConstraintTable::merge_loader_constraints(
}
void LoaderConstraintTable::verify(Dictionary* dictionary) {
void LoaderConstraintTable::verify(Dictionary* dictionary,
PlaceholderTable* placeholders) {
Thread *thread = Thread::current();
for (int cindex = 0; cindex < _loader_constraint_size; cindex++) {
for (LoaderConstraintEntry* probe = bucket(cindex);
@ -472,7 +473,23 @@ void LoaderConstraintTable::verify(Dictionary* dictionary) {
unsigned int d_hash = dictionary->compute_hash(name, loader);
int d_index = dictionary->hash_to_index(d_hash);
klassOop k = dictionary->find_class(d_index, d_hash, name, loader);
guarantee(k == probe->klass(), "klass should be in dictionary");
if (k != NULL) {
// We found the class in the system dictionary, so we should
// make sure that the klassOop matches what we already have.
guarantee(k == probe->klass(), "klass should be in dictionary");
} else {
// If we don't find the class in the system dictionary, it
// has to be in the placeholders table.
unsigned int p_hash = placeholders->compute_hash(name, loader);
int p_index = placeholders->hash_to_index(p_hash);
PlaceholderEntry* entry = placeholders->get_entry(p_index, p_hash,
name, loader);
// The instanceKlass might not be on the entry, so the only
// thing we can check here is whether we were successful in
// finding the class in the placeholders table.
guarantee(entry != NULL, "klass should be in the placeholders");
}
}
for (int n = 0; n< probe->num_loaders(); n++) {
guarantee(probe->loader(n)->is_oop_or_null(), "should be oop");

View File

@ -84,7 +84,7 @@ public:
void purge_loader_constraints(BoolObjectClosure* is_alive);
void verify(Dictionary* dictionary);
void verify(Dictionary* dictionary, PlaceholderTable* placeholders);
#ifndef PRODUCT
void print();
#endif

View File

@ -2573,7 +2573,7 @@ void SystemDictionary::verify() {
// Verify constraint table
guarantee(constraints() != NULL, "Verify of loader constraints failed");
constraints()->verify(dictionary());
constraints()->verify(dictionary(), placeholders());
}

View File

@ -282,6 +282,7 @@ void DebugInformationRecorder::describe_scope(int pc_offset,
int bci,
bool reexecute,
bool is_method_handle_invoke,
bool return_oop,
DebugToken* locals,
DebugToken* expressions,
DebugToken* monitors) {
@ -296,6 +297,7 @@ void DebugInformationRecorder::describe_scope(int pc_offset,
// Record flags into pcDesc.
last_pd->set_should_reexecute(reexecute);
last_pd->set_is_method_handle_invoke(is_method_handle_invoke);
last_pd->set_return_oop(return_oop);
// serialize sender stream offest
stream()->write_int(sender_stream_offset);

View File

@ -89,6 +89,7 @@ class DebugInformationRecorder: public ResourceObj {
int bci,
bool reexecute,
bool is_method_handle_invoke = false,
bool return_oop = false,
DebugToken* locals = NULL,
DebugToken* expressions = NULL,
DebugToken* monitors = NULL);

View File

@ -988,7 +988,8 @@ ScopeDesc* nmethod::scope_desc_at(address pc) {
PcDesc* pd = pc_desc_at(pc);
guarantee(pd != NULL, "scope must be present");
return new ScopeDesc(this, pd->scope_decode_offset(),
pd->obj_decode_offset(), pd->should_reexecute());
pd->obj_decode_offset(), pd->should_reexecute(),
pd->return_oop());
}
@ -2010,7 +2011,10 @@ address nmethod::continuation_for_implicit_exception(address pc) {
print_pcs();
}
#endif
guarantee(cont_offset != 0, "unhandled implicit exception in compiled code");
if (cont_offset == 0) {
// Let the normal error handling report the exception
return NULL;
}
return instructions_begin() + cont_offset;
}
@ -2156,7 +2160,8 @@ void nmethod::verify_interrupt_point(address call_site) {
PcDesc* pd = pc_desc_at(ic->end_of_call());
assert(pd != NULL, "PcDesc must exist");
for (ScopeDesc* sd = new ScopeDesc(this, pd->scope_decode_offset(),
pd->obj_decode_offset(), pd->should_reexecute());
pd->obj_decode_offset(), pd->should_reexecute(),
pd->return_oop());
!sd->is_top(); sd = sd->sender()) {
sd->verify();
}
@ -2421,7 +2426,8 @@ ScopeDesc* nmethod::scope_desc_in(address begin, address end) {
PcDesc* p = pc_desc_near(begin+1);
if (p != NULL && p->real_pc(this) <= end) {
return new ScopeDesc(this, p->scope_decode_offset(),
p->obj_decode_offset(), p->should_reexecute());
p->obj_decode_offset(), p->should_reexecute(),
p->return_oop());
}
return NULL;
}

View File

@ -1,5 +1,5 @@
/*
* Copyright 1997-2009 Sun Microsystems, Inc. All Rights Reserved.
* Copyright 1997-2010 Sun Microsystems, Inc. All Rights Reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -52,7 +52,8 @@ void PcDesc::print(nmethod* code) {
tty->print(" ");
sd->method()->print_short_name(tty);
tty->print(" @%d", sd->bci());
tty->print(" reexecute=%s", sd->should_reexecute()?"true":"false");
if (sd->should_reexecute())
tty->print(" reexecute=true");
tty->cr();
}
#endif

View File

@ -39,6 +39,7 @@ class PcDesc VALUE_OBJ_CLASS_SPEC {
struct {
unsigned int reexecute: 1;
unsigned int is_method_handle_invoke: 1;
unsigned int return_oop: 1;
} bits;
bool operator ==(const PcDescFlags& other) { return word == other.word; }
} _flags;
@ -76,6 +77,9 @@ class PcDesc VALUE_OBJ_CLASS_SPEC {
bool is_method_handle_invoke() const { return _flags.bits.is_method_handle_invoke; }
void set_is_method_handle_invoke(bool z) { _flags.bits.is_method_handle_invoke = z; }
bool return_oop() const { return _flags.bits.return_oop; }
void set_return_oop(bool z) { _flags.bits.return_oop = z; }
// Returns the real pc
address real_pc(const nmethod* code) const;

View File

@ -26,19 +26,21 @@
# include "incls/_scopeDesc.cpp.incl"
ScopeDesc::ScopeDesc(const nmethod* code, int decode_offset, int obj_decode_offset, bool reexecute) {
ScopeDesc::ScopeDesc(const nmethod* code, int decode_offset, int obj_decode_offset, bool reexecute, bool return_oop) {
_code = code;
_decode_offset = decode_offset;
_objects = decode_object_values(obj_decode_offset);
_reexecute = reexecute;
_return_oop = return_oop;
decode_body();
}
ScopeDesc::ScopeDesc(const nmethod* code, int decode_offset, bool reexecute) {
ScopeDesc::ScopeDesc(const nmethod* code, int decode_offset, bool reexecute, bool return_oop) {
_code = code;
_decode_offset = decode_offset;
_objects = decode_object_values(DebugInformationRecorder::serialized_null);
_reexecute = reexecute;
_return_oop = return_oop;
decode_body();
}
@ -48,6 +50,7 @@ ScopeDesc::ScopeDesc(const ScopeDesc* parent) {
_decode_offset = parent->_sender_decode_offset;
_objects = parent->_objects;
_reexecute = false; //reexecute only applies to the first scope
_return_oop = false;
decode_body();
}

View File

@ -52,17 +52,18 @@ class SimpleScopeDesc : public StackObj {
class ScopeDesc : public ResourceObj {
public:
// Constructor
ScopeDesc(const nmethod* code, int decode_offset, int obj_decode_offset, bool reexecute);
ScopeDesc(const nmethod* code, int decode_offset, int obj_decode_offset, bool reexecute, bool return_oop);
// Calls above, giving default value of "serialized_null" to the
// "obj_decode_offset" argument. (We don't use a default argument to
// avoid a .hpp-.hpp dependency.)
ScopeDesc(const nmethod* code, int decode_offset, bool reexecute);
ScopeDesc(const nmethod* code, int decode_offset, bool reexecute, bool return_oop);
// JVM state
methodHandle method() const { return _method; }
int bci() const { return _bci; }
bool should_reexecute() const { return _reexecute; }
bool return_oop() const { return _return_oop; }
GrowableArray<ScopeValue*>* locals();
GrowableArray<ScopeValue*>* expressions();
@ -88,6 +89,7 @@ class ScopeDesc : public ResourceObj {
methodHandle _method;
int _bci;
bool _reexecute;
bool _return_oop;
// Decoding offsets
int _decode_offset;

View File

@ -300,7 +300,23 @@ jbyte* ConcurrentG1Refine::cache_insert(jbyte* card_ptr, bool* defer) {
int count;
jbyte* cached_ptr = add_card_count(card_ptr, &count, defer);
assert(cached_ptr != NULL, "bad cached card ptr");
assert(!is_young_card(cached_ptr), "shouldn't get a card in young region");
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 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 pointer we obtained from card count cache is not hot
// so do not store it in the cache; return it for immediate

View File

@ -2505,6 +2505,7 @@ G1CollectedHeap* G1CollectedHeap::heap() {
}
void G1CollectedHeap::gc_prologue(bool full /* Ignored */) {
// always_do_update_barrier = false;
assert(InlineCacheBuffer::is_empty(), "should have cleaned up ICBuffer");
// Call allocation profiler
AllocationProfiler::iterate_since_last_gc();
@ -2518,6 +2519,7 @@ void G1CollectedHeap::gc_epilogue(bool full /* Ignored */) {
// is set.
COMPILER2_PRESENT(assert(DerivedPointerTable::is_empty(),
"derived pointer present"));
// always_do_update_barrier = true;
}
void G1CollectedHeap::do_collection_pause() {
@ -2644,6 +2646,13 @@ G1CollectedHeap::cleanup_surviving_young_words() {
// </NEW PREDICTION>
struct PrepareForRSScanningClosure : public HeapRegionClosure {
bool doHeapRegion(HeapRegion *r) {
r->rem_set()->set_iter_claimed(0);
return false;
}
};
void
G1CollectedHeap::do_collection_pause_at_safepoint() {
if (PrintHeapAtGC) {
@ -2782,6 +2791,8 @@ G1CollectedHeap::do_collection_pause_at_safepoint() {
gclog_or_tty->print_cr("\nAfter pause, heap:");
print();
#endif
PrepareForRSScanningClosure prepare_for_rs_scan;
collection_set_iterate(&prepare_for_rs_scan);
setup_surviving_young_words();
@ -3779,22 +3790,16 @@ oop G1ParCopyHelper::copy_to_survivor_space(oop old) {
return obj;
}
template <bool do_gen_barrier, G1Barrier barrier, bool do_mark_forwardee, bool skip_cset_test>
template <bool do_gen_barrier, G1Barrier barrier, bool do_mark_forwardee>
template <class T>
void G1ParCopyClosure <do_gen_barrier, barrier, do_mark_forwardee, skip_cset_test>
void G1ParCopyClosure <do_gen_barrier, barrier, do_mark_forwardee>
::do_oop_work(T* p) {
oop obj = oopDesc::load_decode_heap_oop(p);
assert(barrier != G1BarrierRS || obj != NULL,
"Precondition: G1BarrierRS implies obj is nonNull");
// The only time we skip the cset test is when we're scanning
// references popped from the queue. And we only push on the queue
// references that we know point into the cset, so no point in
// checking again. But we'll leave an assert here for peace of mind.
assert(!skip_cset_test || _g1->obj_in_cs(obj), "invariant");
// here the null check is implicit in the cset_fast_test() test
if (skip_cset_test || _g1->in_cset_fast_test(obj)) {
if (_g1->in_cset_fast_test(obj)) {
#if G1_REM_SET_LOGGING
gclog_or_tty->print_cr("Loc "PTR_FORMAT" contains pointer "PTR_FORMAT" "
"into CS.", p, (void*) obj);
@ -3811,7 +3816,6 @@ void G1ParCopyClosure <do_gen_barrier, barrier, do_mark_forwardee, skip_cset_tes
}
}
// When scanning moved objs, must look at all oops.
if (barrier == G1BarrierEvac && obj != NULL) {
_par_scan_state->update_rs(_from, p, _par_scan_state->queue_num());
}
@ -3821,8 +3825,8 @@ void G1ParCopyClosure <do_gen_barrier, barrier, do_mark_forwardee, skip_cset_tes
}
}
template void G1ParCopyClosure<false, G1BarrierEvac, false, true>::do_oop_work(oop* p);
template void G1ParCopyClosure<false, G1BarrierEvac, false, true>::do_oop_work(narrowOop* p);
template void G1ParCopyClosure<false, G1BarrierEvac, false>::do_oop_work(oop* p);
template void G1ParCopyClosure<false, G1BarrierEvac, false>::do_oop_work(narrowOop* p);
template <class T> void G1ParScanPartialArrayClosure::do_oop_nv(T* p) {
assert(has_partial_array_mask(p), "invariant");
@ -3894,11 +3898,11 @@ public:
assert(UseCompressedOops, "Error");
narrowOop* p = (narrowOop*) stolen_task;
assert(has_partial_array_mask(p) ||
_g1h->obj_in_cs(oopDesc::load_decode_heap_oop(p)), "Error");
_g1h->is_in_g1_reserved(oopDesc::load_decode_heap_oop(p)), "Error");
pss->push_on_queue(p);
} else {
oop* p = (oop*) stolen_task;
assert(has_partial_array_mask(p) || _g1h->obj_in_cs(*p), "Error");
assert(has_partial_array_mask(p) || _g1h->is_in_g1_reserved(*p), "Error");
pss->push_on_queue(p);
}
continue;
@ -3960,6 +3964,7 @@ public:
G1ParScanExtRootClosure only_scan_root_cl(_g1h, &pss);
G1ParScanPermClosure only_scan_perm_cl(_g1h, &pss);
G1ParScanHeapRSClosure only_scan_heap_rs_cl(_g1h, &pss);
G1ParPushHeapRSClosure push_heap_rs_cl(_g1h, &pss);
G1ParScanAndMarkExtRootClosure scan_mark_root_cl(_g1h, &pss);
G1ParScanAndMarkPermClosure scan_mark_perm_cl(_g1h, &pss);
@ -3983,7 +3988,7 @@ public:
_g1h->g1_process_strong_roots(/* not collecting perm */ false,
SharedHeap::SO_AllClasses,
scan_root_cl,
&only_scan_heap_rs_cl,
&push_heap_rs_cl,
scan_so_cl,
scan_perm_cl,
i);

View File

@ -1623,7 +1623,7 @@ public:
template <class T> void push_on_queue(T* ref) {
assert(ref != NULL, "invariant");
assert(has_partial_array_mask(ref) ||
_g1h->obj_in_cs(oopDesc::load_decode_heap_oop(ref)), "invariant");
_g1h->is_in_g1_reserved(oopDesc::load_decode_heap_oop(ref)), "invariant");
#ifdef ASSERT
if (has_partial_array_mask(ref)) {
oop p = clear_partial_array_mask(ref);
@ -1644,9 +1644,9 @@ public:
assert((oop*)ref != NULL, "pop_local() returned true");
assert(UseCompressedOops || !ref.is_narrow(), "Error");
assert(has_partial_array_mask((oop*)ref) ||
_g1h->obj_in_cs(ref.is_narrow() ? oopDesc::load_decode_heap_oop((narrowOop*)ref)
: oopDesc::load_decode_heap_oop((oop*)ref)),
"invariant");
_g1h->is_in_g1_reserved(ref.is_narrow() ? oopDesc::load_decode_heap_oop((narrowOop*)ref)
: oopDesc::load_decode_heap_oop((oop*)ref)),
"invariant");
IF_G1_DETAILED_STATS(note_pop());
} else {
StarTask null_task;
@ -1659,9 +1659,9 @@ public:
assert((oop*)new_ref != NULL, "pop() from a local non-empty stack");
assert(UseCompressedOops || !new_ref.is_narrow(), "Error");
assert(has_partial_array_mask((oop*)new_ref) ||
_g1h->obj_in_cs(new_ref.is_narrow() ? oopDesc::load_decode_heap_oop((narrowOop*)new_ref)
: oopDesc::load_decode_heap_oop((oop*)new_ref)),
"invariant");
_g1h->is_in_g1_reserved(new_ref.is_narrow() ? oopDesc::load_decode_heap_oop((narrowOop*)new_ref)
: oopDesc::load_decode_heap_oop((oop*)new_ref)),
"invariant");
ref = new_ref;
}
@ -1825,12 +1825,12 @@ public:
assert(UseCompressedOops, "Error");
narrowOop* p = (narrowOop*)ref_to_scan;
assert(!has_partial_array_mask(p) &&
_g1h->obj_in_cs(oopDesc::load_decode_heap_oop(p)), "sanity");
_g1h->is_in_g1_reserved(oopDesc::load_decode_heap_oop(p)), "sanity");
deal_with_reference(p);
} else {
oop* p = (oop*)ref_to_scan;
assert((has_partial_array_mask(p) && _g1h->obj_in_cs(clear_partial_array_mask(p))) ||
_g1h->obj_in_cs(oopDesc::load_decode_heap_oop(p)), "sanity");
assert((has_partial_array_mask(p) && _g1h->is_in_g1_reserved(clear_partial_array_mask(p))) ||
_g1h->is_in_g1_reserved(oopDesc::load_decode_heap_oop(p)), "sanity");
deal_with_reference(p);
}
}
@ -1844,12 +1844,12 @@ public:
assert(UseCompressedOops, "Error");
narrowOop* p = (narrowOop*)ref_to_scan;
assert(!has_partial_array_mask(p) &&
_g1h->obj_in_cs(oopDesc::load_decode_heap_oop(p)), "sanity");
_g1h->is_in_g1_reserved(oopDesc::load_decode_heap_oop(p)), "sanity");
deal_with_reference(p);
} else {
oop* p = (oop*)ref_to_scan;
assert((has_partial_array_mask(p) && _g1h->obj_in_cs(clear_partial_array_mask(p))) ||
_g1h->obj_in_cs(oopDesc::load_decode_heap_oop(p)), "sanity");
_g1h->is_in_g1_reserved(oopDesc::load_decode_heap_oop(p)), "sanity");
deal_with_reference(p);
}
}

View File

@ -205,6 +205,7 @@ G1CollectorPolicy::G1CollectorPolicy() :
// policy is created before the heap, we have to set this up here,
// so it's done as soon as possible.
HeapRegion::setup_heap_region_size(Arguments::min_heap_size());
HeapRegionRemSet::setup_remset_size();
_recent_prev_end_times_for_all_gcs_sec->add(os::elapsedTime());
_prev_collection_pause_end_ms = os::elapsedTime() * 1000.0;

View File

@ -53,6 +53,15 @@ public:
bool apply_to_weak_ref_discovered_field() { return true; }
};
class G1ParPushHeapRSClosure : public G1ParClosureSuper {
public:
G1ParPushHeapRSClosure(G1CollectedHeap* g1, G1ParScanThreadState* par_scan_state) :
G1ParClosureSuper(g1, par_scan_state) { }
template <class T> void do_oop_nv(T* p);
virtual void do_oop(oop* p) { do_oop_nv(p); }
virtual void do_oop(narrowOop* p) { do_oop_nv(p); }
};
class G1ParScanClosure : public G1ParClosureSuper {
public:
G1ParScanClosure(G1CollectedHeap* g1, G1ParScanThreadState* par_scan_state) :
@ -100,7 +109,7 @@ public:
};
template<bool do_gen_barrier, G1Barrier barrier,
bool do_mark_forwardee, bool skip_cset_test>
bool do_mark_forwardee>
class G1ParCopyClosure : public G1ParCopyHelper {
G1ParScanClosure _scanner;
template <class T> void do_oop_work(T* p);
@ -116,12 +125,13 @@ public:
virtual void do_oop(narrowOop* p) { do_oop_nv(p); }
};
typedef G1ParCopyClosure<false, G1BarrierNone, false, false> G1ParScanExtRootClosure;
typedef G1ParCopyClosure<true, G1BarrierNone, false, false> G1ParScanPermClosure;
typedef G1ParCopyClosure<false, G1BarrierRS, false, false> G1ParScanHeapRSClosure;
typedef G1ParCopyClosure<false, G1BarrierNone, true, false> G1ParScanAndMarkExtRootClosure;
typedef G1ParCopyClosure<true, G1BarrierNone, true, false> G1ParScanAndMarkPermClosure;
typedef G1ParCopyClosure<false, G1BarrierRS, true, false> G1ParScanAndMarkHeapRSClosure;
typedef G1ParCopyClosure<false, G1BarrierNone, false> G1ParScanExtRootClosure;
typedef G1ParCopyClosure<true, G1BarrierNone, false> G1ParScanPermClosure;
typedef G1ParCopyClosure<false, G1BarrierRS, false> G1ParScanHeapRSClosure;
typedef G1ParCopyClosure<false, G1BarrierNone, true> G1ParScanAndMarkExtRootClosure;
typedef G1ParCopyClosure<true, G1BarrierNone, true> G1ParScanAndMarkPermClosure;
typedef G1ParCopyClosure<false, G1BarrierRS, true> G1ParScanAndMarkHeapRSClosure;
// This is the only case when we set skip_cset_test. Basically, this
// closure is (should?) only be called directly while we're draining
// the overflow and task queues. In that case we know that the
@ -132,7 +142,7 @@ typedef G1ParCopyClosure<false, G1BarrierRS, true, false> G1ParScanAndMarkHea
// We need a separate closure to handle references during evacuation
// failure processing, as we cannot asume that the reference already
// points into the collection set (like G1ParScanHeapEvacClosure does).
typedef G1ParCopyClosure<false, G1BarrierEvac, false, false> G1ParScanHeapEvacFailureClosure;
typedef G1ParCopyClosure<false, G1BarrierEvac, false> G1ParScanHeapEvacFailureClosure;
class FilterIntoCSClosure: public OopClosure {
G1CollectedHeap* _g1;

View File

@ -104,3 +104,16 @@ template <class T> inline void G1ParScanClosure::do_oop_nv(T* p) {
}
}
}
template <class T> inline void G1ParPushHeapRSClosure::do_oop_nv(T* p) {
T heap_oop = oopDesc::load_heap_oop(p);
if (!oopDesc::is_null(heap_oop)) {
oop obj = oopDesc::decode_heap_oop_not_null(heap_oop);
if (_g1->in_cset_fast_test(obj)) {
Prefetch::write(obj->mark_addr(), 0);
Prefetch::read(obj->mark_addr(), (HeapWordSize*2));
_par_scan_state->push_on_queue(p);
}
}
}

View File

@ -155,8 +155,8 @@ class ScanRSClosure : public HeapRegionClosure {
G1BlockOffsetSharedArray* _bot_shared;
CardTableModRefBS *_ct_bs;
int _worker_i;
int _block_size;
bool _try_claimed;
size_t _min_skip_distance, _max_skip_distance;
public:
ScanRSClosure(OopsInHeapRegionClosure* oc, int worker_i) :
_oc(oc),
@ -168,8 +168,7 @@ public:
_g1h = G1CollectedHeap::heap();
_bot_shared = _g1h->bot_shared();
_ct_bs = (CardTableModRefBS*) (_g1h->barrier_set());
_min_skip_distance = 16;
_max_skip_distance = 2 * _g1h->n_par_threads() * _min_skip_distance;
_block_size = MAX2<int>(G1RSetScanBlockSize, 1);
}
void set_try_claimed() { _try_claimed = true; }
@ -225,12 +224,15 @@ public:
HeapRegionRemSetIterator* iter = _g1h->rem_set_iterator(_worker_i);
hrrs->init_iterator(iter);
size_t card_index;
size_t skip_distance = 0, current_card = 0, jump_to_card = 0;
while (iter->has_next(card_index)) {
if (current_card < jump_to_card) {
++current_card;
continue;
// We claim cards in block so as to recude the contention. The block size is determined by
// the G1RSetScanBlockSize parameter.
size_t jump_to_card = hrrs->iter_claimed_next(_block_size);
for (size_t current_card = 0; iter->has_next(card_index); current_card++) {
if (current_card >= jump_to_card + _block_size) {
jump_to_card = hrrs->iter_claimed_next(_block_size);
}
if (current_card < jump_to_card) continue;
HeapWord* card_start = _g1h->bot_shared()->address_for_index(card_index);
#if 0
gclog_or_tty->print("Rem set iteration yielded card [" PTR_FORMAT ", " PTR_FORMAT ").\n",
@ -247,22 +249,14 @@ public:
// If the card is dirty, then we will scan it during updateRS.
if (!card_region->in_collection_set() && !_ct_bs->is_card_dirty(card_index)) {
if (!_ct_bs->is_card_claimed(card_index) && _ct_bs->claim_card(card_index)) {
scanCard(card_index, card_region);
} else if (_try_claimed) {
if (jump_to_card == 0 || jump_to_card != current_card) {
// We did some useful work in the previous iteration.
// Decrease the distance.
skip_distance = MAX2(skip_distance >> 1, _min_skip_distance);
} else {
// Previous iteration resulted in a claim failure.
// Increase the distance.
skip_distance = MIN2(skip_distance << 1, _max_skip_distance);
}
jump_to_card = current_card + skip_distance;
}
// We make the card as "claimed" lazily (so races are possible but they're benign),
// which reduces the number of duplicate scans (the rsets of the regions in the cset
// can intersect).
if (!_ct_bs->is_card_claimed(card_index)) {
_ct_bs->set_card_claimed(card_index);
scanCard(card_index, card_region);
}
}
++current_card;
}
if (!_try_claimed) {
hrrs->set_iter_complete();
@ -299,30 +293,18 @@ void HRInto_G1RemSet::scanRS(OopsInHeapRegionClosure* oc, int worker_i) {
double rs_time_start = os::elapsedTime();
HeapRegion *startRegion = calculateStartRegion(worker_i);
BufferingOopsInHeapRegionClosure boc(oc);
ScanRSClosure scanRScl(&boc, worker_i);
ScanRSClosure scanRScl(oc, worker_i);
_g1->collection_set_iterate_from(startRegion, &scanRScl);
scanRScl.set_try_claimed();
_g1->collection_set_iterate_from(startRegion, &scanRScl);
boc.done();
double closure_app_time_sec = boc.closure_app_seconds();
double scan_rs_time_sec = (os::elapsedTime() - rs_time_start) -
closure_app_time_sec;
double closure_app_time_ms = closure_app_time_sec * 1000.0;
double scan_rs_time_sec = os::elapsedTime() - rs_time_start;
assert( _cards_scanned != NULL, "invariant" );
_cards_scanned[worker_i] = scanRScl.cards_done();
_g1p->record_scan_rs_start_time(worker_i, rs_time_start * 1000.0);
_g1p->record_scan_rs_time(worker_i, scan_rs_time_sec * 1000.0);
double scan_new_refs_time_ms = _g1p->get_scan_new_refs_time(worker_i);
if (scan_new_refs_time_ms > 0.0) {
closure_app_time_ms += scan_new_refs_time_ms;
}
_g1p->record_obj_copy_time(worker_i, closure_app_time_ms);
}
void HRInto_G1RemSet::updateRS(int worker_i) {
@ -449,9 +431,8 @@ HRInto_G1RemSet::scanNewRefsRS_work(OopsInHeapRegionClosure* oc,
oc->do_oop(p);
}
}
_g1p->record_scan_new_refs_time(worker_i,
(os::elapsedTime() - scan_new_refs_start_sec)
* 1000.0);
double scan_new_refs_time_ms = (os::elapsedTime() - scan_new_refs_start_sec) * 1000.0;
_g1p->record_scan_new_refs_time(worker_i, scan_new_refs_time_ms);
}
void HRInto_G1RemSet::cleanupHRRS() {

View File

@ -207,8 +207,20 @@
develop(bool, G1PrintOopAppls, false, \
"When true, print applications of closures to external locs.") \
\
develop(intx, G1LogRSRegionEntries, 7, \
"Log_2 of max number of regions for which we keep bitmaps.") \
develop(intx, G1RSetRegionEntriesBase, 256, \
"Max number of regions in a fine-grain table per MB.") \
\
product(intx, G1RSetRegionEntries, 0, \
"Max number of regions for which we keep bitmaps." \
"Will be set ergonomically by default") \
\
develop(intx, G1RSetSparseRegionEntriesBase, 4, \
"Max number of entries per region in a sparse table " \
"per MB.") \
\
product(intx, G1RSetSparseRegionEntries, 0, \
"Max number of entries per region in a sparse table." \
"Will be set ergonomically by default.") \
\
develop(bool, G1RecordHRRSOops, false, \
"When true, record recent calls to rem set operations.") \
@ -293,6 +305,10 @@
develop(bool, G1VerifyCTCleanup, false, \
"Verify card table cleanup.") \
\
product(uintx, G1RSetScanBlockSize, 64, \
"Size of a work unit of cards claimed by a worker thread" \
"during RSet scanning.") \
\
develop(bool, ReduceInitialCardMarksForG1, false, \
"When ReduceInitialCardMarks is true, this flag setting " \
" controls whether G1 allows the RICM optimization")

View File

@ -33,11 +33,12 @@ enum G1Barrier {
};
template<bool do_gen_barrier, G1Barrier barrier,
bool do_mark_forwardee, bool skip_cset_test>
bool do_mark_forwardee>
class G1ParCopyClosure;
class G1ParScanClosure;
class G1ParPushHeapRSClosure;
typedef G1ParCopyClosure<false, G1BarrierEvac, false, true> G1ParScanHeapEvacClosure;
typedef G1ParCopyClosure<false, G1BarrierEvac, false> G1ParScanHeapEvacClosure;
class FilterIntoCSClosure;
class FilterOutOfRegionClosure;
@ -51,6 +52,7 @@ class FilterAndMarkInHeapRegionAndIntoCSClosure;
#define FURTHER_SPECIALIZED_OOP_OOP_ITERATE_CLOSURES(f) \
f(G1ParScanHeapEvacClosure,_nv) \
f(G1ParScanClosure,_nv) \
f(G1ParPushHeapRSClosure,_nv) \
f(FilterIntoCSClosure,_nv) \
f(FilterOutOfRegionClosure,_nv) \
f(FilterInHeapRegionAndIntoCSClosure,_nv) \

View File

@ -258,42 +258,6 @@ class PosParPRT: public PerRegionTable {
ReserveParTableExpansion = 1
};
void par_expand() {
int n = HeapRegionRemSet::num_par_rem_sets()-1;
if (n <= 0) return;
if (_par_tables == NULL) {
PerRegionTable* res =
(PerRegionTable*)
Atomic::cmpxchg_ptr((PerRegionTable*)ReserveParTableExpansion,
&_par_tables, NULL);
if (res != NULL) return;
// Otherwise, we reserved the right to do the expansion.
PerRegionTable** ptables = NEW_C_HEAP_ARRAY(PerRegionTable*, n);
for (int i = 0; i < n; i++) {
PerRegionTable* ptable = PerRegionTable::alloc(hr());
ptables[i] = ptable;
}
// Here we do not need an atomic.
_par_tables = ptables;
#if COUNT_PAR_EXPANDS
print_par_expand();
#endif
// We must put this table on the expanded list.
PosParPRT* exp_head = _par_expanded_list;
while (true) {
set_next_par_expanded(exp_head);
PosParPRT* res =
(PosParPRT*)
Atomic::cmpxchg_ptr(this, &_par_expanded_list, exp_head);
if (res == exp_head) return;
// Otherwise.
exp_head = res;
}
ShouldNotReachHere();
}
}
void par_contract() {
assert(_par_tables != NULL, "Precondition.");
int n = HeapRegionRemSet::num_par_rem_sets()-1;
@ -391,13 +355,49 @@ public:
void set_next(PosParPRT* nxt) { _next = nxt; }
PosParPRT** next_addr() { return &_next; }
bool should_expand(int tid) {
return par_tables() == NULL && tid > 0 && hr()->is_gc_alloc_region();
}
void par_expand() {
int n = HeapRegionRemSet::num_par_rem_sets()-1;
if (n <= 0) return;
if (_par_tables == NULL) {
PerRegionTable* res =
(PerRegionTable*)
Atomic::cmpxchg_ptr((PerRegionTable*)ReserveParTableExpansion,
&_par_tables, NULL);
if (res != NULL) return;
// Otherwise, we reserved the right to do the expansion.
PerRegionTable** ptables = NEW_C_HEAP_ARRAY(PerRegionTable*, n);
for (int i = 0; i < n; i++) {
PerRegionTable* ptable = PerRegionTable::alloc(hr());
ptables[i] = ptable;
}
// Here we do not need an atomic.
_par_tables = ptables;
#if COUNT_PAR_EXPANDS
print_par_expand();
#endif
// We must put this table on the expanded list.
PosParPRT* exp_head = _par_expanded_list;
while (true) {
set_next_par_expanded(exp_head);
PosParPRT* res =
(PosParPRT*)
Atomic::cmpxchg_ptr(this, &_par_expanded_list, exp_head);
if (res == exp_head) return;
// Otherwise.
exp_head = res;
}
ShouldNotReachHere();
}
}
void add_reference(OopOrNarrowOopStar from, int tid) {
// Expand if necessary.
PerRegionTable** pt = par_tables();
if (par_tables() == NULL && tid > 0 && hr()->is_gc_alloc_region()) {
par_expand();
pt = par_tables();
}
if (pt != NULL) {
// We always have to assume that mods to table 0 are in parallel,
// because of the claiming scheme in parallel expansion. A thread
@ -505,12 +505,13 @@ OtherRegionsTable::OtherRegionsTable(HeapRegion* hr) :
typedef PosParPRT* PosParPRTPtr;
if (_max_fine_entries == 0) {
assert(_mod_max_fine_entries_mask == 0, "Both or none.");
_max_fine_entries = (size_t)(1 << G1LogRSRegionEntries);
size_t max_entries_log = (size_t)log2_long((jlong)G1RSetRegionEntries);
_max_fine_entries = (size_t)(1 << max_entries_log);
_mod_max_fine_entries_mask = _max_fine_entries - 1;
#if SAMPLE_FOR_EVICTION
assert(_fine_eviction_sample_size == 0
&& _fine_eviction_stride == 0, "All init at same time.");
_fine_eviction_sample_size = MAX2((size_t)4, (size_t)G1LogRSRegionEntries);
_fine_eviction_sample_size = MAX2((size_t)4, max_entries_log);
_fine_eviction_stride = _max_fine_entries / _fine_eviction_sample_size;
#endif
}
@ -655,13 +656,6 @@ void OtherRegionsTable::add_reference(OopOrNarrowOopStar from, int tid) {
#endif
}
// Otherwise, transfer from sparse to fine-grain.
CardIdx_t cards[SparsePRTEntry::CardsPerEntry];
if (G1HRRSUseSparseTable) {
bool res = _sparse_table.get_cards(from_hrs_ind, &cards[0]);
assert(res, "There should have been an entry");
}
if (_n_fine_entries == _max_fine_entries) {
prt = delete_region_table();
} else {
@ -676,10 +670,12 @@ void OtherRegionsTable::add_reference(OopOrNarrowOopStar from, int tid) {
_fine_grain_regions[ind] = prt;
_n_fine_entries++;
// Add in the cards from the sparse table.
if (G1HRRSUseSparseTable) {
for (int i = 0; i < SparsePRTEntry::CardsPerEntry; i++) {
CardIdx_t c = cards[i];
// Transfer from sparse to fine-grain.
SparsePRTEntry *sprt_entry = _sparse_table.get_entry(from_hrs_ind);
assert(sprt_entry != NULL, "There should have been an entry");
for (int i = 0; i < SparsePRTEntry::cards_num(); i++) {
CardIdx_t c = sprt_entry->card(i);
if (c != SparsePRTEntry::NullEntry) {
prt->add_card(c);
}
@ -696,7 +692,21 @@ void OtherRegionsTable::add_reference(OopOrNarrowOopStar from, int tid) {
// OtherRegionsTable for why this is OK.
assert(prt != NULL, "Inv");
prt->add_reference(from, tid);
if (prt->should_expand(tid)) {
MutexLockerEx x(&_m, Mutex::_no_safepoint_check_flag);
HeapRegion* prt_hr = prt->hr();
if (prt_hr == from_hr) {
// Make sure the table still corresponds to the same region
prt->par_expand();
prt->add_reference(from, tid);
}
// else: The table has been concurrently coarsened, evicted, and
// the table data structure re-used for another table. So, we
// don't need to add the reference any more given that the table
// has been coarsened and the whole region will be scanned anyway.
} else {
prt->add_reference(from, tid);
}
if (G1RecordHRRSOops) {
HeapRegionRemSet::record(hr(), from);
#if HRRS_VERBOSE
@ -1070,6 +1080,19 @@ HeapRegionRemSet::HeapRegionRemSet(G1BlockOffsetSharedArray* bosa,
{}
void HeapRegionRemSet::setup_remset_size() {
// Setup sparse and fine-grain tables sizes.
// table_size = base * (log(region_size / 1M) + 1)
int region_size_log_mb = MAX2((int)HeapRegion::LogOfHRGrainBytes - (int)LOG_M, 0);
if (FLAG_IS_DEFAULT(G1RSetSparseRegionEntries)) {
G1RSetSparseRegionEntries = G1RSetSparseRegionEntriesBase * (region_size_log_mb + 1);
}
if (FLAG_IS_DEFAULT(G1RSetRegionEntries)) {
G1RSetRegionEntries = G1RSetRegionEntriesBase * (region_size_log_mb + 1);
}
guarantee(G1RSetSparseRegionEntries > 0 && G1RSetRegionEntries > 0 , "Sanity");
}
void HeapRegionRemSet::init_for_par_iteration() {
_iter_state = Unclaimed;
}
@ -1385,7 +1408,7 @@ void HeapRegionRemSet::test() {
os::sleep(Thread::current(), (jlong)5000, false);
G1CollectedHeap* g1h = G1CollectedHeap::heap();
// Run with "-XX:G1LogRSRegionEntries=2", so that 1 and 5 end up in same
// Run with "-XX:G1LogRSetRegionEntries=2", so that 1 and 5 end up in same
// hash bucket.
HeapRegion* hr0 = g1h->region_at(0);
HeapRegion* hr1 = g1h->region_at(1);

View File

@ -187,7 +187,8 @@ private:
void clear_outgoing_entries();
enum ParIterState { Unclaimed, Claimed, Complete };
ParIterState _iter_state;
volatile ParIterState _iter_state;
volatile jlong _iter_claimed;
// Unused unless G1RecordHRRSOops is true.
@ -209,6 +210,7 @@ public:
HeapRegion* hr);
static int num_par_rem_sets();
static void setup_remset_size();
HeapRegion* hr() const {
return _other_regions.hr();
@ -272,6 +274,19 @@ public:
// Returns "true" iff the region's iteration is complete.
bool iter_is_complete();
// Support for claiming blocks of cards during iteration
void set_iter_claimed(size_t x) { _iter_claimed = (jlong)x; }
size_t iter_claimed() const { return (size_t)_iter_claimed; }
// Claim the next block of cards
size_t iter_claimed_next(size_t step) {
size_t current, next;
do {
current = iter_claimed();
next = current + step;
} while (Atomic::cmpxchg((jlong)next, &_iter_claimed, (jlong)current) != (jlong)current);
return current;
}
// Initialize the given iterator to iterate over this rem set.
void init_iterator(HeapRegionRemSetIterator* iter) const;

View File

@ -27,7 +27,7 @@
#define SPARSE_PRT_VERBOSE 0
#define UNROLL_CARD_LOOPS 1
#define UNROLL_CARD_LOOPS 1
void SparsePRT::init_iterator(SparsePRTIter* sprt_iter) {
sprt_iter->init(this);
@ -36,27 +36,32 @@ void SparsePRT::init_iterator(SparsePRTIter* sprt_iter) {
void SparsePRTEntry::init(RegionIdx_t region_ind) {
_region_ind = region_ind;
_next_index = NullEntry;
#if UNROLL_CARD_LOOPS
assert(CardsPerEntry == 4, "Assumption. If changes, un-unroll.");
_cards[0] = NullEntry;
_cards[1] = NullEntry;
_cards[2] = NullEntry;
_cards[3] = NullEntry;
assert((cards_num() & (UnrollFactor - 1)) == 0, "Invalid number of cards in the entry");
for (int i = 0; i < cards_num(); i += UnrollFactor) {
_cards[i] = NullEntry;
_cards[i + 1] = NullEntry;
_cards[i + 2] = NullEntry;
_cards[i + 3] = NullEntry;
}
#else
for (int i = 0; i < CardsPerEntry; i++)
for (int i = 0; i < cards_num(); i++)
_cards[i] = NullEntry;
#endif
}
bool SparsePRTEntry::contains_card(CardIdx_t card_index) const {
#if UNROLL_CARD_LOOPS
assert(CardsPerEntry == 4, "Assumption. If changes, un-unroll.");
if (_cards[0] == card_index) return true;
if (_cards[1] == card_index) return true;
if (_cards[2] == card_index) return true;
if (_cards[3] == card_index) return true;
assert((cards_num() & (UnrollFactor - 1)) == 0, "Invalid number of cards in the entry");
for (int i = 0; i < cards_num(); i += UnrollFactor) {
if (_cards[i] == card_index ||
_cards[i + 1] == card_index ||
_cards[i + 2] == card_index ||
_cards[i + 3] == card_index) return true;
}
#else
for (int i = 0; i < CardsPerEntry; i++) {
for (int i = 0; i < cards_num(); i++) {
if (_cards[i] == card_index) return true;
}
#endif
@ -67,14 +72,16 @@ bool SparsePRTEntry::contains_card(CardIdx_t card_index) const {
int SparsePRTEntry::num_valid_cards() const {
int sum = 0;
#if UNROLL_CARD_LOOPS
assert(CardsPerEntry == 4, "Assumption. If changes, un-unroll.");
if (_cards[0] != NullEntry) sum++;
if (_cards[1] != NullEntry) sum++;
if (_cards[2] != NullEntry) sum++;
if (_cards[3] != NullEntry) sum++;
assert((cards_num() & (UnrollFactor - 1)) == 0, "Invalid number of cards in the entry");
for (int i = 0; i < cards_num(); i += UnrollFactor) {
sum += (_cards[i] != NullEntry);
sum += (_cards[i + 1] != NullEntry);
sum += (_cards[i + 2] != NullEntry);
sum += (_cards[i + 3] != NullEntry);
}
#else
for (int i = 0; i < CardsPerEntry; i++) {
if (_cards[i] != NulLEntry) sum++;
for (int i = 0; i < cards_num(); i++) {
sum += (_cards[i] != NullEntry);
}
#endif
// Otherwise, we're full.
@ -83,27 +90,27 @@ int SparsePRTEntry::num_valid_cards() const {
SparsePRTEntry::AddCardResult SparsePRTEntry::add_card(CardIdx_t card_index) {
#if UNROLL_CARD_LOOPS
assert(CardsPerEntry == 4, "Assumption. If changes, un-unroll.");
CardIdx_t c = _cards[0];
if (c == card_index) return found;
if (c == NullEntry) { _cards[0] = card_index; return added; }
c = _cards[1];
if (c == card_index) return found;
if (c == NullEntry) { _cards[1] = card_index; return added; }
c = _cards[2];
if (c == card_index) return found;
if (c == NullEntry) { _cards[2] = card_index; return added; }
c = _cards[3];
if (c == card_index) return found;
if (c == NullEntry) { _cards[3] = card_index; return added; }
assert((cards_num() & (UnrollFactor - 1)) == 0, "Invalid number of cards in the entry");
CardIdx_t c;
for (int i = 0; i < cards_num(); i += UnrollFactor) {
c = _cards[i];
if (c == card_index) return found;
if (c == NullEntry) { _cards[i] = card_index; return added; }
c = _cards[i + 1];
if (c == card_index) return found;
if (c == NullEntry) { _cards[i + 1] = card_index; return added; }
c = _cards[i + 2];
if (c == card_index) return found;
if (c == NullEntry) { _cards[i + 2] = card_index; return added; }
c = _cards[i + 3];
if (c == card_index) return found;
if (c == NullEntry) { _cards[i + 3] = card_index; return added; }
}
#else
for (int i = 0; i < CardsPerEntry; i++) {
for (int i = 0; i < cards_num(); i++) {
CardIdx_t c = _cards[i];
if (c == card_index) return found;
if (c == NullEntry) {
_cards[i] = card_index;
return added;
}
if (c == NullEntry) { _cards[i] = card_index; return added; }
}
#endif
// Otherwise, we're full.
@ -112,13 +119,15 @@ SparsePRTEntry::AddCardResult SparsePRTEntry::add_card(CardIdx_t card_index) {
void SparsePRTEntry::copy_cards(CardIdx_t* cards) const {
#if UNROLL_CARD_LOOPS
assert(CardsPerEntry == 4, "Assumption. If changes, un-unroll.");
cards[0] = _cards[0];
cards[1] = _cards[1];
cards[2] = _cards[2];
cards[3] = _cards[3];
assert((cards_num() & (UnrollFactor - 1)) == 0, "Invalid number of cards in the entry");
for (int i = 0; i < cards_num(); i += UnrollFactor) {
cards[i] = _cards[i];
cards[i + 1] = _cards[i + 1];
cards[i + 2] = _cards[i + 2];
cards[i + 3] = _cards[i + 3];
}
#else
for (int i = 0; i < CardsPerEntry; i++) {
for (int i = 0; i < cards_num(); i++) {
cards[i] = _cards[i];
}
#endif
@ -133,7 +142,7 @@ void SparsePRTEntry::copy_cards(SparsePRTEntry* e) const {
RSHashTable::RSHashTable(size_t capacity) :
_capacity(capacity), _capacity_mask(capacity-1),
_occupied_entries(0), _occupied_cards(0),
_entries(NEW_C_HEAP_ARRAY(SparsePRTEntry, capacity)),
_entries((SparsePRTEntry*)NEW_C_HEAP_ARRAY(char, SparsePRTEntry::size() * capacity)),
_buckets(NEW_C_HEAP_ARRAY(int, capacity)),
_free_list(NullEntry), _free_region(0)
{
@ -161,8 +170,8 @@ void RSHashTable::clear() {
"_capacity too large");
// This will put -1 == NullEntry in the key field of all entries.
memset(_entries, -1, _capacity * sizeof(SparsePRTEntry));
memset(_buckets, -1, _capacity * sizeof(int));
memset(_entries, NullEntry, _capacity * SparsePRTEntry::size());
memset(_buckets, NullEntry, _capacity * sizeof(int));
_free_list = NullEntry;
_free_region = 0;
}
@ -175,8 +184,8 @@ bool RSHashTable::add_card(RegionIdx_t region_ind, CardIdx_t card_index) {
if (res == SparsePRTEntry::added) _occupied_cards++;
#if SPARSE_PRT_VERBOSE
gclog_or_tty->print_cr(" after add_card[%d]: valid-cards = %d.",
pointer_delta(e, _entries, sizeof(SparsePRTEntry)),
e->num_valid_cards());
pointer_delta(e, _entries, SparsePRTEntry::size()),
e->num_valid_cards());
#endif
assert(e->num_valid_cards() > 0, "Postcondition");
return res != SparsePRTEntry::overflow;
@ -199,6 +208,22 @@ bool RSHashTable::get_cards(RegionIdx_t region_ind, CardIdx_t* cards) {
return true;
}
SparsePRTEntry* RSHashTable::get_entry(RegionIdx_t region_ind) {
int ind = (int) (region_ind & capacity_mask());
int cur_ind = _buckets[ind];
SparsePRTEntry* cur;
while (cur_ind != NullEntry &&
(cur = entry(cur_ind))->r_ind() != region_ind) {
cur_ind = cur->next_index();
}
if (cur_ind == NullEntry) return NULL;
// Otherwise...
assert(cur->r_ind() == region_ind, "Postcondition of loop + test above.");
assert(cur->num_valid_cards() > 0, "Inv");
return cur;
}
bool RSHashTable::delete_entry(RegionIdx_t region_ind) {
int ind = (int) (region_ind & capacity_mask());
int* prev_loc = &_buckets[ind];
@ -225,20 +250,8 @@ RSHashTable::entry_for_region_ind(RegionIdx_t region_ind) const {
int ind = (int) (region_ind & capacity_mask());
int cur_ind = _buckets[ind];
SparsePRTEntry* cur;
// XXX
// int k = 0;
while (cur_ind != NullEntry &&
(cur = entry(cur_ind))->r_ind() != region_ind) {
/*
k++;
if (k > 10) {
gclog_or_tty->print_cr("RSHashTable::entry_for_region_ind(%d): "
"k = %d, cur_ind = %d.", region_ind, k, cur_ind);
if (k >= 1000) {
while (1) ;
}
}
*/
cur_ind = cur->next_index();
}
@ -319,7 +332,7 @@ size_t /* RSHashTable:: */ RSHashTableIter::compute_card_ind(CardIdx_t ci) {
bool /* RSHashTable:: */ RSHashTableIter::has_next(size_t& card_index) {
_card_ind++;
CardIdx_t ci;
if (_card_ind < SparsePRTEntry::CardsPerEntry &&
if (_card_ind < SparsePRTEntry::cards_num() &&
((ci = _rsht->entry(_bl_ind)->card(_card_ind)) !=
SparsePRTEntry::NullEntry)) {
card_index = compute_card_ind(ci);
@ -359,7 +372,7 @@ bool RSHashTable::contains_card(RegionIdx_t region_index, CardIdx_t card_index)
size_t RSHashTable::mem_size() const {
return sizeof(this) +
capacity() * (sizeof(SparsePRTEntry) + sizeof(int));
capacity() * (SparsePRTEntry::size() + sizeof(int));
}
// ----------------------------------------------------------------------
@ -446,6 +459,10 @@ bool SparsePRT::get_cards(RegionIdx_t region_id, CardIdx_t* cards) {
return _next->get_cards(region_id, cards);
}
SparsePRTEntry* SparsePRT::get_entry(RegionIdx_t region_id) {
return _next->get_entry(region_id);
}
bool SparsePRT::delete_entry(RegionIdx_t region_id) {
return _next->delete_entry(region_id);
}

View File

@ -32,21 +32,28 @@
// insertions only enqueue old versions for deletions, but do not delete
// old versions synchronously.
class SparsePRTEntry: public CHeapObj {
public:
enum SomePublicConstants {
CardsPerEntry = 4,
NullEntry = -1
NullEntry = -1,
UnrollFactor = 4
};
private:
RegionIdx_t _region_ind;
int _next_index;
CardIdx_t _cards[CardsPerEntry];
CardIdx_t _cards[1];
// WARNING: Don't put any data members beyond this line. Card array has, in fact, variable length.
// It should always be the last data member.
public:
// Returns the size of the entry, used for entry allocation.
static size_t size() { return sizeof(SparsePRTEntry) + sizeof(CardIdx_t) * (cards_num() - 1); }
// Returns the size of the card array.
static int cards_num() {
// The number of cards should be a multiple of 4, because that's our current
// unrolling factor.
static const int s = MAX2<int>(G1RSetSparseRegionEntries & ~(UnrollFactor - 1), UnrollFactor);
return s;
}
// Set the region_ind to the given value, and delete all cards.
inline void init(RegionIdx_t region_ind);
@ -134,12 +141,15 @@ public:
bool add_card(RegionIdx_t region_id, CardIdx_t card_index);
bool get_cards(RegionIdx_t region_id, CardIdx_t* cards);
bool delete_entry(RegionIdx_t region_id);
bool contains_card(RegionIdx_t region_id, CardIdx_t card_index) const;
void add_entry(SparsePRTEntry* e);
SparsePRTEntry* get_entry(RegionIdx_t region_id);
void clear();
size_t capacity() const { return _capacity; }
@ -148,7 +158,7 @@ public:
size_t occupied_cards() const { return _occupied_cards; }
size_t mem_size() const;
SparsePRTEntry* entry(int i) const { return &_entries[i]; }
SparsePRTEntry* entry(int i) const { return (SparsePRTEntry*)((char*)_entries + SparsePRTEntry::size() * i); }
void print();
};
@ -157,7 +167,7 @@ public:
class RSHashTableIter VALUE_OBJ_CLASS_SPEC {
int _tbl_ind; // [-1, 0.._rsht->_capacity)
int _bl_ind; // [-1, 0.._rsht->_capacity)
short _card_ind; // [0..CardsPerEntry)
short _card_ind; // [0..SparsePRTEntry::cards_num())
RSHashTable* _rsht;
size_t _heap_bot_card_ind;
@ -176,7 +186,7 @@ public:
RSHashTableIter(size_t heap_bot_card_ind) :
_tbl_ind(RSHashTable::NullEntry),
_bl_ind(RSHashTable::NullEntry),
_card_ind((SparsePRTEntry::CardsPerEntry-1)),
_card_ind((SparsePRTEntry::cards_num() - 1)),
_rsht(NULL),
_heap_bot_card_ind(heap_bot_card_ind)
{}
@ -185,7 +195,7 @@ public:
_rsht = rsht;
_tbl_ind = -1; // So that first increment gets to 0.
_bl_ind = RSHashTable::NullEntry;
_card_ind = (SparsePRTEntry::CardsPerEntry-1);
_card_ind = (SparsePRTEntry::cards_num() - 1);
}
bool has_next(size_t& card_index);
@ -241,9 +251,13 @@ public:
// If the table hold an entry for "region_ind", Copies its
// cards into "cards", which must be an array of length at least
// "CardsPerEntry", and returns "true"; otherwise, returns "false".
// "SparePRTEntry::cards_num()", and returns "true"; otherwise,
// returns "false".
bool get_cards(RegionIdx_t region_ind, CardIdx_t* cards);
// Return the pointer to the entry associated with the given region.
SparsePRTEntry* get_entry(RegionIdx_t region_ind);
// If there is an entry for "region_ind", removes it and return "true";
// otherwise returns "false."
bool delete_entry(RegionIdx_t region_ind);

View File

@ -175,6 +175,7 @@ arguments.cpp jvmtiExport.hpp
arguments.cpp management.hpp
arguments.cpp oop.inline.hpp
arguments.cpp os_<os_family>.inline.hpp
arguments.cpp referenceProcessor.hpp
arguments.cpp universe.inline.hpp
arguments.cpp vm_version_<arch>.hpp
@ -1483,6 +1484,7 @@ deoptimization.cpp thread.hpp
deoptimization.cpp vframe.hpp
deoptimization.cpp vframeArray.hpp
deoptimization.cpp vframe_hp.hpp
deoptimization.cpp vmreg_<arch>.inline.hpp
deoptimization.cpp xmlstream.hpp
deoptimization.hpp allocation.hpp
@ -2653,6 +2655,7 @@ loaderConstraints.cpp resourceArea.hpp
loaderConstraints.cpp safepoint.hpp
loaderConstraints.hpp dictionary.hpp
loaderConstraints.hpp placeholders.hpp
loaderConstraints.hpp hashtable.hpp
location.cpp debugInfo.hpp

View File

@ -124,8 +124,6 @@ public:
// Below length is the # array elements being written
virtual void write_ref_array_pre( oop* dst, int length) {}
virtual void write_ref_array_pre(narrowOop* dst, int length) {}
// Below MemRegion mr is expected to be HeapWord-aligned
inline void write_ref_array(MemRegion mr);
// Below count is the # array elements being written, starting
// at the address "start", which may not necessarily be HeapWord-aligned
inline void write_ref_array(HeapWord* start, size_t count);

View File

@ -42,16 +42,6 @@ void BarrierSet::write_ref_field(void* field, oop new_val) {
}
}
void BarrierSet::write_ref_array(MemRegion mr) {
assert((HeapWord*)align_size_down((uintptr_t)mr.start(), HeapWordSize) == mr.start() , "Unaligned start");
assert((HeapWord*)align_size_up ((uintptr_t)mr.end(), HeapWordSize) == mr.end(), "Unaligned end" );
if (kind() == CardTableModRef) {
((CardTableModRefBS*)this)->inline_write_ref_array(mr);
} else {
write_ref_array_work(mr);
}
}
// count is number of array elements being written
void BarrierSet::write_ref_array(HeapWord* start, size_t count) {
assert(count <= (size_t)max_intx, "count too large");
@ -61,12 +51,12 @@ void BarrierSet::write_ref_array(HeapWord* start, size_t count) {
// strictly necessary for current uses, but a case of good hygiene and,
// if you will, aesthetics) and the second upward (this is essential for
// current uses) to a HeapWord boundary, so we mark all cards overlapping
// this write. In the event that this evolves in the future to calling a
// this write. If this evolves in the future to calling a
// logging barrier of narrow oop granularity, like the pre-barrier for G1
// (mentioned here merely by way of example), we will need to change this
// interface, much like the pre-barrier one above, so it is "exactly precise"
// (if i may be allowed the adverbial redundancy for emphasis) and does not
// include narrow oop slots not included in the original write interval.
// interface, so it is "exactly precise" (if i may be allowed the adverbial
// redundancy for emphasis) and does not include narrow oop slots not
// included in the original write interval.
HeapWord* aligned_start = (HeapWord*)align_size_down((uintptr_t)start, HeapWordSize);
HeapWord* aligned_end = (HeapWord*)align_size_up ((uintptr_t)end, HeapWordSize);
// If compressed oops were not being used, these should already be aligned

View File

@ -339,6 +339,16 @@ public:
return (val & (clean_card_mask_val() | claimed_card_val())) == claimed_card_val();
}
void set_card_claimed(size_t card_index) {
jbyte val = _byte_map[card_index];
if (val == clean_card_val()) {
val = (jbyte)claimed_card_val();
} else {
val |= (jbyte)claimed_card_val();
}
_byte_map[card_index] = val;
}
bool claim_card(size_t card_index);
bool is_card_clean(size_t card_index) {

View File

@ -263,10 +263,13 @@ class ReferenceProcessor : public CHeapObj {
int parallel_gc_threads = 1,
bool mt_processing = false,
bool discovered_list_needs_barrier = false);
// RefDiscoveryPolicy values
enum {
enum DiscoveryPolicy {
ReferenceBasedDiscovery = 0,
ReferentBasedDiscovery = 1
ReferentBasedDiscovery = 1,
DiscoveryPolicyMin = ReferenceBasedDiscovery,
DiscoveryPolicyMax = ReferentBasedDiscovery
};
static void init_statics();

View File

@ -1,5 +1,5 @@
/*
* Copyright 2000-2009 Sun Microsystems, Inc. All Rights Reserved.
* Copyright 2000-2010 Sun Microsystems, Inc. All Rights Reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -545,6 +545,10 @@ public:
return cell_offset(counter_cell_count);
}
void set_count(uint count) {
set_uint_at(count_off, count);
}
#ifndef PRODUCT
void print_data_on(outputStream* st);
#endif
@ -692,6 +696,23 @@ public:
void clear_row(uint row) {
assert(row < row_limit(), "oob");
// Clear total count - indicator of polymorphic call site.
// The site may look like as monomorphic after that but
// it allow to have more accurate profiling information because
// there was execution phase change since klasses were unloaded.
// If the site is still polymorphic then MDO will be updated
// to reflect it. But it could be the case that the site becomes
// only bimorphic. Then keeping total count not 0 will be wrong.
// Even if we use monomorphic (when it is not) for compilation
// we will only have trap, deoptimization and recompile again
// with updated MDO after executing method in Interpreter.
// An additional receiver will be recorded in the cleaned row
// during next call execution.
//
// Note: our profiling logic works with empty rows in any slot.
// We do sorting a profiling info (ciCallProfile) for compilation.
//
set_count(0);
set_receiver(row, NULL);
set_receiver_count(row, 0);
}

View File

@ -1,5 +1,5 @@
/*
* Copyright 2000-2009 Sun Microsystems, Inc. All Rights Reserved.
* Copyright 2000-2010 Sun Microsystems, Inc. All Rights Reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -136,8 +136,10 @@ JVMState* DirectCallGenerator::generate(JVMState* jvms) {
}
// Mark the call node as virtual, sort of:
call->set_optimized_virtual(true);
if (method()->is_method_handle_invoke())
if (method()->is_method_handle_invoke()) {
call->set_method_handle_invoke(true);
kit.C->set_has_method_handle_invokes(true);
}
}
kit.set_arguments_for_java_call(call);
kit.set_edges_for_java_call(call, false, _separate_io_proj);
@ -194,6 +196,7 @@ JVMState* DynamicCallGenerator::generate(JVMState* jvms) {
call->set_optimized_virtual(true);
// Take extra care (in the presence of argument motion) not to trash the SP:
call->set_method_handle_invoke(true);
kit.C->set_has_method_handle_invokes(true);
// Pass the target MethodHandle as first argument and shift the
// other arguments.

View File

@ -1,5 +1,5 @@
/*
* Copyright 1997-2009 Sun Microsystems, Inc. All Rights Reserved.
* Copyright 1997-2010 Sun Microsystems, Inc. All Rights Reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -465,6 +465,7 @@ Compile::Compile( ciEnv* ci_env, C2Compiler* compiler, ciMethod* target, int osr
_code_buffer("Compile::Fill_buffer"),
_orig_pc_slot(0),
_orig_pc_slot_offset_in_bytes(0),
_has_method_handle_invokes(false),
_node_bundling_limit(0),
_node_bundling_base(NULL),
_java_calls(0),
@ -759,6 +760,7 @@ Compile::Compile( ciEnv* ci_env,
_do_escape_analysis(false),
_failure_reason(NULL),
_code_buffer("Compile::Fill_buffer"),
_has_method_handle_invokes(false),
_node_bundling_limit(0),
_node_bundling_base(NULL),
_java_calls(0),

View File

@ -1,5 +1,5 @@
/*
* Copyright 1997-2009 Sun Microsystems, Inc. All Rights Reserved.
* Copyright 1997-2010 Sun Microsystems, Inc. All Rights Reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -166,6 +166,9 @@ class Compile : public Phase {
bool _parsed_irreducible_loop; // True if ciTypeFlow detected irreducible loops during parsing
#endif
// JSR 292
bool _has_method_handle_invokes; // True if this method has MethodHandle invokes.
// Compilation environment.
Arena _comp_arena; // Arena with lifetime equivalent to Compile
ciEnv* _env; // CI interface
@ -336,6 +339,10 @@ class Compile : public Phase {
void set_parsed_irreducible_loop(bool z) { _parsed_irreducible_loop = z; }
#endif
// JSR 292
bool has_method_handle_invokes() const { return _has_method_handle_invokes; }
void set_has_method_handle_invokes(bool z) { _has_method_handle_invokes = z; }
void begin_method() {
#ifndef PRODUCT
if (_printer) _printer->begin_method(this);

View File

@ -1,5 +1,5 @@
/*
* Copyright 1998-2009 Sun Microsystems, Inc. All Rights Reserved.
* Copyright 1998-2010 Sun Microsystems, Inc. All Rights Reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -70,7 +70,7 @@ CallGenerator* Compile::call_generator(ciMethod* call_method, int vtable_index,
CompileLog* log = this->log();
if (log != NULL) {
int rid = (receiver_count >= 0)? log->identify(profile.receiver(0)): -1;
int r2id = (profile.morphism() == 2)? log->identify(profile.receiver(1)):-1;
int r2id = (rid != -1 && profile.has_receiver(1))? log->identify(profile.receiver(1)):-1;
log->begin_elem("call method='%d' count='%d' prof_factor='%g'",
log->identify(call_method), site_count, prof_factor);
if (call_is_virtual) log->print(" virtual='1'");

View File

@ -780,12 +780,20 @@ bool GraphKit::dead_locals_are_killed() {
// Helper function for enforcing certain bytecodes to reexecute if
// deoptimization happens
static bool should_reexecute_implied_by_bytecode(JVMState *jvms) {
static bool should_reexecute_implied_by_bytecode(JVMState *jvms, bool is_anewarray) {
ciMethod* cur_method = jvms->method();
int cur_bci = jvms->bci();
if (cur_method != NULL && cur_bci != InvocationEntryBci) {
Bytecodes::Code code = cur_method->java_code_at_bci(cur_bci);
return Interpreter::bytecode_should_reexecute(code);
return Interpreter::bytecode_should_reexecute(code) ||
is_anewarray && code == Bytecodes::_multianewarray;
// Reexecute _multianewarray bytecode which was replaced with
// sequence of [a]newarray. See Parse::do_multianewarray().
//
// Note: interpreter should not have it set since this optimization
// is limited by dimensions and guarded by flag so in some cases
// multianewarray() runtime calls will be generated and
// the bytecode should not be reexecutes (stack will not be reset).
} else
return false;
}
@ -836,7 +844,7 @@ void GraphKit::add_safepoint_edges(SafePointNode* call, bool must_throw) {
// For a known set of bytecodes, the interpreter should reexecute them if
// deoptimization happens. We set the reexecute state for them here
if (out_jvms->is_reexecute_undefined() && //don't change if already specified
should_reexecute_implied_by_bytecode(out_jvms)) {
should_reexecute_implied_by_bytecode(out_jvms, call->is_AllocateArray())) {
out_jvms->set_should_reexecute(true); //NOTE: youngest_jvms not changed
}

View File

@ -1,5 +1,5 @@
/*
* Copyright 1999-2009 Sun Microsystems, Inc. All Rights Reserved.
* Copyright 1999-2010 Sun Microsystems, Inc. All Rights Reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -47,7 +47,7 @@ Node *PhaseIdealLoop::split_thru_phi( Node *n, Node *region, int policy ) {
int offset = t_oop->offset();
phi = new (C,region->req()) PhiNode(region, type, NULL, iid, index, offset);
} else {
phi = new (C,region->req()) PhiNode(region, type);
phi = PhiNode::make_blank(region, n);
}
uint old_unique = C->unique();
for( uint i = 1; i < region->req(); i++ ) {

View File

@ -795,6 +795,7 @@ void Compile::Process_OopMap_Node(MachNode *mach, int current_offset) {
int safepoint_pc_offset = current_offset;
bool is_method_handle_invoke = false;
bool return_oop = false;
// Add the safepoint in the DebugInfoRecorder
if( !mach->is_MachCall() ) {
@ -804,9 +805,18 @@ void Compile::Process_OopMap_Node(MachNode *mach, int current_offset) {
mcall = mach->as_MachCall();
// Is the call a MethodHandle call?
if (mcall->is_MachCallJava())
is_method_handle_invoke = mcall->as_MachCallJava()->_method_handle_invoke;
if (mcall->is_MachCallJava()) {
if (mcall->as_MachCallJava()->_method_handle_invoke) {
assert(has_method_handle_invokes(), "must have been set during call generation");
is_method_handle_invoke = true;
}
}
// Check if a call returns an object.
if (mcall->return_value_is_used() &&
mcall->tf()->range()->field_at(TypeFunc::Parms)->isa_ptr()) {
return_oop = true;
}
safepoint_pc_offset += mcall->ret_addr_offset();
debug_info()->add_safepoint(safepoint_pc_offset, mcall->_oop_map);
}
@ -919,7 +929,7 @@ void Compile::Process_OopMap_Node(MachNode *mach, int current_offset) {
assert(jvms->bci() >= InvocationEntryBci && jvms->bci() <= 0x10000, "must be a valid or entry BCI");
assert(!jvms->should_reexecute() || depth == max_depth, "reexecute allowed only for the youngest");
// Now we can describe the scope.
debug_info()->describe_scope(safepoint_pc_offset, scope_method, jvms->bci(), jvms->should_reexecute(), is_method_handle_invoke, locvals, expvals, monvals);
debug_info()->describe_scope(safepoint_pc_offset, scope_method, jvms->bci(), jvms->should_reexecute(), is_method_handle_invoke, return_oop, locvals, expvals, monvals);
} // End jvms loop
// Mark the end of the scope set.
@ -1086,9 +1096,21 @@ void Compile::Fill_buffer() {
deopt_handler_req += MAX_stubs_size; // add marginal slop for handler
stub_req += MAX_stubs_size; // ensure per-stub margin
code_req += MAX_inst_size; // ensure per-instruction margin
if (StressCodeBuffers)
code_req = const_req = stub_req = exception_handler_req = deopt_handler_req = 0x10; // force expansion
int total_req = code_req + pad_req + stub_req + exception_handler_req + deopt_handler_req + const_req;
int total_req =
code_req +
pad_req +
stub_req +
exception_handler_req +
deopt_handler_req + // deopt handler
const_req;
if (has_method_handle_invokes())
total_req += deopt_handler_req; // deopt MH handler
CodeBuffer* cb = code_buffer();
cb->initialize(total_req, locs_req);
@ -1430,10 +1452,13 @@ void Compile::Fill_buffer() {
_code_offsets.set_value(CodeOffsets::Exceptions, emit_exception_handler(*cb));
// Emit the deopt handler code.
_code_offsets.set_value(CodeOffsets::Deopt, emit_deopt_handler(*cb));
// Emit the MethodHandle deopt handler code. We can use the same
// code as for the normal deopt handler, we just need a different
// entry point address.
_code_offsets.set_value(CodeOffsets::DeoptMH, emit_deopt_handler(*cb));
// Emit the MethodHandle deopt handler code (if required).
if (has_method_handle_invokes()) {
// We can use the same code as for the normal deopt handler, we
// just need a different entry point address.
_code_offsets.set_value(CodeOffsets::DeoptMH, emit_deopt_handler(*cb));
}
}
// One last check for failed CodeBuffer::expand:

View File

@ -824,7 +824,6 @@ bool Parse::can_rerun_bytecode() {
case Bytecodes::_ddiv:
case Bytecodes::_checkcast:
case Bytecodes::_instanceof:
case Bytecodes::_athrow:
case Bytecodes::_anewarray:
case Bytecodes::_newarray:
case Bytecodes::_multianewarray:
@ -834,6 +833,8 @@ bool Parse::can_rerun_bytecode() {
return true;
break;
// Don't rerun athrow since it's part of the exception path.
case Bytecodes::_athrow:
case Bytecodes::_invokestatic:
case Bytecodes::_invokedynamic:
case Bytecodes::_invokespecial:

View File

@ -1,5 +1,5 @@
/*
* Copyright 1998-2009 Sun Microsystems, Inc. All Rights Reserved.
* Copyright 1998-2010 Sun Microsystems, Inc. All Rights Reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -439,8 +439,18 @@ void Parse::do_multianewarray() {
// Can use multianewarray instead of [a]newarray if only one dimension,
// or if all non-final dimensions are small constants.
if (expand_count == 1 || (1 <= expand_count && expand_count <= expand_limit)) {
Node* obj = expand_multianewarray(array_klass, &length[0], ndimensions, ndimensions);
if (ndimensions == 1 || (1 <= expand_count && expand_count <= expand_limit)) {
Node* obj = NULL;
// Set the original stack and the reexecute bit for the interpreter
// to reexecute the multianewarray bytecode if deoptimization happens.
// Do it unconditionally even for one dimension multianewarray.
// Note: the reexecute bit will be set in GraphKit::add_safepoint_edges()
// when AllocateArray node for newarray is created.
{ PreserveReexecuteState preexecs(this);
_sp += ndimensions;
// Pass 0 as nargs since uncommon trap code does not need to restore stack.
obj = expand_multianewarray(array_klass, &length[0], ndimensions, 0);
} //original reexecute and sp are set back here
push(obj);
return;
}

View File

@ -708,7 +708,7 @@ JRT_LEAF(void, OptoRuntime::profile_receiver_type_C(DataLayout* data, oopDesc* r
*(mdp + count_off) = DataLayout::counter_increment;
} else {
// Receiver did not match any saved receiver and there is no empty row for it.
// Increment total counter to indicate polimorphic case.
// Increment total counter to indicate polymorphic case.
intptr_t* count_p = (intptr_t*)(((byte*)(data)) + in_bytes(CounterData::count_offset()));
*count_p += DataLayout::counter_increment;
}

View File

@ -1,5 +1,5 @@
/*
* Copyright 2009 Sun Microsystems, Inc. All Rights Reserved.
* Copyright 2009-2010 Sun Microsystems, Inc. All Rights Reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -1073,7 +1073,7 @@ void PhaseStringOpts::int_getChars(GraphKit& kit, Node* arg, Node* char_array, N
kit.set_control(head);
kit.set_memory(mem, char_adr_idx);
Node* q = __ DivI(kit.null(), i_phi, __ intcon(10));
Node* q = __ DivI(NULL, i_phi, __ intcon(10));
Node* r = __ SubI(i_phi, __ AddI(__ LShiftI(q, __ intcon(3)),
__ LShiftI(q, __ intcon(1))));
Node* m1 = __ SubI(charPos, __ intcon(1));
@ -1270,14 +1270,15 @@ void PhaseStringOpts::replace_string_concat(StringConcat* sc) {
// length = length + (s.count - s.offset);
RegionNode *r = new (C, 3) RegionNode(3);
kit.gvn().set_type(r, Type::CONTROL);
Node *phi = new (C, 3) PhiNode(r, type->join(TypeInstPtr::NOTNULL));
Node *phi = new (C, 3) PhiNode(r, type);
kit.gvn().set_type(phi, phi->bottom_type());
Node* p = __ Bool(__ CmpP(arg, kit.null()), BoolTest::ne);
IfNode* iff = kit.create_and_map_if(kit.control(), p, PROB_MIN, COUNT_UNKNOWN);
Node* notnull = __ IfTrue(iff);
Node* isnull = __ IfFalse(iff);
kit.set_control(notnull); // set control for the cast_not_null
r->init_req(1, notnull);
phi->init_req(1, arg);
phi->init_req(1, kit.cast_not_null(arg, false));
r->init_req(2, isnull);
phi->init_req(2, null_string);
kit.set_control(r);

View File

@ -402,7 +402,7 @@ void JvmtiCodeBlobEvents::build_jvmti_addr_location_map(nmethod *nm,
address scopes_data = nm->scopes_data_begin();
for( pcd = nm->scopes_pcs_begin(); pcd < nm->scopes_pcs_end(); ++pcd ) {
ScopeDesc sc0(nm, pcd->scope_decode_offset(), pcd->should_reexecute());
ScopeDesc sc0(nm, pcd->scope_decode_offset(), pcd->should_reexecute(), pcd->return_oop());
ScopeDesc *sd = &sc0;
while( !sd->is_top() ) { sd = sd->sender(); }
int bci = sd->bci();

View File

@ -1,5 +1,5 @@
/*
* Copyright 1997-2009 Sun Microsystems, Inc. All Rights Reserved.
* Copyright 1997-2010 Sun Microsystems, Inc. All Rights Reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -1487,6 +1487,20 @@ bool Arguments::created_by_java_launcher() {
//===========================================================================================================
// Parsing of main arguments
bool Arguments::verify_interval(uintx val, uintx min,
uintx max, const char* name) {
// Returns true iff value is in the inclusive interval [min..max]
// false, otherwise.
if (val >= min && val <= max) {
return true;
}
jio_fprintf(defaultStream::error_stream(),
"%s of " UINTX_FORMAT " is invalid; must be between " UINTX_FORMAT
" and " UINTX_FORMAT "\n",
name, val, min, max);
return false;
}
bool Arguments::verify_percentage(uintx value, const char* name) {
if (value <= 100) {
return true;
@ -1723,6 +1737,16 @@ bool Arguments::check_vm_args_consistency() {
status = false;
}
status = status && verify_interval(RefDiscoveryPolicy,
ReferenceProcessor::DiscoveryPolicyMin,
ReferenceProcessor::DiscoveryPolicyMax,
"RefDiscoveryPolicy");
// Limit the lower bound of this flag to 1 as it is used in a division
// expression.
status = status && verify_interval(TLABWasteTargetPercent,
1, 100, "TLABWasteTargetPercent");
return status;
}
@ -2500,6 +2524,9 @@ jint Arguments::finalize_vm_init_args(SysClassPath* scp_p, bool scp_assembly_req
SOLARIS_ONLY(FLAG_SET_DEFAULT(UseISM, false));
}
// Tiered compilation is undefined with C1.
TieredCompilation = false;
#else
if (!FLAG_IS_DEFAULT(OptoLoopAlignment) && FLAG_IS_DEFAULT(MaxLoopPad)) {
FLAG_SET_DEFAULT(MaxLoopPad, OptoLoopAlignment-1);

View File

@ -336,6 +336,8 @@ class Arguments : AllStatic {
static bool is_bad_option(const JavaVMOption* option, jboolean ignore) {
return is_bad_option(option, ignore, NULL);
}
static bool verify_interval(uintx val, uintx min,
uintx max, const char* name);
static bool verify_percentage(uintx value, const char* name);
static void describe_range_error(ArgsRange errcode);
static ArgsRange check_memory_size(julong size, julong min_size);

View File

@ -145,6 +145,27 @@ Deoptimization::UnrollBlock* Deoptimization::fetch_unroll_info_helper(JavaThread
if (EliminateAllocations) {
assert (chunk->at(0)->scope() != NULL,"expect only compiled java frames");
GrowableArray<ScopeValue*>* objects = chunk->at(0)->scope()->objects();
// The flag return_oop() indicates call sites which return oop
// in compiled code. Such sites include java method calls,
// runtime calls (for example, used to allocate new objects/arrays
// on slow code path) and any other calls generated in compiled code.
// It is not guaranteed that we can get such information here only
// by analyzing bytecode in deoptimized frames. This is why this flag
// is set during method compilation (see Compile::Process_OopMap_Node()).
bool save_oop_result = chunk->at(0)->scope()->return_oop();
Handle return_value;
if (save_oop_result) {
// Reallocation may trigger GC. If deoptimization happened on return from
// call which returns oop we need to save it since it is not in oopmap.
oop result = deoptee.saved_oop_result(&map);
assert(result == NULL || result->is_oop(), "must be oop");
return_value = Handle(thread, result);
assert(Universe::heap()->is_in_or_null(result), "must be heap pointer");
if (TraceDeoptimization) {
tty->print_cr("SAVED OOP RESULT " INTPTR_FORMAT " in thread " INTPTR_FORMAT, result, thread);
}
}
bool reallocated = false;
if (objects != NULL) {
JRT_BLOCK
@ -158,9 +179,13 @@ Deoptimization::UnrollBlock* Deoptimization::fetch_unroll_info_helper(JavaThread
ttyLocker ttyl;
tty->print_cr("REALLOC OBJECTS in thread " INTPTR_FORMAT, thread);
print_objects(objects);
}
}
#endif
}
if (save_oop_result) {
// Restore result.
deoptee.set_saved_oop_result(&map, return_value());
}
}
if (EliminateLocks) {
#ifndef PRODUCT
@ -913,21 +938,6 @@ vframeArray* Deoptimization::create_vframeArray(JavaThread* thread, frame fr, Re
if (TraceDeoptimization) {
ttyLocker ttyl;
tty->print_cr(" Created vframeArray " INTPTR_FORMAT, array);
if (Verbose) {
int count = 0;
// this used to leak deoptimizedVFrame like it was going out of style!!!
for (int index = 0; index < array->frames(); index++ ) {
vframeArrayElement* e = array->element(index);
e->print(tty);
/*
No printing yet.
array->vframe_at(index)->print_activation(count++);
// better as...
array->print_activation_for(index, count++);
*/
}
}
}
#endif // PRODUCT

View File

@ -606,12 +606,12 @@ void frame::interpreter_frame_print_on(outputStream* st) const {
for (BasicObjectLock* current = interpreter_frame_monitor_end();
current < interpreter_frame_monitor_begin();
current = next_monitor_in_interpreter_frame(current)) {
st->print_cr(" [ - obj ");
st->print(" - obj [");
current->obj()->print_value_on(st);
st->cr();
st->print_cr(" - lock ");
st->print_cr("]");
st->print(" - lock [");
current->lock()->print_on(st);
st->cr();
st->print_cr("]");
}
// monitor
st->print_cr(" - monitor[" INTPTR_FORMAT "]", interpreter_frame_monitor_begin());

View File

@ -607,7 +607,9 @@ address SharedRuntime::continuation_for_implicit_exception(JavaThread* thread,
_implicit_null_throws++;
#endif
target_pc = nm->continuation_for_implicit_exception(pc);
guarantee(target_pc != 0, "must have a continuation point");
// If there's an unexpected fault, target_pc might be NULL,
// in which case we want to fall through into the normal
// error handling code.
}
break; // fall through
@ -621,14 +623,15 @@ address SharedRuntime::continuation_for_implicit_exception(JavaThread* thread,
_implicit_div0_throws++;
#endif
target_pc = nm->continuation_for_implicit_exception(pc);
guarantee(target_pc != 0, "must have a continuation point");
// If there's an unexpected fault, target_pc might be NULL,
// in which case we want to fall through into the normal
// error handling code.
break; // fall through
}
default: ShouldNotReachHere();
}
guarantee(target_pc != NULL, "must have computed destination PC for implicit exception");
assert(exception_kind == IMPLICIT_NULL || exception_kind == IMPLICIT_DIVIDE_BY_ZERO, "wrong implicit exception kind");
// for AbortVMOnException flag
@ -1944,7 +1947,7 @@ class AdapterHandlerTable : public BasicHashtable {
private:
#ifdef ASSERT
#ifndef PRODUCT
static int _lookups; // number of calls to lookup
static int _buckets; // number of buckets checked
static int _equals; // number of buckets checked with matching hash
@ -1980,16 +1983,16 @@ class AdapterHandlerTable : public BasicHashtable {
// Find a entry with the same fingerprint if it exists
AdapterHandlerEntry* lookup(int total_args_passed, BasicType* sig_bt) {
debug_only(_lookups++);
NOT_PRODUCT(_lookups++);
AdapterFingerPrint fp(total_args_passed, sig_bt);
unsigned int hash = fp.compute_hash();
int index = hash_to_index(hash);
for (AdapterHandlerEntry* e = bucket(index); e != NULL; e = e->next()) {
debug_only(_buckets++);
NOT_PRODUCT(_buckets++);
if (e->hash() == hash) {
debug_only(_equals++);
NOT_PRODUCT(_equals++);
if (fp.equals(e->fingerprint())) {
#ifdef ASSERT
#ifndef PRODUCT
if (fp.is_compact()) _compact++;
_hits++;
#endif
@ -2000,6 +2003,7 @@ class AdapterHandlerTable : public BasicHashtable {
return NULL;
}
#ifndef PRODUCT
void print_statistics() {
ResourceMark rm;
int longest = 0;
@ -2018,15 +2022,14 @@ class AdapterHandlerTable : public BasicHashtable {
}
tty->print_cr("AdapterHandlerTable: empty %d longest %d total %d average %f",
empty, longest, total, total / (double)nonempty);
#ifdef ASSERT
tty->print_cr("AdapterHandlerTable: lookups %d buckets %d equals %d hits %d compact %d",
_lookups, _buckets, _equals, _hits, _compact);
#endif
}
#endif
};
#ifdef ASSERT
#ifndef PRODUCT
int AdapterHandlerTable::_lookups;
int AdapterHandlerTable::_buckets;

View File

@ -196,11 +196,19 @@ void stubRoutines_init2() { StubRoutines::initialize2(); }
// Default versions of arraycopy functions
//
static void gen_arraycopy_barrier_pre(oop* dest, size_t count) {
assert(count != 0, "count should be non-zero");
assert(count <= (size_t)max_intx, "count too large");
BarrierSet* bs = Universe::heap()->barrier_set();
assert(bs->has_write_ref_array_pre_opt(), "Must have pre-barrier opt");
bs->write_ref_array_pre(dest, (int)count);
}
static void gen_arraycopy_barrier(oop* dest, size_t count) {
assert(count != 0, "count should be non-zero");
BarrierSet* bs = Universe::heap()->barrier_set();
assert(bs->has_write_ref_array_opt(), "Barrier set must have ref array opt");
bs->write_ref_array(MemRegion((HeapWord*)dest, (HeapWord*)(dest + count)));
bs->write_ref_array((HeapWord*)dest, count);
}
JRT_LEAF(void, StubRoutines::jbyte_copy(jbyte* src, jbyte* dest, size_t count))
@ -240,6 +248,7 @@ JRT_LEAF(void, StubRoutines::oop_copy(oop* src, oop* dest, size_t count))
SharedRuntime::_oop_array_copy_ctr++; // Slow-path oop array copy
#endif // !PRODUCT
assert(count != 0, "count should be non-zero");
gen_arraycopy_barrier_pre(dest, count);
Copy::conjoint_oops_atomic(src, dest, count);
gen_arraycopy_barrier(dest, count);
JRT_END
@ -281,6 +290,7 @@ JRT_LEAF(void, StubRoutines::arrayof_oop_copy(HeapWord* src, HeapWord* dest, siz
SharedRuntime::_oop_array_copy_ctr++; // Slow-path oop array copy
#endif // !PRODUCT
assert(count != 0, "count should be non-zero");
gen_arraycopy_barrier_pre((oop *) dest, count);
Copy::arrayof_conjoint_oops(src, dest, count);
gen_arraycopy_barrier((oop *) dest, count);
JRT_END

View File

@ -1,5 +1,5 @@
/*
* Copyright 1997-2009 Sun Microsystems, Inc. All Rights Reserved.
* Copyright 1997-2010 Sun Microsystems, Inc. All Rights Reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -186,7 +186,7 @@ void vframeArrayElement::unpack_on_stack(int callee_parameters,
int popframe_preserved_args_size_in_bytes = 0;
int popframe_preserved_args_size_in_words = 0;
if (is_top_frame) {
JvmtiThreadState *state = thread->jvmti_thread_state();
JvmtiThreadState *state = thread->jvmti_thread_state();
if (JvmtiExport::can_pop_frame() &&
(thread->has_pending_popframe() || thread->popframe_forcing_deopt_reexecution())) {
if (thread->has_pending_popframe()) {
@ -381,7 +381,6 @@ void vframeArrayElement::unpack_on_stack(int callee_parameters,
RegisterMap map(thread);
vframe* f = vframe::new_vframe(iframe(), &map, thread);
f->print();
iframe()->interpreter_frame_print_on(tty);
tty->print_cr("locals size %d", locals()->size());
tty->print_cr("expression size %d", expressions()->size());
@ -582,7 +581,7 @@ void vframeArray::print_on_2(outputStream* st) {
}
void vframeArrayElement::print(outputStream* st) {
st->print_cr(" - interpreter_frame -> sp: ", INTPTR_FORMAT, iframe()->sp());
st->print_cr(" - interpreter_frame -> sp: " INTPTR_FORMAT, iframe()->sp());
}
void vframeArray::print_value_on(outputStream* st) const {

View File

@ -1,5 +1,5 @@
/*
* Copyright 1998-2009 Sun Microsystems, Inc. All Rights Reserved.
* Copyright 1998-2010 Sun Microsystems, Inc. All Rights Reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -426,11 +426,6 @@ void VMThread::loop() {
// follow that also require a safepoint
if (_cur_vm_operation->evaluate_at_safepoint()) {
if (PrintGCApplicationConcurrentTime) {
gclog_or_tty->print_cr("Application time: %3.7f seconds",
RuntimeService::last_application_time_sec());
}
_vm_queue->set_drain_list(safepoint_ops); // ensure ops can be scanned
SafepointSynchronize::begin();
@ -477,12 +472,6 @@ void VMThread::loop() {
// Complete safepoint synchronization
SafepointSynchronize::end();
if (PrintGCApplicationStoppedTime) {
gclog_or_tty->print_cr("Total time for which application threads "
"were stopped: %3.7f seconds",
RuntimeService::last_safepoint_time_sec());
}
} else { // not a safepoint operation
if (TraceLongCompiles) {
elapsedTimer t;

View File

@ -1,5 +1,5 @@
/*
* Copyright 2003-2006 Sun Microsystems, Inc. All Rights Reserved.
* Copyright 2003-2010 Sun Microsystems, Inc. All Rights Reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -104,6 +104,13 @@ void RuntimeService::init() {
void RuntimeService::record_safepoint_begin() {
HS_DTRACE_PROBE(hs_private, safepoint__begin);
// Print the time interval in which the app was executing
if (PrintGCApplicationConcurrentTime) {
gclog_or_tty->print_cr("Application time: %3.7f seconds",
last_application_time_sec());
}
// update the time stamp to begin recording safepoint time
_safepoint_timer.update();
if (UsePerfData) {
@ -122,6 +129,15 @@ void RuntimeService::record_safepoint_synchronized() {
void RuntimeService::record_safepoint_end() {
HS_DTRACE_PROBE(hs_private, safepoint__end);
// Print the time interval for which the app was stopped
// during the current safepoint operation.
if (PrintGCApplicationStoppedTime) {
gclog_or_tty->print_cr("Total time for which application threads "
"were stopped: %3.7f seconds",
last_safepoint_time_sec());
}
// update the time stamp to begin recording app time
_app_timer.update();
if (UsePerfData) {

View File

@ -139,6 +139,10 @@ const size_t M = K*K;
const size_t G = M*K;
const size_t HWperKB = K / sizeof(HeapWord);
const size_t LOG_K = 10;
const size_t LOG_M = 2 * LOG_K;
const size_t LOG_G = 2 * LOG_M;
const jint min_jint = (jint)1 << (sizeof(jint)*BitsPerByte-1); // 0x80000000 == smallest jint
const jint max_jint = (juint)min_jint - 1; // 0x7FFFFFFF == largest jint

View File

@ -0,0 +1,78 @@
/*
* Copyright 2010 Sun Microsystems, Inc. All Rights Reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact 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 6910605
* @summary C2: NullPointerException/ClassCaseException is thrown when C2 with DeoptimizeALot is used
*
* @run main/othervm -XX:+IgnoreUnrecognizedVMOptions -XX:+DeoptimizeALot -Xbatch Test
*
* original test: nsk/coverage/runtime/runtime007
*/
import java.io.*;
public class Test {
public static int buf=0;
public static void main( String argv[] ) {
System.exit(run(argv, System.out)+95);
}
public static int run(String argv[],PrintStream out) {
int ret=0, retx=0, bad=0;
for( int i=0; (i < 100000) && (bad < 10) ; i++ ) {
retx = OptoRuntime_f2i_Type(out);
ret += retx;
if( retx !=0 ) {
out.println("i="+i);
bad++;
}
}
return ret==0 ? 0 : 2 ;
}
public static int OptoRuntime_f2i_Type(PrintStream out) {
int c1=2, c2=3, c3=4, c4=5, c5=6;
int j=0, k=0;
try {
int[][] iii=(int[][])(new int[c1][c2]);
for( j=0; j<c1; j++ ) {
for( k=0; k<c2; k++ ) {
iii[j][k]=(int)((float)(j+1)/(float)(k+1));
}
}
} catch (Throwable e) {
out.println("Unexpected exception " + e);
e.printStackTrace(out);
out.println("j="+j+", k="+k);
return 1;
}
return 0;
}
}

View File

@ -0,0 +1,74 @@
/*
* Copyright 2010 Sun Microsystems, Inc. All Rights Reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact 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 6910605
* @summary C2: NullPointerException/ClassCaseException is thrown when C2 with DeoptimizeALot is used
*
* @run main/othervm -Xmx64m -XX:+IgnoreUnrecognizedVMOptions -XX:+DeoptimizeALot -XX:+DoEscapeAnalysis -Xbatch -XX:InlineSmallCode=2000 Test
*
*/
/*
* Added InlineSmallCode=2000 to guaranty inlining of StringBuilder::append() to allow scalar replace StringBuilder object.
*
* original test: gc/gctests/StringGC
*/
public class Test {
private final String toAdd = "0123456789abcdef";
private int maxLength;
private static final int numberOfThreads = 8;
private class StringAdder extends Thread {
private String s;
public void test() {
s = s + toAdd;
}
public void run() {
do {
test();
} while (s.length() < maxLength);
}
}
public void test() throws InterruptedException {
maxLength = toAdd.length() * 15000/ numberOfThreads;
StringAdder[] sa = new StringAdder[numberOfThreads];
for (int i = 0; i < numberOfThreads; i++) {
sa[i] = new StringAdder();
sa[i].start();
}
for (int i = 0; i < numberOfThreads; i++) {
sa[i].join();
}
}
public static void main(String[] args) throws InterruptedException {
Test t = new Test();
t.test();
}
}

View File

@ -58,3 +58,4 @@ b1005c504358c18694c84e95fec16b28cdce7ae1 jdk7-b79
204e59d488cdaa9eafa8cb7164ea955b5a9d4a51 jdk7-b81
c876ad22e4bf9d3c6460080db7ace478e29a3ff9 jdk7-b82
309a0a7fc6ceb1c9fc3a85b3608e97ef8f7b0dfd jdk7-b83
32c0cf01d555747918529a6ff9e06b0090c7a474 jdk7-b84

View File

@ -58,3 +58,4 @@ c08894f5b6e594b9b12993e256b96c1b38099632 jdk7-b79
f051045fe94a48fae1097f90cbd9227e6aae6b7e jdk7-b81
31573ae8eed15a6c170f3f0d1abd0b9109c0e086 jdk7-b82
371e3ded591d09112a9f231e37cb072781c486ac jdk7-b83
8bc02839eee4ef02cd1b50e87638874368a26535 jdk7-b84

View File

@ -58,3 +58,4 @@ e6a5d095c356a547cf5b3c8885885aca5e91e09b jdk7-b77
10b993d417fcdb40480dad7032ac241f4b87f1af jdk7-b81
69ef657320ad5c35cfa12e4d8322d877e778f8b3 jdk7-b82
9027c6b9d7e2c9ca04a1add691b5b50d0f22b1aa jdk7-b83
7cb9388bb1a16365fa5118c5efa38b1cd58be40d jdk7-b84

View File

@ -28,6 +28,8 @@ import java.awt.peer.FileDialogPeer;
import java.io.FilenameFilter;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.File;
import sun.awt.AWTAccessor;
/**
* The <code>FileDialog</code> class displays a dialog window
@ -93,6 +95,25 @@ public class FileDialog extends Dialog {
*/
String file;
/**
* Contains the File instances for all the files that the user selects.
*
* @serial
* @see getFiles
* @since 1.7
*/
private File[] files;
/**
* Represents whether the file dialog allows the multiple file selection.
*
* @serial
* @see #setMultipleMode
* @see #isMultipleMode
* @since 1.7
*/
private boolean multipleMode = false;
/*
* The filter used as the file dialog's filename filter.
* The file dialog will only be displaying files whose
@ -123,6 +144,26 @@ public class FileDialog extends Dialog {
}
}
static {
AWTAccessor.setFileDialogAccessor(
new AWTAccessor.FileDialogAccessor() {
public void setFiles(FileDialog fileDialog, String directory, String files[]) {
fileDialog.setFiles(directory, files);
}
public void setFile(FileDialog fileDialog, String file) {
fileDialog.file = ("".equals(file)) ? null : file;
}
public void setDirectory(FileDialog fileDialog, String directory) {
fileDialog.dir = ("".equals(directory)) ? null : directory;
}
public boolean isMultipleMode(FileDialog fileDialog) {
synchronized (fileDialog.getObjectLock()) {
return fileDialog.multipleMode;
}
}
});
}
/**
* Initialize JNI field and method IDs for fields that may be
accessed from C.
@ -370,6 +411,51 @@ public class FileDialog extends Dialog {
return file;
}
/**
* Returns files that the user selects.
* <p>
* If the user cancels the file dialog,
* then the method returns an empty array.
*
* @return files that the user selects or an empty array
* if the user cancels the file dialog.
* @see #setFile(String)
* @see #getFile
* @since 1.7
*/
public File[] getFiles() {
synchronized (getObjectLock()) {
if (files != null) {
return files.clone();
} else {
return new File[0];
}
}
}
/**
* Stores the names of all the files that the user selects.
*
* Note that the method is private and it's intended to be used
* by the peers through the AWTAccessor API.
*
* @param directory the current directory
* @param files the array that contains the short names of
* all the files that the user selects.
*
* @see #getFiles
* @since 1.7
*/
private void setFiles(String directory, String files[]) {
synchronized (getObjectLock()) {
int filesNumber = (files != null) ? files.length : 0;
this.files = new File[filesNumber];
for (int i = 0; i < filesNumber; i++) {
this.files[i] = new File(directory, files[i]);
}
}
}
/**
* Sets the selected file for this file dialog window to be the
* specified file. This file becomes the default file if it is set
@ -380,7 +466,8 @@ public class FileDialog extends Dialog {
* as the file.
*
* @param file the file being set
* @see java.awt.FileDialog#getFile
* @see #getFile
* @see #getFiles
*/
public void setFile(String file) {
this.file = (file != null && file.equals("")) ? null : file;
@ -390,6 +477,34 @@ public class FileDialog extends Dialog {
}
}
/**
* Enables or disables multiple file selection for the file dialog.
*
* @param enable if {@code true}, multiple file selection is enabled;
* {@code false} - disabled.
* @see #isMultipleMode
* @since 1.7
*/
public void setMultipleMode(boolean enable) {
synchronized (getObjectLock()) {
this.multipleMode = enable;
}
}
/**
* Returns whether the file dialog allows the multiple file selection.
*
* @return {@code true} if the file dialog allows the multiple
* file selection; {@code false} otherwise.
* @see #setMultipleMode
* @since 1.7
*/
public boolean isMultipleMode() {
synchronized (getObjectLock()) {
return multipleMode;
}
}
/**
* Determines this file dialog's filename filter. A filename filter
* allows the user to specify which files appear in the file dialog

View File

@ -390,6 +390,30 @@ public final class AWTAccessor {
boolean isTrayIconPopup(PopupMenu popupMenu);
}
/*
* An accessor for the FileDialog class
*/
public interface FileDialogAccessor {
/*
* Sets the files the user selects
*/
void setFiles(FileDialog fileDialog, String directory, String files[]);
/*
* Sets the file the user selects
*/
void setFile(FileDialog fileDialog, String file);
/*
* Sets the directory the user selects
*/
void setDirectory(FileDialog fileDialog, String directory);
/*
* Returns whether the file dialog allows the multiple file selection.
*/
boolean isMultipleMode(FileDialog fileDialog);
}
/*
* The java.awt.Component class accessor object.
@ -431,6 +455,11 @@ public final class AWTAccessor {
*/
private static PopupMenuAccessor popupMenuAccessor;
/*
* The java.awt.FileDialog class accessor object.
*/
private static FileDialogAccessor fileDialogAccessor;
/*
* Set an accessor object for the java.awt.Component class.
*/
@ -567,4 +596,22 @@ public final class AWTAccessor {
}
return popupMenuAccessor;
}
/*
* Set an accessor object for the java.awt.FileDialog class.
*/
public static void setFileDialogAccessor(FileDialogAccessor fda) {
fileDialogAccessor = fda;
}
/*
* Retrieve the accessor object for the java.awt.FileDialog class.
*/
public static FileDialogAccessor getFileDialogAccessor() {
if (fileDialogAccessor == null) {
unsafe.ensureClassInitialized(FileDialog.class);
}
return fileDialogAccessor;
}
}

View File

@ -37,6 +37,7 @@ import javax.swing.plaf.ComponentUI;
import java.security.AccessController;
import java.security.PrivilegedAction;
import sun.util.logging.PlatformLogger;
import sun.awt.AWTAccessor;
class XFileDialogPeer extends XDialogPeer implements FileDialogPeer, ActionListener, ItemListener, KeyEventDispatcher, XChoicePeerListener {
private static final PlatformLogger log = PlatformLogger.getLogger("sun.awt.X11.XFileDialogPeer");
@ -171,6 +172,10 @@ class XFileDialogPeer extends XDialogPeer implements FileDialogPeer, ActionListe
filterField = new TextField();
selectionField = new TextField();
boolean isMultipleMode =
AWTAccessor.getFileDialogAccessor().isMultipleMode(target);
fileList.setMultipleMode(isMultipleMode);
// the insets used by the components in the fileDialog
Insets noInset = new Insets(0, 0, 0, 0);
Insets textFieldInset = new Insets(0, 8, 0, 8);
@ -380,7 +385,8 @@ class XFileDialogPeer extends XDialogPeer implements FileDialogPeer, ActionListe
* handle the selection event
*/
void handleSelection(String file) {
int index = file.lastIndexOf('/');
int index = file.lastIndexOf(java.io.File.separatorChar);
if (index == -1) {
savedDir = this.dir;
@ -389,8 +395,12 @@ class XFileDialogPeer extends XDialogPeer implements FileDialogPeer, ActionListe
savedDir = file.substring(0, index+1);
savedFile = file.substring(index+1);
}
target.setDirectory(savedDir);
target.setFile(savedFile);
AWTAccessor.FileDialogAccessor fileDialogAccessor = AWTAccessor.getFileDialogAccessor();
fileDialogAccessor.setDirectory(target, savedDir);
fileDialogAccessor.setFile(target, savedFile);
fileDialogAccessor.setFiles(target, savedDir, fileList.getSelectedItems());
}
/**
@ -404,8 +414,13 @@ class XFileDialogPeer extends XDialogPeer implements FileDialogPeer, ActionListe
setFilterField(null);
directoryList.clear();
fileList.clear();
target.setFile(null);
target.setDirectory(null);
AWTAccessor.FileDialogAccessor fileDialogAccessor = AWTAccessor.getFileDialogAccessor();
fileDialogAccessor.setDirectory(target, null);
fileDialogAccessor.setFile(target, null);
fileDialogAccessor.setFiles(target, null, null);
handleQuitButton();
}

View File

@ -117,26 +117,57 @@ public class WFileDialogPeer extends WWindowPeer implements FileDialogPeer {
}
}
// NOTE: This method is called by privileged threads.
// DO NOT INVOKE CLIENT CODE ON THIS THREAD!
void handleSelected(final String file) {
final FileDialog fileDialog = (FileDialog)target;
WToolkit.executeOnEventHandlerThread(fileDialog, new Runnable() {
public void run() {
int index = file.lastIndexOf(java.io.File.separatorChar);/*2509*//*ibm*/
String dir;
/*
* The function converts the file names (the buffer parameter)
* in the Windows format into the Java format and saves the results
* into the FileDialog instance.
*
* If it's the multi-select mode, the buffer contains the current
* directory followed by the short names of the files.
* The directory and file name strings are NULL separated.
* If it's the single-select mode, the buffer doesn't have the NULL
* separator between the path and the file name.
*
* NOTE: This method is called by privileged threads.
* DO NOT INVOKE CLIENT CODE ON THIS THREAD!
*/
void handleSelected(final char[] buffer)
{
String[] wFiles = (new String(buffer)).split("\0"); // NULL is the delimiter
boolean multiple = (wFiles.length > 1);
if (index == -1) {
dir = "."+java.io.File.separator;
fileDialog.setFile(file);
}
else {
dir = file.substring(0, index + 1);
fileDialog.setFile(file.substring(index + 1));
}
fileDialog.setDirectory(dir);
fileDialog.hide();
String jDirectory = null;
String jFile = null;
String jFiles[] = null;
if (multiple) {
jDirectory = wFiles[0];
jFiles = new String[wFiles.length - 1];
System.arraycopy(wFiles, 1, jFiles, 0, jFiles.length);
jFile = jFiles[1]; // choose any file
} else {
int index = wFiles[0].lastIndexOf(java.io.File.separatorChar);
if (index == -1) {
jDirectory = "."+java.io.File.separator;
jFile = wFiles[0];
} else {
jDirectory = wFiles[0].substring(0, index + 1);
jFile = wFiles[0].substring(index + 1);
}
jFiles = new String[] { jFile };
}
final FileDialog fileDialog = (FileDialog)target;
AWTAccessor.FileDialogAccessor fileDialogAccessor = AWTAccessor.getFileDialogAccessor();
fileDialogAccessor.setDirectory(fileDialog, jDirectory);
fileDialogAccessor.setFile(fileDialog, jFile);
fileDialogAccessor.setFiles(fileDialog, jDirectory, jFiles);
WToolkit.executeOnEventHandlerThread(fileDialog, new Runnable() {
public void run() {
fileDialog.hide();
}
});
} // handleSelected()
@ -144,11 +175,14 @@ public class WFileDialogPeer extends WWindowPeer implements FileDialogPeer {
// DO NOT INVOKE CLIENT CODE ON THIS THREAD!
void handleCancel() {
final FileDialog fileDialog = (FileDialog)target;
AWTAccessor.getFileDialogAccessor().setFile(fileDialog, null);
AWTAccessor.getFileDialogAccessor().setFiles(fileDialog, null, null);
WToolkit.executeOnEventHandlerThread(fileDialog, new Runnable() {
public void run() {
fileDialog.setFile(null);
fileDialog.hide();
}
public void run() {
fileDialog.hide();
}
});
} // handleCancel()
@ -244,4 +278,9 @@ public class WFileDialogPeer extends WWindowPeer implements FileDialogPeer {
public void createScreenSurface(boolean isResize) {}
@Override
public void replaceSurfaceData() {}
public boolean isMultipleMode() {
FileDialog fileDialog = (FileDialog)target;
return AWTAccessor.getFileDialogAccessor().isMultipleMode(fileDialog);
}
}

View File

@ -44,6 +44,7 @@ jmethodID AwtFileDialog::setHWndMID;
jmethodID AwtFileDialog::handleSelectedMID;
jmethodID AwtFileDialog::handleCancelMID;
jmethodID AwtFileDialog::checkFilenameFilterMID;
jmethodID AwtFileDialog::isMultipleModeMID;
/* FileDialog ids */
jfieldID AwtFileDialog::modeID;
@ -57,6 +58,13 @@ static TCHAR s_fileFilterString[MAX_FILTER_STRING];
/* Non-localized suffix of the filter string */
static const TCHAR s_additionalString[] = TEXT(" (*.*)\0*.*\0");
// Default limit of the output buffer.
#define SINGLE_MODE_BUFFER_LIMIT MAX_PATH+1
#define MULTIPLE_MODE_BUFFER_LIMIT 32768
// The name of the property holding the pointer to the OPENFILENAME structure.
static LPCTSTR OpenFileNameProp = TEXT("AWT_OFN");
/***********************************************************************/
void
@ -140,6 +148,8 @@ FileDialogHookProc(HWND hdlg, UINT uiMsg, WPARAM wParam, LPARAM lParam)
FileDialogWndProc);
::SetProp(parent, NativeDialogWndProcProp, reinterpret_cast<HANDLE>(lpfnWndProc));
::SetProp(parent, OpenFileNameProp, (void *)lParam);
break;
}
case WM_DESTROY: {
@ -149,6 +159,7 @@ FileDialogHookProc(HWND hdlg, UINT uiMsg, WPARAM wParam, LPARAM lParam)
lpfnWndProc);
::RemoveProp(parent, ModalDialogPeerProp);
::RemoveProp(parent, NativeDialogWndProcProp);
::RemoveProp(parent, OpenFileNameProp);
break;
}
case WM_NOTIFY: {
@ -174,6 +185,30 @@ FileDialogHookProc(HWND hdlg, UINT uiMsg, WPARAM wParam, LPARAM lParam)
// to unblock all the windows blocked by this dialog as it will
// be closed soon
env->CallVoidMethod(peer, AwtFileDialog::setHWndMID, (jlong)0);
} else if (notifyEx->hdr.code == CDN_SELCHANGE) {
// reallocate the buffer if the buffer is too small
LPOPENFILENAME lpofn = (LPOPENFILENAME)GetProp(parent, OpenFileNameProp);
UINT nLength = CommDlg_OpenSave_GetSpec(parent, NULL, 0) +
CommDlg_OpenSave_GetFolderPath(parent, NULL, 0);
if (lpofn->nMaxFile < nLength)
{
// allocate new buffer
LPTSTR newBuffer = new TCHAR[nLength];
if (newBuffer) {
memset(newBuffer, 0, nLength * sizeof(TCHAR));
LPTSTR oldBuffer = lpofn->lpstrFile;
lpofn->lpstrFile = newBuffer;
lpofn->nMaxFile = nLength;
// free the previously allocated buffer
if (oldBuffer) {
delete[] oldBuffer;
}
}
}
}
}
break;
@ -193,7 +228,6 @@ AwtFileDialog::Show(void *p)
WCHAR unicodeChar = L' ';
LPTSTR fileBuffer = NULL;
LPTSTR currentDirectory = NULL;
OPENFILENAME ofn;
jint mode = 0;
BOOL result = FALSE;
DWORD dlgerr;
@ -204,6 +238,10 @@ AwtFileDialog::Show(void *p)
jobject target = NULL;
jobject parent = NULL;
AwtComponent* awtParent = NULL;
jboolean multipleMode = JNI_FALSE;
OPENFILENAME ofn;
memset(&ofn, 0, sizeof(ofn));
/*
* There's a situation (see bug 4906972) when InvokeFunction (by which this method is called)
@ -233,7 +271,16 @@ AwtFileDialog::Show(void *p)
(jstring)env->GetObjectField(target, AwtFileDialog::dirID);
JavaStringBuffer directoryBuffer(env, directory);
fileBuffer = new TCHAR[MAX_PATH+1];
multipleMode = env->CallBooleanMethod(peer, AwtFileDialog::isMultipleModeMID);
UINT bufferLimit;
if (multipleMode == JNI_TRUE) {
bufferLimit = MULTIPLE_MODE_BUFFER_LIMIT;
} else {
bufferLimit = SINGLE_MODE_BUFFER_LIMIT;
}
LPTSTR fileBuffer = new TCHAR[bufferLimit];
memset(fileBuffer, 0, bufferLimit * sizeof(TCHAR));
file = (jstring)env->GetObjectField(target, AwtFileDialog::fileID);
if (file != NULL) {
@ -244,8 +291,6 @@ AwtFileDialog::Show(void *p)
fileBuffer[0] = _T('\0');
}
memset(&ofn, 0, sizeof(ofn));
ofn.lStructSize = sizeof(ofn);
ofn.lpstrFilter = s_fileFilterString;
ofn.nFilterIndex = 1;
@ -265,19 +310,23 @@ AwtFileDialog::Show(void *p)
ofn.hwndOwner = NULL;
}
ofn.lpstrFile = fileBuffer;
ofn.nMaxFile = MAX_PATH;
ofn.nMaxFile = bufferLimit;
ofn.lpstrTitle = titleBuffer;
ofn.lpstrInitialDir = directoryBuffer;
ofn.Flags = OFN_LONGNAMES | OFN_OVERWRITEPROMPT | OFN_HIDEREADONLY |
OFN_ENABLEHOOK | OFN_EXPLORER | OFN_ENABLESIZING;
fileFilter = env->GetObjectField(peer,
AwtFileDialog::fileFilterID);
if (!JNU_IsNull(env,fileFilter)) {
ofn.Flags |= OFN_ENABLEINCLUDENOTIFY;
}
if (!JNU_IsNull(env,fileFilter)) {
ofn.Flags |= OFN_ENABLEINCLUDENOTIFY;
}
ofn.lCustData = (LPARAM)peer;
ofn.lpfnHook = (LPOFNHOOKPROC)FileDialogHookProc;
if (multipleMode == JNI_TRUE) {
ofn.Flags |= OFN_ALLOWMULTISELECT;
}
// Save current directory, so we can reset if it changes.
currentDirectory = new TCHAR[MAX_PATH+1];
@ -318,11 +367,12 @@ AwtFileDialog::Show(void *p)
// Report result to peer.
if (result) {
jstring tmpJString = (_tcslen(ofn.lpstrFile) == 0 ?
JNU_NewStringPlatform(env, L"") :
JNU_NewStringPlatform(env, ofn.lpstrFile));
env->CallVoidMethod(peer, AwtFileDialog::handleSelectedMID, tmpJString);
env->DeleteLocalRef(tmpJString);
jint length = (jint)GetBufferLength(ofn.lpstrFile, ofn.nMaxFile);
jcharArray jnames = env->NewCharArray(length);
env->SetCharArrayRegion(jnames, 0, length, (jchar*)ofn.lpstrFile);
env->CallVoidMethod(peer, AwtFileDialog::handleSelectedMID, jnames);
env->DeleteLocalRef(jnames);
} else {
env->CallVoidMethod(peer, AwtFileDialog::handleCancelMID);
}
@ -338,7 +388,8 @@ AwtFileDialog::Show(void *p)
env->DeleteGlobalRef(peer);
delete[] currentDirectory;
delete[] fileBuffer;
if (ofn.lpstrFile)
delete[] ofn.lpstrFile;
throw;
}
@ -351,7 +402,8 @@ AwtFileDialog::Show(void *p)
env->DeleteGlobalRef(peer);
delete[] currentDirectory;
delete[] fileBuffer;
if (ofn.lpstrFile)
delete[] ofn.lpstrFile;
}
BOOL
@ -416,6 +468,18 @@ void AwtFileDialog::_ToBack(void *param)
env->DeleteGlobalRef(self);
}
// Returns the length of the double null terminated output buffer
UINT AwtFileDialog::GetBufferLength(LPTSTR buffer, UINT limit)
{
UINT index = 0;
while ((index < limit) &&
(buffer[index] != NULL || buffer[index+1] != NULL))
{
index++;
}
return index;
}
/************************************************************************
* WFileDialogPeer native methods
*/
@ -434,11 +498,12 @@ Java_sun_awt_windows_WFileDialogPeer_initIDs(JNIEnv *env, jclass cls)
AwtFileDialog::setHWndMID =
env->GetMethodID(cls, "setHWnd", "(J)V");
AwtFileDialog::handleSelectedMID =
env->GetMethodID(cls, "handleSelected", "(Ljava/lang/String;)V");
env->GetMethodID(cls, "handleSelected", "([C)V");
AwtFileDialog::handleCancelMID =
env->GetMethodID(cls, "handleCancel", "()V");
AwtFileDialog::checkFilenameFilterMID =
env->GetMethodID(cls, "checkFilenameFilter", "(Ljava/lang/String;)Z");
AwtFileDialog::isMultipleModeMID = env->GetMethodID(cls, "isMultipleMode", "()Z");
/* java.awt.FileDialog fields */
cls = env->FindClass("java/awt/FileDialog");
@ -455,6 +520,7 @@ Java_sun_awt_windows_WFileDialogPeer_initIDs(JNIEnv *env, jclass cls)
DASSERT(AwtFileDialog::setHWndMID != NULL);
DASSERT(AwtFileDialog::handleSelectedMID != NULL);
DASSERT(AwtFileDialog::handleCancelMID != NULL);
DASSERT(AwtFileDialog::isMultipleModeMID != NULL);
DASSERT(AwtFileDialog::modeID != NULL);
DASSERT(AwtFileDialog::dirID != NULL);

View File

@ -49,6 +49,7 @@ public:
static jmethodID handleSelectedMID;
static jmethodID handleCancelMID;
static jmethodID checkFilenameFilterMID;
static jmethodID isMultipleModeMID;
/* java.awt.FileDialog field and method ids */
static jfieldID modeID;
@ -68,6 +69,9 @@ public:
static void _DisposeOrHide(void *param);
static void _ToFront(void *param);
static void _ToBack(void *param);
private:
static UINT GetBufferLength(LPTSTR buffer, UINT limit);
};
#endif /* FILE_DIALOG_H */

View File

@ -0,0 +1,20 @@
<html>
<!--
@test
@bug 6467204
@summary Need to implement "extended" native FileDialog for JFileChooser
@author dmitry.cherepanov@sun.com area=awt.filedialog
@run applet/manual=yesno MultipleMode.html
-->
<head>
<title> MultipleMode </title>
</head>
<body>
<h1>MultipleMode<br>Bug ID: 6467204</h1>
<p> See the dialog box (usually in upper left corner) for instructions</p>
<APPLET CODE="MultipleMode.class" WIDTH=200 HEIGHT=200></APPLET>
</body>
</html>

View File

@ -0,0 +1,289 @@
/*
* Copyright 2010 Sun Microsystems, Inc. All Rights Reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact 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 6467204
@summary Need to implement "extended" native FileDialog for JFileChooser
@author dmitry.cherepanov@sun.com area=awt.filedialog
@run applet/manual=yesno MultipleMode.html
*/
// Note there is no @ in front of test above. This is so that the
// harness will not mistake this file as a test file. It should
// only see the html file as a test file. (the harness runs all
// valid test files, so it would run this test twice if this file
// were valid as well as the html file.)
// Also, note the area= after Your Name in the author tag. Here, you
// should put which functional area the test falls in. See the
// AWT-core home page -> test areas and/or -> AWT team for a list of
// areas.
// There are several places where ManualYesNoTest appear. It is
// recommended that these be changed by a global search and replace,
// such as ESC-% in xemacs.
/**
* MultipleMode.java
*
* summary:
*/
import java.applet.Applet;
import java.awt.*;
import java.awt.event.*;
import java.io.File;
//Manual tests should run as applet tests if possible because they
// get their environments cleaned up, including AWT threads, any
// test created threads, and any system resources used by the test
// such as file descriptors. (This is normally not a problem as
// main tests usually run in a separate VM, however on some platforms
// such as the Mac, separate VMs are not possible and non-applet
// tests will cause problems). Also, you don't have to worry about
// synchronisation stuff in Applet tests the way you do in main
// tests...
public class MultipleMode extends Applet
{
//Declare things used in the test, like buttons and labels here
public void init()
{
//Create instructions for the user here, as well as set up
// the environment -- set the layout manager, add buttons,
// etc.
this.setLayout (new BorderLayout ());
String[] instructions =
{
" 1. Turn the 'multiple' checkbox off and press the 'open' button ",
" 2. Verify that the file dialog doesn't allow the multiple file selection ",
" 3. Select any file and close the file dialog ",
" 4. The results will be displayed, verify the results ",
" 5. Turn the 'multiple' checkbox on and press the 'open' button ",
" 6. Verify that the file dialog allows the multiple file selection ",
" 7. Select several files and close the file dialog ",
" 8. The results will be displayed, verify the results "
};
Sysout.createDialogWithInstructions( instructions );
}//End init()
public void start ()
{
final Checkbox mode = new Checkbox("multiple", true);
Button open = new Button("open");
open.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
FileDialog d = new FileDialog((Frame)null);
d.setMultipleMode(mode.getState());
d.setVisible(true);
// print the results
Sysout.println("DIR:");
Sysout.println(d.getDirectory());
Sysout.println("FILE:");
Sysout.println(d.getFile());
Sysout.println("FILES:");
File files[] = d.getFiles();
for (File f : files) {
Sysout.println(String.valueOf(f));
}
}
});
setLayout(new FlowLayout());
add(mode);
add(open);
//Get things going. Request focus, set size, et cetera
setSize (200,200);
setVisible(true);
validate();
}// start()
//The rest of this class is the actions which perform the test...
//Use Sysout.println to communicate with the user NOT System.out!!
//Sysout.println ("Something Happened!");
}// class ManualYesNoTest
/* Place other classes related to the test after this line */
/****************************************************
Standard Test Machinery
DO NOT modify anything below -- it's a standard
chunk of code whose purpose is to make user
interaction uniform, and thereby make it simpler
to read and understand someone else's test.
****************************************************/
/**
This is part of the standard test machinery.
It creates a dialog (with the instructions), and is the interface
for sending text messages to the user.
To print the instructions, send an array of strings to Sysout.createDialog
WithInstructions method. Put one line of instructions per array entry.
To display a message for the tester to see, simply call Sysout.println
with the string to be displayed.
This mimics System.out.println but works within the test harness as well
as standalone.
*/
class Sysout
{
private static TestDialog dialog;
private static boolean numbering = false;
private static int messageNumber = 0;
public static void createDialogWithInstructions( String[] instructions )
{
dialog = new TestDialog( new Frame(), "Instructions" );
dialog.printInstructions( instructions );
dialog.setVisible(true);
println( "Any messages for the tester will display here." );
}
public static void createDialog( )
{
dialog = new TestDialog( new Frame(), "Instructions" );
String[] defInstr = { "Instructions will appear here. ", "" } ;
dialog.printInstructions( defInstr );
dialog.setVisible(true);
println( "Any messages for the tester will display here." );
}
/* Enables message counting for the tester. */
public static void enableNumbering(boolean enable){
numbering = enable;
}
public static void printInstructions( String[] instructions )
{
dialog.printInstructions( instructions );
}
public static void println( String messageIn )
{
if (numbering) {
messageIn = "" + messageNumber + " " + messageIn;
messageNumber++;
}
dialog.displayMessage( messageIn );
}
}// Sysout class
/**
This is part of the standard test machinery. It provides a place for the
test instructions to be displayed, and a place for interactive messages
to the user to be displayed.
To have the test instructions displayed, see Sysout.
To have a message to the user be displayed, see Sysout.
Do not call anything in this dialog directly.
*/
class TestDialog extends Dialog
{
TextArea instructionsText;
TextArea messageText;
int maxStringLength = 80;
//DO NOT call this directly, go through Sysout
public TestDialog( Frame frame, String name )
{
super( frame, name );
int scrollBoth = TextArea.SCROLLBARS_BOTH;
instructionsText = new TextArea( "", 15, maxStringLength, scrollBoth );
add( "North", instructionsText );
messageText = new TextArea( "", 5, maxStringLength, scrollBoth );
add("Center", messageText);
pack();
setVisible(true);
}// TestDialog()
//DO NOT call this directly, go through Sysout
public void printInstructions( String[] instructions )
{
//Clear out any current instructions
instructionsText.setText( "" );
//Go down array of instruction strings
String printStr, remainingStr;
for( int i=0; i < instructions.length; i++ )
{
//chop up each into pieces maxSringLength long
remainingStr = instructions[ i ];
while( remainingStr.length() > 0 )
{
//if longer than max then chop off first max chars to print
if( remainingStr.length() >= maxStringLength )
{
//Try to chop on a word boundary
int posOfSpace = remainingStr.
lastIndexOf( ' ', maxStringLength - 1 );
if( posOfSpace <= 0 ) posOfSpace = maxStringLength - 1;
printStr = remainingStr.substring( 0, posOfSpace + 1 );
remainingStr = remainingStr.substring( posOfSpace + 1 );
}
//else just print
else
{
printStr = remainingStr;
remainingStr = "";
}
instructionsText.append( printStr + "\n" );
}// while
}// for
}//printInstructions()
//DO NOT call this directly, go through Sysout
public void displayMessage( String messageIn )
{
messageText.append( messageIn + "\n" );
System.out.println(messageIn);
}
}// TestDialog class

View File

@ -58,3 +58,4 @@ f0074aa48d4e2a4c03c92b9c4f880679fea0306c jdk7-b80
cfabfcf9f110ef896cbdd382903d20eefbceefe0 jdk7-b81
47003a3622f6a17756ab0338bfa8a43e36549e99 jdk7-b82
c9f4ae1f1480e89aaf7e72173184089d9cea397a jdk7-b83
d9cd5b8286e44f3baf90da290cd295433e21c05a jdk7-b84

View File

@ -70,7 +70,7 @@ ifdef QUIET
endif
ifdef VERBOSE
ANT_OPTIONS += -verbose -diagnostics
ANT_OPTIONS += -verbose -debug
endif
ifdef JDK_VERSION

View File

@ -101,7 +101,11 @@ class SourceOrderDeclScanner extends DeclarationScanner {
}
@SuppressWarnings("cast")
private int compareEqualPosition(Declaration d1, Declaration d2) {
assert d1.getPosition() == d2.getPosition();
assert
(d1.getPosition() == d2.getPosition()) || // Handles two null positions.
(d1.getPosition().file().compareTo(d2.getPosition().file()) == 0 &&
d1.getPosition().line() == d2.getPosition().line() &&
d1.getPosition().column() == d2.getPosition().column());
DeclPartialOrder dpo1 = new DeclPartialOrder();
DeclPartialOrder dpo2 = new DeclPartialOrder();

View File

@ -496,57 +496,12 @@ public class Apt extends ListBuffer<Env<AttrContext>> {
* won't match anything.
*/
Pattern importStringToPattern(String s) {
if (s.equals("*")) {
return allMatches;
if (com.sun.tools.javac.processing.JavacProcessingEnvironment.isValidImportString(s)) {
return com.sun.tools.javac.processing.JavacProcessingEnvironment.validImportStringToPattern(s);
} else {
String t = s;
boolean star = false;
/*
* Validate string from factory is legal. If the string
* has more than one asterisks or the asterisks does not
* appear as the last character (preceded by a period),
* the string is not legal.
*/
boolean valid = true;
int index = t.indexOf('*');
if (index != -1) {
// '*' must be last character...
if (index == t.length() -1) {
// ... and preceeding character must be '.'
if ( index-1 >= 0 ) {
valid = t.charAt(index-1) == '.';
// Strip off ".*$" for identifier checks
t = t.substring(0, t.length()-2);
}
} else
valid = false;
}
// Verify string is off the form (javaId \.)+ or javaId
if (valid) {
String[] javaIds = t.split("\\.", t.length()+2);
for(String javaId: javaIds)
valid &= isJavaIdentifier(javaId);
}
if (!valid) {
Bark bark = Bark.instance(context);
bark.aptWarning("MalformedSupportedString", s);
return noMatches; // won't match any valid identifier
}
String s_prime = s.replaceAll("\\.", "\\\\.");
if (s_prime.endsWith("*")) {
s_prime = s_prime.substring(0, s_prime.length() - 1) + ".+";
}
return Pattern.compile(s_prime);
Bark bark = Bark.instance(context);
bark.aptWarning("MalformedSupportedString", s);
return com.sun.tools.javac.processing.JavacProcessingEnvironment.noMatches;
}
}
private static final Pattern allMatches = Pattern.compile(".*");
private static final Pattern noMatches = Pattern.compile("(\\P{all})+");
}

View File

@ -56,6 +56,8 @@ import com.sun.tools.apt.comp.UsageMessageNeededException;
import com.sun.tools.apt.util.Bark;
import com.sun.mirror.apt.AnnotationProcessorFactory;
import static com.sun.tools.javac.file.Paths.pathToURLs;
/** This class provides a commandline interface to the apt build-time
* tool.
*
@ -1276,59 +1278,4 @@ public class Main {
}
}
}
// Borrowed from DocletInvoker
/**
* Utility method for converting a search path string to an array
* of directory and JAR file URLs.
*
* @param path the search path string
* @return the resulting array of directory and JAR file URLs
*/
static URL[] pathToURLs(String path) {
StringTokenizer st = new StringTokenizer(path, File.pathSeparator);
URL[] urls = new URL[st.countTokens()];
int count = 0;
while (st.hasMoreTokens()) {
URL url = fileToURL(new File(st.nextToken()));
if (url != null) {
urls[count++] = url;
}
}
if (urls.length != count) {
URL[] tmp = new URL[count];
System.arraycopy(urls, 0, tmp, 0, count);
urls = tmp;
}
return urls;
}
/**
* Returns the directory or JAR file URL corresponding to the specified
* local file name.
*
* @param file the File object
* @return the resulting directory or JAR file URL, or null if unknown
*/
static URL fileToURL(File file) {
String name;
try {
name = file.getCanonicalPath();
} catch (IOException e) {
name = file.getAbsolutePath();
}
name = name.replace(File.separatorChar, '/');
if (!name.startsWith("/")) {
name = "/" + name;
}
// If the file does not exist, then assume that it's a directory
if (!file.isFile()) {
name = name + "/";
}
try {
return new URL("file", "", name);
} catch (MalformedURLException e) {
throw new IllegalArgumentException("file");
}
}
}

View File

@ -27,6 +27,8 @@ package com.sun.tools.javac.file;
import java.io.File;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
@ -34,6 +36,7 @@ import java.util.Set;
import java.util.Collection;
import java.util.Collections;
import java.util.LinkedHashSet;
import java.util.StringTokenizer;
import java.util.zip.ZipFile;
import javax.tools.JavaFileManager.Location;
@ -449,4 +452,60 @@ public class Paths {
return fsInfo.isFile(file)
&& (n.endsWith(".jar") || n.endsWith(".zip"));
}
/**
* Utility method for converting a search path string to an array
* of directory and JAR file URLs.
*
* Note that this method is called by apt and the DocletInvoker.
*
* @param path the search path string
* @return the resulting array of directory and JAR file URLs
*/
public static URL[] pathToURLs(String path) {
StringTokenizer st = new StringTokenizer(path, File.pathSeparator);
URL[] urls = new URL[st.countTokens()];
int count = 0;
while (st.hasMoreTokens()) {
URL url = fileToURL(new File(st.nextToken()));
if (url != null) {
urls[count++] = url;
}
}
if (urls.length != count) {
URL[] tmp = new URL[count];
System.arraycopy(urls, 0, tmp, 0, count);
urls = tmp;
}
return urls;
}
/**
* Returns the directory or JAR file URL corresponding to the specified
* local file name.
*
* @param file the File object
* @return the resulting directory or JAR file URL, or null if unknown
*/
private static URL fileToURL(File file) {
String name;
try {
name = file.getCanonicalPath();
} catch (IOException e) {
name = file.getAbsolutePath();
}
name = name.replace(File.separatorChar, '/');
if (!name.startsWith("/")) {
name = "/" + name;
}
// If the file does not exist, then assume that it's a directory
if (!file.isFile()) {
name = name + "/";
}
try {
return new URL("file", "", name);
} catch (MalformedURLException e) {
throw new IllegalArgumentException(file.toString());
}
}
}

View File

@ -25,7 +25,6 @@
package com.sun.tools.javac.processing;
import java.lang.reflect.*;
import java.util.*;
import java.util.regex.*;
@ -874,20 +873,9 @@ public class JavacProcessingEnvironment implements ProcessingEnvironment, Closea
JavaFileManager fileManager = currentContext.get(JavaFileManager.class);
List<JavaFileObject> fileObjects = List.nil();
for (JavaFileObject jfo : filer.getGeneratedSourceFileObjects() ) {
fileObjects = fileObjects.prepend(jfo);
}
compiler = JavaCompiler.instance(currentContext);
List<JCCompilationUnit> parsedFiles = compiler.parseFiles(fileObjects);
roots = cleanTrees(roots).reverse();
for (JCCompilationUnit unit : parsedFiles)
roots = roots.prepend(unit);
roots = roots.reverse();
List<JCCompilationUnit> parsedFiles = sourcesToParsedFiles(compiler);
roots = cleanTrees(roots).appendList(parsedFiles);
// Check for errors after parsing
if (compiler.parseErrors()) {
@ -921,11 +909,16 @@ public class JavacProcessingEnvironment implements ProcessingEnvironment, Closea
break runAround; // No new files
}
}
runLastRound(xout, roundNumber, errorStatus, taskListener);
roots = runLastRound(xout, roundNumber, errorStatus, compiler, roots, taskListener);
// Set error status for any files compiled and generated in
// the last round
if (compiler.parseErrors())
errorStatus = true;
compiler.close(false);
currentContext = contextForNextRound(currentContext, true);
compiler = JavaCompiler.instance(currentContext);
filer.newRound(currentContext, true);
filer.warnIfUnclosedFiles();
warnIfUnmatchedOptions();
@ -979,10 +972,22 @@ public class JavacProcessingEnvironment implements ProcessingEnvironment, Closea
return compiler;
}
private List<JCCompilationUnit> sourcesToParsedFiles(JavaCompiler compiler)
throws IOException {
List<JavaFileObject> fileObjects = List.nil();
for (JavaFileObject jfo : filer.getGeneratedSourceFileObjects() ) {
fileObjects = fileObjects.prepend(jfo);
}
return compiler.parseFiles(fileObjects);
}
// Call the last round of annotation processing
private void runLastRound(PrintWriter xout,
int roundNumber,
boolean errorStatus,
private List<JCCompilationUnit> runLastRound(PrintWriter xout,
int roundNumber,
boolean errorStatus,
JavaCompiler compiler,
List<JCCompilationUnit> roots,
TaskListener taskListener) throws IOException {
roundNumber++;
List<ClassSymbol> noTopLevelClasses = List.nil();
@ -1003,6 +1008,15 @@ public class JavacProcessingEnvironment implements ProcessingEnvironment, Closea
if (taskListener != null)
taskListener.finished(new TaskEvent(TaskEvent.Kind.ANNOTATION_PROCESSING_ROUND));
}
// Add any sources generated during the last round to the set
// of files to be compiled.
if (moreToDo()) {
List<JCCompilationUnit> parsedFiles = sourcesToParsedFiles(compiler);
roots = cleanTrees(roots).appendList(parsedFiles);
}
return roots;
}
private void updateProcessingState(Context currentContext, boolean lastRound) {
@ -1340,115 +1354,62 @@ public class JavacProcessingEnvironment implements ProcessingEnvironment, Closea
return specifiedPackages;
}
// Borrowed from DocletInvoker and apt
// TODO: remove from apt's Main
/**
* Utility method for converting a search path string to an array
* of directory and JAR file URLs.
*
* @param path the search path string
* @return the resulting array of directory and JAR file URLs
*/
public static URL[] pathToURLs(String path) {
StringTokenizer st = new StringTokenizer(path, File.pathSeparator);
URL[] urls = new URL[st.countTokens()];
int count = 0;
while (st.hasMoreTokens()) {
URL url = fileToURL(new File(st.nextToken()));
if (url != null) {
urls[count++] = url;
}
}
if (urls.length != count) {
URL[] tmp = new URL[count];
System.arraycopy(urls, 0, tmp, 0, count);
urls = tmp;
}
return urls;
}
/**
* Returns the directory or JAR file URL corresponding to the specified
* local file name.
*
* @param file the File object
* @return the resulting directory or JAR file URL, or null if unknown
*/
private static URL fileToURL(File file) {
String name;
try {
name = file.getCanonicalPath();
} catch (IOException e) {
name = file.getAbsolutePath();
}
name = name.replace(File.separatorChar, '/');
if (!name.startsWith("/")) {
name = "/" + name;
}
// If the file does not exist, then assume that it's a directory
if (!file.isFile()) {
name = name + "/";
}
try {
return new URL("file", "", name);
} catch (MalformedURLException e) {
throw new IllegalArgumentException("file");
}
}
private static final Pattern allMatches = Pattern.compile(".*");
public static final Pattern noMatches = Pattern.compile("(\\P{all})+");
private static final Pattern noMatches = Pattern.compile("(\\P{all})+");
/**
* Convert import-style string to regex matching that string. If
* the string is a valid import-style string, return a regex that
* won't match anything.
* Convert import-style string for supported annotations into a
* regex matching that string. If the string is a valid
* import-style string, return a regex that won't match anything.
*/
// TODO: remove version in Apt.java
public static Pattern importStringToPattern(String s, Processor p, Log log) {
private static Pattern importStringToPattern(String s, Processor p, Log log) {
if (isValidImportString(s)) {
return validImportStringToPattern(s);
} else {
log.warning("proc.malformed.supported.string", s, p.getClass().getName());
return noMatches; // won't match any valid identifier
}
}
/**
* Return true if the argument string is a valid import-style
* string specifying claimed annotations; return false otherwise.
*/
public static boolean isValidImportString(String s) {
if (s.equals("*"))
return true;
boolean valid = true;
String t = s;
int index = t.indexOf('*');
if (index != -1) {
// '*' must be last character...
if (index == t.length() -1) {
// ... any and preceding character must be '.'
if ( index-1 >= 0 ) {
valid = t.charAt(index-1) == '.';
// Strip off ".*$" for identifier checks
t = t.substring(0, t.length()-2);
}
} else
return false;
}
// Verify string is off the form (javaId \.)+ or javaId
if (valid) {
String[] javaIds = t.split("\\.", t.length()+2);
for(String javaId: javaIds)
valid &= SourceVersion.isIdentifier(javaId);
}
return valid;
}
public static Pattern validImportStringToPattern(String s) {
if (s.equals("*")) {
return allMatches;
} else {
String t = s;
boolean star = false;
/*
* Validate string from factory is legal. If the string
* has more than one asterisks or the asterisks does not
* appear as the last character (preceded by a period),
* the string is not legal.
*/
boolean valid = true;
int index = t.indexOf('*');
if (index != -1) {
// '*' must be last character...
if (index == t.length() -1) {
// ... and preceeding character must be '.'
if ( index-1 >= 0 ) {
valid = t.charAt(index-1) == '.';
// Strip off ".*$" for identifier checks
t = t.substring(0, t.length()-2);
}
} else
valid = false;
}
// Verify string is off the form (javaId \.)+ or javaId
if (valid) {
String[] javaIds = t.split("\\.", t.length()+2);
for(String javaId: javaIds)
valid &= SourceVersion.isIdentifier(javaId);
}
if (!valid) {
log.warning("proc.malformed.supported.string", s, p.getClass().getName());
return noMatches; // won't match any valid identifier
}
String s_prime = s.replaceAll("\\.", "\\\\.");
String s_prime = s.replace(".", "\\.");
if (s_prime.endsWith("*")) {
s_prime = s_prime.substring(0, s_prime.length() - 1) + ".+";

View File

@ -81,7 +81,7 @@ public class DocletInvoker {
cpString = appendPath(System.getProperty("env.class.path"), cpString);
cpString = appendPath(System.getProperty("java.class.path"), cpString);
cpString = appendPath(docletPath, cpString);
URL[] urls = pathToURLs(cpString);
URL[] urls = com.sun.tools.javac.file.Paths.pathToURLs(cpString);
if (docletParentClassLoader == null)
appClassLoader = new URLClassLoader(urls, getDelegationClassLoader(docletClassName));
else
@ -313,58 +313,4 @@ public class DocletInvoker {
Thread.currentThread().setContextClassLoader(savedCCL);
}
}
/**
* Utility method for converting a search path string to an array
* of directory and JAR file URLs.
*
* @param path the search path string
* @return the resulting array of directory and JAR file URLs
*/
static URL[] pathToURLs(String path) {
StringTokenizer st = new StringTokenizer(path, File.pathSeparator);
URL[] urls = new URL[st.countTokens()];
int count = 0;
while (st.hasMoreTokens()) {
URL url = fileToURL(new File(st.nextToken()));
if (url != null) {
urls[count++] = url;
}
}
if (urls.length != count) {
URL[] tmp = new URL[count];
System.arraycopy(urls, 0, tmp, 0, count);
urls = tmp;
}
return urls;
}
/**
* Returns the directory or JAR file URL corresponding to the specified
* local file name.
*
* @param file the File object
* @return the resulting directory or JAR file URL, or null if unknown
*/
static URL fileToURL(File file) {
String name;
try {
name = file.getCanonicalPath();
} catch (IOException e) {
name = file.getAbsolutePath();
}
name = name.replace(File.separatorChar, '/');
if (!name.startsWith("/")) {
name = "/" + name;
}
// If the file does not exist, then assume that it's a directory
if (!file.isFile()) {
name = name + "/";
}
try {
return new URL("file", "", name);
} catch (MalformedURLException e) {
throw new IllegalArgumentException("file");
}
}
}

View File

@ -27,7 +27,6 @@ import javax.lang.model.*;
import javax.lang.model.element.*;
@SupportedAnnotationTypes("*")
@SupportedSourceVersion(SourceVersion.RELEASE_7)
public class Anno extends AbstractProcessor {
public boolean process(Set<? extends TypeElement> annotations,
RoundEnvironment roundEnv) {
@ -35,4 +34,9 @@ public class Anno extends AbstractProcessor {
// System.err.println("annotation processing");
return true;
}
@Override
public SourceVersion getSupportedSourceVersion() {
return SourceVersion.latest();
}
}

View File

@ -27,6 +27,8 @@
* @summary Verify that assertions are enabled before the class is initialized
* and not thereafter
* @author gafter
* @build EarlyAssert EarlyAssertWrapper
* @run main EarlyAssertWrapper
*/
/*

View File

@ -0,0 +1,83 @@
/*
* Copyright 2010 Sun Microsystems, Inc. All Rights Reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact 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.
*/
import java.io.*;
import java.util.*;
/*
* Wrapper for the EarlyAssert test to run the test in a JVM without assertions
* enabled.
*/
public class EarlyAssertWrapper {
public static void main(String... args) throws Exception {
EarlyAssertWrapper w = new EarlyAssertWrapper();
w.run();
}
void run() throws Exception {
List<String> cmd = new ArrayList<String>();
File java_home = new File(System.getProperty("java.home"));
if (java_home.getName().equals("jre"))
java_home = java_home.getParentFile();
cmd.add(new File(new File(java_home, "bin"), "java").getPath());
// ensure we run with the same bootclasspath as this test,
// in case this test is being run with -Xbootclasspath
cmd.add("-Xbootclasspath:" + System.getProperty("sun.boot.class.path"));
// propogate classpath
cmd.add("-classpath");
cmd.add(System.getProperty("java.class.path"));
// ensure all assertions disabled in target VM
cmd.add("-da");
cmd.add("-dsa");
cmd.add("EarlyAssert");
System.err.println("Running command: " + cmd);
ProcessBuilder pb = new ProcessBuilder(cmd);
pb.redirectErrorStream(true);
Process p = pb.start();
p.getOutputStream().close();
StringWriter sw = new StringWriter();
PrintWriter pw = new PrintWriter(sw);
String line;
DataInputStream in = new DataInputStream(p.getInputStream());
try {
while ((line = in.readLine()) != null)
pw.println(line);
} finally {
in.close();
}
pw.close();
String out = sw.toString();
int rc = p.waitFor();
if (rc != 0 || out.length() > 0)
throw new Error("failed: rc=" + rc + (out.length() > 0 ? ": " + out : ""));
}
}

View File

@ -41,7 +41,6 @@ import com.sun.tools.javac.api.JavacTool;
@Wrap
@SupportedAnnotationTypes("Wrap")
@SupportedSourceVersion(SourceVersion.RELEASE_6)
public class T6403466 extends AbstractProcessor {
static final String testSrcDir = System.getProperty("test.src");
@ -73,24 +72,31 @@ public class T6403466 extends AbstractProcessor {
}
public boolean process(Set<? extends TypeElement> annos, RoundEnvironment rEnv) {
Filer filer = processingEnv.getFiler();
for (TypeElement anno: annos) {
Set<? extends Element> elts = rEnv.getElementsAnnotatedWith(anno);
System.err.println("anno: " + anno);
System.err.println("elts: " + elts);
for (TypeElement te: ElementFilter.typesIn(elts)) {
try {
Writer out = filer.createSourceFile(te.getSimpleName() + "Wrapper").openWriter();
out.write("class " + te.getSimpleName() + "Wrapper { }");
out.close();
} catch (IOException ex) {
ex.printStackTrace();
if (!rEnv.processingOver()) {
Filer filer = processingEnv.getFiler();
for (TypeElement anno: annos) {
Set<? extends Element> elts = rEnv.getElementsAnnotatedWith(anno);
System.err.println("anno: " + anno);
System.err.println("elts: " + elts);
for (TypeElement te: ElementFilter.typesIn(elts)) {
try {
Writer out = filer.createSourceFile(te.getSimpleName() + "Wrapper").openWriter();
out.write("class " + te.getSimpleName() + "Wrapper { }");
out.close();
} catch (IOException ex) {
ex.printStackTrace();
}
}
}
}
}
return true;
}
@Override
public SourceVersion getSupportedSourceVersion() {
return SourceVersion.latest();
}
}
@Retention(RetentionPolicy.SOURCE)

View File

@ -17,7 +17,7 @@ import com.sun.source.tree.*;
import com.sun.source.util.*;
import com.sun.tools.javac.tree.JCTree;
@SupportedSourceVersion(SourceVersion.RELEASE_6)
@SupportedAnnotationTypes("*")
public class T6406771 extends AbstractProcessor {
String[] tests = {
@ -95,4 +95,8 @@ public class T6406771 extends AbstractProcessor {
return true;
}
@Override
public SourceVersion getSupportedSourceVersion() {
return SourceVersion.latest();
}
}

View File

@ -37,7 +37,6 @@ import com.sun.source.tree.*;
import com.sun.source.util.*;
@SupportedAnnotationTypes("*")
@SupportedSourceVersion(SourceVersion.RELEASE_6)
public class T6411379 extends AbstractProcessor {
public boolean process(Set<? extends TypeElement> annoElems,
@ -58,6 +57,11 @@ public class T6411379 extends AbstractProcessor {
return true;
}
@Override
public SourceVersion getSupportedSourceVersion() {
return SourceVersion.latest();
}
public void checkNull(Object o) {
if (o != null)
throw new AssertionError("expected null");

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