6958668: repeated uncommon trapping for new of klass which is being initialized
Reviewed-by: kvn, jrose
--- a/hotspot/src/share/vm/ci/ciInstanceKlass.cpp Thu Jul 08 14:29:44 2010 -0700
+++ b/hotspot/src/share/vm/ci/ciInstanceKlass.cpp Mon Jul 12 10:58:25 2010 -0700
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1999, 2008, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -44,9 +44,7 @@
_flags = ciFlags(access_flags);
_has_finalizer = access_flags.has_finalizer();
_has_subklass = ik->subklass() != NULL;
- _is_initialized = ik->is_initialized();
- // Next line must follow and use the result of the previous line:
- _is_linked = _is_initialized || ik->is_linked();
+ _init_state = (instanceKlass::ClassState)ik->get_init_state();
_nonstatic_field_size = ik->nonstatic_field_size();
_has_nonstatic_fields = ik->has_nonstatic_fields();
_nonstatic_fields = NULL; // initialized lazily by compute_nonstatic_fields:
@@ -91,8 +89,7 @@
: ciKlass(name, ciInstanceKlassKlass::make())
{
assert(name->byte_at(0) != '[', "not an instance klass");
- _is_initialized = false;
- _is_linked = false;
+ _init_state = (instanceKlass::ClassState)0;
_nonstatic_field_size = -1;
_has_nonstatic_fields = false;
_nonstatic_fields = NULL;
@@ -109,21 +106,10 @@
// ------------------------------------------------------------------
// ciInstanceKlass::compute_shared_is_initialized
-bool ciInstanceKlass::compute_shared_is_initialized() {
+void ciInstanceKlass::compute_shared_init_state() {
GUARDED_VM_ENTRY(
instanceKlass* ik = get_instanceKlass();
- _is_initialized = ik->is_initialized();
- return _is_initialized;
- )
-}
-
-// ------------------------------------------------------------------
-// ciInstanceKlass::compute_shared_is_linked
-bool ciInstanceKlass::compute_shared_is_linked() {
- GUARDED_VM_ENTRY(
- instanceKlass* ik = get_instanceKlass();
- _is_linked = ik->is_linked();
- return _is_linked;
+ _init_state = (instanceKlass::ClassState)ik->get_init_state();
)
}
--- a/hotspot/src/share/vm/ci/ciInstanceKlass.hpp Thu Jul 08 14:29:44 2010 -0700
+++ b/hotspot/src/share/vm/ci/ciInstanceKlass.hpp Mon Jul 12 10:58:25 2010 -0700
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1999, 2008, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -39,9 +39,8 @@
jobject _loader;
jobject _protection_domain;
+ instanceKlass::ClassState _init_state; // state of class
bool _is_shared;
- bool _is_initialized;
- bool _is_linked;
bool _has_finalizer;
bool _has_subklass;
bool _has_nonstatic_fields;
@@ -87,27 +86,34 @@
bool is_shared() { return _is_shared; }
- bool compute_shared_is_initialized();
- bool compute_shared_is_linked();
+ void compute_shared_init_state();
bool compute_shared_has_subklass();
int compute_shared_nof_implementors();
int compute_nonstatic_fields();
GrowableArray<ciField*>* compute_nonstatic_fields_impl(GrowableArray<ciField*>* super_fields);
+ // Update the init_state for shared klasses
+ void update_if_shared(instanceKlass::ClassState expected) {
+ if (_is_shared && _init_state != expected) {
+ if (is_loaded()) compute_shared_init_state();
+ }
+ }
+
public:
// Has this klass been initialized?
bool is_initialized() {
- if (_is_shared && !_is_initialized) {
- return is_loaded() && compute_shared_is_initialized();
- }
- return _is_initialized;
+ update_if_shared(instanceKlass::fully_initialized);
+ return _init_state == instanceKlass::fully_initialized;
+ }
+ // Is this klass being initialized?
+ bool is_being_initialized() {
+ update_if_shared(instanceKlass::being_initialized);
+ return _init_state == instanceKlass::being_initialized;
}
// Has this klass been linked?
bool is_linked() {
- if (_is_shared && !_is_linked) {
- return is_loaded() && compute_shared_is_linked();
- }
- return _is_linked;
+ update_if_shared(instanceKlass::linked);
+ return _init_state >= instanceKlass::linked;
}
// General klass information.
--- a/hotspot/src/share/vm/opto/doCall.cpp Thu Jul 08 14:29:44 2010 -0700
+++ b/hotspot/src/share/vm/opto/doCall.cpp Mon Jul 12 10:58:25 2010 -0700
@@ -343,7 +343,8 @@
// being initialized. Uncommon-trap for not-initialized static or
// v-calls. Let interface calls happen.
ciInstanceKlass* holder_klass = dest_method->holder();
- if (!holder_klass->is_initialized() &&
+ if (!holder_klass->is_being_initialized() &&
+ !holder_klass->is_initialized() &&
!holder_klass->is_interface()) {
uncommon_trap(Deoptimization::Reason_uninitialized,
Deoptimization::Action_reinterpret,
--- a/hotspot/src/share/vm/opto/parse.hpp Thu Jul 08 14:29:44 2010 -0700
+++ b/hotspot/src/share/vm/opto/parse.hpp Mon Jul 12 10:58:25 2010 -0700
@@ -480,6 +480,7 @@
bool push_constant(ciConstant con, bool require_constant = false);
// implementation of object creation bytecodes
+ void emit_guard_for_new(ciInstanceKlass* klass);
void do_new();
void do_newarray(BasicType elemtype);
void do_anewarray();
--- a/hotspot/src/share/vm/opto/parseHelper.cpp Thu Jul 08 14:29:44 2010 -0700
+++ b/hotspot/src/share/vm/opto/parseHelper.cpp Mon Jul 12 10:58:25 2010 -0700
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1998, 2009, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1998, 2010, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -197,6 +197,43 @@
}
+void Parse::emit_guard_for_new(ciInstanceKlass* klass) {
+ // Emit guarded new
+ // if (klass->_init_thread != current_thread ||
+ // klass->_init_state != being_initialized)
+ // uncommon_trap
+ Node* cur_thread = _gvn.transform( new (C, 1) ThreadLocalNode() );
+ Node* merge = new (C, 3) RegionNode(3);
+ _gvn.set_type(merge, Type::CONTROL);
+ Node* kls = makecon(TypeKlassPtr::make(klass));
+
+ Node* init_thread_offset = _gvn.MakeConX(instanceKlass::init_thread_offset_in_bytes() + klassOopDesc::klass_part_offset_in_bytes());
+ Node* adr_node = basic_plus_adr(kls, kls, init_thread_offset);
+ Node* init_thread = make_load(NULL, adr_node, TypeRawPtr::BOTTOM, T_ADDRESS);
+ Node *tst = Bool( CmpP( init_thread, cur_thread), BoolTest::eq);
+ IfNode* iff = create_and_map_if(control(), tst, PROB_ALWAYS, COUNT_UNKNOWN);
+ set_control(IfTrue(iff));
+ merge->set_req(1, IfFalse(iff));
+
+ Node* init_state_offset = _gvn.MakeConX(instanceKlass::init_state_offset_in_bytes() + klassOopDesc::klass_part_offset_in_bytes());
+ adr_node = basic_plus_adr(kls, kls, init_state_offset);
+ Node* init_state = make_load(NULL, adr_node, TypeInt::INT, T_INT);
+ Node* being_init = _gvn.intcon(instanceKlass::being_initialized);
+ tst = Bool( CmpI( init_state, being_init), BoolTest::eq);
+ iff = create_and_map_if(control(), tst, PROB_ALWAYS, COUNT_UNKNOWN);
+ set_control(IfTrue(iff));
+ merge->set_req(2, IfFalse(iff));
+
+ PreserveJVMState pjvms(this);
+ record_for_igvn(merge);
+ set_control(merge);
+
+ uncommon_trap(Deoptimization::Reason_uninitialized,
+ Deoptimization::Action_reinterpret,
+ klass);
+}
+
+
//------------------------------do_new-----------------------------------------
void Parse::do_new() {
kill_dead_locals();
@@ -206,7 +243,7 @@
assert(will_link, "_new: typeflow responsibility");
// Should initialize, or throw an InstantiationError?
- if (!klass->is_initialized() ||
+ if (!klass->is_initialized() && !klass->is_being_initialized() ||
klass->is_abstract() || klass->is_interface() ||
klass->name() == ciSymbol::java_lang_Class() ||
iter().is_unresolved_klass()) {
@@ -215,6 +252,9 @@
klass);
return;
}
+ if (klass->is_being_initialized()) {
+ emit_guard_for_new(klass);
+ }
Node* kls = makecon(TypeKlassPtr::make(klass));
Node* obj = new_instance(kls);