< prev index next > src/hotspot/share/classfile/stackMapFrame.hpp
Print this page
/*
! * Copyright (c) 2003, 2023, 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.
/*
! * Copyright (c) 2003, 2025, 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.
enum {
FLAG_THIS_UNINIT = 0x01
};
class StackMapFrame : public ResourceObj {
+ public:
+ static unsigned int nameandsig_hash(NameAndSig const& field) {
+ Symbol* name = field._name;
+ return (unsigned int) name->identity_hash();
+ }
+
+ static inline bool nameandsig_equals(NameAndSig const& f1, NameAndSig const& f2) {
+ return f1._name == f2._name &&
+ f1._signature == f2._signature;
+ }
+
+ // Maps a strict field's name and signature to whether or not it was initialized
+ typedef ResourceHashtable<NameAndSig, bool, 17,
+ AnyObj::RESOURCE_AREA, mtInternal,
+ nameandsig_hash, nameandsig_equals> AssertUnsetFieldTable;
private:
int32_t _offset;
// See comment in StackMapTable about _frame_count about why these
// fields are int32_t instead of u2.
u1 _flags;
VerificationType* _locals; // local variable type array
VerificationType* _stack; // operand stack type array
+ AssertUnsetFieldTable* _assert_unset_fields; // List of unsatisfied strict fields in the basic block
+
ClassVerifier* _verifier; // the verifier verifying this method
StackMapFrame(const StackMapFrame& cp) :
ResourceObj(cp),
_offset(cp._offset), _locals_size(cp._locals_size),
_stack[i] = cp._stack[i];
} else {
_stack[i] = VerificationType::bogus_type();
}
}
_verifier = nullptr;
}
public:
// constructors
// This constructor is used by the type checker to allocate frames
// in type state, which have _max_locals and _max_stack array elements
// in _locals and _stack.
! StackMapFrame(u2 max_locals, u2 max_stack, ClassVerifier* verifier);
// This constructor is used to initialize stackmap frames in stackmap table,
// which have _locals_size and _stack_size array elements in _locals and _stack.
StackMapFrame(int32_t offset,
u1 flags,
_stack[i] = cp._stack[i];
} else {
_stack[i] = VerificationType::bogus_type();
}
}
+ _assert_unset_fields = cp._assert_unset_fields;
_verifier = nullptr;
}
public:
// constructors
// This constructor is used by the type checker to allocate frames
// in type state, which have _max_locals and _max_stack array elements
// in _locals and _stack.
! StackMapFrame(u2 max_locals, u2 max_stack, AssertUnsetFieldTable* initial_strict_fields, ClassVerifier* verifier);
// This constructor is used to initialize stackmap frames in stackmap table,
// which have _locals_size and _stack_size array elements in _locals and _stack.
StackMapFrame(int32_t offset,
u1 flags,
int32_t stack_size,
u2 max_locals,
u2 max_stack,
VerificationType* locals,
VerificationType* stack,
+ AssertUnsetFieldTable* assert_unset_fields,
ClassVerifier* v) : _offset(offset),
_locals_size(locals_size),
_stack_size(stack_size),
_stack_mark(-1),
_max_locals(max_locals),
_max_stack(max_stack), _flags(flags),
_locals(locals), _stack(stack),
+ _assert_unset_fields(assert_unset_fields),
_verifier(v) { }
static StackMapFrame* copy(StackMapFrame* smf) {
return new StackMapFrame(*smf);
}
inline VerificationType* stack() const { return _stack; }
inline u2 max_locals() const { return _max_locals; }
inline u2 max_stack() const { return _max_stack; }
inline bool flag_this_uninit() const { return _flags & FLAG_THIS_UNINIT; }
+ AssertUnsetFieldTable* assert_unset_fields() const {
+ return _assert_unset_fields;
+ }
+
+ void set_assert_unset_fields(AssertUnsetFieldTable* table) {
+ _assert_unset_fields = table;
+ }
+
+ // Called when verifying putfields to mark strict instance fields as satisfied
+ bool satisfy_unset_field(Symbol* name, Symbol* signature) {
+ NameAndSig dummy_field(name, signature);
+
+ if (_assert_unset_fields->contains(dummy_field)) {
+ _assert_unset_fields->put(dummy_field, true);
+ return true;
+ }
+ return false;
+ }
+
+ // Verify that all strict fields have been initialized
+ // Strict fields must be initialized before the super constructor is called
+ bool verify_unset_fields_satisfied() {
+ bool all_satisfied = true;
+ auto check_satisfied = [&] (const NameAndSig& key, const bool& value) {
+ all_satisfied &= value;
+ };
+ _assert_unset_fields->iterate_all(check_satisfied);
+ return all_satisfied;
+ }
+
+ // Merge incoming unset strict fields from StackMapTable with
+ // initial strict instance fields
+ AssertUnsetFieldTable* merge_unset_fields(AssertUnsetFieldTable* new_fields) {
+ auto merge_satisfied = [&] (const NameAndSig& key, const bool& value) {
+ if (!new_fields->contains(key)) {
+ new_fields->put(key, true);
+ }
+ };
+ _assert_unset_fields->iterate_all(merge_satisfied);
+ return new_fields;
+ }
+
+ // Verify that strict fields are compatible between the current frame and the successor
+ // Called during merging of frames
+ bool verify_unset_fields_compatibility(AssertUnsetFieldTable* target_table) const {
+ bool compatible = true;
+ auto is_unset = [&] (const NameAndSig& key, const bool& value) {
+ // Successor must have same debts as current frame
+ if (!value) {
+ if (*target_table->get(key) == true) {
+ compatible = false;
+ }
+ }
+ };
+ _assert_unset_fields->iterate_all(is_unset);
+ return compatible;
+ }
+
+ void unsatisfied_strict_fields_error(InstanceKlass* ik, int bci);
+ static void print_strict_fields(AssertUnsetFieldTable* table);
+
// Set locals and stack types to bogus
inline void reset() {
int32_t i;
for (i = 0; i < _max_locals; i++) {
_locals[i] = VerificationType::bogus_type();
< prev index next >