From 6a30097f6579d8d6d1456c69c8d1294374c32d2a Mon Sep 17 00:00:00 2001 From: kamg Date: Thu, 21 Oct 2010 10:10:23 -0400 Subject: [PATCH] 6991315: RedefineClasses fails with java.lang.VerifyError Summary: Repair stackmap table attribute when relocating bytecode Reviewed-by: acorn, never --- .../vm/classfile/stackMapTableFormat.hpp | 916 ++++++++++++++++++ src/share/vm/includeDB_core | 4 + src/share/vm/oops/methodOop.hpp | 4 + src/share/vm/runtime/relocator.cpp | 118 +++ src/share/vm/runtime/relocator.hpp | 1 + 5 files changed, 1043 insertions(+) create mode 100644 src/share/vm/classfile/stackMapTableFormat.hpp diff --git a/src/share/vm/classfile/stackMapTableFormat.hpp b/src/share/vm/classfile/stackMapTableFormat.hpp new file mode 100644 index 000000000..d20520abe --- /dev/null +++ b/src/share/vm/classfile/stackMapTableFormat.hpp @@ -0,0 +1,916 @@ +/* + * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +// These classes represent the stack-map substructures described in the JVMS +// (hence the non-conforming naming scheme). + +// These classes work with the types in their compressed form in-place (as they +// would appear in the classfile). No virtual methods or fields allowed. + +class verification_type_info { + private: + // u1 tag + // u2 cpool_index || u2 bci (for ITEM_Object & ITEM_Uninitailized only) + + address tag_addr() const { return (address)this; } + address cpool_index_addr() const { return tag_addr() + sizeof(u1); } + address bci_addr() const { return cpool_index_addr(); } + + protected: + // No constructors - should be 'private', but GCC issues a warning if it is + verification_type_info() {} + verification_type_info(const verification_type_info&) {} + + public: + + static verification_type_info* at(address addr) { + return (verification_type_info*)addr; + } + + static verification_type_info* create_at(address addr, u1 tag) { + verification_type_info* vti = (verification_type_info*)addr; + vti->set_tag(tag); + return vti; + } + + static verification_type_info* create_object_at(address addr, u2 cp_idx) { + verification_type_info* vti = (verification_type_info*)addr; + vti->set_tag(ITEM_Object); + vti->set_cpool_index(cp_idx); + return vti; + } + + static verification_type_info* create_uninit_at(address addr, u2 bci) { + verification_type_info* vti = (verification_type_info*)addr; + vti->set_tag(ITEM_Uninitialized); + vti->set_bci(bci); + return vti; + } + + static size_t calculate_size(u1 tag) { + if (tag == ITEM_Object || tag == ITEM_Uninitialized) { + return sizeof(u1) + sizeof(u2); + } else { + return sizeof(u1); + } + } + + static size_t max_size() { return sizeof(u1) + sizeof(u2); } + + u1 tag() const { return *(u1*)tag_addr(); } + void set_tag(u1 tag) { *((u1*)tag_addr()) = tag; } + + bool is_object() const { return tag() == ITEM_Object; } + bool is_uninitialized() const { return tag() == ITEM_Uninitialized; } + + u2 cpool_index() const { + assert(is_object(), "This type has no cp_index"); + return Bytes::get_Java_u2(cpool_index_addr()); + } + void set_cpool_index(u2 idx) { + assert(is_object(), "This type has no cp_index"); + Bytes::put_Java_u2(cpool_index_addr(), idx); + } + + u2 bci() const { + assert(is_uninitialized(), "This type has no bci"); + return Bytes::get_Java_u2(bci_addr()); + } + + void set_bci(u2 bci) { + assert(is_uninitialized(), "This type has no bci"); + Bytes::put_Java_u2(bci_addr(), bci); + } + + void copy_from(verification_type_info* from) { + set_tag(from->tag()); + if (from->is_object()) { + set_cpool_index(from->cpool_index()); + } else if (from->is_uninitialized()) { + set_bci(from->bci()); + } + } + + size_t size() const { + return calculate_size(tag()); + } + + verification_type_info* next() { + return (verification_type_info*)((address)this + size()); + } + + // This method is used when reading unverified data in order to ensure + // that we don't read past a particular memory limit. It returns false + // if any part of the data structure is outside the specified memory bounds. + bool verify(address start, address end) { + return ((address)this >= start && + (address)this < end && + (bci_addr() + sizeof(u2) <= end || + !is_object() && !is_uninitialized())); + } + +#ifdef ASSERT + void print_on(outputStream* st) { + switch (tag()) { + case ITEM_Top: st->print("Top"); break; + case ITEM_Integer: st->print("Integer"); break; + case ITEM_Float: st->print("Float"); break; + case ITEM_Double: st->print("Double"); break; + case ITEM_Long: st->print("Long"); break; + case ITEM_Null: st->print("Null"); break; + case ITEM_UninitializedThis: + st->print("UninitializedThis"); break; + case ITEM_Uninitialized: + st->print("Uninitialized[#%d]", bci()); break; + case ITEM_Object: + st->print("Object[#%d]", cpool_index()); break; + default: + assert(false, "Bad verification_type_info"); + } + } +#endif +}; + +#define FOR_EACH_STACKMAP_FRAME_TYPE(macro, arg1, arg2) \ + macro(same_frame, arg1, arg2) \ + macro(same_frame_extended, arg1, arg2) \ + macro(same_frame_1_stack_item_frame, arg1, arg2) \ + macro(same_frame_1_stack_item_extended, arg1, arg2) \ + macro(chop_frame, arg1, arg2) \ + macro(append_frame, arg1, arg2) \ + macro(full_frame, arg1, arg2) + +#define SM_FORWARD_DECL(type, arg1, arg2) class type; +FOR_EACH_STACKMAP_FRAME_TYPE(SM_FORWARD_DECL, x, x) +#undef SM_FORWARD_DECL + +class stack_map_frame { + protected: + address frame_type_addr() const { return (address)this; } + + // No constructors - should be 'private', but GCC issues a warning if it is + stack_map_frame() {} + stack_map_frame(const stack_map_frame&) {} + + public: + + static stack_map_frame* at(address addr) { + return (stack_map_frame*)addr; + } + + stack_map_frame* next() const { + return at((address)this + size()); + } + + u1 frame_type() const { return *(u1*)frame_type_addr(); } + void set_frame_type(u1 type) { *((u1*)frame_type_addr()) = type; } + + // pseudo-virtual methods + inline size_t size() const; + inline int offset_delta() const; + inline void set_offset_delta(int offset_delta); + inline int number_of_types() const; // number of types contained in the frame + inline verification_type_info* types() const; // pointer to first type + inline bool is_valid_offset(int offset_delta) const; + + // This method must be used when reading unverified data in order to ensure + // that we don't read past a particular memory limit. It returns false + // if any part of the data structure is outside the specified memory bounds. + inline bool verify(address start, address end) const; +#ifdef ASSERT + inline void print_on(outputStream* st) const; +#endif + + // Create as_xxx and is_xxx methods for the subtypes +#define FRAME_TYPE_DECL(stackmap_frame_type, arg1, arg2) \ + inline stackmap_frame_type* as_##stackmap_frame_type() const; \ + bool is_##stackmap_frame_type() { \ + return as_##stackmap_frame_type() != NULL; \ + } + + FOR_EACH_STACKMAP_FRAME_TYPE(FRAME_TYPE_DECL, x, x) +#undef FRAME_TYPE_DECL +}; + +class same_frame : public stack_map_frame { + private: + static int frame_type_to_offset_delta(u1 frame_type) { + return frame_type + 1; } + static u1 offset_delta_to_frame_type(int offset_delta) { + return (u1)(offset_delta - 1); } + + public: + + static bool is_frame_type(u1 tag) { + return tag < 64; + } + + static same_frame* at(address addr) { + assert(is_frame_type(*addr), "Wrong frame id"); + return (same_frame*)addr; + } + + static same_frame* create_at(address addr, int offset_delta) { + same_frame* sm = (same_frame*)addr; + sm->set_offset_delta(offset_delta); + return sm; + } + + static size_t calculate_size() { return sizeof(u1); } + + size_t size() const { return calculate_size(); } + int offset_delta() const { return frame_type_to_offset_delta(frame_type()); } + + void set_offset_delta(int offset_delta) { + assert(offset_delta <= 64, "Offset too large for same_frame"); + set_frame_type(offset_delta_to_frame_type(offset_delta)); + } + + int number_of_types() const { return 0; } + verification_type_info* types() const { return NULL; } + + bool is_valid_offset(int offset_delta) const { + return is_frame_type(offset_delta_to_frame_type(offset_delta)); + } + + bool verify_subtype(address start, address end) const { + return true; + } + +#ifdef ASSERT + void print_on(outputStream* st) const { + st->print("same_frame(%d)", offset_delta()); + } +#endif +}; + +class same_frame_extended : public stack_map_frame { + private: + enum { _frame_id = 251 }; + address offset_delta_addr() const { return frame_type_addr() + sizeof(u1); } + + public: + static bool is_frame_type(u1 tag) { + return tag == _frame_id; + } + + static same_frame_extended* at(address addr) { + assert(is_frame_type(*addr), "Wrong frame type"); + return (same_frame_extended*)addr; + } + + static same_frame_extended* create_at(address addr, u2 offset_delta) { + same_frame_extended* sm = (same_frame_extended*)addr; + sm->set_frame_type(_frame_id); + sm->set_offset_delta(offset_delta); + return sm; + } + + static size_t calculate_size() { return sizeof(u1) + sizeof(u2); } + + size_t size() const { return calculate_size(); } + int offset_delta() const { + return Bytes::get_Java_u2(offset_delta_addr()) + 1; + } + + void set_offset_delta(int offset_delta) { + Bytes::put_Java_u2(offset_delta_addr(), offset_delta - 1); + } + + int number_of_types() const { return 0; } + verification_type_info* types() const { return NULL; } + bool is_valid_offset(int offset) const { return true; } + + bool verify_subtype(address start, address end) const { + return frame_type_addr() + size() <= end; + } + +#ifdef ASSERT + void print_on(outputStream* st) const { + st->print("same_frame_extended(%d)", offset_delta()); + } +#endif +}; + +class same_frame_1_stack_item_frame : public stack_map_frame { + private: + address type_addr() const { return frame_type_addr() + sizeof(u1); } + + static int frame_type_to_offset_delta(u1 frame_type) { + return frame_type - 63; } + static u1 offset_delta_to_frame_type(int offset_delta) { + return (u1)(offset_delta + 63); } + + public: + static bool is_frame_type(u1 tag) { + return tag >= 64 && tag < 128; + } + + static same_frame_1_stack_item_frame* at(address addr) { + assert(is_frame_type(*addr), "Wrong frame id"); + return (same_frame_1_stack_item_frame*)addr; + } + + static same_frame_1_stack_item_frame* create_at( + address addr, int offset_delta, verification_type_info* vti) { + same_frame_1_stack_item_frame* sm = (same_frame_1_stack_item_frame*)addr; + sm->set_offset_delta(offset_delta); + if (vti != NULL) { + sm->set_type(vti); + } + return sm; + } + + static size_t calculate_size(verification_type_info* vti) { + return sizeof(u1) + vti->size(); + } + + static size_t max_size() { + return sizeof(u1) + verification_type_info::max_size(); + } + + size_t size() const { return calculate_size(types()); } + int offset_delta() const { return frame_type_to_offset_delta(frame_type()); } + + void set_offset_delta(int offset_delta) { + assert(offset_delta > 0 && offset_delta <= 64, + "Offset too large for this frame type"); + set_frame_type(offset_delta_to_frame_type(offset_delta)); + } + + void set_type(verification_type_info* vti) { + verification_type_info* cur = types(); + cur->copy_from(vti); + } + + int number_of_types() const { return 1; } + verification_type_info* types() const { + return verification_type_info::at(type_addr()); + } + + bool is_valid_offset(int offset_delta) const { + return is_frame_type(offset_delta_to_frame_type(offset_delta)); + } + + bool verify_subtype(address start, address end) const { + return types()->verify(start, end); + } + +#ifdef ASSERT + void print_on(outputStream* st) const { + st->print("same_frame_1_stack_item_frame(%d,", offset_delta()); + types()->print_on(st); + st->print(")"); + } +#endif +}; + +class same_frame_1_stack_item_extended : public stack_map_frame { + private: + address offset_delta_addr() const { return frame_type_addr() + sizeof(u1); } + address type_addr() const { return offset_delta_addr() + sizeof(u2); } + + enum { _frame_id = 247 }; + + public: + static bool is_frame_type(u1 tag) { + return tag == _frame_id; + } + + static same_frame_1_stack_item_extended* at(address addr) { + assert(is_frame_type(*addr), "Wrong frame id"); + return (same_frame_1_stack_item_extended*)addr; + } + + static same_frame_1_stack_item_extended* create_at( + address addr, int offset_delta, verification_type_info* vti) { + same_frame_1_stack_item_extended* sm = + (same_frame_1_stack_item_extended*)addr; + sm->set_frame_type(_frame_id); + sm->set_offset_delta(offset_delta); + if (vti != NULL) { + sm->set_type(vti); + } + return sm; + } + + static size_t calculate_size(verification_type_info* vti) { + return sizeof(u1) + sizeof(u2) + vti->size(); + } + + size_t size() const { return calculate_size(types()); } + int offset_delta() const { + return Bytes::get_Java_u2(offset_delta_addr()) + 1; + } + + void set_offset_delta(int offset_delta) { + Bytes::put_Java_u2(offset_delta_addr(), offset_delta - 1); + } + + void set_type(verification_type_info* vti) { + verification_type_info* cur = types(); + cur->copy_from(vti); + } + + int number_of_types() const { return 1; } + verification_type_info* types() const { + return verification_type_info::at(type_addr()); + } + bool is_valid_offset(int offset) { return true; } + + bool verify_subtype(address start, address end) const { + return type_addr() < end && types()->verify(start, end); + } + +#ifdef ASSERT + void print_on(outputStream* st) const { + st->print("same_frame_1_stack_item_extended(%d,", offset_delta()); + types()->print_on(st); + st->print(")"); + } +#endif +}; + +class chop_frame : public stack_map_frame { + private: + address offset_delta_addr() const { return frame_type_addr() + sizeof(u1); } + + static int frame_type_to_chops(u1 frame_type) { + int chop = 251 - frame_type; + return chop; + } + + static u1 chops_to_frame_type(int chop) { + return 251 - chop; + } + + public: + static bool is_frame_type(u1 tag) { + return frame_type_to_chops(tag) > 0 && frame_type_to_chops(tag) < 4; + } + + static chop_frame* at(address addr) { + assert(is_frame_type(*addr), "Wrong frame id"); + return (chop_frame*)addr; + } + + static chop_frame* create_at(address addr, int offset_delta, int chops) { + chop_frame* sm = (chop_frame*)addr; + sm->set_chops(chops); + sm->set_offset_delta(offset_delta); + return sm; + } + + static size_t calculate_size() { + return sizeof(u1) + sizeof(u2); + } + + size_t size() const { return calculate_size(); } + int offset_delta() const { + return Bytes::get_Java_u2(offset_delta_addr()) + 1; + } + void set_offset_delta(int offset_delta) { + Bytes::put_Java_u2(offset_delta_addr(), offset_delta - 1); + } + + int chops() const { + int chops = frame_type_to_chops(frame_type()); + assert(chops > 0 && chops < 4, "Invalid number of chops in frame"); + return chops; + } + void set_chops(int chops) { + assert(chops > 0 && chops <= 3, "Bad number of chops"); + set_frame_type(chops_to_frame_type(chops)); + } + + int number_of_types() const { return 0; } + verification_type_info* types() const { return NULL; } + bool is_valid_offset(int offset) { return true; } + + bool verify_subtype(address start, address end) const { + return frame_type_addr() + size() <= end; + } + +#ifdef ASSERT + void print_on(outputStream* st) const { + st->print("chop_frame(%d,%d)", offset_delta(), chops()); + } +#endif +}; + +class append_frame : public stack_map_frame { + private: + address offset_delta_addr() const { return frame_type_addr() + sizeof(u1); } + address types_addr() const { return offset_delta_addr() + sizeof(u2); } + + static int frame_type_to_appends(u1 frame_type) { + int append = frame_type - 251; + return append; + } + + static u1 appends_to_frame_type(int appends) { + assert(appends > 0 && appends < 4, "Invalid append amount"); + return 251 + appends; + } + + public: + static bool is_frame_type(u1 tag) { + return frame_type_to_appends(tag) > 0 && frame_type_to_appends(tag) < 4; + } + + static append_frame* at(address addr) { + assert(is_frame_type(*addr), "Wrong frame id"); + return (append_frame*)addr; + } + + static append_frame* create_at( + address addr, int offset_delta, int appends, + verification_type_info* types) { + append_frame* sm = (append_frame*)addr; + sm->set_appends(appends); + sm->set_offset_delta(offset_delta); + if (types != NULL) { + verification_type_info* cur = sm->types(); + for (int i = 0; i < appends; ++i) { + cur->copy_from(types); + cur = cur->next(); + types = types->next(); + } + } + return sm; + } + + static size_t calculate_size(int appends, verification_type_info* types) { + size_t sz = sizeof(u1) + sizeof(u2); + for (int i = 0; i < appends; ++i) { + sz += types->size(); + types = types->next(); + } + return sz; + } + + static size_t max_size() { + return sizeof(u1) + sizeof(u2) + 3 * verification_type_info::max_size(); + } + + size_t size() const { return calculate_size(number_of_types(), types()); } + int offset_delta() const { + return Bytes::get_Java_u2(offset_delta_addr()) + 1; + } + + void set_offset_delta(int offset_delta) { + Bytes::put_Java_u2(offset_delta_addr(), offset_delta - 1); + } + + void set_appends(int appends) { + assert(appends > 0 && appends < 4, "Bad number of appends"); + set_frame_type(appends_to_frame_type(appends)); + } + + int number_of_types() const { + int appends = frame_type_to_appends(frame_type()); + assert(appends > 0 && appends < 4, "Invalid number of appends in frame"); + return appends; + } + verification_type_info* types() const { + return verification_type_info::at(types_addr()); + } + bool is_valid_offset(int offset) const { return true; } + + bool verify_subtype(address start, address end) const { + verification_type_info* vti = types(); + if ((address)vti < end && vti->verify(start, end)) { + int nof = number_of_types(); + vti = vti->next(); + if (nof < 2 || vti->verify(start, end)) { + vti = vti->next(); + if (nof < 3 || vti->verify(start, end)) { + return true; + } + } + } + return false; + } + +#ifdef ASSERT + void print_on(outputStream* st) const { + st->print("append_frame(%d,", offset_delta()); + verification_type_info* vti = types(); + for (int i = 0; i < number_of_types(); ++i) { + vti->print_on(st); + if (i != number_of_types() - 1) { + st->print(","); + } + vti = vti->next(); + } + st->print(")"); + } +#endif +}; + +class full_frame : public stack_map_frame { + private: + address offset_delta_addr() const { return frame_type_addr() + sizeof(u1); } + address num_locals_addr() const { return offset_delta_addr() + sizeof(u2); } + address locals_addr() const { return num_locals_addr() + sizeof(u2); } + address stack_slots_addr(address end_of_locals) const { + return end_of_locals; } + address stack_addr(address end_of_locals) const { + return stack_slots_addr(end_of_locals) + sizeof(u2); } + + enum { _frame_id = 255 }; + + public: + static bool is_frame_type(u1 tag) { + return tag == _frame_id; + } + + static full_frame* at(address addr) { + assert(is_frame_type(*addr), "Wrong frame id"); + return (full_frame*)addr; + } + + static full_frame* create_at( + address addr, int offset_delta, int num_locals, + verification_type_info* locals, + int stack_slots, verification_type_info* stack) { + full_frame* sm = (full_frame*)addr; + sm->set_frame_type(_frame_id); + sm->set_offset_delta(offset_delta); + sm->set_num_locals(num_locals); + if (locals != NULL) { + verification_type_info* cur = sm->locals(); + for (int i = 0; i < num_locals; ++i) { + cur->copy_from(locals); + cur = cur->next(); + locals = locals->next(); + } + address end_of_locals = (address)cur; + sm->set_stack_slots(end_of_locals, stack_slots); + cur = sm->stack(end_of_locals); + for (int i = 0; i < stack_slots; ++i) { + cur->copy_from(stack); + cur = cur->next(); + stack = stack->next(); + } + } + return sm; + } + + static size_t calculate_size( + int num_locals, verification_type_info* locals, + int stack_slots, verification_type_info* stack) { + size_t sz = sizeof(u1) + sizeof(u2) + sizeof(u2) + sizeof(u2); + verification_type_info* vti = locals; + for (int i = 0; i < num_locals; ++i) { + sz += vti->size(); + vti = vti->next(); + } + vti = stack; + for (int i = 0; i < stack_slots; ++i) { + sz += vti->size(); + vti = vti->next(); + } + return sz; + } + + static size_t max_size(int locals, int stack) { + return sizeof(u1) + 3 * sizeof(u2) + + (locals + stack) * verification_type_info::max_size(); + } + + size_t size() const { + address eol = end_of_locals(); + return calculate_size(num_locals(), locals(), stack_slots(eol), stack(eol)); + } + + int offset_delta() const { + return Bytes::get_Java_u2(offset_delta_addr()) + 1; + } + int num_locals() const { return Bytes::get_Java_u2(num_locals_addr()); } + verification_type_info* locals() const { + return verification_type_info::at(locals_addr()); + } + address end_of_locals() const { + verification_type_info* vti = locals(); + for (int i = 0; i < num_locals(); ++i) { + vti = vti->next(); + } + return (address)vti; + } + int stack_slots(address end_of_locals) const { + return Bytes::get_Java_u2(stack_slots_addr(end_of_locals)); + } + verification_type_info* stack(address end_of_locals) const { + return verification_type_info::at(stack_addr(end_of_locals)); + } + + void set_offset_delta(int offset_delta) { + Bytes::put_Java_u2(offset_delta_addr(), offset_delta - 1); + } + void set_num_locals(int num_locals) { + Bytes::put_Java_u2(num_locals_addr(), num_locals); + } + void set_stack_slots(address end_of_locals, int stack_slots) { + Bytes::put_Java_u2(stack_slots_addr(end_of_locals), stack_slots); + } + + // These return only the locals. Extra processing is required for stack + // types of full frames. + int number_of_types() const { return num_locals(); } + verification_type_info* types() const { return locals(); } + bool is_valid_offset(int offset) { return true; } + + bool verify_subtype(address start, address end) const { + verification_type_info* vti = types(); + if ((address)vti >= end) { + return false; + } + int count = number_of_types(); + for (int i = 0; i < count; ++i) { + if (!vti->verify(start, end)) { + return false; + } + vti = vti->next(); + } + address eol = (address)vti; + if (eol + sizeof(u2) > end) { + return false; + } + count = stack_slots(eol); + vti = stack(eol); + for (int i = 0; i < stack_slots(eol); ++i) { + if (!vti->verify(start, end)) { + return false; + } + vti = vti->next(); + } + return true; + } + +#ifdef ASSERT + void print_on(outputStream* st) const { + st->print("full_frame(%d,{", offset_delta()); + verification_type_info* vti = locals(); + for (int i = 0; i < num_locals(); ++i) { + vti->print_on(st); + if (i != num_locals() - 1) { + st->print(","); + } + vti = vti->next(); + } + st->print("},{"); + address end_of_locals = (address)vti; + vti = stack(end_of_locals); + int ss = stack_slots(end_of_locals); + for (int i = 0; i < ss; ++i) { + vti->print_on(st); + if (i != ss - 1) { + st->print(","); + } + vti = vti->next(); + } + st->print("})"); + } +#endif +}; + +#define VIRTUAL_DISPATCH(stack_frame_type, func_name, args) \ + stack_frame_type* item_##stack_frame_type = as_##stack_frame_type(); \ + if (item_##stack_frame_type != NULL) { \ + return item_##stack_frame_type->func_name args; \ + } + +#define VOID_VIRTUAL_DISPATCH(stack_frame_type, func_name, args) \ + stack_frame_type* item_##stack_frame_type = as_##stack_frame_type(); \ + if (item_##stack_frame_type != NULL) { \ + item_##stack_frame_type->func_name args; \ + return; \ + } + +size_t stack_map_frame::size() const { + FOR_EACH_STACKMAP_FRAME_TYPE(VIRTUAL_DISPATCH, size, ()); + return 0; +} + +int stack_map_frame::offset_delta() const { + FOR_EACH_STACKMAP_FRAME_TYPE(VIRTUAL_DISPATCH, offset_delta, ()); + return 0; +} + +void stack_map_frame::set_offset_delta(int offset_delta) { + FOR_EACH_STACKMAP_FRAME_TYPE( + VOID_VIRTUAL_DISPATCH, set_offset_delta, (offset_delta)); +} + +int stack_map_frame::number_of_types() const { + FOR_EACH_STACKMAP_FRAME_TYPE(VIRTUAL_DISPATCH, number_of_types, ()); + return 0; +} + +verification_type_info* stack_map_frame::types() const { + FOR_EACH_STACKMAP_FRAME_TYPE(VIRTUAL_DISPATCH, types, ()); + return NULL; +} + +bool stack_map_frame::is_valid_offset(int offset) const { + FOR_EACH_STACKMAP_FRAME_TYPE(VIRTUAL_DISPATCH, is_valid_offset, (offset)); + return true; +} + +bool stack_map_frame::verify(address start, address end) const { + if (frame_type_addr() >= start && frame_type_addr() < end) { + FOR_EACH_STACKMAP_FRAME_TYPE( + VIRTUAL_DISPATCH, verify_subtype, (start, end)); + } + return false; +} + +#ifdef ASSERT +void stack_map_frame::print_on(outputStream* st) const { + FOR_EACH_STACKMAP_FRAME_TYPE(VOID_VIRTUAL_DISPATCH, print_on, (st)); +} +#endif + +#undef VIRTUAL_DISPATCH +#undef VOID_VIRTUAL_DISPATCH + +#define AS_SUBTYPE_DEF(stack_frame_type, arg1, arg2) \ +stack_frame_type* stack_map_frame::as_##stack_frame_type() const { \ + if (stack_frame_type::is_frame_type(frame_type())) { \ + return (stack_frame_type*)this; \ + } else { \ + return NULL; \ + } \ +} + +FOR_EACH_STACKMAP_FRAME_TYPE(AS_SUBTYPE_DEF, x, x) +#undef AS_SUBTYPE_DEF + +class stack_map_table_attribute { + private: + address name_index_addr() const { + return (address)this; } + address attribute_length_addr() const { + return name_index_addr() + sizeof(u2); } + address number_of_entries_addr() const { + return attribute_length_addr() + sizeof(u4); } + address entries_addr() const { + return number_of_entries_addr() + sizeof(u2); } + + protected: + // No constructors - should be 'private', but GCC issues a warning if it is + stack_map_table_attribute() {} + stack_map_table_attribute(const stack_map_table_attribute&) {} + + public: + + static stack_map_table_attribute* at(address addr) { + return (stack_map_table_attribute*)addr; + } + + u2 name_index() const { + return Bytes::get_Java_u2(name_index_addr()); } + u4 attribute_length() const { + return Bytes::get_Java_u4(attribute_length_addr()); } + u2 number_of_entries() const { + return Bytes::get_Java_u2(number_of_entries_addr()); } + stack_map_frame* entries() const { + return stack_map_frame::at(entries_addr()); + } + + static size_t header_size() { + return sizeof(u2) + sizeof(u4); + } + + void set_name_index(u2 idx) { + Bytes::put_Java_u2(name_index_addr(), idx); + } + void set_attribute_length(u4 len) { + Bytes::put_Java_u4(attribute_length_addr(), len); + } + void set_number_of_entries(u2 num) { + Bytes::put_Java_u2(number_of_entries_addr(), num); + } +}; diff --git a/src/share/vm/includeDB_core b/src/share/vm/includeDB_core index 14d78e91d..a16805a0a 100644 --- a/src/share/vm/includeDB_core +++ b/src/share/vm/includeDB_core @@ -3601,7 +3601,9 @@ relocInfo_.hpp generate_platform_dependent_include relocator.cpp bytecodes.hpp relocator.cpp handles.inline.hpp relocator.cpp oop.inline.hpp +relocator.cpp oopFactory.hpp relocator.cpp relocator.hpp +relocator.cpp stackMapTableFormat.hpp relocator.cpp universe.inline.hpp relocator.hpp bytecodes.hpp @@ -3908,6 +3910,8 @@ stackMapTable.hpp globalDefinitions.hpp stackMapTable.hpp methodOop.hpp stackMapTable.hpp stackMapFrame.hpp +stackMapTableFormat.hpp verificationType.hpp + stackValue.cpp debugInfo.hpp stackValue.cpp frame.inline.hpp stackValue.cpp handles.inline.hpp diff --git a/src/share/vm/oops/methodOop.hpp b/src/share/vm/oops/methodOop.hpp index 827e58f1a..9ae2ca907 100644 --- a/src/share/vm/oops/methodOop.hpp +++ b/src/share/vm/oops/methodOop.hpp @@ -247,6 +247,10 @@ class methodOopDesc : public oopDesc { return constMethod()->stackmap_data(); } + void set_stackmap_data(typeArrayOop sd) { + constMethod()->set_stackmap_data(sd); + } + // exception handler table typeArrayOop exception_table() const { return constMethod()->exception_table(); } diff --git a/src/share/vm/runtime/relocator.cpp b/src/share/vm/runtime/relocator.cpp index bf796680f..483d21bd3 100644 --- a/src/share/vm/runtime/relocator.cpp +++ b/src/share/vm/runtime/relocator.cpp @@ -435,6 +435,120 @@ void Relocator::adjust_local_var_table(int bci, int delta) { } } +// Create a new array, copying the src array but adding a hole at +// the specified location +static typeArrayOop insert_hole_at( + size_t where, int hole_sz, typeArrayOop src) { + Thread* THREAD = Thread::current(); + Handle src_hnd(THREAD, src); + typeArrayOop dst = + oopFactory::new_permanent_byteArray(src->length() + hole_sz, CHECK_NULL); + src = (typeArrayOop)src_hnd(); + + address src_addr = (address)src->byte_at_addr(0); + address dst_addr = (address)dst->byte_at_addr(0); + + memcpy(dst_addr, src_addr, where); + memcpy(dst_addr + where + hole_sz, + src_addr + where, src->length() - where); + return dst; +} + +// The width of instruction at "bci" is changing by "delta". Adjust the stack +// map frames. +void Relocator::adjust_stack_map_table(int bci, int delta) { + if (method()->has_stackmap_table()) { + typeArrayOop data = method()->stackmap_data(); + // The data in the array is a classfile representation of the stackmap + // table attribute, less the initial u2 tag and u4 attribute_length fields. + stack_map_table_attribute* attr = stack_map_table_attribute::at( + (address)data->byte_at_addr(0) - (sizeof(u2) + sizeof(u4))); + + int count = attr->number_of_entries(); + stack_map_frame* frame = attr->entries(); + int bci_iter = -1; + bool offset_adjusted = false; // only need to adjust one offset + + for (int i = 0; i < count; ++i) { + int offset_delta = frame->offset_delta(); + bci_iter += offset_delta; + + if (!offset_adjusted && bci_iter > bci) { + int new_offset_delta = offset_delta + delta; + + if (frame->is_valid_offset(new_offset_delta)) { + frame->set_offset_delta(new_offset_delta); + } else { + assert(frame->is_same_frame() || + frame->is_same_frame_1_stack_item_frame(), + "Frame must be one of the compressed forms"); + // The new delta exceeds the capacity of the 'same_frame' or + // 'same_frame_1_stack_item_frame' frame types. We need to + // convert these frames to the extended versions, but the extended + // version is bigger and requires more room. So we allocate a + // new array and copy the data, being sure to leave u2-sized hole + // right after the 'frame_type' for the new offset field. + // + // We can safely ignore the reverse situation as a small delta + // can still be used in an extended version of the frame. + + size_t frame_offset = (address)frame - (address)data->byte_at_addr(0); + + data = insert_hole_at(frame_offset + 1, 2, data); + if (data == NULL) { + return; // out-of-memory? + } + + address frame_addr = (address)(data->byte_at_addr(0) + frame_offset); + frame = stack_map_frame::at(frame_addr); + + + // Now convert the frames in place + if (frame->is_same_frame()) { + same_frame_extended::create_at(frame_addr, new_offset_delta); + } else { + same_frame_1_stack_item_extended::create_at( + frame_addr, new_offset_delta, NULL); + // the verification_info_type should already be at the right spot + } + } + offset_adjusted = true; // needs to be done only once, since subsequent + // values are offsets from the current + } + + // The stack map frame may contain verification types, if so we need to + // check and update any Uninitialized type's bci (no matter where it is). + int number_of_types = frame->number_of_types(); + verification_type_info* types = frame->types(); + + for (int i = 0; i < number_of_types; ++i) { + if (types->is_uninitialized() && types->bci() > bci) { + types->set_bci(types->bci() + delta); + } + types = types->next(); + } + + // Full frame has stack values too + full_frame* ff = frame->as_full_frame(); + if (ff != NULL) { + address eol = (address)types; + number_of_types = ff->stack_slots(eol); + types = ff->stack(eol); + for (int i = 0; i < number_of_types; ++i) { + if (types->is_uninitialized() && types->bci() > bci) { + types->set_bci(types->bci() + delta); + } + types = types->next(); + } + } + + frame = frame->next(); + } + + method()->set_stackmap_data(data); // in case it has changed + } +} + bool Relocator::expand_code_array(int delta) { int length = MAX2(code_length() + delta, code_length() * (100+code_slop_pct()) / 100); @@ -499,6 +613,9 @@ bool Relocator::relocate_code(int bci, int ilen, int delta) { // And local variable table... adjust_local_var_table(bci, delta); + // Adjust stack maps + adjust_stack_map_table(bci, delta); + // Relocate the pending change stack... for (int j = 0; j < _changes->length(); j++) { ChangeItem* ci = _changes->at(j); @@ -641,6 +758,7 @@ bool Relocator::handle_switch_pad(int bci, int old_pad, bool is_lookup_switch) { memmove(addr_at(bci +1 + new_pad), addr_at(bci +1 + old_pad), len * 4); + memset(addr_at(bci + 1), 0, new_pad); // pad must be 0 } } return true; diff --git a/src/share/vm/runtime/relocator.hpp b/src/share/vm/runtime/relocator.hpp index be925e6a8..3f163723d 100644 --- a/src/share/vm/runtime/relocator.hpp +++ b/src/share/vm/runtime/relocator.hpp @@ -105,6 +105,7 @@ class Relocator : public ResourceObj { void adjust_exception_table(int bci, int delta); void adjust_line_no_table (int bci, int delta); void adjust_local_var_table(int bci, int delta); + void adjust_stack_map_table(int bci, int delta); int get_orig_switch_pad (int bci, bool is_lookup_switch); int rc_instr_len (int bci); bool expand_code_array (int delta); -- GitLab