Mercurial > hg > truffle
annotate src/share/vm/classfile/stackMapTable.cpp @ 3762:5c0a3c1858b1
7048782: CMS: assert(last_chunk_index_to_check<= last_chunk_index) failed: parCardTableModRefBS.cpp:359
Summary: The LNC array is sized before the start of a scavenge, while the heap may expand during a scavenge. With CMS, the last block of an arbitrary suffice of the LNC array may expand due to coalition with the expansion delta. We now take care not to attempt access past the end of the LNC array. LNC array code will be cleaned up and suitably encapsulated as part of the forthcoming performance RFE 7043675.
Reviewed-by: brutisso
author | ysr |
---|---|
date | Thu, 02 Jun 2011 10:23:36 -0700 |
parents | 3449f5e02cc4 |
children | 4ee06e614636 |
rev | line source |
---|---|
0 | 1 /* |
2426
1d1603768966
7010070: Update all 2010 Oracle-changed OpenJDK files to have the proper copyright dates - second pass
trims
parents:
2177
diff
changeset
|
2 * Copyright (c) 2003, 2011, Oracle and/or its affiliates. All rights reserved. |
0 | 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. |
4 * | |
5 * This code is free software; you can redistribute it and/or modify it | |
6 * under the terms of the GNU General Public License version 2 only, as | |
7 * published by the Free Software Foundation. | |
8 * | |
9 * This code is distributed in the hope that it will be useful, but WITHOUT | |
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |
12 * version 2 for more details (a copy is included in the LICENSE file that | |
13 * accompanied this code). | |
14 * | |
15 * You should have received a copy of the GNU General Public License version | |
16 * 2 along with this work; if not, write to the Free Software Foundation, | |
17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. | |
18 * | |
1552
c18cbe5936b8
6941466: Oracle rebranding changes for Hotspot repositories
trims
parents:
0
diff
changeset
|
19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA |
c18cbe5936b8
6941466: Oracle rebranding changes for Hotspot repositories
trims
parents:
0
diff
changeset
|
20 * or visit www.oracle.com if you need additional information or have any |
c18cbe5936b8
6941466: Oracle rebranding changes for Hotspot repositories
trims
parents:
0
diff
changeset
|
21 * questions. |
0 | 22 * |
23 */ | |
24 | |
1972 | 25 #include "precompiled.hpp" |
26 #include "classfile/stackMapTable.hpp" | |
27 #include "classfile/verifier.hpp" | |
28 #include "memory/resourceArea.hpp" | |
29 #include "oops/oop.inline.hpp" | |
30 #include "runtime/fieldType.hpp" | |
31 #include "runtime/handles.inline.hpp" | |
0 | 32 |
33 StackMapTable::StackMapTable(StackMapReader* reader, StackMapFrame* init_frame, | |
34 u2 max_locals, u2 max_stack, | |
35 char* code_data, int code_len, TRAPS) { | |
36 _code_length = code_len; | |
37 _frame_count = reader->get_frame_count(); | |
38 if (_frame_count > 0) { | |
39 _frame_array = NEW_RESOURCE_ARRAY_IN_THREAD(THREAD, | |
40 StackMapFrame*, _frame_count); | |
41 StackMapFrame* pre_frame = init_frame; | |
42 for (int32_t i = 0; i < _frame_count; i++) { | |
43 StackMapFrame* frame = reader->next( | |
44 pre_frame, i == 0, max_locals, max_stack, | |
45 CHECK_VERIFY(pre_frame->verifier())); | |
46 _frame_array[i] = frame; | |
47 int offset = frame->offset(); | |
48 if (offset >= code_len || code_data[offset] == 0) { | |
49 frame->verifier()->verify_error("StackMapTable error: bad offset"); | |
50 return; | |
51 } | |
52 pre_frame = frame; | |
53 } | |
54 } | |
55 reader->check_end(CHECK); | |
56 } | |
57 | |
58 // This method is only called by method in StackMapTable. | |
59 int StackMapTable::get_index_from_offset(int32_t offset) const { | |
60 int i = 0; | |
61 for (; i < _frame_count; i++) { | |
62 if (_frame_array[i]->offset() == offset) { | |
63 return i; | |
64 } | |
65 } | |
66 return i; // frame with offset doesn't exist in the array | |
67 } | |
68 | |
69 bool StackMapTable::match_stackmap( | |
70 StackMapFrame* frame, int32_t target, | |
71 bool match, bool update, TRAPS) const { | |
72 int index = get_index_from_offset(target); | |
73 | |
74 return match_stackmap( | |
75 frame, target, index, match, | |
76 update, CHECK_VERIFY_(frame->verifier(), false)); | |
77 } | |
78 | |
79 // Match and/or update current_frame to the frame in stackmap table with | |
80 // specified offset and frame index. Return true if the two frames match. | |
81 // | |
82 // The values of match and update are: _match__update_ | |
83 // | |
84 // checking a branch target/exception handler: true false | |
85 // linear bytecode verification following an | |
86 // unconditional branch: false true | |
87 // linear bytecode verification not following an | |
88 // unconditional branch: true true | |
89 bool StackMapTable::match_stackmap( | |
90 StackMapFrame* frame, int32_t target, int32_t frame_index, | |
91 bool match, bool update, TRAPS) const { | |
92 if (frame_index < 0 || frame_index >= _frame_count) { | |
93 frame->verifier()->verify_error(frame->offset(), | |
94 "Expecting a stackmap frame at branch target %d", target); | |
95 return false; | |
96 } | |
97 | |
98 bool result = true; | |
99 StackMapFrame *stackmap_frame = _frame_array[frame_index]; | |
100 if (match) { | |
2472
7144a1d6e0a9
7030388: JCK test failed to reject invalid class check01304m10n.
kamg
parents:
2177
diff
changeset
|
101 // when checking handler target, match == true && update == false |
7144a1d6e0a9
7030388: JCK test failed to reject invalid class check01304m10n.
kamg
parents:
2177
diff
changeset
|
102 bool is_exception_handler = !update; |
0 | 103 // Has direct control flow from last instruction, need to match the two |
104 // frames. | |
105 result = frame->is_assignable_to( | |
2472
7144a1d6e0a9
7030388: JCK test failed to reject invalid class check01304m10n.
kamg
parents:
2177
diff
changeset
|
106 stackmap_frame, is_exception_handler, |
7144a1d6e0a9
7030388: JCK test failed to reject invalid class check01304m10n.
kamg
parents:
2177
diff
changeset
|
107 CHECK_VERIFY_(frame->verifier(), false)); |
0 | 108 } |
109 if (update) { | |
110 // Use the frame in stackmap table as current frame | |
111 int lsize = stackmap_frame->locals_size(); | |
112 int ssize = stackmap_frame->stack_size(); | |
113 if (frame->locals_size() > lsize || frame->stack_size() > ssize) { | |
114 // Make sure unused type array items are all _bogus_type. | |
115 frame->reset(); | |
116 } | |
117 frame->set_locals_size(lsize); | |
118 frame->copy_locals(stackmap_frame); | |
119 frame->set_stack_size(ssize); | |
120 frame->copy_stack(stackmap_frame); | |
121 frame->set_flags(stackmap_frame->flags()); | |
122 } | |
123 return result; | |
124 } | |
125 | |
126 void StackMapTable::check_jump_target( | |
127 StackMapFrame* frame, int32_t target, TRAPS) const { | |
128 bool match = match_stackmap( | |
129 frame, target, true, false, CHECK_VERIFY(frame->verifier())); | |
130 if (!match || (target < 0 || target >= _code_length)) { | |
131 frame->verifier()->verify_error(frame->offset(), | |
132 "Inconsistent stackmap frames at branch target %d", target); | |
133 return; | |
134 } | |
135 // check if uninitialized objects exist on backward branches | |
136 check_new_object(frame, target, CHECK_VERIFY(frame->verifier())); | |
137 } | |
138 | |
139 void StackMapTable::check_new_object( | |
140 const StackMapFrame* frame, int32_t target, TRAPS) const { | |
141 if (frame->offset() > target && frame->has_new_object()) { | |
142 frame->verifier()->verify_error(frame->offset(), | |
143 "Uninitialized object exists on backward branch %d", target); | |
144 return; | |
145 } | |
146 } | |
147 | |
148 #ifndef PRODUCT | |
149 | |
150 void StackMapTable::print() const { | |
151 tty->print_cr("StackMapTable: frame_count = %d", _frame_count); | |
152 tty->print_cr("table = { "); | |
153 for (int32_t i = 0; i < _frame_count; i++) { | |
154 _frame_array[i]->print(); | |
155 } | |
156 tty->print_cr(" }"); | |
157 } | |
158 | |
159 #endif | |
160 | |
161 int32_t StackMapReader::chop( | |
162 VerificationType* locals, int32_t length, int32_t chops) { | |
1769 | 163 if (locals == NULL) return -1; |
0 | 164 int32_t pos = length - 1; |
165 for (int32_t i=0; i<chops; i++) { | |
166 if (locals[pos].is_category2_2nd()) { | |
167 pos -= 2; | |
168 } else { | |
169 pos --; | |
170 } | |
171 if (pos<0 && i<(chops-1)) return -1; | |
172 } | |
173 return pos+1; | |
174 } | |
175 | |
176 VerificationType StackMapReader::parse_verification_type(u1* flags, TRAPS) { | |
177 u1 tag = _stream->get_u1(THREAD); | |
178 if (tag < (u1)ITEM_UninitializedThis) { | |
179 return VerificationType::from_tag(tag); | |
180 } | |
181 if (tag == ITEM_Object) { | |
182 u2 class_index = _stream->get_u2(THREAD); | |
183 int nconstants = _cp->length(); | |
184 if ((class_index <= 0 || class_index >= nconstants) || | |
185 (!_cp->tag_at(class_index).is_klass() && | |
186 !_cp->tag_at(class_index).is_unresolved_klass())) { | |
187 _stream->stackmap_format_error("bad class index", THREAD); | |
188 return VerificationType::bogus_type(); | |
189 } | |
2177
3582bf76420e
6990754: Use native memory and reference counting to implement SymbolTable
coleenp
parents:
1972
diff
changeset
|
190 return VerificationType::reference_type(_cp->klass_name_at(class_index)); |
0 | 191 } |
192 if (tag == ITEM_UninitializedThis) { | |
193 if (flags != NULL) { | |
194 *flags |= FLAG_THIS_UNINIT; | |
195 } | |
196 return VerificationType::uninitialized_this_type(); | |
197 } | |
198 if (tag == ITEM_Uninitialized) { | |
199 u2 offset = _stream->get_u2(THREAD); | |
200 if (offset >= _code_length || | |
201 _code_data[offset] != ClassVerifier::NEW_OFFSET) { | |
202 ResourceMark rm(THREAD); | |
203 _verifier->class_format_error( | |
204 "StackMapTable format error: bad offset for Uninitialized"); | |
205 return VerificationType::bogus_type(); | |
206 } | |
207 return VerificationType::uninitialized_type(offset); | |
208 } | |
209 _stream->stackmap_format_error("bad verification type", THREAD); | |
210 return VerificationType::bogus_type(); | |
211 } | |
212 | |
213 StackMapFrame* StackMapReader::next( | |
214 StackMapFrame* pre_frame, bool first, u2 max_locals, u2 max_stack, TRAPS) { | |
215 StackMapFrame* frame; | |
216 int offset; | |
217 VerificationType* locals = NULL; | |
218 u1 frame_type = _stream->get_u1(THREAD); | |
219 if (frame_type < 64) { | |
220 // same_frame | |
221 if (first) { | |
222 offset = frame_type; | |
223 // Can't share the locals array since that is updated by the verifier. | |
224 if (pre_frame->locals_size() > 0) { | |
225 locals = NEW_RESOURCE_ARRAY_IN_THREAD( | |
226 THREAD, VerificationType, pre_frame->locals_size()); | |
227 } | |
228 } else { | |
229 offset = pre_frame->offset() + frame_type + 1; | |
230 locals = pre_frame->locals(); | |
231 } | |
232 frame = new StackMapFrame( | |
233 offset, pre_frame->flags(), pre_frame->locals_size(), 0, | |
234 max_locals, max_stack, locals, NULL, _verifier); | |
235 if (first && locals != NULL) { | |
236 frame->copy_locals(pre_frame); | |
237 } | |
238 return frame; | |
239 } | |
240 if (frame_type < 128) { | |
241 // same_locals_1_stack_item_frame | |
242 if (first) { | |
243 offset = frame_type - 64; | |
244 // Can't share the locals array since that is updated by the verifier. | |
245 if (pre_frame->locals_size() > 0) { | |
246 locals = NEW_RESOURCE_ARRAY_IN_THREAD( | |
247 THREAD, VerificationType, pre_frame->locals_size()); | |
248 } | |
249 } else { | |
250 offset = pre_frame->offset() + frame_type - 63; | |
251 locals = pre_frame->locals(); | |
252 } | |
253 VerificationType* stack = NEW_RESOURCE_ARRAY_IN_THREAD( | |
254 THREAD, VerificationType, 2); | |
255 u2 stack_size = 1; | |
256 stack[0] = parse_verification_type(NULL, CHECK_VERIFY_(_verifier, NULL)); | |
257 if (stack[0].is_category2()) { | |
258 stack[1] = stack[0].to_category2_2nd(); | |
259 stack_size = 2; | |
260 } | |
261 check_verification_type_array_size( | |
262 stack_size, max_stack, CHECK_VERIFY_(_verifier, NULL)); | |
263 frame = new StackMapFrame( | |
264 offset, pre_frame->flags(), pre_frame->locals_size(), stack_size, | |
265 max_locals, max_stack, locals, stack, _verifier); | |
266 if (first && locals != NULL) { | |
267 frame->copy_locals(pre_frame); | |
268 } | |
269 return frame; | |
270 } | |
271 | |
272 u2 offset_delta = _stream->get_u2(THREAD); | |
273 | |
274 if (frame_type < SAME_LOCALS_1_STACK_ITEM_EXTENDED) { | |
275 // reserved frame types | |
276 _stream->stackmap_format_error( | |
277 "reserved frame type", CHECK_VERIFY_(_verifier, NULL)); | |
278 } | |
279 | |
280 if (frame_type == SAME_LOCALS_1_STACK_ITEM_EXTENDED) { | |
281 // same_locals_1_stack_item_frame_extended | |
282 if (first) { | |
283 offset = offset_delta; | |
284 // Can't share the locals array since that is updated by the verifier. | |
285 if (pre_frame->locals_size() > 0) { | |
286 locals = NEW_RESOURCE_ARRAY_IN_THREAD( | |
287 THREAD, VerificationType, pre_frame->locals_size()); | |
288 } | |
289 } else { | |
290 offset = pre_frame->offset() + offset_delta + 1; | |
291 locals = pre_frame->locals(); | |
292 } | |
293 VerificationType* stack = NEW_RESOURCE_ARRAY_IN_THREAD( | |
294 THREAD, VerificationType, 2); | |
295 u2 stack_size = 1; | |
296 stack[0] = parse_verification_type(NULL, CHECK_VERIFY_(_verifier, NULL)); | |
297 if (stack[0].is_category2()) { | |
298 stack[1] = stack[0].to_category2_2nd(); | |
299 stack_size = 2; | |
300 } | |
301 check_verification_type_array_size( | |
302 stack_size, max_stack, CHECK_VERIFY_(_verifier, NULL)); | |
303 frame = new StackMapFrame( | |
304 offset, pre_frame->flags(), pre_frame->locals_size(), stack_size, | |
305 max_locals, max_stack, locals, stack, _verifier); | |
306 if (first && locals != NULL) { | |
307 frame->copy_locals(pre_frame); | |
308 } | |
309 return frame; | |
310 } | |
311 | |
312 if (frame_type <= SAME_EXTENDED) { | |
313 // chop_frame or same_frame_extended | |
314 locals = pre_frame->locals(); | |
315 int length = pre_frame->locals_size(); | |
316 int chops = SAME_EXTENDED - frame_type; | |
317 int new_length = length; | |
318 u1 flags = pre_frame->flags(); | |
319 if (chops != 0) { | |
320 new_length = chop(locals, length, chops); | |
321 check_verification_type_array_size( | |
322 new_length, max_locals, CHECK_VERIFY_(_verifier, NULL)); | |
323 // Recompute flags since uninitializedThis could have been chopped. | |
324 flags = 0; | |
325 for (int i=0; i<new_length; i++) { | |
326 if (locals[i].is_uninitialized_this()) { | |
327 flags |= FLAG_THIS_UNINIT; | |
328 break; | |
329 } | |
330 } | |
331 } | |
332 if (first) { | |
333 offset = offset_delta; | |
334 // Can't share the locals array since that is updated by the verifier. | |
335 if (new_length > 0) { | |
336 locals = NEW_RESOURCE_ARRAY_IN_THREAD( | |
337 THREAD, VerificationType, new_length); | |
338 } else { | |
339 locals = NULL; | |
340 } | |
341 } else { | |
342 offset = pre_frame->offset() + offset_delta + 1; | |
343 } | |
344 frame = new StackMapFrame( | |
345 offset, flags, new_length, 0, max_locals, max_stack, | |
346 locals, NULL, _verifier); | |
347 if (first && locals != NULL) { | |
348 frame->copy_locals(pre_frame); | |
349 } | |
350 return frame; | |
351 } else if (frame_type < SAME_EXTENDED + 4) { | |
352 // append_frame | |
353 int appends = frame_type - SAME_EXTENDED; | |
354 int real_length = pre_frame->locals_size(); | |
355 int new_length = real_length + appends*2; | |
356 locals = NEW_RESOURCE_ARRAY_IN_THREAD(THREAD, VerificationType, new_length); | |
357 VerificationType* pre_locals = pre_frame->locals(); | |
358 int i; | |
359 for (i=0; i<pre_frame->locals_size(); i++) { | |
360 locals[i] = pre_locals[i]; | |
361 } | |
362 u1 flags = pre_frame->flags(); | |
363 for (i=0; i<appends; i++) { | |
364 locals[real_length] = parse_verification_type(&flags, THREAD); | |
365 if (locals[real_length].is_category2()) { | |
366 locals[real_length + 1] = locals[real_length].to_category2_2nd(); | |
367 ++real_length; | |
368 } | |
369 ++real_length; | |
370 } | |
371 check_verification_type_array_size( | |
372 real_length, max_locals, CHECK_VERIFY_(_verifier, NULL)); | |
373 if (first) { | |
374 offset = offset_delta; | |
375 } else { | |
376 offset = pre_frame->offset() + offset_delta + 1; | |
377 } | |
378 frame = new StackMapFrame( | |
379 offset, flags, real_length, 0, max_locals, | |
380 max_stack, locals, NULL, _verifier); | |
381 return frame; | |
382 } | |
383 if (frame_type == FULL) { | |
384 // full_frame | |
385 u1 flags = 0; | |
386 u2 locals_size = _stream->get_u2(THREAD); | |
387 int real_locals_size = 0; | |
388 if (locals_size > 0) { | |
389 locals = NEW_RESOURCE_ARRAY_IN_THREAD( | |
390 THREAD, VerificationType, locals_size*2); | |
391 } | |
392 int i; | |
393 for (i=0; i<locals_size; i++) { | |
394 locals[real_locals_size] = parse_verification_type(&flags, THREAD); | |
395 if (locals[real_locals_size].is_category2()) { | |
396 locals[real_locals_size + 1] = | |
397 locals[real_locals_size].to_category2_2nd(); | |
398 ++real_locals_size; | |
399 } | |
400 ++real_locals_size; | |
401 } | |
402 check_verification_type_array_size( | |
403 real_locals_size, max_locals, CHECK_VERIFY_(_verifier, NULL)); | |
404 u2 stack_size = _stream->get_u2(THREAD); | |
405 int real_stack_size = 0; | |
406 VerificationType* stack = NULL; | |
407 if (stack_size > 0) { | |
408 stack = NEW_RESOURCE_ARRAY_IN_THREAD( | |
409 THREAD, VerificationType, stack_size*2); | |
410 } | |
411 for (i=0; i<stack_size; i++) { | |
412 stack[real_stack_size] = parse_verification_type(NULL, THREAD); | |
413 if (stack[real_stack_size].is_category2()) { | |
414 stack[real_stack_size + 1] = stack[real_stack_size].to_category2_2nd(); | |
415 ++real_stack_size; | |
416 } | |
417 ++real_stack_size; | |
418 } | |
419 check_verification_type_array_size( | |
420 real_stack_size, max_stack, CHECK_VERIFY_(_verifier, NULL)); | |
421 if (first) { | |
422 offset = offset_delta; | |
423 } else { | |
424 offset = pre_frame->offset() + offset_delta + 1; | |
425 } | |
426 frame = new StackMapFrame( | |
427 offset, flags, real_locals_size, real_stack_size, | |
428 max_locals, max_stack, locals, stack, _verifier); | |
429 return frame; | |
430 } | |
431 | |
432 _stream->stackmap_format_error( | |
433 "reserved frame type", CHECK_VERIFY_(pre_frame->verifier(), NULL)); | |
434 return NULL; | |
435 } |