< prev index next >

src/hotspot/share/classfile/stackMapFrame.hpp

Print this page
*** 1,7 ***
  /*
!  * 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.
--- 1,7 ---
  /*
!  * 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.

*** 39,10 ***
--- 39,25 ---
  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.

*** 58,10 ***
--- 73,12 ---
  
    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),

*** 83,20 ***
          _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,
--- 100,21 ---
          _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,

*** 104,17 ***
--- 122,19 ---
                  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);
    }

*** 134,10 ***
--- 154,71 ---
    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 >