| File: | jdk/src/hotspot/share/classfile/stackMapTable.hpp |
| Warning: | line 94, column 12 Called C++ object pointer is null |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
| 1 | /* | |||
| 2 | * Copyright (c) 2003, 2020, Oracle and/or its affiliates. All rights reserved. | |||
| 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 | * | |||
| 19 | * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA | |||
| 20 | * or visit www.oracle.com if you need additional information or have any | |||
| 21 | * questions. | |||
| 22 | * | |||
| 23 | */ | |||
| 24 | ||||
| 25 | #include "precompiled.hpp" | |||
| 26 | #include "classfile/stackMapTable.hpp" | |||
| 27 | #include "classfile/verifier.hpp" | |||
| 28 | #include "memory/resourceArea.hpp" | |||
| 29 | #include "oops/constantPool.hpp" | |||
| 30 | #include "oops/oop.inline.hpp" | |||
| 31 | #include "runtime/handles.inline.hpp" | |||
| 32 | ||||
| 33 | StackMapTable::StackMapTable(StackMapReader* reader, StackMapFrame* init_frame, | |||
| 34 | u2 max_locals, u2 max_stack, | |||
| 35 | char* code_data, int code_len, TRAPSJavaThread* __the_thread__) { | |||
| 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,(StackMapFrame**) resource_allocate_bytes(__the_thread__, (_frame_count ) * sizeof(StackMapFrame*)) | |||
| 40 | StackMapFrame*, _frame_count)(StackMapFrame**) resource_allocate_bytes(__the_thread__, (_frame_count ) * sizeof(StackMapFrame*)); | |||
| 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())__the_thread__); if ((((ThreadShadow*)__the_thread__)->has_pending_exception ())) return ; (void)(0); if ((pre_frame->verifier())->has_error ()) return; ((void)0); | |||
| 46 | _frame_array[i] = frame; | |||
| 47 | int offset = frame->offset(); | |||
| 48 | if (offset >= code_len || code_data[offset] == 0) { | |||
| 49 | frame->verifier()->verify_error( | |||
| 50 | ErrorContext::bad_stackmap(i, frame), | |||
| 51 | "StackMapTable error: bad offset"); | |||
| 52 | return; | |||
| 53 | } | |||
| 54 | pre_frame = frame; | |||
| 55 | } | |||
| 56 | } | |||
| 57 | reader->check_end(CHECK__the_thread__); if ((((ThreadShadow*)__the_thread__)->has_pending_exception ())) return ; (void)(0); | |||
| 58 | } | |||
| 59 | ||||
| 60 | // This method is only called by method in StackMapTable. | |||
| 61 | int StackMapTable::get_index_from_offset(int32_t offset) const { | |||
| 62 | int i = 0; | |||
| 63 | for (; i < _frame_count; i++) { | |||
| 64 | if (_frame_array[i]->offset() == offset) { | |||
| 65 | return i; | |||
| 66 | } | |||
| 67 | } | |||
| 68 | return i; // frame with offset doesn't exist in the array | |||
| 69 | } | |||
| 70 | ||||
| 71 | bool StackMapTable::match_stackmap( | |||
| 72 | StackMapFrame* frame, int32_t target, | |||
| 73 | bool match, bool update, ErrorContext* ctx, TRAPSJavaThread* __the_thread__) const { | |||
| 74 | int index = get_index_from_offset(target); | |||
| 75 | return match_stackmap(frame, target, index, match, update, ctx, THREAD__the_thread__); | |||
| 76 | } | |||
| 77 | ||||
| 78 | // Match and/or update current_frame to the frame in stackmap table with | |||
| 79 | // specified offset and frame index. Return true if the two frames match. | |||
| 80 | // | |||
| 81 | // The values of match and update are: _match__update | |||
| 82 | // | |||
| 83 | // checking a branch target: true false | |||
| 84 | // checking an 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, ErrorContext* ctx, TRAPSJavaThread* __the_thread__) const { | |||
| 92 | if (frame_index < 0 || frame_index >= _frame_count) { | |||
| 93 | *ctx = ErrorContext::missing_stackmap(frame->offset()); | |||
| 94 | frame->verifier()->verify_error( | |||
| 95 | *ctx, "Expecting a stackmap frame at branch target %d", target); | |||
| 96 | return false; | |||
| 97 | } | |||
| 98 | ||||
| 99 | StackMapFrame *stackmap_frame = _frame_array[frame_index]; | |||
| 100 | bool result = true; | |||
| 101 | if (match) { | |||
| 102 | // Has direct control flow from last instruction, need to match the two | |||
| 103 | // frames. | |||
| 104 | result = frame->is_assignable_to(stackmap_frame, | |||
| 105 | ctx, CHECK_VERIFY_(frame->verifier(), result)__the_thread__); if ((((ThreadShadow*)__the_thread__)->has_pending_exception ())) return result; (void)(0); if ((frame->verifier())-> has_error()) return (result); ((void)0); | |||
| 106 | } | |||
| 107 | if (update) { | |||
| 108 | // Use the frame in stackmap table as current frame | |||
| 109 | int lsize = stackmap_frame->locals_size(); | |||
| 110 | int ssize = stackmap_frame->stack_size(); | |||
| 111 | if (frame->locals_size() > lsize || frame->stack_size() > ssize) { | |||
| 112 | // Make sure unused type array items are all _bogus_type. | |||
| 113 | frame->reset(); | |||
| 114 | } | |||
| 115 | frame->set_locals_size(lsize); | |||
| 116 | frame->copy_locals(stackmap_frame); | |||
| 117 | frame->set_stack_size(ssize); | |||
| 118 | frame->copy_stack(stackmap_frame); | |||
| 119 | frame->set_flags(stackmap_frame->flags()); | |||
| 120 | } | |||
| 121 | return result; | |||
| 122 | } | |||
| 123 | ||||
| 124 | void StackMapTable::check_jump_target( | |||
| 125 | StackMapFrame* frame, int32_t target, TRAPSJavaThread* __the_thread__) const { | |||
| 126 | ErrorContext ctx; | |||
| 127 | bool match = match_stackmap( | |||
| 128 | frame, target, true, false, &ctx, CHECK_VERIFY(frame->verifier())__the_thread__); if ((((ThreadShadow*)__the_thread__)->has_pending_exception ())) return ; (void)(0); if ((frame->verifier())->has_error ()) return; ((void)0); | |||
| 129 | if (!match || (target < 0 || target >= _code_length)) { | |||
| 130 | frame->verifier()->verify_error(ctx, | |||
| 131 | "Inconsistent stackmap frames at branch target %d", target); | |||
| 132 | } | |||
| 133 | } | |||
| 134 | ||||
| 135 | void StackMapTable::print_on(outputStream* str) const { | |||
| 136 | str->indent().print_cr("StackMapTable: frame_count = %d", _frame_count); | |||
| 137 | str->indent().print_cr("table = { "); | |||
| 138 | { | |||
| 139 | streamIndentor si(str); | |||
| 140 | for (int32_t i = 0; i < _frame_count; ++i) { | |||
| 141 | _frame_array[i]->print_on(str); | |||
| 142 | } | |||
| 143 | } | |||
| 144 | str->print_cr(" }"); | |||
| 145 | } | |||
| 146 | ||||
| 147 | StackMapReader::StackMapReader(ClassVerifier* v, StackMapStream* stream, char* code_data, | |||
| 148 | int32_t code_len, TRAPSJavaThread* __the_thread__) : | |||
| 149 | _verifier(v), _stream(stream), | |||
| 150 | _code_data(code_data), _code_length(code_len) { | |||
| 151 | methodHandle m = v->method(); | |||
| 152 | if (m->has_stackmap_table()) { | |||
| 153 | _cp = constantPoolHandle(THREAD__the_thread__, m->constants()); | |||
| 154 | _frame_count = _stream->get_u2(CHECK__the_thread__); if ((((ThreadShadow*)__the_thread__)->has_pending_exception ())) return ; (void)(0); | |||
| 155 | } else { | |||
| 156 | // There's no stackmap table present. Frame count and size are 0. | |||
| 157 | _frame_count = 0; | |||
| 158 | } | |||
| 159 | } | |||
| 160 | ||||
| 161 | int32_t StackMapReader::chop( | |||
| 162 | VerificationType* locals, int32_t length, int32_t chops) { | |||
| 163 | if (locals == NULL__null) return -1; | |||
| 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, TRAPSJavaThread* __the_thread__) { | |||
| 177 | u1 tag = _stream->get_u1(THREAD__the_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__the_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__the_thread__); | |||
| 188 | return VerificationType::bogus_type(); | |||
| 189 | } | |||
| 190 | return VerificationType::reference_type(_cp->klass_name_at(class_index)); | |||
| 191 | } | |||
| 192 | if (tag == ITEM_UninitializedThis) { | |||
| 193 | if (flags != NULL__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__the_thread__); | |||
| 200 | if (offset >= _code_length || | |||
| 201 | _code_data[offset] != ClassVerifier::NEW_OFFSET) { | |||
| 202 | _verifier->class_format_error( | |||
| 203 | "StackMapTable format error: bad offset for Uninitialized"); | |||
| 204 | return VerificationType::bogus_type(); | |||
| 205 | } | |||
| 206 | return VerificationType::uninitialized_type(offset); | |||
| 207 | } | |||
| 208 | _stream->stackmap_format_error("bad verification type", THREAD__the_thread__); | |||
| 209 | return VerificationType::bogus_type(); | |||
| 210 | } | |||
| 211 | ||||
| 212 | StackMapFrame* StackMapReader::next( | |||
| 213 | StackMapFrame* pre_frame, bool first, u2 max_locals, u2 max_stack, TRAPSJavaThread* __the_thread__) { | |||
| 214 | StackMapFrame* frame; | |||
| 215 | int offset; | |||
| 216 | VerificationType* locals = NULL__null; | |||
| 217 | u1 frame_type = _stream->get_u1(THREAD__the_thread__); | |||
| ||||
| 218 | if (frame_type < 64) { | |||
| 219 | // same_frame | |||
| 220 | if (first) { | |||
| 221 | offset = frame_type; | |||
| 222 | // Can't share the locals array since that is updated by the verifier. | |||
| 223 | if (pre_frame->locals_size() > 0) { | |||
| 224 | locals = NEW_RESOURCE_ARRAY_IN_THREAD((VerificationType*) resource_allocate_bytes(__the_thread__, ( pre_frame->locals_size()) * sizeof(VerificationType)) | |||
| 225 | THREAD, VerificationType, pre_frame->locals_size())(VerificationType*) resource_allocate_bytes(__the_thread__, ( pre_frame->locals_size()) * sizeof(VerificationType)); | |||
| 226 | } | |||
| 227 | } else { | |||
| 228 | offset = pre_frame->offset() + frame_type + 1; | |||
| 229 | locals = pre_frame->locals(); | |||
| 230 | } | |||
| 231 | frame = new StackMapFrame( | |||
| 232 | offset, pre_frame->flags(), pre_frame->locals_size(), 0, | |||
| 233 | max_locals, max_stack, locals, NULL__null, _verifier); | |||
| 234 | if (first && locals != NULL__null) { | |||
| 235 | frame->copy_locals(pre_frame); | |||
| 236 | } | |||
| 237 | return frame; | |||
| 238 | } | |||
| 239 | if (frame_type < 128) { | |||
| 240 | // same_locals_1_stack_item_frame | |||
| 241 | if (first) { | |||
| 242 | offset = frame_type - 64; | |||
| 243 | // Can't share the locals array since that is updated by the verifier. | |||
| 244 | if (pre_frame->locals_size() > 0) { | |||
| 245 | locals = NEW_RESOURCE_ARRAY_IN_THREAD((VerificationType*) resource_allocate_bytes(__the_thread__, ( pre_frame->locals_size()) * sizeof(VerificationType)) | |||
| 246 | THREAD, VerificationType, pre_frame->locals_size())(VerificationType*) resource_allocate_bytes(__the_thread__, ( pre_frame->locals_size()) * sizeof(VerificationType)); | |||
| 247 | } | |||
| 248 | } else { | |||
| 249 | offset = pre_frame->offset() + frame_type - 63; | |||
| 250 | locals = pre_frame->locals(); | |||
| 251 | } | |||
| 252 | VerificationType* stack = NEW_RESOURCE_ARRAY_IN_THREAD((VerificationType*) resource_allocate_bytes(__the_thread__, ( 2) * sizeof(VerificationType)) | |||
| 253 | THREAD, VerificationType, 2)(VerificationType*) resource_allocate_bytes(__the_thread__, ( 2) * sizeof(VerificationType)); | |||
| 254 | u2 stack_size = 1; | |||
| 255 | stack[0] = parse_verification_type(NULL__null, CHECK_VERIFY_(_verifier, NULL)__the_thread__); if ((((ThreadShadow*)__the_thread__)->has_pending_exception ())) return __null; (void)(0); if ((_verifier)->has_error( )) return (__null); ((void)0); | |||
| 256 | if (stack[0].is_category2()) { | |||
| 257 | stack[1] = stack[0].to_category2_2nd(); | |||
| 258 | stack_size = 2; | |||
| 259 | } | |||
| 260 | check_verification_type_array_size( | |||
| 261 | stack_size, max_stack, CHECK_VERIFY_(_verifier, NULL)__the_thread__); if ((((ThreadShadow*)__the_thread__)->has_pending_exception ())) return __null; (void)(0); if ((_verifier)->has_error( )) return (__null); ((void)0); | |||
| 262 | frame = new StackMapFrame( | |||
| 263 | offset, pre_frame->flags(), pre_frame->locals_size(), stack_size, | |||
| 264 | max_locals, max_stack, locals, stack, _verifier); | |||
| 265 | if (first && locals != NULL__null) { | |||
| 266 | frame->copy_locals(pre_frame); | |||
| 267 | } | |||
| 268 | return frame; | |||
| 269 | } | |||
| 270 | ||||
| 271 | u2 offset_delta = _stream->get_u2(THREAD__the_thread__); | |||
| 272 | ||||
| 273 | if (frame_type < SAME_LOCALS_1_STACK_ITEM_EXTENDED) { | |||
| 274 | // reserved frame types | |||
| 275 | _stream->stackmap_format_error( | |||
| 276 | "reserved frame type", CHECK_VERIFY_(_verifier, NULL)__the_thread__); if ((((ThreadShadow*)__the_thread__)->has_pending_exception ())) return __null; (void)(0); if ((_verifier)->has_error( )) return (__null); ((void)0); | |||
| 277 | } | |||
| 278 | ||||
| 279 | if (frame_type == SAME_LOCALS_1_STACK_ITEM_EXTENDED) { | |||
| 280 | // same_locals_1_stack_item_frame_extended | |||
| 281 | if (first) { | |||
| 282 | offset = offset_delta; | |||
| 283 | // Can't share the locals array since that is updated by the verifier. | |||
| 284 | if (pre_frame->locals_size() > 0) { | |||
| 285 | locals = NEW_RESOURCE_ARRAY_IN_THREAD((VerificationType*) resource_allocate_bytes(__the_thread__, ( pre_frame->locals_size()) * sizeof(VerificationType)) | |||
| 286 | THREAD, VerificationType, pre_frame->locals_size())(VerificationType*) resource_allocate_bytes(__the_thread__, ( pre_frame->locals_size()) * sizeof(VerificationType)); | |||
| 287 | } | |||
| 288 | } else { | |||
| 289 | offset = pre_frame->offset() + offset_delta + 1; | |||
| 290 | locals = pre_frame->locals(); | |||
| 291 | } | |||
| 292 | VerificationType* stack = NEW_RESOURCE_ARRAY_IN_THREAD((VerificationType*) resource_allocate_bytes(__the_thread__, ( 2) * sizeof(VerificationType)) | |||
| 293 | THREAD, VerificationType, 2)(VerificationType*) resource_allocate_bytes(__the_thread__, ( 2) * sizeof(VerificationType)); | |||
| 294 | u2 stack_size = 1; | |||
| 295 | stack[0] = parse_verification_type(NULL__null, CHECK_VERIFY_(_verifier, NULL)__the_thread__); if ((((ThreadShadow*)__the_thread__)->has_pending_exception ())) return __null; (void)(0); if ((_verifier)->has_error( )) return (__null); ((void)0); | |||
| 296 | if (stack[0].is_category2()) { | |||
| 297 | stack[1] = stack[0].to_category2_2nd(); | |||
| 298 | stack_size = 2; | |||
| 299 | } | |||
| 300 | check_verification_type_array_size( | |||
| 301 | stack_size, max_stack, CHECK_VERIFY_(_verifier, NULL)__the_thread__); if ((((ThreadShadow*)__the_thread__)->has_pending_exception ())) return __null; (void)(0); if ((_verifier)->has_error( )) return (__null); ((void)0); | |||
| 302 | frame = new StackMapFrame( | |||
| 303 | offset, pre_frame->flags(), pre_frame->locals_size(), stack_size, | |||
| 304 | max_locals, max_stack, locals, stack, _verifier); | |||
| 305 | if (first && locals != NULL__null) { | |||
| 306 | frame->copy_locals(pre_frame); | |||
| 307 | } | |||
| 308 | return frame; | |||
| 309 | } | |||
| 310 | ||||
| 311 | if (frame_type <= SAME_EXTENDED) { | |||
| 312 | // chop_frame or same_frame_extended | |||
| 313 | locals = pre_frame->locals(); | |||
| 314 | int length = pre_frame->locals_size(); | |||
| 315 | int chops = SAME_EXTENDED - frame_type; | |||
| 316 | int new_length = length; | |||
| 317 | u1 flags = pre_frame->flags(); | |||
| 318 | if (chops != 0) { | |||
| 319 | new_length = chop(locals, length, chops); | |||
| 320 | check_verification_type_array_size( | |||
| 321 | new_length, max_locals, CHECK_VERIFY_(_verifier, NULL)__the_thread__); if ((((ThreadShadow*)__the_thread__)->has_pending_exception ())) return __null; (void)(0); if ((_verifier)->has_error( )) return (__null); ((void)0); | |||
| 322 | // Recompute flags since uninitializedThis could have been chopped. | |||
| 323 | flags = 0; | |||
| 324 | for (int i=0; i<new_length; i++) { | |||
| 325 | if (locals[i].is_uninitialized_this()) { | |||
| 326 | flags |= FLAG_THIS_UNINIT; | |||
| 327 | break; | |||
| 328 | } | |||
| 329 | } | |||
| 330 | } | |||
| 331 | if (first) { | |||
| 332 | offset = offset_delta; | |||
| 333 | // Can't share the locals array since that is updated by the verifier. | |||
| 334 | if (new_length > 0) { | |||
| 335 | locals = NEW_RESOURCE_ARRAY_IN_THREAD((VerificationType*) resource_allocate_bytes(__the_thread__, ( new_length) * sizeof(VerificationType)) | |||
| 336 | THREAD, VerificationType, new_length)(VerificationType*) resource_allocate_bytes(__the_thread__, ( new_length) * sizeof(VerificationType)); | |||
| 337 | } else { | |||
| 338 | locals = NULL__null; | |||
| 339 | } | |||
| 340 | } else { | |||
| 341 | offset = pre_frame->offset() + offset_delta + 1; | |||
| 342 | } | |||
| 343 | frame = new StackMapFrame( | |||
| 344 | offset, flags, new_length, 0, max_locals, max_stack, | |||
| 345 | locals, NULL__null, _verifier); | |||
| 346 | if (first && locals != NULL__null) { | |||
| 347 | frame->copy_locals(pre_frame); | |||
| 348 | } | |||
| 349 | return frame; | |||
| 350 | } else if (frame_type < SAME_EXTENDED + 4) { | |||
| 351 | // append_frame | |||
| 352 | int appends = frame_type - SAME_EXTENDED; | |||
| 353 | int real_length = pre_frame->locals_size(); | |||
| 354 | int new_length = real_length + appends*2; | |||
| 355 | locals = NEW_RESOURCE_ARRAY_IN_THREAD(THREAD, VerificationType, new_length)(VerificationType*) resource_allocate_bytes(__the_thread__, ( new_length) * sizeof(VerificationType)); | |||
| 356 | VerificationType* pre_locals = pre_frame->locals(); | |||
| 357 | int i; | |||
| 358 | for (i=0; i<pre_frame->locals_size(); i++) { | |||
| 359 | locals[i] = pre_locals[i]; | |||
| 360 | } | |||
| 361 | u1 flags = pre_frame->flags(); | |||
| 362 | for (i=0; i<appends; i++) { | |||
| 363 | locals[real_length] = parse_verification_type(&flags, THREAD__the_thread__); | |||
| 364 | if (locals[real_length].is_category2()) { | |||
| 365 | locals[real_length + 1] = locals[real_length].to_category2_2nd(); | |||
| 366 | ++real_length; | |||
| 367 | } | |||
| 368 | ++real_length; | |||
| 369 | } | |||
| 370 | check_verification_type_array_size( | |||
| 371 | real_length, max_locals, CHECK_VERIFY_(_verifier, NULL)__the_thread__); if ((((ThreadShadow*)__the_thread__)->has_pending_exception ())) return __null; (void)(0); if ((_verifier)->has_error( )) return (__null); ((void)0); | |||
| 372 | if (first) { | |||
| 373 | offset = offset_delta; | |||
| 374 | } else { | |||
| 375 | offset = pre_frame->offset() + offset_delta + 1; | |||
| 376 | } | |||
| 377 | frame = new StackMapFrame( | |||
| 378 | offset, flags, real_length, 0, max_locals, | |||
| 379 | max_stack, locals, NULL__null, _verifier); | |||
| 380 | return frame; | |||
| 381 | } | |||
| 382 | if (frame_type == FULL) { | |||
| 383 | // full_frame | |||
| 384 | u1 flags = 0; | |||
| 385 | u2 locals_size = _stream->get_u2(THREAD__the_thread__); | |||
| 386 | int real_locals_size = 0; | |||
| 387 | if (locals_size > 0) { | |||
| 388 | locals = NEW_RESOURCE_ARRAY_IN_THREAD((VerificationType*) resource_allocate_bytes(__the_thread__, ( locals_size*2) * sizeof(VerificationType)) | |||
| 389 | THREAD, VerificationType, locals_size*2)(VerificationType*) resource_allocate_bytes(__the_thread__, ( locals_size*2) * sizeof(VerificationType)); | |||
| 390 | } | |||
| 391 | int i; | |||
| 392 | for (i=0; i<locals_size; i++) { | |||
| 393 | locals[real_locals_size] = parse_verification_type(&flags, THREAD__the_thread__); | |||
| 394 | if (locals[real_locals_size].is_category2()) { | |||
| 395 | locals[real_locals_size + 1] = | |||
| 396 | locals[real_locals_size].to_category2_2nd(); | |||
| 397 | ++real_locals_size; | |||
| 398 | } | |||
| 399 | ++real_locals_size; | |||
| 400 | } | |||
| 401 | check_verification_type_array_size( | |||
| 402 | real_locals_size, max_locals, CHECK_VERIFY_(_verifier, NULL)__the_thread__); if ((((ThreadShadow*)__the_thread__)->has_pending_exception ())) return __null; (void)(0); if ((_verifier)->has_error( )) return (__null); ((void)0); | |||
| 403 | u2 stack_size = _stream->get_u2(THREAD__the_thread__); | |||
| 404 | int real_stack_size = 0; | |||
| 405 | VerificationType* stack = NULL__null; | |||
| 406 | if (stack_size > 0) { | |||
| 407 | stack = NEW_RESOURCE_ARRAY_IN_THREAD((VerificationType*) resource_allocate_bytes(__the_thread__, ( stack_size*2) * sizeof(VerificationType)) | |||
| 408 | THREAD, VerificationType, stack_size*2)(VerificationType*) resource_allocate_bytes(__the_thread__, ( stack_size*2) * sizeof(VerificationType)); | |||
| 409 | } | |||
| 410 | for (i=0; i<stack_size; i++) { | |||
| 411 | stack[real_stack_size] = parse_verification_type(NULL__null, THREAD__the_thread__); | |||
| 412 | if (stack[real_stack_size].is_category2()) { | |||
| 413 | stack[real_stack_size + 1] = stack[real_stack_size].to_category2_2nd(); | |||
| 414 | ++real_stack_size; | |||
| 415 | } | |||
| 416 | ++real_stack_size; | |||
| 417 | } | |||
| 418 | check_verification_type_array_size( | |||
| 419 | real_stack_size, max_stack, CHECK_VERIFY_(_verifier, NULL)__the_thread__); if ((((ThreadShadow*)__the_thread__)->has_pending_exception ())) return __null; (void)(0); if ((_verifier)->has_error( )) return (__null); ((void)0); | |||
| 420 | if (first) { | |||
| 421 | offset = offset_delta; | |||
| 422 | } else { | |||
| 423 | offset = pre_frame->offset() + offset_delta + 1; | |||
| 424 | } | |||
| 425 | frame = new StackMapFrame( | |||
| 426 | offset, flags, real_locals_size, real_stack_size, | |||
| 427 | max_locals, max_stack, locals, stack, _verifier); | |||
| 428 | return frame; | |||
| 429 | } | |||
| 430 | ||||
| 431 | _stream->stackmap_format_error( | |||
| 432 | "reserved frame type", CHECK_VERIFY_(pre_frame->verifier(), NULL)__the_thread__); if ((((ThreadShadow*)__the_thread__)->has_pending_exception ())) return __null; (void)(0); if ((pre_frame->verifier()) ->has_error()) return (__null); ((void)0); | |||
| 433 | return NULL__null; | |||
| 434 | } |
| 1 | /* | |||
| 2 | * Copyright (c) 2003, 2019, Oracle and/or its affiliates. All rights reserved. | |||
| 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 | * | |||
| 19 | * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA | |||
| 20 | * or visit www.oracle.com if you need additional information or have any | |||
| 21 | * questions. | |||
| 22 | * | |||
| 23 | */ | |||
| 24 | ||||
| 25 | #ifndef SHARE_CLASSFILE_STACKMAPTABLE_HPP | |||
| 26 | #define SHARE_CLASSFILE_STACKMAPTABLE_HPP | |||
| 27 | ||||
| 28 | #include "classfile/stackMapFrame.hpp" | |||
| 29 | #include "classfile/verifier.hpp" | |||
| 30 | #include "memory/allocation.hpp" | |||
| 31 | #include "oops/constantPool.hpp" | |||
| 32 | #include "oops/method.hpp" | |||
| 33 | #include "utilities/bytes.hpp" | |||
| 34 | #include "utilities/globalDefinitions.hpp" | |||
| 35 | ||||
| 36 | class StackMapReader; | |||
| 37 | ||||
| 38 | // StackMapTable class is the StackMap table used by type checker | |||
| 39 | class StackMapTable : public StackObj { | |||
| 40 | private: | |||
| 41 | // Logically, the _frame_count (as well as many fields in the StackFrame) | |||
| 42 | // should be a u2, but if we defined the variable as that type it will | |||
| 43 | // be difficult to detect/recover from overflow or underflow conditions. | |||
| 44 | // Widening the type and making it signed will help detect these. | |||
| 45 | int32_t _code_length; | |||
| 46 | int32_t _frame_count; // Stackmap frame count | |||
| 47 | StackMapFrame** _frame_array; | |||
| 48 | ||||
| 49 | public: | |||
| 50 | StackMapTable(StackMapReader* reader, StackMapFrame* init_frame, | |||
| 51 | u2 max_locals, u2 max_stack, | |||
| 52 | char* code_data, int code_len, TRAPSJavaThread* __the_thread__); | |||
| 53 | ||||
| 54 | inline int32_t get_frame_count() const { return _frame_count; } | |||
| 55 | inline int get_offset(int index) const { | |||
| 56 | return _frame_array[index]->offset(); | |||
| 57 | } | |||
| 58 | ||||
| 59 | // Match and/or update current_frame to the frame in stackmap table with | |||
| 60 | // specified offset. Return true if the two frames match. | |||
| 61 | bool match_stackmap( | |||
| 62 | StackMapFrame* current_frame, int32_t offset, | |||
| 63 | bool match, bool update, ErrorContext* ctx, TRAPSJavaThread* __the_thread__) const; | |||
| 64 | // Match and/or update current_frame to the frame in stackmap table with | |||
| 65 | // specified offset and frame index. Return true if the two frames match. | |||
| 66 | bool match_stackmap( | |||
| 67 | StackMapFrame* current_frame, int32_t offset, int32_t frame_index, | |||
| 68 | bool match, bool update, ErrorContext* ctx, TRAPSJavaThread* __the_thread__) const; | |||
| 69 | ||||
| 70 | // Check jump instructions. Make sure there are no uninitialized | |||
| 71 | // instances on backward branch. | |||
| 72 | void check_jump_target(StackMapFrame* frame, int32_t target, TRAPSJavaThread* __the_thread__) const; | |||
| 73 | ||||
| 74 | // The following methods are only used inside this class. | |||
| 75 | ||||
| 76 | // Returns the frame array index where the frame with offset is stored. | |||
| 77 | int get_index_from_offset(int32_t offset) const; | |||
| 78 | ||||
| 79 | void print_on(outputStream* str) const; | |||
| 80 | }; | |||
| 81 | ||||
| 82 | class StackMapStream : StackObj { | |||
| 83 | private: | |||
| 84 | Array<u1>* _data; | |||
| 85 | int _index; | |||
| 86 | public: | |||
| 87 | StackMapStream(Array<u1>* ah) | |||
| 88 | : _data(ah), _index(0) { | |||
| 89 | } | |||
| 90 | u1 get_u1(TRAPSJavaThread* __the_thread__) { | |||
| 91 | if (_data == NULL__null || _index >= _data->length()) { | |||
| 92 | stackmap_format_error("access beyond the end of attribute", CHECK_0__the_thread__); if ((((ThreadShadow*)__the_thread__)->has_pending_exception ())) return 0; (void)(0); | |||
| 93 | } | |||
| 94 | return _data->at(_index++); | |||
| ||||
| 95 | } | |||
| 96 | u2 get_u2(TRAPSJavaThread* __the_thread__) { | |||
| 97 | if (_data == NULL__null || _index >= _data->length() - 1) { | |||
| 98 | stackmap_format_error("access beyond the end of attribute", CHECK_0__the_thread__); if ((((ThreadShadow*)__the_thread__)->has_pending_exception ())) return 0; (void)(0); | |||
| 99 | } | |||
| 100 | u2 res = Bytes::get_Java_u2(_data->adr_at(_index)); | |||
| 101 | _index += 2; | |||
| 102 | return res; | |||
| 103 | } | |||
| 104 | bool at_end() { | |||
| 105 | return (_data == NULL__null) || (_index == _data->length()); | |||
| 106 | } | |||
| 107 | static void stackmap_format_error(const char* msg, TRAPSJavaThread* __the_thread__); | |||
| 108 | }; | |||
| 109 | ||||
| 110 | class StackMapReader : StackObj { | |||
| 111 | private: | |||
| 112 | // information about the class and method | |||
| 113 | constantPoolHandle _cp; | |||
| 114 | ClassVerifier* _verifier; | |||
| 115 | StackMapStream* _stream; | |||
| 116 | char* _code_data; | |||
| 117 | int32_t _code_length; | |||
| 118 | ||||
| 119 | // information get from the attribute | |||
| 120 | int32_t _frame_count; // frame count | |||
| 121 | ||||
| 122 | int32_t chop(VerificationType* locals, int32_t length, int32_t chops); | |||
| 123 | VerificationType parse_verification_type(u1* flags, TRAPSJavaThread* __the_thread__); | |||
| 124 | void check_verification_type_array_size( | |||
| 125 | int32_t size, int32_t max_size, TRAPSJavaThread* __the_thread__) { | |||
| 126 | if (size < 0 || size > max_size) { | |||
| 127 | // Since this error could be caused someone rewriting the method | |||
| 128 | // but not knowing to update the stackmap data, we call the the | |||
| 129 | // verifier's error method, which may not throw an exception and | |||
| 130 | // failover to the old verifier instead. | |||
| 131 | _verifier->class_format_error( | |||
| 132 | "StackMapTable format error: bad type array size"); | |||
| 133 | } | |||
| 134 | } | |||
| 135 | ||||
| 136 | enum { | |||
| 137 | SAME_LOCALS_1_STACK_ITEM_EXTENDED = 247, | |||
| 138 | SAME_EXTENDED = 251, | |||
| 139 | FULL = 255 | |||
| 140 | }; | |||
| 141 | ||||
| 142 | public: | |||
| 143 | // Constructor | |||
| 144 | StackMapReader(ClassVerifier* v, StackMapStream* stream, char* code_data, | |||
| 145 | int32_t code_len, TRAPSJavaThread* __the_thread__); | |||
| 146 | ||||
| 147 | inline int32_t get_frame_count() const { return _frame_count; } | |||
| 148 | StackMapFrame* next(StackMapFrame* pre_frame, bool first, | |||
| 149 | u2 max_locals, u2 max_stack, TRAPSJavaThread* __the_thread__); | |||
| 150 | ||||
| 151 | void check_end(TRAPSJavaThread* __the_thread__) { | |||
| 152 | if (!_stream->at_end()) { | |||
| 153 | StackMapStream::stackmap_format_error("wrong attribute size", CHECK__the_thread__); if ((((ThreadShadow*)__the_thread__)->has_pending_exception ())) return ; (void)(0); | |||
| 154 | } | |||
| 155 | } | |||
| 156 | }; | |||
| 157 | ||||
| 158 | #endif // SHARE_CLASSFILE_STACKMAPTABLE_HPP |
| 1 | /* |
| 2 | * Copyright (c) 1998, 2021, Oracle and/or its affiliates. All rights reserved. |
| 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 | * |
| 19 | * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA |
| 20 | * or visit www.oracle.com if you need additional information or have any |
| 21 | * questions. |
| 22 | * |
| 23 | */ |
| 24 | |
| 25 | #ifndef SHARE_UTILITIES_EXCEPTIONS_HPP |
| 26 | #define SHARE_UTILITIES_EXCEPTIONS_HPP |
| 27 | |
| 28 | #include "memory/allocation.hpp" |
| 29 | #include "oops/oopsHierarchy.hpp" |
| 30 | #include "utilities/ostream.hpp" |
| 31 | #include "utilities/sizes.hpp" |
| 32 | |
| 33 | // This file provides the basic support for exception handling in the VM. |
| 34 | // Note: We do not use C++ exceptions to avoid compiler dependencies and |
| 35 | // unpredictable performance. |
| 36 | // |
| 37 | // Scheme: Exceptions are stored with the thread. There is never more |
| 38 | // than one pending exception per thread. All functions that can throw |
| 39 | // an exception carry a THREAD argument (usually the last argument and |
| 40 | // declared with the TRAPS macro). Throwing an exception means setting |
| 41 | // a pending exception in the thread. Upon return from a function that |
| 42 | // can throw an exception, we must check if an exception is pending. |
| 43 | // The CHECK macros do this in a convenient way. Carrying around the |
| 44 | // thread provides also convenient access to it (e.g. for Handle |
| 45 | // creation, w/o the need for recomputation). |
| 46 | |
| 47 | |
| 48 | |
| 49 | // Forward declarations to be independent of the include structure. |
| 50 | |
| 51 | class JavaThread; |
| 52 | class Handle; |
| 53 | class Symbol; |
| 54 | class JavaCallArguments; |
| 55 | class methodHandle; |
| 56 | |
| 57 | // The ThreadShadow class is a helper class to access the _pending_exception |
| 58 | // field of the Thread class w/o having access to the Thread's interface (for |
| 59 | // include hierachy reasons). |
| 60 | |
| 61 | class ThreadShadow: public CHeapObj<mtThread> { |
| 62 | friend class VMStructs; |
| 63 | friend class JVMCIVMStructs; |
| 64 | |
| 65 | protected: |
| 66 | oop _pending_exception; // Thread has gc actions. |
| 67 | const char* _exception_file; // file information for exception (debugging only) |
| 68 | int _exception_line; // line information for exception (debugging only) |
| 69 | friend void check_ThreadShadow(); // checks _pending_exception offset |
| 70 | |
| 71 | // The following virtual exists only to force creation of a vtable. |
| 72 | // We need ThreadShadow to have a vtable, even in product builds, |
| 73 | // so that its layout will start at an offset of zero relative to Thread. |
| 74 | // Some C++ compilers are so "clever" that they put the ThreadShadow |
| 75 | // base class at offset 4 in Thread (after Thread's vtable), if they |
| 76 | // notice that Thread has a vtable but ThreadShadow does not. |
| 77 | virtual void unused_initial_virtual() { } |
| 78 | |
| 79 | public: |
| 80 | oop pending_exception() const { return _pending_exception; } |
| 81 | bool has_pending_exception() const { return _pending_exception != NULL__null; } |
| 82 | const char* exception_file() const { return _exception_file; } |
| 83 | int exception_line() const { return _exception_line; } |
| 84 | |
| 85 | // Code generation support |
| 86 | static ByteSize pending_exception_offset() { return byte_offset_of(ThreadShadow, _pending_exception)in_ByteSize((int)(size_t)((intx)&(((ThreadShadow*)16)-> _pending_exception) - 16)); } |
| 87 | |
| 88 | // use THROW whenever possible! |
| 89 | void set_pending_exception(oop exception, const char* file, int line); |
| 90 | |
| 91 | // use CLEAR_PENDING_EXCEPTION whenever possible! |
| 92 | void clear_pending_exception(); |
| 93 | |
| 94 | // use CLEAR_PENDING_NONASYNC_EXCEPTION to clear probable nonasync exception. |
| 95 | void clear_pending_nonasync_exception(); |
| 96 | |
| 97 | ThreadShadow() : _pending_exception(NULL__null), |
| 98 | _exception_file(NULL__null), _exception_line(0) {} |
| 99 | }; |
| 100 | |
| 101 | |
| 102 | // Exceptions is a helper class that encapsulates all operations |
| 103 | // that require access to the thread interface and which are |
| 104 | // relatively rare. The Exceptions operations should only be |
| 105 | // used directly if the macros below are insufficient. |
| 106 | |
| 107 | class Exceptions { |
| 108 | static bool special_exception(JavaThread* thread, const char* file, int line, Handle exception); |
| 109 | static bool special_exception(JavaThread* thread, const char* file, int line, Symbol* name, const char* message); |
| 110 | |
| 111 | // Count out of memory errors that are interesting in error diagnosis |
| 112 | static volatile int _out_of_memory_error_java_heap_errors; |
| 113 | static volatile int _out_of_memory_error_metaspace_errors; |
| 114 | static volatile int _out_of_memory_error_class_metaspace_errors; |
| 115 | |
| 116 | // Count linkage errors |
| 117 | static volatile int _linkage_errors; |
| 118 | public: |
| 119 | // this enum is defined to indicate whether it is safe to |
| 120 | // ignore the encoding scheme of the original message string. |
| 121 | typedef enum { |
| 122 | safe_to_utf8 = 0, |
| 123 | unsafe_to_utf8 = 1 |
| 124 | } ExceptionMsgToUtf8Mode; |
| 125 | // Throw exceptions: w/o message, w/ message & with formatted message. |
| 126 | static void _throw_oop(JavaThread* thread, const char* file, int line, oop exception); |
| 127 | static void _throw(JavaThread* thread, const char* file, int line, Handle exception, const char* msg = NULL__null); |
| 128 | |
| 129 | static void _throw_msg(JavaThread* thread, const char* file, int line, Symbol* name, const char* message); |
| 130 | static void _throw_msg(JavaThread* thread, const char* file, int line, Symbol* name, const char* message, |
| 131 | Handle loader, Handle protection_domain); |
| 132 | |
| 133 | static void _throw_msg_cause(JavaThread* thread, const char* file, int line, Symbol* name, const char* message, Handle h_cause); |
| 134 | static void _throw_msg_cause(JavaThread* thread, const char* file, int line, Symbol* name, const char* message, Handle h_cause, |
| 135 | Handle h_loader, Handle h_protection_domain); |
| 136 | |
| 137 | static void _throw_cause(JavaThread* thread, const char* file, int line, Symbol* name, Handle h_cause); |
| 138 | static void _throw_cause(JavaThread* thread, const char* file, int line, Symbol* name, Handle h_cause, |
| 139 | Handle h_loader, Handle h_protection_domain); |
| 140 | |
| 141 | static void _throw_args(JavaThread* thread, const char* file, int line, |
| 142 | Symbol* name, Symbol* signature, |
| 143 | JavaCallArguments* args); |
| 144 | |
| 145 | // There is no THROW... macro for this method. Caller should remember |
| 146 | // to do a return after calling it. |
| 147 | static void fthrow(JavaThread* thread, const char* file, int line, Symbol* name, |
| 148 | const char* format, ...) ATTRIBUTE_PRINTF(5, 6)__attribute__((format(printf, 5, 6))); |
| 149 | |
| 150 | // Create and initialize a new exception |
| 151 | static Handle new_exception(JavaThread* thread, Symbol* name, |
| 152 | Symbol* signature, JavaCallArguments* args, |
| 153 | Handle loader, Handle protection_domain); |
| 154 | |
| 155 | static Handle new_exception(JavaThread* thread, Symbol* name, |
| 156 | Symbol* signature, JavaCallArguments* args, |
| 157 | Handle cause, |
| 158 | Handle loader, Handle protection_domain); |
| 159 | |
| 160 | static Handle new_exception(JavaThread* thread, Symbol* name, |
| 161 | Handle cause, |
| 162 | Handle loader, Handle protection_domain, |
| 163 | ExceptionMsgToUtf8Mode to_utf8_safe = safe_to_utf8); |
| 164 | |
| 165 | static Handle new_exception(JavaThread* thread, Symbol* name, |
| 166 | const char* message, Handle cause, |
| 167 | Handle loader, Handle protection_domain, |
| 168 | ExceptionMsgToUtf8Mode to_utf8_safe = safe_to_utf8); |
| 169 | |
| 170 | static Handle new_exception(JavaThread* thread, Symbol* name, |
| 171 | const char* message, |
| 172 | ExceptionMsgToUtf8Mode to_utf8_safe = safe_to_utf8); |
| 173 | |
| 174 | static void throw_stack_overflow_exception(JavaThread* thread, const char* file, int line, const methodHandle& method); |
| 175 | |
| 176 | static void throw_unsafe_access_internal_error(JavaThread* thread, const char* file, int line, const char* message); |
| 177 | |
| 178 | static void wrap_dynamic_exception(bool is_indy, JavaThread* thread); |
| 179 | |
| 180 | // Exception counting for error files of interesting exceptions that may have |
| 181 | // caused a problem for the jvm |
| 182 | static volatile int _stack_overflow_errors; |
| 183 | |
| 184 | static bool has_exception_counts(); |
| 185 | static void count_out_of_memory_exceptions(Handle exception); |
| 186 | static void print_exception_counts_on_error(outputStream* st); |
| 187 | |
| 188 | // for AbortVMOnException flag |
| 189 | static void debug_check_abort(Handle exception, const char* message = NULL__null); |
| 190 | static void debug_check_abort_helper(Handle exception, const char* message = NULL__null); |
| 191 | static void debug_check_abort(const char *value_string, const char* message = NULL__null); |
| 192 | |
| 193 | // for logging exceptions |
| 194 | static void log_exception(Handle exception, const char* message); |
| 195 | }; |
| 196 | |
| 197 | |
| 198 | // The THREAD & TRAPS macros facilitate the declaration of functions that throw exceptions. |
| 199 | // Convention: Use the TRAPS macro as the last argument of such a function; e.g.: |
| 200 | // |
| 201 | // int this_function_may_trap(int x, float y, TRAPS) |
| 202 | |
| 203 | #define THREAD__the_thread__ __the_thread__ |
| 204 | #define TRAPSJavaThread* __the_thread__ JavaThread* THREAD__the_thread__ |
| 205 | |
| 206 | |
| 207 | // The CHECK... macros should be used to pass along a THREAD reference and to check for pending |
| 208 | // exceptions. In special situations it is necessary to handle pending exceptions explicitly, |
| 209 | // in these cases the PENDING_EXCEPTION helper macros should be used. |
| 210 | // |
| 211 | // Macro naming conventions: Macros that end with _ require a result value to be returned. They |
| 212 | // are for functions with non-void result type. The result value is usually ignored because of |
| 213 | // the exception and is only needed for syntactic correctness. The _0 ending is a shortcut for |
| 214 | // _(0) since this is a frequent case. Example: |
| 215 | // |
| 216 | // int result = this_function_may_trap(x_arg, y_arg, CHECK_0); |
| 217 | // |
| 218 | // CAUTION: make sure that the function call using a CHECK macro is not the only statement of a |
| 219 | // conditional branch w/o enclosing {} braces, since the CHECK macros expand into several state- |
| 220 | // ments! Also make sure it is not used on a function call that is part of a return statement! |
| 221 | |
| 222 | #define PENDING_EXCEPTION(((ThreadShadow*)__the_thread__)->pending_exception()) (((ThreadShadow*)THREAD__the_thread__)->pending_exception()) |
| 223 | #define HAS_PENDING_EXCEPTION(((ThreadShadow*)__the_thread__)->has_pending_exception()) (((ThreadShadow*)THREAD__the_thread__)->has_pending_exception()) |
| 224 | #define CLEAR_PENDING_EXCEPTION(((ThreadShadow*)__the_thread__)->clear_pending_exception( )) (((ThreadShadow*)THREAD__the_thread__)->clear_pending_exception()) |
| 225 | |
| 226 | #define CHECK__the_thread__); if ((((ThreadShadow*)__the_thread__)->has_pending_exception ())) return ; (void)(0 THREAD__the_thread__); if (HAS_PENDING_EXCEPTION(((ThreadShadow*)__the_thread__)->has_pending_exception())) return ; (void)(0 |
| 227 | #define CHECK_(result)__the_thread__); if ((((ThreadShadow*)__the_thread__)->has_pending_exception ())) return result; (void)(0 THREAD__the_thread__); if (HAS_PENDING_EXCEPTION(((ThreadShadow*)__the_thread__)->has_pending_exception())) return result; (void)(0 |
| 228 | #define CHECK_0__the_thread__); if ((((ThreadShadow*)__the_thread__)->has_pending_exception ())) return 0; (void)(0 CHECK_(0)__the_thread__); if ((((ThreadShadow*)__the_thread__)->has_pending_exception ())) return 0; (void)(0 |
| 229 | #define CHECK_NH__the_thread__); if ((((ThreadShadow*)__the_thread__)->has_pending_exception ())) return Handle(); (void)(0 CHECK_(Handle())__the_thread__); if ((((ThreadShadow*)__the_thread__)->has_pending_exception ())) return Handle(); (void)(0 |
| 230 | #define CHECK_NULL__the_thread__); if ((((ThreadShadow*)__the_thread__)->has_pending_exception ())) return __null; (void)(0 CHECK_(NULL)__the_thread__); if ((((ThreadShadow*)__the_thread__)->has_pending_exception ())) return __null; (void)(0 |
| 231 | #define CHECK_false__the_thread__); if ((((ThreadShadow*)__the_thread__)->has_pending_exception ())) return false; (void)(0 CHECK_(false)__the_thread__); if ((((ThreadShadow*)__the_thread__)->has_pending_exception ())) return false; (void)(0 |
| 232 | #define CHECK_JNI_ERR__the_thread__); if ((((ThreadShadow*)__the_thread__)->has_pending_exception ())) return (-1); (void)(0 CHECK_(JNI_ERR)__the_thread__); if ((((ThreadShadow*)__the_thread__)->has_pending_exception ())) return (-1); (void)(0 |
| 233 | |
| 234 | // CAUTION: These macros clears all exceptions including async exceptions, use it with caution. |
| 235 | #define CHECK_AND_CLEAR__the_thread__); if ((((ThreadShadow*)__the_thread__)->has_pending_exception ())) { (((ThreadShadow*)__the_thread__)->clear_pending_exception ()); return; } (void)(0 THREAD__the_thread__); if (HAS_PENDING_EXCEPTION(((ThreadShadow*)__the_thread__)->has_pending_exception())) { CLEAR_PENDING_EXCEPTION(((ThreadShadow*)__the_thread__)->clear_pending_exception( )); return; } (void)(0 |
| 236 | #define CHECK_AND_CLEAR_(result)__the_thread__); if ((((ThreadShadow*)__the_thread__)->has_pending_exception ())) { (((ThreadShadow*)__the_thread__)->clear_pending_exception ()); return result; } (void)(0 THREAD__the_thread__); if (HAS_PENDING_EXCEPTION(((ThreadShadow*)__the_thread__)->has_pending_exception())) { CLEAR_PENDING_EXCEPTION(((ThreadShadow*)__the_thread__)->clear_pending_exception( )); return result; } (void)(0 |
| 237 | #define CHECK_AND_CLEAR_0__the_thread__); if ((((ThreadShadow*)__the_thread__)->has_pending_exception ())) { (((ThreadShadow*)__the_thread__)->clear_pending_exception ()); return 0; } (void)(0 CHECK_AND_CLEAR_(0)__the_thread__); if ((((ThreadShadow*)__the_thread__)->has_pending_exception ())) { (((ThreadShadow*)__the_thread__)->clear_pending_exception ()); return 0; } (void)(0 |
| 238 | #define CHECK_AND_CLEAR_NH__the_thread__); if ((((ThreadShadow*)__the_thread__)->has_pending_exception ())) { (((ThreadShadow*)__the_thread__)->clear_pending_exception ()); return Handle(); } (void)(0 CHECK_AND_CLEAR_(Handle())__the_thread__); if ((((ThreadShadow*)__the_thread__)->has_pending_exception ())) { (((ThreadShadow*)__the_thread__)->clear_pending_exception ()); return Handle(); } (void)(0 |
| 239 | #define CHECK_AND_CLEAR_NULL__the_thread__); if ((((ThreadShadow*)__the_thread__)->has_pending_exception ())) { (((ThreadShadow*)__the_thread__)->clear_pending_exception ()); return __null; } (void)(0 CHECK_AND_CLEAR_(NULL)__the_thread__); if ((((ThreadShadow*)__the_thread__)->has_pending_exception ())) { (((ThreadShadow*)__the_thread__)->clear_pending_exception ()); return __null; } (void)(0 |
| 240 | #define CHECK_AND_CLEAR_false__the_thread__); if ((((ThreadShadow*)__the_thread__)->has_pending_exception ())) { (((ThreadShadow*)__the_thread__)->clear_pending_exception ()); return false; } (void)(0 CHECK_AND_CLEAR_(false)__the_thread__); if ((((ThreadShadow*)__the_thread__)->has_pending_exception ())) { (((ThreadShadow*)__the_thread__)->clear_pending_exception ()); return false; } (void)(0 |
| 241 | |
| 242 | // CAUTION: These macros clears all exceptions except probable async exceptions j.l.InternalError and j.l.ThreadDeath. |
| 243 | // So use it with caution. |
| 244 | #define CLEAR_PENDING_NONASYNC_EXCEPTION(((ThreadShadow*)__the_thread__)->clear_pending_nonasync_exception ()) (((ThreadShadow*)THREAD__the_thread__)->clear_pending_nonasync_exception()) |
| 245 | #define CHECK_AND_CLEAR_NONASYNC__the_thread__); if ((((ThreadShadow*)__the_thread__)->has_pending_exception ())) { (((ThreadShadow*)__the_thread__)->clear_pending_nonasync_exception ()); return; } (void)(0 THREAD__the_thread__); if (HAS_PENDING_EXCEPTION(((ThreadShadow*)__the_thread__)->has_pending_exception())) { CLEAR_PENDING_NONASYNC_EXCEPTION(((ThreadShadow*)__the_thread__)->clear_pending_nonasync_exception ()); return; } (void)(0 |
| 246 | #define CHECK_AND_CLEAR_NONASYNC_(result)__the_thread__); if ((((ThreadShadow*)__the_thread__)->has_pending_exception ())) { (((ThreadShadow*)__the_thread__)->clear_pending_nonasync_exception ()); return result; } (void)(0 THREAD__the_thread__); if (HAS_PENDING_EXCEPTION(((ThreadShadow*)__the_thread__)->has_pending_exception())) { CLEAR_PENDING_NONASYNC_EXCEPTION(((ThreadShadow*)__the_thread__)->clear_pending_nonasync_exception ()); return result; } (void)(0 |
| 247 | #define CHECK_AND_CLEAR_NONASYNC_0__the_thread__); if ((((ThreadShadow*)__the_thread__)->has_pending_exception ())) { (((ThreadShadow*)__the_thread__)->clear_pending_nonasync_exception ()); return 0; } (void)(0 CHECK_AND_CLEAR_NONASYNC_(0)__the_thread__); if ((((ThreadShadow*)__the_thread__)->has_pending_exception ())) { (((ThreadShadow*)__the_thread__)->clear_pending_nonasync_exception ()); return 0; } (void)(0 |
| 248 | #define CHECK_AND_CLEAR_NONASYNC_NH__the_thread__); if ((((ThreadShadow*)__the_thread__)->has_pending_exception ())) { (((ThreadShadow*)__the_thread__)->clear_pending_nonasync_exception ()); return Handle(); } (void)(0 CHECK_AND_CLEAR_NONASYNC_(Handle())__the_thread__); if ((((ThreadShadow*)__the_thread__)->has_pending_exception ())) { (((ThreadShadow*)__the_thread__)->clear_pending_nonasync_exception ()); return Handle(); } (void)(0 |
| 249 | #define CHECK_AND_CLEAR_NONASYNC_NULL__the_thread__); if ((((ThreadShadow*)__the_thread__)->has_pending_exception ())) { (((ThreadShadow*)__the_thread__)->clear_pending_nonasync_exception ()); return __null; } (void)(0 CHECK_AND_CLEAR_NONASYNC_(NULL)__the_thread__); if ((((ThreadShadow*)__the_thread__)->has_pending_exception ())) { (((ThreadShadow*)__the_thread__)->clear_pending_nonasync_exception ()); return __null; } (void)(0 |
| 250 | #define CHECK_AND_CLEAR_NONASYNC_false__the_thread__); if ((((ThreadShadow*)__the_thread__)->has_pending_exception ())) { (((ThreadShadow*)__the_thread__)->clear_pending_nonasync_exception ()); return false; } (void)(0 CHECK_AND_CLEAR_NONASYNC_(false)__the_thread__); if ((((ThreadShadow*)__the_thread__)->has_pending_exception ())) { (((ThreadShadow*)__the_thread__)->clear_pending_nonasync_exception ()); return false; } (void)(0 |
| 251 | |
| 252 | // The THROW... macros should be used to throw an exception. They require a THREAD variable to be |
| 253 | // visible within the scope containing the THROW. Usually this is achieved by declaring the function |
| 254 | // with a TRAPS argument. |
| 255 | |
| 256 | #define THREAD_AND_LOCATION__the_thread__, "/home/daniel/Projects/java/jdk/src/hotspot/share/utilities/exceptions.hpp" , 256 THREAD__the_thread__, __FILE__"/home/daniel/Projects/java/jdk/src/hotspot/share/utilities/exceptions.hpp", __LINE__256 |
| 257 | |
| 258 | #define THROW_OOP(e){ Exceptions::_throw_oop(__the_thread__, "/home/daniel/Projects/java/jdk/src/hotspot/share/utilities/exceptions.hpp" , 258, e); return; } \ |
| 259 | { Exceptions::_throw_oop(THREAD_AND_LOCATION__the_thread__, "/home/daniel/Projects/java/jdk/src/hotspot/share/utilities/exceptions.hpp" , 259, e); return; } |
| 260 | |
| 261 | #define THROW_HANDLE(e){ Exceptions::_throw(__the_thread__, "/home/daniel/Projects/java/jdk/src/hotspot/share/utilities/exceptions.hpp" , 261, e); return; } \ |
| 262 | { Exceptions::_throw(THREAD_AND_LOCATION__the_thread__, "/home/daniel/Projects/java/jdk/src/hotspot/share/utilities/exceptions.hpp" , 262, e); return; } |
| 263 | |
| 264 | #define THROW(name){ Exceptions::_throw_msg(__the_thread__, "/home/daniel/Projects/java/jdk/src/hotspot/share/utilities/exceptions.hpp" , 264, name, __null); return; } \ |
| 265 | { Exceptions::_throw_msg(THREAD_AND_LOCATION__the_thread__, "/home/daniel/Projects/java/jdk/src/hotspot/share/utilities/exceptions.hpp" , 265, name, NULL__null); return; } |
| 266 | |
| 267 | #define THROW_MSG(name, message){ Exceptions::_throw_msg(__the_thread__, "/home/daniel/Projects/java/jdk/src/hotspot/share/utilities/exceptions.hpp" , 267, name, message); return; } \ |
| 268 | { Exceptions::_throw_msg(THREAD_AND_LOCATION__the_thread__, "/home/daniel/Projects/java/jdk/src/hotspot/share/utilities/exceptions.hpp" , 268, name, message); return; } |
| 269 | |
| 270 | #define THROW_CAUSE(name, cause){ Exceptions::_throw_cause(__the_thread__, "/home/daniel/Projects/java/jdk/src/hotspot/share/utilities/exceptions.hpp" , 270, name, cause); return; } \ |
| 271 | { Exceptions::_throw_cause(THREAD_AND_LOCATION__the_thread__, "/home/daniel/Projects/java/jdk/src/hotspot/share/utilities/exceptions.hpp" , 271, name, cause); return; } |
| 272 | |
| 273 | #define THROW_MSG_LOADER(name, message, loader, protection_domain){ Exceptions::_throw_msg(__the_thread__, "/home/daniel/Projects/java/jdk/src/hotspot/share/utilities/exceptions.hpp" , 273, name, message, loader, protection_domain); return; } \ |
| 274 | { Exceptions::_throw_msg(THREAD_AND_LOCATION__the_thread__, "/home/daniel/Projects/java/jdk/src/hotspot/share/utilities/exceptions.hpp" , 274, name, message, loader, protection_domain); return; } |
| 275 | |
| 276 | #define THROW_ARG(name, signature, args){ Exceptions::_throw_args(__the_thread__, "/home/daniel/Projects/java/jdk/src/hotspot/share/utilities/exceptions.hpp" , 276, name, signature, args); return; } \ |
| 277 | { Exceptions::_throw_args(THREAD_AND_LOCATION__the_thread__, "/home/daniel/Projects/java/jdk/src/hotspot/share/utilities/exceptions.hpp" , 277, name, signature, args); return; } |
| 278 | |
| 279 | #define THROW_OOP_(e, result){ Exceptions::_throw_oop(__the_thread__, "/home/daniel/Projects/java/jdk/src/hotspot/share/utilities/exceptions.hpp" , 279, e); return result; } \ |
| 280 | { Exceptions::_throw_oop(THREAD_AND_LOCATION__the_thread__, "/home/daniel/Projects/java/jdk/src/hotspot/share/utilities/exceptions.hpp" , 280, e); return result; } |
| 281 | |
| 282 | #define THROW_HANDLE_(e, result){ Exceptions::_throw(__the_thread__, "/home/daniel/Projects/java/jdk/src/hotspot/share/utilities/exceptions.hpp" , 282, e); return result; } \ |
| 283 | { Exceptions::_throw(THREAD_AND_LOCATION__the_thread__, "/home/daniel/Projects/java/jdk/src/hotspot/share/utilities/exceptions.hpp" , 283, e); return result; } |
| 284 | |
| 285 | #define THROW_(name, result){ Exceptions::_throw_msg(__the_thread__, "/home/daniel/Projects/java/jdk/src/hotspot/share/utilities/exceptions.hpp" , 285, name, __null); return result; } \ |
| 286 | { Exceptions::_throw_msg(THREAD_AND_LOCATION__the_thread__, "/home/daniel/Projects/java/jdk/src/hotspot/share/utilities/exceptions.hpp" , 286, name, NULL__null); return result; } |
| 287 | |
| 288 | #define THROW_MSG_(name, message, result){ Exceptions::_throw_msg(__the_thread__, "/home/daniel/Projects/java/jdk/src/hotspot/share/utilities/exceptions.hpp" , 288, name, message); return result; } \ |
| 289 | { Exceptions::_throw_msg(THREAD_AND_LOCATION__the_thread__, "/home/daniel/Projects/java/jdk/src/hotspot/share/utilities/exceptions.hpp" , 289, name, message); return result; } |
| 290 | |
| 291 | #define THROW_MSG_LOADER_(name, message, loader, protection_domain, result){ Exceptions::_throw_msg(__the_thread__, "/home/daniel/Projects/java/jdk/src/hotspot/share/utilities/exceptions.hpp" , 291, name, message, loader, protection_domain); return result ; } \ |
| 292 | { Exceptions::_throw_msg(THREAD_AND_LOCATION__the_thread__, "/home/daniel/Projects/java/jdk/src/hotspot/share/utilities/exceptions.hpp" , 292, name, message, loader, protection_domain); return result; } |
| 293 | |
| 294 | #define THROW_ARG_(name, signature, args, result){ Exceptions::_throw_args(__the_thread__, "/home/daniel/Projects/java/jdk/src/hotspot/share/utilities/exceptions.hpp" , 294, name, signature, args); return result; } \ |
| 295 | { Exceptions::_throw_args(THREAD_AND_LOCATION__the_thread__, "/home/daniel/Projects/java/jdk/src/hotspot/share/utilities/exceptions.hpp" , 295, name, signature, args); return result; } |
| 296 | |
| 297 | #define THROW_MSG_CAUSE(name, message, cause){ Exceptions::_throw_msg_cause(__the_thread__, "/home/daniel/Projects/java/jdk/src/hotspot/share/utilities/exceptions.hpp" , 297, name, message, cause); return; } \ |
| 298 | { Exceptions::_throw_msg_cause(THREAD_AND_LOCATION__the_thread__, "/home/daniel/Projects/java/jdk/src/hotspot/share/utilities/exceptions.hpp" , 298, name, message, cause); return; } |
| 299 | |
| 300 | #define THROW_MSG_CAUSE_(name, message, cause, result){ Exceptions::_throw_msg_cause(__the_thread__, "/home/daniel/Projects/java/jdk/src/hotspot/share/utilities/exceptions.hpp" , 300, name, message, cause); return result; } \ |
| 301 | { Exceptions::_throw_msg_cause(THREAD_AND_LOCATION__the_thread__, "/home/daniel/Projects/java/jdk/src/hotspot/share/utilities/exceptions.hpp" , 301, name, message, cause); return result; } |
| 302 | |
| 303 | |
| 304 | #define THROW_OOP_0(e){ Exceptions::_throw_oop(__the_thread__, "/home/daniel/Projects/java/jdk/src/hotspot/share/utilities/exceptions.hpp" , 304, e); return 0; } THROW_OOP_(e, 0){ Exceptions::_throw_oop(__the_thread__, "/home/daniel/Projects/java/jdk/src/hotspot/share/utilities/exceptions.hpp" , 304, e); return 0; } |
| 305 | #define THROW_HANDLE_0(e){ Exceptions::_throw(__the_thread__, "/home/daniel/Projects/java/jdk/src/hotspot/share/utilities/exceptions.hpp" , 305, e); return 0; } THROW_HANDLE_(e, 0){ Exceptions::_throw(__the_thread__, "/home/daniel/Projects/java/jdk/src/hotspot/share/utilities/exceptions.hpp" , 305, e); return 0; } |
| 306 | #define THROW_0(name){ Exceptions::_throw_msg(__the_thread__, "/home/daniel/Projects/java/jdk/src/hotspot/share/utilities/exceptions.hpp" , 306, name, __null); return 0; } THROW_(name, 0){ Exceptions::_throw_msg(__the_thread__, "/home/daniel/Projects/java/jdk/src/hotspot/share/utilities/exceptions.hpp" , 306, name, __null); return 0; } |
| 307 | #define THROW_MSG_0(name, message){ Exceptions::_throw_msg(__the_thread__, "/home/daniel/Projects/java/jdk/src/hotspot/share/utilities/exceptions.hpp" , 307, name, message); return 0; } THROW_MSG_(name, message, 0){ Exceptions::_throw_msg(__the_thread__, "/home/daniel/Projects/java/jdk/src/hotspot/share/utilities/exceptions.hpp" , 307, name, message); return 0; } |
| 308 | #define THROW_WRAPPED_0(name, oop_to_wrap)THROW_WRAPPED_(name, oop_to_wrap, 0) THROW_WRAPPED_(name, oop_to_wrap, 0) |
| 309 | #define THROW_ARG_0(name, signature, arg){ Exceptions::_throw_args(__the_thread__, "/home/daniel/Projects/java/jdk/src/hotspot/share/utilities/exceptions.hpp" , 309, name, signature, arg); return 0; } THROW_ARG_(name, signature, arg, 0){ Exceptions::_throw_args(__the_thread__, "/home/daniel/Projects/java/jdk/src/hotspot/share/utilities/exceptions.hpp" , 309, name, signature, arg); return 0; } |
| 310 | #define THROW_MSG_CAUSE_0(name, message, cause){ Exceptions::_throw_msg_cause(__the_thread__, "/home/daniel/Projects/java/jdk/src/hotspot/share/utilities/exceptions.hpp" , 310, name, message, cause); return 0; } THROW_MSG_CAUSE_(name, message, cause, 0){ Exceptions::_throw_msg_cause(__the_thread__, "/home/daniel/Projects/java/jdk/src/hotspot/share/utilities/exceptions.hpp" , 310, name, message, cause); return 0; } |
| 311 | #define THROW_MSG_CAUSE_NULL(name, message, cause){ Exceptions::_throw_msg_cause(__the_thread__, "/home/daniel/Projects/java/jdk/src/hotspot/share/utilities/exceptions.hpp" , 311, name, message, cause); return __null; } THROW_MSG_CAUSE_(name, message, cause, NULL){ Exceptions::_throw_msg_cause(__the_thread__, "/home/daniel/Projects/java/jdk/src/hotspot/share/utilities/exceptions.hpp" , 311, name, message, cause); return __null; } |
| 312 | |
| 313 | #define THROW_NULL(name){ Exceptions::_throw_msg(__the_thread__, "/home/daniel/Projects/java/jdk/src/hotspot/share/utilities/exceptions.hpp" , 313, name, __null); return __null; } THROW_(name, NULL){ Exceptions::_throw_msg(__the_thread__, "/home/daniel/Projects/java/jdk/src/hotspot/share/utilities/exceptions.hpp" , 313, name, __null); return __null; } |
| 314 | #define THROW_MSG_NULL(name, message){ Exceptions::_throw_msg(__the_thread__, "/home/daniel/Projects/java/jdk/src/hotspot/share/utilities/exceptions.hpp" , 314, name, message); return __null; } THROW_MSG_(name, message, NULL){ Exceptions::_throw_msg(__the_thread__, "/home/daniel/Projects/java/jdk/src/hotspot/share/utilities/exceptions.hpp" , 314, name, message); return __null; } |
| 315 | |
| 316 | // The CATCH macro checks that no exception has been thrown by a function; it is used at |
| 317 | // call sites about which is statically known that the callee cannot throw an exception |
| 318 | // even though it is declared with TRAPS. |
| 319 | |
| 320 | #define CATCH__the_thread__); if ((((ThreadShadow*)__the_thread__)->has_pending_exception ())) { oop ex = (((ThreadShadow*)__the_thread__)->pending_exception ()); (((ThreadShadow*)__the_thread__)->clear_pending_exception ()); ex->print(); do { if (!(false)) { (*g_assert_poison) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/utilities/exceptions.hpp" , 320, "assert(" "false" ") failed", "CATCH"); ::breakpoint() ; } } while (0); } (void)(0 \ |
| 321 | THREAD__the_thread__); if (HAS_PENDING_EXCEPTION(((ThreadShadow*)__the_thread__)->has_pending_exception())) { \ |
| 322 | oop ex = PENDING_EXCEPTION(((ThreadShadow*)__the_thread__)->pending_exception()); \ |
| 323 | CLEAR_PENDING_EXCEPTION(((ThreadShadow*)__the_thread__)->clear_pending_exception( )); \ |
| 324 | DEBUG_ONLY(ex->print();)ex->print(); \ |
| 325 | assert(false, "CATCH")do { if (!(false)) { (*g_assert_poison) = 'X';; report_vm_error ("/home/daniel/Projects/java/jdk/src/hotspot/share/utilities/exceptions.hpp" , 325, "assert(" "false" ") failed", "CATCH"); ::breakpoint() ; } } while (0); \ |
| 326 | } (void)(0 |
| 327 | |
| 328 | // ExceptionMark is a stack-allocated helper class for local exception handling. |
| 329 | // It is used with the EXCEPTION_MARK macro. |
| 330 | |
| 331 | class ExceptionMark { |
| 332 | private: |
| 333 | JavaThread* _thread; |
| 334 | inline void check_no_pending_exception(); |
| 335 | |
| 336 | public: |
| 337 | ExceptionMark(); |
| 338 | ExceptionMark(JavaThread* thread); |
| 339 | ~ExceptionMark(); |
| 340 | |
| 341 | JavaThread* thread() { |
| 342 | return _thread; |
| 343 | } |
| 344 | }; |
| 345 | |
| 346 | // Use an EXCEPTION_MARK for 'local' exceptions. EXCEPTION_MARK makes sure that no |
| 347 | // pending exception exists upon entering its scope and tests that no pending exception |
| 348 | // exists when leaving the scope. |
| 349 | |
| 350 | // See also preserveException.hpp for PreserveExceptionMark |
| 351 | // which preserves pre-existing exceptions and does not allow new |
| 352 | // exceptions. |
| 353 | |
| 354 | #define EXCEPTION_MARKExceptionMark __em; JavaThread* __the_thread__ = __em.thread( ); ExceptionMark __em; JavaThread* THREAD__the_thread__ = __em.thread(); |
| 355 | |
| 356 | #endif // SHARE_UTILITIES_EXCEPTIONS_HPP |
| 1 | /* |
| 2 | * Copyright (c) 1997, 2020, Oracle and/or its affiliates. All rights reserved. |
| 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 | * |
| 19 | * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA |
| 20 | * or visit www.oracle.com if you need additional information or have any |
| 21 | * questions. |
| 22 | * |
| 23 | */ |
| 24 | |
| 25 | #ifndef SHARE_OOPS_OOPSHIERARCHY_HPP |
| 26 | #define SHARE_OOPS_OOPSHIERARCHY_HPP |
| 27 | |
| 28 | #include "metaprogramming/integralConstant.hpp" |
| 29 | #include "metaprogramming/primitiveConversions.hpp" |
| 30 | #include "utilities/globalDefinitions.hpp" |
| 31 | |
| 32 | // OBJECT hierarchy |
| 33 | // This hierarchy is a representation hierarchy, i.e. if A is a superclass |
| 34 | // of B, A's representation is a prefix of B's representation. |
| 35 | |
| 36 | // Global offset instead of address for an oop within a java object. |
| 37 | enum class narrowOop : uint32_t { null = 0 }; |
| 38 | |
| 39 | // If compressed klass pointers then use narrowKlass. |
| 40 | typedef juint narrowKlass; |
| 41 | |
| 42 | typedef void* OopOrNarrowOopStar; |
| 43 | |
| 44 | #ifndef CHECK_UNHANDLED_OOPS1 |
| 45 | |
| 46 | typedef class oopDesc* oop; |
| 47 | typedef class instanceOopDesc* instanceOop; |
| 48 | typedef class arrayOopDesc* arrayOop; |
| 49 | typedef class objArrayOopDesc* objArrayOop; |
| 50 | typedef class typeArrayOopDesc* typeArrayOop; |
| 51 | |
| 52 | #else |
| 53 | |
| 54 | // When CHECK_UNHANDLED_OOPS is defined, an "oop" is a class with a |
| 55 | // carefully chosen set of constructors and conversion operators to go |
| 56 | // to and from the underlying oopDesc pointer type. |
| 57 | // |
| 58 | // Because oop and its subclasses <type>Oop are class types, arbitrary |
| 59 | // conversions are not accepted by the compiler. Applying a cast to |
| 60 | // an oop will cause the best matched conversion operator to be |
| 61 | // invoked returning the underlying oopDesc* type if appropriate. |
| 62 | // No copy constructors, explicit user conversions or operators of |
| 63 | // numerical type should be defined within the oop class. Most C++ |
| 64 | // compilers will issue a compile time error concerning the overloading |
| 65 | // ambiguity between operators of numerical and pointer types. If |
| 66 | // a conversion to or from an oop to a numerical type is needed, |
| 67 | // use the inline template methods, cast_*_oop, defined below. |
| 68 | // |
| 69 | // Converting NULL to oop to Handle implicit is no longer accepted by the |
| 70 | // compiler because there are too many steps in the conversion. Use Handle() |
| 71 | // instead, which generates less code anyway. |
| 72 | |
| 73 | class Thread; |
| 74 | class oopDesc; |
| 75 | |
| 76 | extern "C" bool CheckUnhandledOops; |
| 77 | |
| 78 | class oop { |
| 79 | oopDesc* _o; |
| 80 | |
| 81 | void register_oop(); |
| 82 | void unregister_oop(); |
| 83 | |
| 84 | void register_if_checking() { |
| 85 | if (CheckUnhandledOops) register_oop(); |
| 86 | } |
| 87 | |
| 88 | public: |
| 89 | oop() : _o(nullptr) { register_if_checking(); } |
| 90 | oop(const oop& o) : _o(o._o) { register_if_checking(); } |
| 91 | oop(oopDesc* o) : _o(o) { register_if_checking(); } |
| 92 | ~oop() { |
| 93 | if (CheckUnhandledOops) unregister_oop(); |
| 94 | } |
| 95 | |
| 96 | oopDesc* obj() const { return _o; } |
| 97 | oopDesc* operator->() const { return _o; } |
| 98 | operator oopDesc* () const { return _o; } |
| 99 | |
| 100 | bool operator==(const oop& o) const { return _o == o._o; } |
| 101 | bool operator!=(const oop& o) const { return _o != o._o; } |
| 102 | |
| 103 | bool operator==(std::nullptr_t) const { return _o == nullptr; } |
| 104 | bool operator!=(std::nullptr_t) const { return _o != nullptr; } |
| 105 | |
| 106 | oop& operator=(const oop& o) { _o = o._o; return *this; } |
| 107 | }; |
| 108 | |
| 109 | template<> |
| 110 | struct PrimitiveConversions::Translate<oop> : public TrueType { |
| 111 | typedef oop Value; |
| 112 | typedef oopDesc* Decayed; |
| 113 | |
| 114 | static Decayed decay(Value x) { return x.obj(); } |
| 115 | static Value recover(Decayed x) { return oop(x); } |
| 116 | }; |
| 117 | |
| 118 | #define DEF_OOP(type)class typeOopDesc; class typeOop : public oop { public: typeOop () : oop() {} typeOop(const typeOop& o) : oop(o) {} typeOop (const oop& o) : oop(o) {} typeOop(typeOopDesc* o) : oop( (oopDesc*)o) {} operator typeOopDesc* () const { return (typeOopDesc *)obj(); } typeOopDesc* operator->() const { return (typeOopDesc *)obj(); } typeOop& operator=(const typeOop& o) { oop ::operator=(o); return *this; } }; template<> struct PrimitiveConversions ::Translate<typeOop> : public TrueType { typedef typeOop Value; typedef typeOopDesc* Decayed; static Decayed decay(Value x) { return (typeOopDesc*)x.obj(); } static Value recover(Decayed x) { return typeOop(x); } }; \ |
| 119 | class type##OopDesc; \ |
| 120 | class type##Oop : public oop { \ |
| 121 | public: \ |
| 122 | type##Oop() : oop() {} \ |
| 123 | type##Oop(const type##Oop& o) : oop(o) {} \ |
| 124 | type##Oop(const oop& o) : oop(o) {} \ |
| 125 | type##Oop(type##OopDesc* o) : oop((oopDesc*)o) {} \ |
| 126 | operator type##OopDesc* () const { return (type##OopDesc*)obj(); } \ |
| 127 | type##OopDesc* operator->() const { \ |
| 128 | return (type##OopDesc*)obj(); \ |
| 129 | } \ |
| 130 | type##Oop& operator=(const type##Oop& o) { \ |
| 131 | oop::operator=(o); \ |
| 132 | return *this; \ |
| 133 | } \ |
| 134 | }; \ |
| 135 | \ |
| 136 | template<> \ |
| 137 | struct PrimitiveConversions::Translate<type##Oop> : public TrueType { \ |
| 138 | typedef type##Oop Value; \ |
| 139 | typedef type##OopDesc* Decayed; \ |
| 140 | \ |
| 141 | static Decayed decay(Value x) { return (type##OopDesc*)x.obj(); } \ |
| 142 | static Value recover(Decayed x) { return type##Oop(x); } \ |
| 143 | }; |
| 144 | |
| 145 | DEF_OOP(instance)class instanceOopDesc; class instanceOop : public oop { public : instanceOop() : oop() {} instanceOop(const instanceOop& o) : oop(o) {} instanceOop(const oop& o) : oop(o) {} instanceOop (instanceOopDesc* o) : oop((oopDesc*)o) {} operator instanceOopDesc * () const { return (instanceOopDesc*)obj(); } instanceOopDesc * operator->() const { return (instanceOopDesc*)obj(); } instanceOop & operator=(const instanceOop& o) { oop::operator=(o) ; return *this; } }; template<> struct PrimitiveConversions ::Translate<instanceOop> : public TrueType { typedef instanceOop Value; typedef instanceOopDesc* Decayed; static Decayed decay (Value x) { return (instanceOopDesc*)x.obj(); } static Value recover (Decayed x) { return instanceOop(x); } };; |
| 146 | DEF_OOP(array)class arrayOopDesc; class arrayOop : public oop { public: arrayOop () : oop() {} arrayOop(const arrayOop& o) : oop(o) {} arrayOop (const oop& o) : oop(o) {} arrayOop(arrayOopDesc* o) : oop ((oopDesc*)o) {} operator arrayOopDesc* () const { return (arrayOopDesc *)obj(); } arrayOopDesc* operator->() const { return (arrayOopDesc *)obj(); } arrayOop& operator=(const arrayOop& o) { oop ::operator=(o); return *this; } }; template<> struct PrimitiveConversions ::Translate<arrayOop> : public TrueType { typedef arrayOop Value; typedef arrayOopDesc* Decayed; static Decayed decay(Value x) { return (arrayOopDesc*)x.obj(); } static Value recover(Decayed x) { return arrayOop(x); } };; |
| 147 | DEF_OOP(objArray)class objArrayOopDesc; class objArrayOop : public oop { public : objArrayOop() : oop() {} objArrayOop(const objArrayOop& o) : oop(o) {} objArrayOop(const oop& o) : oop(o) {} objArrayOop (objArrayOopDesc* o) : oop((oopDesc*)o) {} operator objArrayOopDesc * () const { return (objArrayOopDesc*)obj(); } objArrayOopDesc * operator->() const { return (objArrayOopDesc*)obj(); } objArrayOop & operator=(const objArrayOop& o) { oop::operator=(o) ; return *this; } }; template<> struct PrimitiveConversions ::Translate<objArrayOop> : public TrueType { typedef objArrayOop Value; typedef objArrayOopDesc* Decayed; static Decayed decay (Value x) { return (objArrayOopDesc*)x.obj(); } static Value recover (Decayed x) { return objArrayOop(x); } };; |
| 148 | DEF_OOP(typeArray)class typeArrayOopDesc; class typeArrayOop : public oop { public : typeArrayOop() : oop() {} typeArrayOop(const typeArrayOop& o) : oop(o) {} typeArrayOop(const oop& o) : oop(o) {} typeArrayOop (typeArrayOopDesc* o) : oop((oopDesc*)o) {} operator typeArrayOopDesc * () const { return (typeArrayOopDesc*)obj(); } typeArrayOopDesc * operator->() const { return (typeArrayOopDesc*)obj(); } typeArrayOop & operator=(const typeArrayOop& o) { oop::operator=(o ); return *this; } }; template<> struct PrimitiveConversions ::Translate<typeArrayOop> : public TrueType { typedef typeArrayOop Value; typedef typeArrayOopDesc* Decayed; static Decayed decay (Value x) { return (typeArrayOopDesc*)x.obj(); } static Value recover(Decayed x) { return typeArrayOop(x); } };; |
| 149 | |
| 150 | #endif // CHECK_UNHANDLED_OOPS |
| 151 | |
| 152 | // Cast functions to convert to and from oops. |
| 153 | template <typename T> inline oop cast_to_oop(T value) { |
| 154 | return (oopDesc*)value; |
| 155 | } |
| 156 | template <typename T> inline T cast_from_oop(oop o) { |
| 157 | return (T)(CHECK_UNHANDLED_OOPS_ONLY((oopDesc*))(oopDesc*)o); |
| 158 | } |
| 159 | |
| 160 | // The metadata hierarchy is separate from the oop hierarchy |
| 161 | |
| 162 | // class MetaspaceObj |
| 163 | class ConstMethod; |
| 164 | class ConstantPoolCache; |
| 165 | class MethodData; |
| 166 | // class Metadata |
| 167 | class Method; |
| 168 | class ConstantPool; |
| 169 | // class CHeapObj |
| 170 | class CompiledICHolder; |
| 171 | |
| 172 | |
| 173 | // The klass hierarchy is separate from the oop hierarchy. |
| 174 | |
| 175 | class Klass; |
| 176 | class InstanceKlass; |
| 177 | class InstanceMirrorKlass; |
| 178 | class InstanceClassLoaderKlass; |
| 179 | class InstanceRefKlass; |
| 180 | class ArrayKlass; |
| 181 | class ObjArrayKlass; |
| 182 | class TypeArrayKlass; |
| 183 | |
| 184 | #endif // SHARE_OOPS_OOPSHIERARCHY_HPP |