Skip to content

Commit e5b1dbf

Browse files
committed
8231501: VM crash in MethodData::clean_extra_data(CleanExtraDataClosure*): fatal error: unexpected tag 99
Snapshot MDO extra trap and argument data only after it is prepared. Reviewed-by: phh Backport-of: 49048ad
1 parent f139171 commit e5b1dbf

File tree

3 files changed

+53
-25
lines changed

3 files changed

+53
-25
lines changed

src/hotspot/share/ci/ciMethodData.cpp

+47-20
Original file line numberDiff line numberDiff line change
@@ -120,7 +120,7 @@ void ciMethodData::prepare_metadata() {
120120
}
121121
}
122122

123-
void ciMethodData::load_extra_data() {
123+
void ciMethodData::load_remaining_extra_data() {
124124
MethodData* mdo = get_MethodData();
125125
MutexLocker ml(mdo->extra_data_lock());
126126
// Deferred metadata cleaning due to concurrent class unloading.
@@ -129,6 +129,14 @@ void ciMethodData::load_extra_data() {
129129
// and no safepoints can introduce more stale metadata.
130130
NoSafepointVerifier no_safepoint;
131131

132+
assert((mdo->data_size() == _data_size) && (mdo->extra_data_size() == _extra_data_size), "sanity, unchanged");
133+
assert(extra_data_base() == (DataLayout*)((address) _data + _data_size), "sanity");
134+
135+
// Copy the extra data once it is prepared (i.e. cache populated, no release of extra data lock anymore)
136+
Copy::disjoint_words_atomic((HeapWord*) mdo->extra_data_base(),
137+
(HeapWord*)((address) _data + _data_size),
138+
(_extra_data_size - mdo->parameters_size_in_bytes()) / HeapWordSize);
139+
132140
// speculative trap entries also hold a pointer to a Method so need to be translated
133141
DataLayout* dp_src = mdo->extra_data_base();
134142
DataLayout* end_src = mdo->args_data_limit();
@@ -137,19 +145,7 @@ void ciMethodData::load_extra_data() {
137145
assert(dp_src < end_src, "moved past end of extra data");
138146
assert(((intptr_t)dp_dst) - ((intptr_t)extra_data_base()) == ((intptr_t)dp_src) - ((intptr_t)mdo->extra_data_base()), "source and destination don't match");
139147

140-
// New traps in the MDO may have been added since we copied the
141-
// data (concurrent deoptimizations before we acquired
142-
// extra_data_lock above) or can be removed (a safepoint may occur
143-
// in the prepare_metadata call above) as we translate the copy:
144-
// update the copy as we go.
145148
int tag = dp_src->tag();
146-
size_t entry_size = DataLayout::header_size_in_bytes();
147-
if (tag != DataLayout::no_tag) {
148-
ProfileData* src_data = dp_src->data_in();
149-
entry_size = src_data->size_in_bytes();
150-
}
151-
memcpy(dp_dst, dp_src, entry_size);
152-
153149
switch(tag) {
154150
case DataLayout::speculative_trap_data_tag: {
155151
ciSpeculativeTrapData data_dst(dp_dst);
@@ -180,9 +176,31 @@ bool ciMethodData::load_data() {
180176
// To do: don't copy the data if it is not "ripe" -- require a minimum #
181177
// of invocations.
182178

183-
// Snapshot the data -- actually, take an approximate snapshot of
184-
// the data. Any concurrently executing threads may be changing the
185-
// data as we copy it.
179+
// Snapshot the data and extra parameter data first without the extra trap and arg info data.
180+
// Those are copied in a second step. Actually, an approximate snapshot of the data is taken.
181+
// Any concurrently executing threads may be changing the data as we copy it.
182+
//
183+
// The first snapshot step requires two copies (data entries and parameter data entries) since
184+
// the MDO is laid out as follows:
185+
//
186+
// data_base: ---------------------------
187+
// | data entries |
188+
// | ... |
189+
// extra_data_base: ---------------------------
190+
// | trap data entries |
191+
// | ... |
192+
// | one arg info data entry |
193+
// | data for each arg |
194+
// | ... |
195+
// args_data_limit: ---------------------------
196+
// | parameter data entries |
197+
// | ... |
198+
// extra_data_limit: ---------------------------
199+
//
200+
// _data_size = extra_data_base - data_base
201+
// _extra_data_size = extra_data_limit - extra_data_base
202+
// total_size = _data_size + _extra_data_size
203+
// args_data_limit = data_base + total_size - parameter_data_size
186204
STATIC_ASSERT(sizeof(_orig) % HeapWordSize == 0); // "align"
187205
Copy::disjoint_words_atomic((HeapWord*) &mdo->_compiler_counters,
188206
(HeapWord*) &_orig,
@@ -194,8 +212,15 @@ bool ciMethodData::load_data() {
194212
_data = (intptr_t *) arena->Amalloc(total_size);
195213
Copy::disjoint_words_atomic((HeapWord*) mdo->data_base(),
196214
(HeapWord*) _data,
197-
total_size / HeapWordSize);
215+
_data_size / HeapWordSize);
198216

217+
int parameters_data_size = mdo->parameters_size_in_bytes();
218+
if (parameters_data_size > 0) {
219+
// Snapshot the parameter data
220+
Copy::disjoint_words_atomic((HeapWord*) mdo->args_data_limit(),
221+
(HeapWord*) ((address)_data + total_size - parameters_data_size),
222+
parameters_data_size / HeapWordSize);
223+
}
199224
// Traverse the profile data, translating any oops into their
200225
// ci equivalents.
201226
ResourceMark rm;
@@ -212,7 +237,9 @@ bool ciMethodData::load_data() {
212237
parameters->translate_from(mdo->parameters_type_data());
213238
}
214239

215-
load_extra_data();
240+
assert((DataLayout*) ((address)_data + total_size - parameters_data_size) == args_data_limit(),
241+
"sanity - parameter data starts after the argument data of the single ArgInfoData entry");
242+
load_remaining_extra_data();
216243

217244
// Note: Extra data are all BitData, and do not need translation.
218245
_current_mileage = MethodData::mileage_of(mdo->method());
@@ -324,7 +351,7 @@ ciProfileData* ciMethodData::bci_to_extra_data(int bci, ciMethod* m, bool& two_f
324351
two_free_slots = (MethodData::next_extra(dp)->tag() == DataLayout::no_tag);
325352
return NULL;
326353
case DataLayout::arg_info_data_tag:
327-
return NULL; // ArgInfoData is at the end of extra data section.
354+
return NULL; // ArgInfoData is after the trap data right before the parameter data.
328355
case DataLayout::bit_data_tag:
329356
if (m == NULL && dp->bci() == bci) {
330357
return new ciBitData(dp);
@@ -735,7 +762,7 @@ void ciMethodData::print_data_on(outputStream* st) {
735762
break;
736763
case DataLayout::arg_info_data_tag:
737764
data = new ciArgInfoData(dp);
738-
dp = end; // ArgInfoData is at the end of extra data section.
765+
dp = end; // ArgInfoData is after the trap data right before the parameter data.
739766
break;
740767
case DataLayout::speculative_trap_data_tag:
741768
data = new ciSpeculativeTrapData(dp);

src/hotspot/share/ci/ciMethodData.hpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -474,7 +474,7 @@ class ciMethodData : public ciMetadata {
474474
}
475475

476476
void prepare_metadata();
477-
void load_extra_data();
477+
void load_remaining_extra_data();
478478
ciProfileData* bci_to_extra_data(int bci, ciMethod* m, bool& two_free_slots);
479479

480480
void dump_replay_data_type_helper(outputStream* out, int round, int& count, ProfileData* pdata, ByteSize offset, ciKlass* k);

src/hotspot/share/oops/methodData.hpp

+5-4
Original file line numberDiff line numberDiff line change
@@ -2108,10 +2108,6 @@ class MethodData : public Metadata {
21082108
// parameter profiling.
21092109
enum { no_parameters = -2, parameters_uninitialized = -1 };
21102110
int _parameters_type_data_di;
2111-
int parameters_size_in_bytes() const {
2112-
ParametersTypeData* param = parameters_type_data();
2113-
return param == NULL ? 0 : param->size_in_bytes();
2114-
}
21152111

21162112
// Beginning of the data entries
21172113
intptr_t _data[1];
@@ -2322,6 +2318,11 @@ class MethodData : public Metadata {
23222318
return _data_size;
23232319
}
23242320

2321+
int parameters_size_in_bytes() const {
2322+
ParametersTypeData* param = parameters_type_data();
2323+
return param == NULL ? 0 : param->size_in_bytes();
2324+
}
2325+
23252326
// Accessors
23262327
Method* method() const { return _method; }
23272328

0 commit comments

Comments
 (0)