Date: Fri, 14 Mar 2025 22:08:38 +0800
Subject: heap-dump-redact-support

---
 src/hotspot/os/linux/os_linux.cpp             |  37 +-
 src/hotspot/os/linux/os_linux.hpp             |  54 ++
 src/hotspot/share/oops/annotations.hpp        |   1 +
 src/hotspot/share/runtime/arguments.cpp       |  24 +
 src/hotspot/share/runtime/globals.hpp         |  18 +
 src/hotspot/share/runtime/vmStructs.cpp       |  12 +-
 src/hotspot/share/services/heapDumper.cpp     | 693 +++++++++++++++++-
 src/hotspot/share/services/heapRedactor.cpp   | 676 +++++++++++++++++
 src/hotspot/share/services/heapRedactor.hpp   | 225 ++++++
 src/hotspot/share/services/writeableFlags.cpp |   7 +
 .../share/classes/sun/jvm/hotspot/HSDB.java   |  19 +-
 .../classes/sun/jvm/hotspot/SALauncher.java   |  46 +-
 .../sun/jvm/hotspot/oops/Annotation.java      |  70 ++
 .../classes/sun/jvm/hotspot/oops/Field.java   |  10 +
 .../sun/jvm/hotspot/oops/InstanceKlass.java   |   6 +
 .../classes/sun/jvm/hotspot/tools/JMap.java   |  63 +-
 .../hotspot/utilities/AnnotationArray2D.java  |  62 ++
 .../hotspot/utilities/HeapHprofBinWriter.java | 419 ++++++++++-
 .../jvm/hotspot/utilities/HeapRedactor.java   | 454 ++++++++++++
 .../share/classes/sun/tools/jmap/JMap.java    | 258 ++++++-
 20 files changed, 3088 insertions(+), 66 deletions(-)
 create mode 100644 src/hotspot/share/services/heapRedactor.cpp
 create mode 100644 src/hotspot/share/services/heapRedactor.hpp
 create mode 100644 src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/Annotation.java
 create mode 100644 src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/AnnotationArray2D.java
 create mode 100644 src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/HeapRedactor.java

diff --git a/src/hotspot/os/linux/os_linux.cpp b/src/hotspot/os/linux/os_linux.cpp
index 3cb529bc8..43ee4b7db 100644
--- a/src/hotspot/os/linux/os_linux.cpp
+++ b/src/hotspot/os/linux/os_linux.cpp
@@ -4587,6 +4587,12 @@ os::Linux::jboltLog_precalc_t os::Linux::_jboltLog_precalc;
 os::Linux::jboltLog_do_t os::Linux::_jboltLog_do;
 os::Linux::jboltMerge_judge_t os::Linux::_jboltMerge_judge;
 #endif // INCLUDE_JBOLT
+os::Linux::heap_dict_add_t os::Linux::_heap_dict_add;
+os::Linux::heap_dict_lookup_t os::Linux::_heap_dict_lookup;
+os::Linux::heap_dict_free_t os::Linux::_heap_dict_free;
+os::Linux::heap_vector_add_t os::Linux::_heap_vector_add;
+os::Linux::heap_vector_get_next_t os::Linux::_heap_vector_get_next;
+os::Linux::heap_vector_free_t os::Linux::_heap_vector_free;
 
 void os::Linux::load_plugin_library() {
 
@@ -4595,6 +4601,12 @@ void os::Linux::load_plugin_library() {
     _jboltLog_do = CAST_TO_FN_PTR(jboltLog_do_t, dlsym(RTLD_DEFAULT, "JBoltLog_DO"));
     _jboltMerge_judge = CAST_TO_FN_PTR(jboltMerge_judge_t, dlsym(RTLD_DEFAULT, "JBoltMerge_Judge"));
 #endif // INCLUDE_JBOLT
+  _heap_dict_add = CAST_TO_FN_PTR(heap_dict_add_t, dlsym(RTLD_DEFAULT, "HeapDict_Add"));
+  _heap_dict_lookup = CAST_TO_FN_PTR(heap_dict_lookup_t, dlsym(RTLD_DEFAULT, "HeapDict_Lookup"));
+  _heap_dict_free = CAST_TO_FN_PTR(heap_dict_free_t, dlsym(RTLD_DEFAULT, "HeapDict_Free"));
+  _heap_vector_add = CAST_TO_FN_PTR(heap_vector_add_t, dlsym(RTLD_DEFAULT, "HeapVector_Add"));
+  _heap_vector_get_next = CAST_TO_FN_PTR(heap_vector_get_next_t, dlsym(RTLD_DEFAULT, "HeapVector_GetNext"));
+  _heap_vector_free= CAST_TO_FN_PTR(heap_vector_free_t, dlsym(RTLD_DEFAULT, "HeapVector_Free"));
 
   char path[JVM_MAXPATHLEN];
   char ebuf[1024];
@@ -4612,12 +4624,31 @@ void os::Linux::load_plugin_library() {
       _jboltLog_do = CAST_TO_FN_PTR(jboltLog_do_t, dlsym(handle, "JBoltLog_DO"));
     }
     if (_jboltMerge_judge == NULL) {
-      _jboltMerge_judge = CAST_TO_FN_PTR(jboltMerge_judge_t, dlsym(handle, "JBoltMerge_Judge"));   
+      _jboltMerge_judge = CAST_TO_FN_PTR(jboltMerge_judge_t, dlsym(handle, "JBoltMerge_Judge"));
     }
 #endif // INCLUDE_JBOLT
+
+    if(_heap_dict_add == NULL) {
+      _heap_dict_add = CAST_TO_FN_PTR(heap_dict_add_t, dlsym(handle, "HeapDict_Add"));
+    }
+    if(_heap_dict_lookup == NULL) {
+      _heap_dict_lookup = CAST_TO_FN_PTR(heap_dict_lookup_t, dlsym(handle, "HeapDict_Lookup"));
+    }
+    if(_heap_dict_free == NULL) {
+      _heap_dict_free = CAST_TO_FN_PTR(heap_dict_free_t, dlsym(handle, "HeapDict_Free"));
+    }
+    if(_heap_vector_add == NULL) {
+      _heap_vector_add = CAST_TO_FN_PTR(heap_vector_add_t, dlsym(handle, "HeapVector_Add"));
+    }
+    if(_heap_vector_get_next == NULL) {
+      _heap_vector_get_next = CAST_TO_FN_PTR(heap_vector_get_next_t, dlsym(handle, "HeapVector_GetNext"));
+    }
+    if(_heap_vector_free == NULL) {
+      _heap_vector_free= CAST_TO_FN_PTR(heap_vector_free_t, dlsym(handle, "HeapVector_Free"));
+    }
   }
 
-  JBOLT_ONLY(log_debug(jbolt)("Plugin library for JBolt: %s %s %s", BOOL_TO_STR(_jboltLog_precalc != nullptr), 
+  JBOLT_ONLY(log_debug(jbolt)("Plugin library for JBolt: %s %s %s", BOOL_TO_STR(_jboltLog_precalc != nullptr),
                                                          BOOL_TO_STR(_jboltLog_do != nullptr),
                                                          BOOL_TO_STR(_jboltMerge_judge != nullptr));)
 }
@@ -4747,6 +4778,8 @@ jint os::init_2(void) {
   init_adjust_stacksize_for_guard_pages();
 #endif
 
+  Linux::load_plugin_library();
+
   if (UseNUMA || UseNUMAInterleaving) {
     Linux::numa_init();
   }
diff --git a/src/hotspot/os/linux/os_linux.hpp b/src/hotspot/os/linux/os_linux.hpp
index 4192c90bd..871581f58 100644
--- a/src/hotspot/os/linux/os_linux.hpp
+++ b/src/hotspot/os/linux/os_linux.hpp
@@ -223,6 +223,20 @@ class os::Linux {
   static jboltLog_do_t _jboltLog_do;
   static jboltMerge_judge_t _jboltMerge_judge;
 #endif
+
+  typedef void* (*heap_dict_add_t)(void* key, void* val, void* heap_dict, uint8_t type);
+  typedef void* (*heap_dict_lookup_t)(void* key, void* heap_dict, bool deletable);
+  typedef void (*heap_dict_free_t)(void* heap_dict, bool is_nested);
+  typedef void* (*heap_vector_add_t)(void* val, void* heap_vector, bool &_inserted);
+  typedef void* (*heap_vector_get_next_t)(void* heap_vector, void* heap_vector_node, int &_cnt, void** &_items);
+  typedef void (*heap_vector_free_t)(void* heap_vector);
+  static heap_dict_add_t _heap_dict_add;
+  static heap_dict_lookup_t _heap_dict_lookup;
+  static heap_dict_free_t _heap_dict_free;
+  static heap_vector_add_t _heap_vector_add;
+  static heap_vector_get_next_t _heap_vector_get_next;
+  static heap_vector_free_t _heap_vector_free;
+
   static sched_getcpu_func_t _sched_getcpu;
   static numa_node_to_cpus_func_t _numa_node_to_cpus;
   static numa_node_to_cpus_v2_func_t _numa_node_to_cpus_v2;
@@ -459,6 +473,46 @@ class os::Linux {
     return -1;
   }
 #endif // INCLUDE_JBOLT
+
+  static void* heap_dict_add(void* key, void* val, void* heap_dict, uint8_t type) {
+      if(_heap_dict_add == NULL) {
+          return NULL;
+      }
+      return _heap_dict_add(key, val, heap_dict, type);
+  }
+
+  static void* heap_dict_lookup(void* key, void* heap_dict, bool deletable) {
+      if(_heap_dict_lookup == NULL) {
+          return NULL;
+      }
+      return _heap_dict_lookup(key, heap_dict, deletable);
+  };
+
+  static void heap_dict_free(void* heap_dict, bool is_nested) {
+      if(_heap_dict_free != NULL) {
+          _heap_dict_free(heap_dict, is_nested);
+      }
+  }
+
+  static void* heap_vector_add(void* val, void* heap_vector, bool &_inserted) {
+      if(_heap_vector_add == NULL) {
+          return NULL;
+      }
+     return _heap_vector_add(val, heap_vector, _inserted);
+  }
+  
+  static void* heap_vector_get_next(void* heap_vector, void* heap_vector_node, int &_cnt, void** &_items) {
+      if(_heap_vector_get_next == NULL) {
+          return NULL;
+      }
+      return _heap_vector_get_next(heap_vector, heap_vector_node, _cnt, _items);
+  }
+
+  static void heap_vector_free(void* heap_vector) {
+      if(_heap_vector_free != NULL) {
+          _heap_vector_free(heap_vector);
+      }
+  }
 };
 
 #endif // OS_LINUX_OS_LINUX_HPP
diff --git a/src/hotspot/share/oops/annotations.hpp b/src/hotspot/share/oops/annotations.hpp
index c7919ff0f..0260de2d8 100644
--- a/src/hotspot/share/oops/annotations.hpp
+++ b/src/hotspot/share/oops/annotations.hpp
@@ -41,6 +41,7 @@ typedef Array<u1> AnnotationArray;
 // a type_annotation instance.
 
 class Annotations: public MetaspaceObj {
+ friend class VMStructs;
  friend class JVMCIVMStructs;
 
   // If you add a new field that points to any metaspace object, you
diff --git a/src/hotspot/share/runtime/arguments.cpp b/src/hotspot/share/runtime/arguments.cpp
index 2e2a9a0f2..dd053e458 100644
--- a/src/hotspot/share/runtime/arguments.cpp
+++ b/src/hotspot/share/runtime/arguments.cpp
@@ -58,6 +58,7 @@
 #include "runtime/vm_version.hpp"
 #include "services/management.hpp"
 #include "services/nmtCommon.hpp"
+#include "services/heapRedactor.hpp"
 #include "utilities/align.hpp"
 #include "utilities/debug.hpp"
 #include "utilities/defaultStream.hpp"
@@ -3691,6 +3692,29 @@ jint Arguments::match_special_option_and_act(const JavaVMInitArgs* args,
       vm_exit(0);
     }
 
+    if (match_option(option, "-XX:HeapDumpRedact", &tail)) {
+      // HeapDumpRedact arguments.
+      if (!HeapRedactor::check_launcher_heapdump_redact_support(tail)) {
+        warning("Heap dump redacting did not setup properly, using wrong argument?");
+        vm_exit_during_initialization("Syntax error, expecting -XX:HeapDumpRedact=[off|names|basic|full|diyrules|annotation]",NULL);
+      }
+      continue;
+    }
+
+    // heapDump redact password
+    if(match_option(option, "-XX:RedactPassword=", &tail)) {
+      if(tail == NULL || strlen(tail) == 0) {
+        VerifyRedactPassword = false;
+      } else {
+        char* split_char = strstr(const_cast<char*>(tail), ",");
+        VerifyRedactPassword = !(split_char == NULL || strlen(split_char) < SALT_LEN);
+      }
+      if(!VerifyRedactPassword) {
+        jio_fprintf(defaultStream::output_stream(), "redact password is null or with bad format, disable verify heap dump authority.\n");
+      }
+    }
+
+
 #ifndef PRODUCT
     if (match_option(option, "-XX:+PrintFlagsWithComments")) {
       JVMFlag::printFlags(tty, true);
diff --git a/src/hotspot/share/runtime/globals.hpp b/src/hotspot/share/runtime/globals.hpp
index 231c2ef16..5c028a21d 100644
--- a/src/hotspot/share/runtime/globals.hpp
+++ b/src/hotspot/share/runtime/globals.hpp
@@ -565,6 +565,24 @@ const int ObjectAlignmentInBytes = 8;
           "compression. Otherwise the level must be between 1 and 9.")      \
           range(0, 9)                                                       \
                                                                             \
+  product(ccstr, HeapDumpRedact, NULL, MANAGEABLE,                          \
+          "Redact the heapdump information to remove sensitive data")       \
+                                                                            \
+  product(ccstr, RedactMap, NULL, MANAGEABLE,                               \
+          "Redact the class and field names to other strings")              \
+                                                                            \
+  product(ccstr, RedactMapFile, NULL, MANAGEABLE,                           \
+          "File path of the Redact Map")                                    \
+                                                                            \
+  product(ccstr, RedactClassPath, NULL, MANAGEABLE,                         \
+          "full path of the Redact Annotation")                             \
+                                                                            \
+  product(bool, VerifyRedactPassword, false,                                \
+         "verify authority for operating heapDump redact feature")          \
+                                                                            \
+  product(ccstr, RedactPassword, NULL,                                      \
+         "authority for operating heapDump redact feature, format {password,salt}, salt length >= 8")                 \
+                                                                            \
   product(ccstr, NativeMemoryTracking, DEBUG_ONLY("summary") NOT_DEBUG("off"), \
           "Native memory tracking options")                                 \
                                                                             \
diff --git a/src/hotspot/share/runtime/vmStructs.cpp b/src/hotspot/share/runtime/vmStructs.cpp
index 827cb0cdf..15b1102cb 100644
--- a/src/hotspot/share/runtime/vmStructs.cpp
+++ b/src/hotspot/share/runtime/vmStructs.cpp
@@ -325,7 +325,11 @@
   nonstatic_field(Symbol,                      _body[0],                                      u1)                                    \
   nonstatic_field(TypeArrayKlass,              _max_length,                                   jint)                                  \
   nonstatic_field(OopHandle,                   _obj,                                          oop*)                                  \
-                                                                                                                                     \
+  nonstatic_field(Annotations,                 _class_annotations,                            Array<u1>*)                      \
+  nonstatic_field(Annotations,                 _class_type_annotations,                       Array<u1>*)                      \
+  nonstatic_field(Annotations,                 _fields_annotations,                           Array<Array<u1>*>*)              \
+  nonstatic_field(Annotations,                 _fields_type_annotations,                      Array<Array<u1>*>*)              \
+                                                                                                                                       \
   /***********************/                                                                                                          \
   /* Constant Pool Cache */                                                                                                          \
   /***********************/                                                                                                          \
@@ -477,6 +481,8 @@
   nonstatic_field(Array<Klass*>,               _data[0],                                      Klass*)                                \
   nonstatic_field(Array<ResolvedIndyEntry>,    _length,                                       int)                                   \
   nonstatic_field(Array<ResolvedIndyEntry>,    _data[0],                                      ResolvedIndyEntry)                     \
+  nonstatic_field(Array<Array<u1>*>,           _length,                                       int)                                   \
+  nonstatic_field(Array<Array<u1>*>,           _data[0],                                      Array<u1>*)                            \
                                                                                                                                      \
   /*******************/                                                                                                              \
   /* GrowableArrays  */                                                                                                              \
@@ -1032,6 +1038,7 @@
   unchecked_nonstatic_field(Array<Method*>,           _data,                                  sizeof(Method*))                       \
   unchecked_nonstatic_field(Array<Klass*>,            _data,                                  sizeof(Klass*))                        \
   unchecked_nonstatic_field(Array<ResolvedIndyEntry>, _data,                                  sizeof(ResolvedIndyEntry))             \
+  unchecked_nonstatic_field(Array<Array<u1>*>, _data,                                         sizeof(Array<u1>*))                    \
                                                                                                                                      \
   /*********************************/                                                                                                \
   /* java_lang_Class fields        */                                                                                                \
@@ -1238,6 +1245,7 @@
     declare_type(Method, Metadata)                                        \
     declare_type(MethodCounters, MetaspaceObj)                            \
     declare_type(ConstMethod, MetaspaceObj)                               \
+    declare_type(Annotations, MetaspaceObj)                               \
                                                                           \
   declare_toplevel_type(MethodData::CompilerCounters)                     \
                                                                           \
@@ -1960,6 +1969,7 @@
             declare_type(Array<u2>, MetaspaceObj)                         \
             declare_type(Array<Klass*>, MetaspaceObj)                     \
             declare_type(Array<Method*>, MetaspaceObj)                    \
+            declare_type(Array<Array<u1>*>, MetaspaceObj)                 \
             declare_type(Array<ResolvedIndyEntry>, MetaspaceObj)          \
                                                                           \
    declare_toplevel_type(BitMap)                                          \
diff --git a/src/hotspot/share/services/heapDumper.cpp b/src/hotspot/share/services/heapDumper.cpp
index b426f5d4c..82e721c17 100644
--- a/src/hotspot/share/services/heapDumper.cpp
+++ b/src/hotspot/share/services/heapDumper.cpp
@@ -54,11 +54,13 @@
 #include "runtime/vframe.hpp"
 #include "runtime/vmOperations.hpp"
 #include "runtime/vmThread.hpp"
+#include "runtime/fieldDescriptor.inline.hpp"
 #include "services/heapDumper.hpp"
 #include "services/heapDumperCompression.hpp"
 #include "services/threadService.hpp"
 #include "utilities/macros.hpp"
 #include "utilities/ostream.hpp"
+#include "services/heapRedactor.hpp"
 
 /*
  * HPROF binary format - description copied from:
@@ -413,6 +415,8 @@ class AbstractDumpWriter : public StackObj {
 
   void write_address(address a);
 
+  HeapRedactor* redactor;
+
  public:
   AbstractDumpWriter() :
     _buffer(nullptr),
@@ -427,6 +431,7 @@ class AbstractDumpWriter : public StackObj {
   size_t position() const                       { return _pos; }
   // writer functions
   virtual void write_raw(const void* s, size_t len);
+  void write_zero_raw(void* s, size_t len);
   void write_u1(u1 x);
   void write_u2(u2 x);
   void write_u4(u4 x);
@@ -452,6 +457,12 @@ class AbstractDumpWriter : public StackObj {
     // Force flush to guarantee data from parallel dumper are written.
     flush(true);
   }
+
+  // remove sensitive data from heapdump information
+  void setHeapRedactor(HeapRedactor* value);
+  HeapRedactor* heapRedactor();
+  HeapDumpRedactLevel getHeapDumpRedactLevel();
+
   // Called when finished to release the threads.
   virtual void deactivate() = 0;
 };
@@ -489,6 +500,27 @@ void AbstractDumpWriter::write_raw(const void* s, size_t len) {
   set_position(position() + len);
 }
 
+void AbstractDumpWriter::write_zero_raw(void* s, size_t len) {
+    assert(!_in_dump_segment || (_sub_record_left >= len), "sub-record too large");
+    debug_only(_sub_record_left -= len);
+
+    // flush buffer to make room.
+    while (len > buffer_size() - position()) {
+        assert(!_in_dump_segment || _is_huge_sub_record,
+               "Cannot overflow in non-huge sub-record.");
+
+        size_t to_write = buffer_size() - position();
+        memset(buffer() + position(), 0, to_write);
+        s = (void*) ((char*) s + to_write);
+        len -= to_write;
+        set_position(position() + to_write);
+        flush();
+    }
+
+    memset(buffer() + position(), 0, len);
+    set_position(position() + len);
+}
+
 // Makes sure we inline the fast write into the write_u* functions. This is a big speedup.
 #define WRITE_KNOWN_TYPE(p, len) do { if (can_write_fast((len))) write_fast((p), (len)); \
                                       else write_raw((p), (len)); } while (0)
@@ -608,6 +640,21 @@ void AbstractDumpWriter::end_sub_record() {
   debug_only(_sub_record_ended = true);
 }
 
+void AbstractDumpWriter::setHeapRedactor(HeapRedactor* value) {
+  redactor = value;
+}
+
+HeapRedactor* AbstractDumpWriter::heapRedactor() {
+  return redactor;
+}
+
+HeapDumpRedactLevel AbstractDumpWriter::getHeapDumpRedactLevel() {
+  if(redactor==NULL){
+    return REDACT_OFF;
+  }
+  return redactor->redact_level();
+}
+
 // Supports I/O operations for a dump
 
 class DumpWriter : public AbstractDumpWriter {
@@ -886,6 +933,9 @@ Monitor* ParDumpWriter::_lock = nullptr;
 class DumperClassCacheTable;
 class DumperClassCacheTableEntry;
 
+typedef char* (*CALL_DO_LOOKUP_REPLACE_VALUE)(AbstractDumpWriter*, typeArrayOop);
+typedef void (*CALL_DUMP_INSTANCE_FIELDS_DESCRIPTORS)(AbstractDumpWriter*, Klass*);
+typedef void (*CALL_DUMP_PRIM_ARRAY)(AbstractDumpWriter*, typeArrayOop);
 // Support class with a collection of functions used when dumping the heap
 class DumperSupport : AllStatic {
  public:
@@ -915,14 +965,26 @@ class DumperSupport : AllStatic {
   static void dump_static_fields(AbstractDumpWriter* writer, Klass* k);
   // dump the raw values of the instance fields of the given object
   static void dump_instance_fields(AbstractDumpWriter* writer, oop o, DumperClassCacheTableEntry* class_cache_entry);
+  // dump the redact values of the instance fields of the given object
+  static void dump_instance_redact_fields(AbstractDumpWriter* writer, oop o, DumperClassCacheTableEntry* class_cache_entry, void* replace_value_table, uint container_id);
   // get the count of the instance fields for a given class
   static u2 get_instance_fields_count(InstanceKlass* ik);
   // dumps the definition of the instance fields for a given class
   static void dump_instance_field_descriptors(AbstractDumpWriter* writer, Klass* k);
+  // dumps the definition of the instance fields for a given class
+  static void dump_instance_annotation_field_descriptors(AbstractDumpWriter* writer, Klass* k);
+  // dumps the definition of the instance fields for a given class
+  static void dump_instance_diyrules_field_descriptors(AbstractDumpWriter* writer, Klass* k);
   // creates HPROF_GC_INSTANCE_DUMP record for the given object
   static void dump_instance(AbstractDumpWriter* writer, oop o, DumperClassCacheTable* class_cache);
+  // creates HPROF_GC_INSTANCE_REDACT_DUMP record for the given object
+  static void dump_redact_instance(AbstractDumpWriter* writer, oop o, DumperClassCacheTable* class_cache, uint container_id);
+  // lookup different value type depend on redact mode
+  static char* do_lookup_replace_value_with_symbol(AbstractDumpWriter* writer, typeArrayOop array);
+  static char* do_lookup_replace_value_with_char(AbstractDumpWriter* writer, typeArrayOop array);
+  static bool dump_replace_value(CALL_DO_LOOKUP_REPLACE_VALUE fn, AbstractDumpWriter* writer, typeArrayOop array, uint container_id);
   // creates HPROF_GC_CLASS_DUMP record for the given instance class
-  static void dump_instance_class(AbstractDumpWriter* writer, Klass* k);
+  static void dump_instance_class(CALL_DUMP_INSTANCE_FIELDS_DESCRIPTORS fn, AbstractDumpWriter* writer, Klass* k);
   // creates HPROF_GC_CLASS_DUMP record for a given array class
   static void dump_array_class(AbstractDumpWriter* writer, Klass* k);
 
@@ -930,15 +992,22 @@ class DumperSupport : AllStatic {
   static void dump_object_array(AbstractDumpWriter* writer, objArrayOop array);
   // creates HPROF_GC_PRIM_ARRAY_DUMP record for the given type array
   static void dump_prim_array(AbstractDumpWriter* writer, typeArrayOop array);
+  // creates HPROF_GC_PRIM_ARRAY_REDACT_DUMP record for the given type array
+  static void redact_basic_dump_prim_array(AbstractDumpWriter* writer, typeArrayOop array);
+  static void redact_replace_dump_prim_array(CALL_DO_LOOKUP_REPLACE_VALUE fn, AbstractDumpWriter* writer, typeArrayOop array, uint container_id);
+  static void redact_dump_prim_array(CALL_DUMP_PRIM_ARRAY fn, AbstractDumpWriter* dumpWriter, typeArrayOop o);
   // create HPROF_FRAME record for the given method and bci
   static void dump_stack_frame(AbstractDumpWriter* writer, int frame_serial_num, int class_serial_num, Method* m, int bci);
 
   // check if we need to truncate an array
-  static int calculate_array_max_length(AbstractDumpWriter* writer, arrayOop array, short header_size);
+  static int calculate_array_max_length(AbstractDumpWriter* writer, arrayOop array, short header_size, int char_length = 0);
 
   // fixes up the current dump record and writes HPROF_HEAP_DUMP_END record
   static void end_of_dump(AbstractDumpWriter* writer);
 
+  // is_large function, if oop is large object, retrun true
+  static bool is_large(oop o);
+
   static oop mask_dormant_archived_object(oop o, oop ref_obj) {
     if (o != nullptr && o->klass()->java_mirror_no_keepalive() == nullptr) {
       // Ignore this object since the corresponding java mirror is not loaded.
@@ -974,6 +1043,7 @@ class DumperClassCacheTableEntry : public CHeapObj<mtServiceability> {
 private:
   GrowableArray<char> _sigs_start;
   GrowableArray<int> _offsets;
+  GrowableArray<address> _name_symbol_addrs;
   u4 _instance_size;
   int _entries;
 
@@ -983,6 +1053,7 @@ public:
   int field_count()             { return _entries; }
   char sig_start(int field_idx) { return _sigs_start.at(field_idx); }
   int offset(int field_idx)     { return _offsets.at(field_idx); }
+  address name_symbol_addrs(int field_idx) { return _name_symbol_addrs.at(field_idx); }
   u4 instance_size()            { return _instance_size; }
 };
 
@@ -1033,6 +1104,7 @@ public:
           Symbol* sig = fld.signature();
           entry->_sigs_start.push(sig->char_at(0));
           entry->_offsets.push(fld.offset());
+          entry->_name_symbol_addrs.push((address)((uintptr_t)fld.name()));
           entry->_entries++;
           entry->_instance_size += DumperSupport::sig2size(sig);
         }
@@ -1309,6 +1381,37 @@ void DumperSupport::dump_instance_fields(AbstractDumpWriter* writer, oop o, Dump
   }
 }
 
+// dump the diyrules values of the instance fields of the given object
+void DumperSupport::dump_instance_redact_fields(AbstractDumpWriter* writer, oop o, DumperClassCacheTableEntry* class_cache_entry, void* replace_value_table, uint container_id) {
+  InstanceKlass* ik = InstanceKlass::cast(o->klass());
+
+  for (int idx = 0; idx < class_cache_entry->field_count(); idx++) {
+
+      char type = class_cache_entry->sig_start(idx);
+      int offset = class_cache_entry->offset(idx);
+
+      ResourceMark rm;
+      address field_adr = class_cache_entry->name_symbol_addrs(idx);
+      void* replace_value = writer->heapRedactor()->lookup_value(field_adr, replace_value_table, false);
+
+      if (replace_value != nullptr) {
+          oop field_oop = o->obj_field_access<ON_UNKNOWN_OOP_REF | AS_NO_KEEPALIVE>(offset);
+          if (!java_lang_String::is_instance(field_oop)) {
+              // data not completed, skip this field value;
+              writer->write_objectID(nullptr);
+              continue;
+          }
+
+          typeArrayOop field_value_oop = java_lang_String::value(field_oop);
+          address type_array_addr = cast_from_oop<address>(field_value_oop);
+          writer->heapRedactor()->insert_anonymous_value(type_array_addr, replace_value, container_id);
+          writer->write_objectID(field_oop);
+          continue;
+      }
+      dump_field_value(writer, type, o, offset);
+  }
+}
+
 // dumps the definition of the instance fields for a given class
 u2 DumperSupport::get_instance_fields_count(InstanceKlass* ik) {
   u2 field_count = 0;
@@ -1335,6 +1438,97 @@ void DumperSupport::dump_instance_field_descriptors(AbstractDumpWriter* writer,
   }
 }
 
+// dumps the definition of the instance fields for a given class
+void DumperSupport::dump_instance_annotation_field_descriptors(AbstractDumpWriter* writer, Klass* k) {
+    ResourceMark rm;
+    InstanceKlass* ik = InstanceKlass::cast(k);
+    Symbol *class_name_symbol = ik->name();
+    bool in_exclude_package = false;
+    if (Symbol::is_valid(class_name_symbol)) {
+        char *class_name = class_name_symbol->as_C_string();
+        in_exclude_package = (strncmp("java/", class_name, 5) == 0) || (strncmp("org/springframework", class_name, 19) == 0);
+    }
+
+    if(in_exclude_package) {
+        DumperSupport::dump_instance_field_descriptors(writer, k);
+        return;
+    }
+
+    address obj_adr = (address)((uintptr_t)class_name_symbol);
+    // dump the field descriptors
+    for (JavaFieldStream fld(ik); !fld.done(); fld.next()) {
+        if (!fld.access_flags().is_static()) {
+            Symbol* sig = fld.signature();
+            Symbol* field_name = fld.name();
+
+            writer->write_symbolID(field_name);   // name
+            writer->write_u1(sig2tag(sig));       // type
+
+            if(strcmp(sig->as_C_string(), "Ljava/lang/String;") != 0) {
+                continue;
+            }
+
+            AnnotationArray *field_annotations = fld.field_descriptor().annotations();
+            if (field_annotations == nullptr || field_annotations->length() == 0) {
+                continue;
+            }
+
+            // byte index into field_annotations
+            ConstantPool *cp = fld.field_descriptor().field_holder()->constants();
+            int byte_i = 0;
+            if (writer->heapRedactor()->lookup_annotation_index_in_constant_pool(field_annotations, cp, byte_i)) {
+                address element_value_addr = (address) field_annotations->adr_at(byte_i);
+                u2 cp_str_index = Bytes::get_Java_u2(element_value_addr);
+                Symbol *element_value_symbol = cp->symbol_at(cp_str_index);
+
+                address field_adr = (address) ((uintptr_t) field_name);
+                writer->heapRedactor()->insert_class_field_value(obj_adr, field_adr, element_value_symbol);
+            }
+        }
+    }
+}
+
+// dumps the definition of the instance fields for a given class
+void DumperSupport::dump_instance_diyrules_field_descriptors(AbstractDumpWriter *writer, Klass *k) {
+    ResourceMark rm;
+    InstanceKlass* ik = InstanceKlass::cast(k);
+    Symbol *class_name_symbol = ik->name();
+    void* redact_class_table = nullptr;
+    bool has_diyrules = false;
+    if (Symbol::is_valid(class_name_symbol)) {
+        char *class_name = class_name_symbol->as_C_string();
+        redact_class_table = writer->heapRedactor()->lookup_class_rules(class_name);
+        has_diyrules = (redact_class_table != nullptr);
+    }
+
+    if (!has_diyrules) {
+        DumperSupport::dump_instance_field_descriptors(writer, k);
+        return;
+    }
+
+    address obj_adr = (address) ((uintptr_t) class_name_symbol);
+    // dump the field descriptors
+    for (JavaFieldStream fld(ik); !fld.done(); fld.next()) {
+        if (!fld.access_flags().is_static()) {
+            Symbol* sig = fld.signature();
+            Symbol* field_name = fld.name();
+
+            writer->write_symbolID(field_name);   // name
+            writer->write_u1(sig2tag(sig));       // type
+
+            if(strcmp(sig->as_C_string(), "Ljava/lang/String;") != 0) {
+                continue;
+            }
+            char *field_name_str = field_name->as_C_string();
+            char *replace_value = (char *) writer->heapRedactor()->lookup_value(field_name_str, redact_class_table, false);
+            if (replace_value != nullptr) {
+                address field_adr = (address) ((uintptr_t) field_name);
+                writer->heapRedactor()->insert_class_field_value(obj_adr, field_adr, replace_value);
+            }
+        }
+    }
+}
+
 // creates HPROF_GC_INSTANCE_DUMP record for the given object
 void DumperSupport::dump_instance(AbstractDumpWriter* writer, oop o, DumperClassCacheTable* class_cache) {
   InstanceKlass* ik = InstanceKlass::cast(o->klass());
@@ -1360,8 +1554,104 @@ void DumperSupport::dump_instance(AbstractDumpWriter* writer, oop o, DumperClass
   writer->end_sub_record();
 }
 
+// creates HPROF_GC_INSTANCE_REDACT_DUMP record for the given object
+void DumperSupport::dump_redact_instance(AbstractDumpWriter* writer, oop o, DumperClassCacheTable* class_cache, uint container_id) {
+    InstanceKlass* ik = InstanceKlass::cast(o->klass());
+
+    DumperClassCacheTableEntry* cache_entry = class_cache->lookup_or_create(ik);
+
+    u4 is = instance_size(ik);
+    u4 size = 1 + sizeof(address) + 4 + sizeof(address) + 4 + is;
+
+    writer->start_sub_record(HPROF_GC_INSTANCE_DUMP, size);
+    writer->write_objectID(o);
+    writer->write_u4(STACK_TRACE_ID);
+
+    // class ID
+    writer->write_classID(ik);
+
+    // number of bytes that follow
+    writer->write_u4(is);
+
+    // field values
+    void* replace_value_table = nullptr;
+    InstanceKlass* java_super = ik;
+    do {
+        Symbol * class_name_symbol = java_super->name();
+        address obj_adr = (address)((uintptr_t)class_name_symbol);
+        replace_value_table = writer->heapRedactor()->lookup_class_value(obj_adr);
+        java_super = java_super->java_super();
+    } while (replace_value_table == nullptr && java_super != nullptr);
+
+    bool has_rules = replace_value_table != nullptr;
+    if(has_rules) {
+        dump_instance_redact_fields(writer, o, cache_entry, replace_value_table, container_id);
+    } else {
+        dump_instance_fields(writer, o, cache_entry);
+    }
+
+    writer->end_sub_record();
+}
+
+char* DumperSupport::do_lookup_replace_value_with_symbol(AbstractDumpWriter* writer, typeArrayOop array) {
+    address obj_addr = cast_from_oop<address>(array);
+    Symbol* anonymous_value_symbol = writer->heapRedactor()->lookup_replace_value<Symbol*>(obj_addr);
+    if(anonymous_value_symbol == nullptr) {
+        return nullptr;
+    }
+    return anonymous_value_symbol->as_C_string();
+}
+
+char* DumperSupport::do_lookup_replace_value_with_char(AbstractDumpWriter* writer, typeArrayOop array) {
+    address obj_addr = cast_from_oop<address>(array);
+    char* anonymous_value = writer->heapRedactor()->lookup_replace_value<char*>(obj_addr);
+    return anonymous_value;
+}
+
+bool DumperSupport::dump_replace_value(CALL_DO_LOOKUP_REPLACE_VALUE fn, AbstractDumpWriter* writer, typeArrayOop array, uint container_id) {
+    BasicType type = TypeArrayKlass::cast(array->klass())->element_type();
+    if(type != T_BYTE) {
+        return false;
+    }
+
+    // 2 * sizeof(u1) + 2 * sizeof(u4) + sizeof(objectID)
+    short header_size = 2 * 1 + 2 * 4 + sizeof(address);
+
+    int length = 0;
+
+    char *anonymous_value = nullptr;
+    anonymous_value = fn(writer, array);
+    if(anonymous_value == nullptr) {
+        // record all array, expect who's replace value can be find now
+        return writer->heapRedactor()->record_typeArrayOop(array, container_id);
+    }
+
+    size_t char_length = strlen(anonymous_value);
+    length = DumperSupport::calculate_array_max_length(writer, array, header_size, char_length);
+
+    int type_size = type2aelembytes(type);
+    u4 length_in_bytes = (u4)length * type_size;
+    u4 size = header_size + length_in_bytes;
+
+    writer->start_sub_record(HPROF_GC_PRIM_ARRAY_DUMP, size);
+    writer->write_objectID(array);
+    writer->write_u4(STACK_TRACE_ID);
+    writer->write_u4(length);
+    writer->write_u1(HPROF_BYTE);
+
+    // nothing to copy
+    if (length == 0) {
+        writer->end_sub_record();
+        return true;
+    }
+
+    writer->write_raw(anonymous_value, char_length);
+    writer->end_sub_record();
+    return true;
+}
+
 // creates HPROF_GC_CLASS_DUMP record for the given instance class
-void DumperSupport::dump_instance_class(AbstractDumpWriter* writer, Klass* k) {
+void DumperSupport::dump_instance_class(CALL_DUMP_INSTANCE_FIELDS_DESCRIPTORS fn, AbstractDumpWriter* writer, Klass* k) {
   InstanceKlass* ik = InstanceKlass::cast(k);
 
   // We can safepoint and do a heap dump at a point where we have a Klass,
@@ -1411,7 +1701,7 @@ void DumperSupport::dump_instance_class(AbstractDumpWriter* writer, Klass* k) {
 
   // description of instance fields
   writer->write_u2(instance_fields_count);
-  dump_instance_field_descriptors(writer, ik);
+  fn(writer, ik);
 
   writer->end_sub_record();
 }
@@ -1454,12 +1744,11 @@ void DumperSupport::dump_array_class(AbstractDumpWriter* writer, Klass* k) {
 
 // Hprof uses an u4 as record length field,
 // which means we need to truncate arrays that are too long.
-int DumperSupport::calculate_array_max_length(AbstractDumpWriter* writer, arrayOop array, short header_size) {
+int DumperSupport::calculate_array_max_length(AbstractDumpWriter* writer, arrayOop array, short header_size, int char_length) {
   BasicType type = ArrayKlass::cast(array->klass())->element_type();
   assert(type >= T_BOOLEAN && type <= T_OBJECT, "invalid array element type");
 
-  int length = array->length();
-
+  int length = char_length == 0 ? array->length() : char_length;
   int type_size;
   if (type == T_OBJECT) {
     type_size = sizeof(address);
@@ -1543,7 +1832,7 @@ void DumperSupport::dump_prim_array(AbstractDumpWriter* writer, typeArrayOop arr
       break;
     }
     case T_BYTE : {
-      writer->write_raw(array->byte_at_addr(0), length_in_bytes);
+      writer->write_raw((void*)(array->byte_at_addr(0)), length_in_bytes);
       break;
     }
     case T_CHAR : {
@@ -1601,6 +1890,101 @@ void DumperSupport::dump_prim_array(AbstractDumpWriter* writer, typeArrayOop arr
   writer->end_sub_record();
 }
 
+// creates HPROF_GC_PRIM_ARRAY_DUMP redact record for the given type array
+void DumperSupport::redact_basic_dump_prim_array(AbstractDumpWriter* writer, typeArrayOop array) {
+  BasicType type = TypeArrayKlass::cast(array->klass())->element_type();
+
+  // 2 * sizeof(u1) + 2 * sizeof(u4) + sizeof(objectID)
+  short header_size = 2 * 1 + 2 * 4 + sizeof(address);
+
+  int length = calculate_array_max_length(writer, array, header_size);
+  int type_size = type2aelembytes(type);
+  u4 length_in_bytes = (u4)length * type_size;
+  u4 size = header_size + length_in_bytes;
+
+  writer->start_sub_record(HPROF_GC_PRIM_ARRAY_DUMP, size);
+  writer->write_objectID(array);
+  writer->write_u4(STACK_TRACE_ID);
+  writer->write_u4(length);
+  writer->write_u1(type2tag(type));
+
+  // nothing to copy
+  if (length == 0) {
+    writer->end_sub_record();
+    return;
+  }
+
+  // If the byte ordering is big endian then we can copy most types directly
+
+  switch (type) {
+    case T_INT : {
+      writer->write_zero_raw((void*)(array->int_at_addr(0)), length_in_bytes);
+      break;
+    }
+    case T_BYTE : {
+      writer->write_zero_raw((void*)(array->byte_at_addr(0)), length_in_bytes);
+      break;
+    }
+    case T_CHAR : {
+      writer->write_zero_raw((void*)(array->char_at_addr(0)), length_in_bytes);
+      break;
+    }
+    case T_SHORT : {
+      if (Endian::is_Java_byte_ordering_different()) {
+        WRITE_ARRAY(array, short, u2, length);
+      } else {
+        writer->write_raw((void*)(array->short_at_addr(0)), length_in_bytes);
+      }
+      break;
+    }
+    case T_BOOLEAN : {
+      if (Endian::is_Java_byte_ordering_different()) {
+        WRITE_ARRAY(array, bool, u1, length);
+      } else {
+        writer->write_raw((void*)(array->bool_at_addr(0)), length_in_bytes);
+      }
+      break;
+    }
+    case T_LONG : {
+      if (Endian::is_Java_byte_ordering_different()) {
+        WRITE_ARRAY(array, long, u8, length);
+      } else {
+        writer->write_raw((void*)(array->long_at_addr(0)), length_in_bytes);
+      }
+      break;
+    }
+
+      // handle float/doubles in a special value to ensure than NaNs are
+      // written correctly. TO DO: Check if we can avoid this on processors that
+      // use IEEE 754.
+
+    case T_FLOAT : {
+      for (int i = 0; i < length; i++) {
+        dump_float(writer, array->float_at(i));
+      }
+      break;
+    }
+    case T_DOUBLE : {
+      for (int i = 0; i < length; i++) {
+        dump_double(writer, array->double_at(i));
+      }
+      break;
+    }
+    default : ShouldNotReachHere();
+  }
+
+  writer->end_sub_record();
+}
+
+// creates HPROF_GC_PRIM_ARRAY_DUMP redact record for the given type array
+void DumperSupport::redact_replace_dump_prim_array(CALL_DO_LOOKUP_REPLACE_VALUE fn, AbstractDumpWriter *writer, typeArrayOop array, uint container_id) {
+    if(dump_replace_value(fn, writer, array, container_id)) {
+        return;
+    }
+
+    DumperSupport::dump_prim_array(writer, array);
+}
+
 // create a HPROF_FRAME record of the given Method* and bci
 void DumperSupport::dump_stack_frame(AbstractDumpWriter* writer,
                                      int frame_serial_num,
@@ -1650,6 +2034,39 @@ void SymbolTableDumper::do_symbol(Symbol** p) {
   }
 }
 
+// Support class used to generate HPROF_UTF8 records from the entries in the
+// SymbolTable and Redact the sensitive String.
+
+class SymbolTableRedactDumper : public SymbolClosure {
+private:
+    AbstractDumpWriter* _writer;
+    AbstractDumpWriter* writer() const                { return _writer; }
+public:
+    SymbolTableRedactDumper(AbstractDumpWriter* writer)     { _writer = writer; }
+    void do_symbol(Symbol** p);
+};
+
+void SymbolTableRedactDumper::do_symbol(Symbol** p) {
+  ResourceMark rm;
+  Symbol* sym = *p;
+  int len = sym->utf8_length();
+  if (len > 0) {
+    char* s = sym->as_utf8();
+
+    char* redact_field = NULL;
+    HeapDumpRedactLevel level = writer()->getHeapDumpRedactLevel();
+    if((level == REDACT_NAMES || level == REDACT_FULL) &&
+       (redact_field = writer()->heapRedactor()->lookup_redact_name(s)) != NULL){
+      len = (int)strlen(redact_field);
+      s = redact_field;
+    }
+
+    DumperSupport::write_header(writer(), HPROF_UTF8, oopSize + len);
+    writer()->write_symbolID(sym);
+    writer()->write_raw(s, len);
+  }
+}
+
 // Support class used to generate HPROF_GC_ROOT_JNI_LOCAL records
 
 class JNILocalsDumper : public OopClosure {
@@ -1809,17 +2226,19 @@ class HeapObjectDumper : public ObjectClosure {
  private:
   AbstractDumpWriter* _writer;
   HeapDumpLargeObjectList* _list;
+  CALL_DUMP_PRIM_ARRAY _redact_dump_prim_array;
 
   AbstractDumpWriter* writer()                  { return _writer; }
-  bool is_large(oop o);
+  // bool is_large(oop o);
 
   DumperClassCacheTable _class_cache;
 
  public:
-  HeapObjectDumper(AbstractDumpWriter* writer, HeapDumpLargeObjectList* list = nullptr) {
-    _writer = writer;
-    _list = list;
-  }
+  HeapObjectDumper(AbstractDumpWriter* writer, CALL_DUMP_PRIM_ARRAY fn = DumperSupport::dump_prim_array, HeapDumpLargeObjectList* list = nullptr) {
+     _writer = writer;
+     _list = list;
+     _redact_dump_prim_array = fn;
+   }
 
   // called for each object in the heap
   void do_object(oop o);
@@ -1839,7 +2258,7 @@ void HeapObjectDumper::do_object(oop o) {
 
   // If large object list exists and it is large object/array,
   // add oop into the list and skip scan. VM thread will process it later.
-  if (_list != nullptr && is_large(o)) {
+  if (_list != nullptr && DumperSupport::is_large(o)) {
     _list->atomic_push(o);
     return;
   }
@@ -1852,11 +2271,72 @@ void HeapObjectDumper::do_object(oop o) {
     DumperSupport::dump_object_array(writer(), objArrayOop(o));
   } else if (o->is_typeArray()) {
     // create a HPROF_GC_PRIM_ARRAY_DUMP record for each type array
-    DumperSupport::dump_prim_array(writer(), typeArrayOop(o));
+    DumperSupport::redact_dump_prim_array(_redact_dump_prim_array, writer(), typeArrayOop(o));
   }
 }
 
-bool HeapObjectDumper::is_large(oop o) {
+void DumperSupport::redact_dump_prim_array(CALL_DUMP_PRIM_ARRAY fn, AbstractDumpWriter* dumpWriter, typeArrayOop o){
+  fn(dumpWriter, o);
+}
+
+class HeapObjectRedactDumper : public ObjectClosure {
+private:
+    AbstractDumpWriter* _writer;
+    HeapDumpLargeObjectList* _list;
+
+    AbstractDumpWriter* writer()                  { return _writer; }
+
+    CALL_DO_LOOKUP_REPLACE_VALUE _do_lookup_replace_value;
+
+    DumperClassCacheTable _class_cache;
+
+    uint container_id;
+
+public:
+    HeapObjectRedactDumper(AbstractDumpWriter* writer, CALL_DO_LOOKUP_REPLACE_VALUE  do_lookup_replace_value, HeapDumpLargeObjectList* list = nullptr, uint id = 0) {
+      _writer = writer;
+      _list = list;
+      container_id = id;
+      _do_lookup_replace_value = do_lookup_replace_value;
+    }
+
+    // called for each object in the heap
+    void do_object(oop o);
+};
+
+void HeapObjectRedactDumper::do_object(oop o) {
+  // skip classes as these emitted as HPROF_GC_CLASS_DUMP records
+  if (o->klass() == vmClasses::Class_klass()) {
+    if (!java_lang_Class::is_primitive(o)) {
+      return;
+    }
+  }
+
+  if (DumperSupport::mask_dormant_archived_object(o, nullptr) == nullptr) {
+    log_debug(cds, heap)("skipped dormant archived object " INTPTR_FORMAT " (%s)", p2i(o), o->klass()->external_name());
+    return;
+  }
+
+  // If large object list exists and it is large object/array,
+  // and oop into the list and skip scan. VM thread will process it later.
+  if (_list != nullptr && DumperSupport::is_large(o)) {
+    _list->atomic_push(o);
+    return;
+  }
+
+  if (o->is_instance()) {
+    // create a HPROF_GC_INSTANCE record for each object
+    DumperSupport::dump_redact_instance(writer(), o, &_class_cache, container_id);
+  } else if (o->is_objArray()) {
+    // create a HPROF_GC_OBJ_ARRAY_DUMP record for each object array
+    DumperSupport::dump_object_array(writer(), objArrayOop(o));
+  } else if (o->is_typeArray()) {
+    // create a HPROF_GC_PRIM_ARRAY_DUMP record for each type array
+     DumperSupport::redact_replace_dump_prim_array(_do_lookup_replace_value, writer(), typeArrayOop(o), container_id);
+  }
+}
+
+bool DumperSupport::is_large(oop o) {
   size_t size = 0;
   if (o->is_instance()) {
     // Use o->size() * 8 as the upper limit of instance size to avoid iterating static fields
@@ -1941,6 +2421,7 @@ class VM_HeapDumper : public VM_GC_Operation, public WorkerTask {
   ThreadStackTrace**      _stack_traces;
   int                     _num_threads;
   // parallel heap dump support
+  static CALL_DUMP_INSTANCE_FIELDS_DESCRIPTORS _dump_instance_fields_descriptors;
   uint                    _num_dumper_threads;
   uint                    _num_writer_threads;
   DumperController*       _dumper_controller;
@@ -2033,6 +2514,9 @@ class VM_HeapDumper : public VM_GC_Operation, public WorkerTask {
   // HPROF_TRACE and HPROF_FRAME records
   void dump_stack_traces();
 
+  // HeapVector Records
+  void do_heapVector();
+
   // large objects
   void dump_large_objects(ObjectClosure* writer);
 
@@ -2052,6 +2536,14 @@ class VM_HeapDumper : public VM_GC_Operation, public WorkerTask {
     _dumper_controller = nullptr;
     _poi = nullptr;
     _large_object_list = new (std::nothrow) HeapDumpLargeObjectList();
+    if(writer->getHeapDumpRedactLevel() == REDACT_ANNOTATION) {
+      _dump_instance_fields_descriptors = DumperSupport::dump_instance_annotation_field_descriptors;
+    } else if(writer->getHeapDumpRedactLevel() == REDACT_DIYRULES) {
+      _dump_instance_fields_descriptors = DumperSupport::dump_instance_diyrules_field_descriptors;
+    } else {
+      _dump_instance_fields_descriptors = DumperSupport::dump_instance_field_descriptors;
+    }
+
     if (oome) {
       assert(!Thread::current()->is_VM_thread(), "Dump from OutOfMemoryError cannot be called by the VMThread");
       // get OutOfMemoryError zero-parameter constructor
@@ -2089,6 +2581,7 @@ class VM_HeapDumper : public VM_GC_Operation, public WorkerTask {
 
 VM_HeapDumper* VM_HeapDumper::_global_dumper = nullptr;
 DumpWriter*    VM_HeapDumper::_global_writer = nullptr;
+CALL_DUMP_INSTANCE_FIELDS_DESCRIPTORS    VM_HeapDumper::_dump_instance_fields_descriptors = nullptr;
 
 bool VM_HeapDumper::skip_operation() const {
   return false;
@@ -2131,8 +2624,8 @@ void VM_HeapDumper::do_load_class(Klass* k) {
 // writes a HPROF_GC_CLASS_DUMP record for the given class
 void VM_HeapDumper::do_class_dump(Klass* k) {
   if (k->is_instance_klass()) {
-    DumperSupport::dump_instance_class(writer(), k);
-  } else {
+    DumperSupport::dump_instance_class(_dump_instance_fields_descriptors, writer(), k);
+   } else {
     DumperSupport::dump_array_class(writer(), k);
   }
 }
@@ -2317,14 +2810,15 @@ void VM_HeapDumper::doit() {
   set_global_writer();
 
   WorkerThreads* workers = ch->safepoint_workers();
-
   if (workers == nullptr) {
     // Use serial dump, set dumper threads and writer threads number to 1.
     _num_dumper_threads=1;
     _num_writer_threads=1;
+    writer()->heapRedactor()->init_containers(_num_dumper_threads);
     work(0);
   } else {
     prepare_parallel_dump(workers->active_workers());
+    writer()->heapRedactor()->init_containers(_num_dumper_threads);
     if (_num_dumper_threads > 1) {
       ParallelObjectIterator poi(_num_dumper_threads);
       _poi = &poi;
@@ -2361,8 +2855,14 @@ void VM_HeapDumper::work(uint worker_id) {
     // timestamp is current time in ms
     writer()->write_u8(os::javaTimeMillis());
     // HPROF_UTF8 records
-    SymbolTableDumper sym_dumper(writer());
-    SymbolTable::symbols_do(&sym_dumper);
+    if(writer()->heapRedactor() != NULL && (writer()->heapRedactor()->redact_level() == REDACT_NAMES ||
+                                            writer()->heapRedactor()->redact_level() == REDACT_FULL)){
+      SymbolTableRedactDumper sym_dumper(writer());
+      SymbolTable::symbols_do(&sym_dumper);
+    } else{
+      SymbolTableDumper sym_dumper(writer());
+      SymbolTable::symbols_do(&sym_dumper);
+    }
 
     // write HPROF_LOAD_CLASS records
     {
@@ -2403,8 +2903,20 @@ void VM_HeapDumper::work(uint worker_id) {
   // of the heap dump.
   if (_num_dumper_threads <= 1) {
     ResourceMark rm;
-    HeapObjectDumper obj_dumper(writer());
-    Universe::heap()->object_iterate(&obj_dumper);
+    if(writer()->heapRedactor() != NULL && (writer()->heapRedactor()->redact_level() == REDACT_BASIC ||
+                                            writer()->heapRedactor()->redact_level() == REDACT_FULL)) {
+      HeapObjectDumper obj_dumper(writer(), DumperSupport::redact_basic_dump_prim_array);
+      Universe::heap()->object_iterate(&obj_dumper);
+    } else if(writer()->heapRedactor() != NULL && writer()->heapRedactor()->redact_level() == REDACT_ANNOTATION) {
+      HeapObjectRedactDumper obj_dumper(writer(), DumperSupport::do_lookup_replace_value_with_symbol);
+      Universe::heap()->object_iterate(&obj_dumper);
+    } else if(writer()->heapRedactor() != NULL && writer()->heapRedactor()->redact_level() == REDACT_DIYRULES) {
+      HeapObjectRedactDumper obj_dumper(writer(), DumperSupport::do_lookup_replace_value_with_char);
+      Universe::heap()->object_iterate(&obj_dumper);
+    } else {
+      HeapObjectDumper obj_dumper(writer());
+      Universe::heap()->object_iterate(&obj_dumper);
+    }
   } else {
     assert(get_worker_type(worker_id) == DumperType
           || get_worker_type(worker_id) == VMDumperType,
@@ -2418,10 +2930,23 @@ void VM_HeapDumper::work(uint worker_id) {
     // Heap iteration.
     {
        ParDumpWriter pw(writer());
+       pw.setHeapRedactor(writer()->heapRedactor());
        {
          ResourceMark rm;
-         HeapObjectDumper obj_dumper(&pw, _large_object_list);
-         _poi->object_iterate(&obj_dumper, worker_id);
+         if(writer()->heapRedactor() != NULL && (writer()->heapRedactor()->redact_level() == REDACT_BASIC ||
+                                            writer()->heapRedactor()->redact_level() == REDACT_FULL)) {
+            HeapObjectDumper obj_dumper(&pw, DumperSupport::redact_basic_dump_prim_array, _large_object_list);
+            _poi->object_iterate(&obj_dumper, worker_id);
+          } else if(writer()->heapRedactor() != NULL && writer()->heapRedactor()->redact_level() == REDACT_ANNOTATION) {
+            HeapObjectRedactDumper obj_dumper(&pw, DumperSupport::do_lookup_replace_value_with_symbol, _large_object_list, worker_id);
+            _poi->object_iterate(&obj_dumper, worker_id);
+          } else if(writer()->heapRedactor() != NULL && writer()->heapRedactor()->redact_level() == REDACT_DIYRULES) {
+            HeapObjectRedactDumper obj_dumper(&pw, DumperSupport::do_lookup_replace_value_with_char, _large_object_list, worker_id);
+            _poi->object_iterate(&obj_dumper, worker_id);
+          } else {
+            HeapObjectDumper obj_dumper(&pw, DumperSupport::dump_prim_array, _large_object_list);
+            _poi->object_iterate(&obj_dumper, worker_id);
+          }
        }
 
        if (get_worker_type(worker_id) == VMDumperType) {
@@ -2441,8 +2966,26 @@ void VM_HeapDumper::work(uint worker_id) {
   assert(get_worker_type(worker_id) == VMDumperType, "Heap dumper must be VMDumper");
   // Use writer() rather than ParDumpWriter to avoid memory consumption.
   ResourceMark rm;
-  HeapObjectDumper obj_dumper(writer());
-  dump_large_objects(&obj_dumper);
+  if(writer()->heapRedactor() != NULL && (writer()->heapRedactor()->redact_level() == REDACT_BASIC ||
+                                          writer()->heapRedactor()->redact_level() == REDACT_FULL)) {
+    HeapObjectDumper obj_dumper(writer(), DumperSupport::redact_basic_dump_prim_array);
+    dump_large_objects(&obj_dumper);
+  } else if(writer()->heapRedactor() != NULL && writer()->heapRedactor()->redact_level() == REDACT_ANNOTATION) {
+    HeapObjectRedactDumper obj_dumper(writer(), DumperSupport::do_lookup_replace_value_with_symbol);
+    dump_large_objects(&obj_dumper);
+  } else if(writer()->heapRedactor() != NULL && writer()->heapRedactor()->redact_level() == REDACT_DIYRULES) {
+    HeapObjectRedactDumper obj_dumper(writer(), DumperSupport::do_lookup_replace_value_with_char);
+    dump_large_objects(&obj_dumper);
+  } else {
+    HeapObjectDumper obj_dumper(writer());
+    dump_large_objects(&obj_dumper);
+  }
+
+  // if value in INSTANCE is sensitive
+  // and redact level is REDACT_ANNOTATION
+  // writes HeapVector here
+  do_heapVector();
+
   // Writes the HPROF_HEAP_DUMP_END record.
   DumperSupport::end_of_dump(writer());
   // We are done with writing. Release the worker threads.
@@ -2507,6 +3050,68 @@ void VM_HeapDumper::dump_stack_traces() {
   }
 }
 
+void VM_HeapDumper::do_heapVector(){
+  CALL_DO_LOOKUP_REPLACE_VALUE fn = nullptr;
+  if(writer()->getHeapDumpRedactLevel() == REDACT_ANNOTATION) {
+    fn = DumperSupport::do_lookup_replace_value_with_symbol;
+  } else if(writer()->getHeapDumpRedactLevel() == REDACT_DIYRULES) {
+    fn = DumperSupport::do_lookup_replace_value_with_char;
+  } else {
+    return;
+  }
+
+  BasicType type = T_BYTE;
+  short header_size = 2 * 1 + 2 * 4 + sizeof(address);
+  int type_size = type2aelembytes(type);
+  uint max_bytes = max_juint - header_size;
+
+  uint container_nums = writer()->heapRedactor()->get_container_nums();
+  for (uint container_index = 0; container_index < container_nums; container_index++) {
+    int node_len = 0, i =0;
+    void** items = nullptr;
+    void *vector_node = writer()->heapRedactor()->get_vector_node_next(nullptr, node_len, items, container_index);
+    while (vector_node != NULL && items != NULL) {
+      for (i = 0; i < node_len; i++) {
+        typeArrayOop array = (typeArrayOopDesc*)items[i];
+
+        char *anonymous_value = fn(writer(), array);
+        int length = anonymous_value == NULL ? array->length() : strlen(anonymous_value);
+
+        u4 length_in_bytes = (u4) length * type_size;
+        if (length_in_bytes > max_bytes) {
+          length = max_bytes / type_size;
+          length_in_bytes = (size_t)length * type_size;
+        }
+        u4 size = header_size + length_in_bytes;
+
+        writer()->start_sub_record(HPROF_GC_PRIM_ARRAY_DUMP, size);
+        writer()->write_objectID(array);
+        writer()->write_u4(STACK_TRACE_ID);
+        writer()->write_u4(length);
+        writer()->write_u1(HPROF_BYTE);
+
+        // nothing to copy
+        if (length == 0) {
+          writer()->end_sub_record();
+          continue;
+        }
+        if(anonymous_value != nullptr){
+            writer()->write_raw(anonymous_value, length);
+        } else {
+            writer()->write_raw((void *) (array->byte_at_addr(0)), length_in_bytes);
+        }
+        writer()->end_sub_record();
+      }
+
+      // clear current node info, maybe next node items is NULL, node_len = 0 will skip this NULL point error
+      node_len = 0;
+      items = nullptr;
+      void *temp = writer()->heapRedactor()->get_vector_node_next(vector_node, node_len, items, container_index);
+      vector_node = temp;
+    }
+  }
+}
+
 // dump the large objects.
 void VM_HeapDumper::dump_large_objects(ObjectClosure* cl) {
   _large_object_list->drain(cl);
@@ -2516,9 +3121,22 @@ void VM_HeapDumper::dump_large_objects(ObjectClosure* cl) {
 int HeapDumper::dump(const char* path, outputStream* out, int compression, bool overwrite, uint num_dump_threads) {
   assert(path != nullptr && strlen(path) > 0, "path missing");
 
+  const char* path_and_anonymous = path;
+  const char* redact_params = nullptr;
+  // parse args[0] to get real path and redact_params
+  const char* split_char = strstr(path_and_anonymous, ";");
+  size_t path_length = (split_char == nullptr) ? strlen(path_and_anonymous) : (unsigned long)(split_char - path_and_anonymous);
+  size_t path_and_anonymous_length = strlen(path_and_anonymous);
+  char* _path = NEW_C_HEAP_ARRAY(char, path_and_anonymous_length + 1, mtInternal);
+  strncpy(_path, path_and_anonymous, path_and_anonymous_length + 1);
+  _path[path_length] = '\0';
+  if (split_char != NULL) {
+    redact_params = split_char + 1;
+  }
+
   // print message in interactive case
   if (out != nullptr) {
-    out->print_cr("Dumping heap to %s ...", path);
+    out->print_cr("Dumping heap to %s ...", _path);
     timer()->start();
   }
   // create JFR event
@@ -2535,17 +3153,26 @@ int HeapDumper::dump(const char* path, outputStream* out, int compression, bool
     }
   }
 
-  DumpWriter writer(new (std::nothrow) FileWriter(path, overwrite), compressor);
+  HeapRedactor heapRedactor(redact_params, out);
+  DumpWriter writer(new (std::nothrow) FileWriter(_path, overwrite), compressor);
+  if(heapRedactor.redact_level() > REDACT_UNKNOWN) {
+    if(out != NULL) {
+      out->print_cr("HeapDump Redact Level = %s", heapRedactor.get_redact_level_string());
+    }
+  }
+  writer.setHeapRedactor(&heapRedactor);
 
   if (writer.error() != nullptr) {
     set_error(writer.error());
     if (out != nullptr) {
-      out->print_cr("Unable to create %s: %s", path,
-        (error() != nullptr) ? error() : "reason unknown");
-    }
-    return -1;
+      out->print_cr("Unable to create %s: %s", _path,
+                     (error() != NULL) ? error() : "reason unknown");
+     }
+     FREE_C_HEAP_ARRAY(char, _path);
+     return -1;
   }
 
+  FREE_C_HEAP_ARRAY(char, _path);
   // generate the dump
   VM_HeapDumper dumper(&writer, _gc_before_heap_dump, _oome, num_dump_threads);
   if (Thread::current()->is_VM_thread()) {
diff --git a/src/hotspot/share/services/heapRedactor.cpp b/src/hotspot/share/services/heapRedactor.cpp
new file mode 100644
index 000000000..9fe4648df
--- /dev/null
+++ b/src/hotspot/share/services/heapRedactor.cpp
@@ -0,0 +1,676 @@
+/*
+ * Copyright (c) 2020, 2023, Huawei Technologies Co., Ltd. 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.  Huawei designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Huawei in the LICENSE file that accompanied this code.
+ *
+ * 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 visit https://gitee.com/openeuler/bishengjdk-8 if you need additional
+ * information or have any questions.
+ */
+
+#include "runtime/globals.hpp"
+#include "runtime/os.hpp"
+#include "runtime/arguments.hpp"
+#include "utilities/ostream.hpp"
+#include "memory/allocation.hpp"
+#include "memory/allocation.inline.hpp"
+#include "jvm_md.h"
+#include "utilities/debug.hpp"
+#include "services/heapRedactor.hpp"
+#include "logging/log.hpp"
+#include "logging/logLevel.hpp"
+
+const char* HeapRedactor::REDACT_UNKNOWN_STR = "UNKNOWN";
+const char* HeapRedactor::REDACT_OFF_STR = "OFF";
+const char* HeapRedactor::REDACT_NAMES_STR = "NAMES";
+const char* HeapRedactor::REDACT_BASIC_STR = "BASIC";
+const char* HeapRedactor::REDACT_ANNOTATION_STR = "ANNOTATION";
+const char* HeapRedactor::REDACT_DIYRULES_STR = "DIYRULES";
+const char* HeapRedactor::REDACT_FULL_STR = "FULL";
+
+HeapRedactor::HeapRedactor(outputStream* out) {
+  init_fields();
+  _use_sys_params = true;
+  init(out);
+}
+
+HeapRedactor::HeapRedactor(const char *redact_params_string, outputStream* out) {
+  init_fields();
+  if (redact_params_string != NULL && strlen(redact_params_string) > 0) {
+    _use_sys_params = false;
+    parse_redact_params(redact_params_string);
+  } else {
+    _use_sys_params = true;
+  }
+  init(out);
+}
+
+HeapRedactor::~HeapRedactor() {
+#ifdef LINUX
+  if(_redact_name_table != NULL) {
+    os::Linux::heap_dict_free(_redact_name_table,false);
+    _redact_name_table = NULL;
+  }
+
+  if(_redact_rules_table != NULL) {
+    os::Linux::heap_dict_free(_redact_rules_table, true);
+    _redact_rules_table = NULL;
+  }
+
+  if(_annotation_value_tables != NULL) {
+    for(uint i = 0; i < _container_nums; i++) {
+      if(_annotation_value_tables[i] != NULL) {
+        os::Linux::heap_dict_free(_annotation_value_tables[i], false);
+        _annotation_value_tables[i] = NULL;
+      }
+    }
+  }
+
+  if(_redact_class_field_table != NULL) {
+    os::Linux::heap_dict_free(_redact_class_field_table, true);
+    _redact_class_field_table = NULL;
+  }
+
+  if(_redact_records!= NULL) {
+    for(uint i = 0; i < _container_nums; i++) {
+      if(_redact_records[i] != NULL) {
+        os::Linux::heap_vector_free(_redact_records[i]);
+        _redact_records[i] = NULL;
+      }
+    }
+  }
+#endif
+  if(_annotation_value_tables != NULL) {
+    FREE_C_HEAP_ARRAY(void*, _annotation_value_tables);
+  }
+
+  if(_redact_records != NULL) {
+    FREE_C_HEAP_ARRAY(void*, _redact_records);
+  }
+
+  if(_name_map_list != NULL){
+    FREE_C_HEAP_ARRAY(char, _name_map_list);
+  }
+  if(_file_name_map_list != NULL){
+    FREE_C_HEAP_ARRAY(char, _file_name_map_list);
+  }
+  if(_annotation_class_path != NULL) {
+    FREE_C_HEAP_ARRAY(char, _annotation_class_path);
+  }
+  _file_name_map_list = NULL;
+  _name_map_list = NULL;
+  _annotation_class_path = NULL;
+}
+
+void HeapRedactor::init_fields() {
+  _redact_level = REDACT_UNKNOWN;
+  _redact_name_table = NULL;
+  _redact_rules_table= NULL;
+  _annotation_value_tables = NULL;
+  _redact_records = NULL;
+  _redact_class_field_table = NULL;
+  _file_name_map_list = NULL;
+  _name_map_list = NULL;
+  _redact_class_full_name = NULL;
+  _annotation_class_path = NULL;
+
+  _redact_params.params_string = NULL;
+  _redact_params.heap_dump_redact = NULL;
+  _redact_params.redact_map = NULL;
+  _redact_params.redact_map_file = NULL;
+  _redact_params.annotation_class_path = NULL;
+  _redact_params.redact_password = NULL;
+}
+
+void HeapRedactor::parse_redact_params(const char *redact_params_string) {
+  size_t length = strlen(redact_params_string);
+  char* buf = NEW_C_HEAP_ARRAY(char, length + 1, mtInternal);
+  _redact_params.params_string = buf;
+  strncpy(_redact_params.params_string, redact_params_string, length + 1);
+  size_t start = strlen("-HeapDumpRedact=");
+  _redact_params.heap_dump_redact = _redact_params.params_string + start;
+  char* map_pos = strstr(_redact_params.heap_dump_redact, ",RedactMap=");
+  char* file_pos = strstr(_redact_params.heap_dump_redact, ",RedactMapFile=");
+  char* class_path_pos = strstr(_redact_params.heap_dump_redact, ",RedactClassPath=");
+  char* redact_password_pos = strstr(_redact_params.heap_dump_redact, ",RedactPassword=");
+
+  _redact_params.redact_map = parse_redact_child_param(map_pos, ",RedactMap=",
+                                                       file_pos);
+  _redact_params.redact_map_file = parse_redact_child_param(file_pos, ",RedactMapFile=",
+                                                            class_path_pos);
+  _redact_params.annotation_class_path = parse_redact_child_param(class_path_pos, ",RedactClassPath=",
+                                                                  redact_password_pos);
+  _redact_params.redact_password = parse_redact_child_param(redact_password_pos, ",RedactPassword=",
+                                                            _redact_params.params_string + length);
+}
+
+char* HeapRedactor::parse_redact_child_param(char *redact_params_sub_string, const char* redact_param_prefix,
+                                             const char* next_redact_param_prefix) {
+    char* pos = NULL;
+    if (redact_params_sub_string == NULL) {
+        pos = NULL;
+    } else {
+        *redact_params_sub_string = '\0';
+        pos = redact_params_sub_string + strlen(redact_param_prefix);
+        if (pos == next_redact_param_prefix) {
+            pos = NULL;
+        }
+    }
+    return pos;
+}
+
+bool HeapRedactor::check_launcher_heapdump_redact_support(const char *value) {
+  if (!strcmp(value, "=basic") || !strcmp(value, "=names") || !strcmp(value, "=off")
+      || !strcmp(value, "=diyrules") || !strcmp(value, "=annotation") || !strcmp(value, "=full")) {
+    return true;
+  }
+  return false;
+}
+
+void HeapRedactor::init(outputStream* out) {
+  /** -XX:+VerifyRedactPassword,
+   * if HeapDumpRedact is NULL , jmap operation can not open redact feature without password
+   * if HeapDumpRedact is not NULL, jmap operation can not change redact level without password
+   **/
+    char* split_char = NULL;
+    if(RedactPassword == NULL || (split_char = strstr(const_cast<char*>(RedactPassword), ",")) == NULL || strlen(split_char) < SALT_LEN) {
+        VerifyRedactPassword = false;
+    }
+    if(VerifyRedactPassword && !_use_sys_params) {
+      size_t auth_len = strlen(RedactPassword);
+      size_t suffix_len = strlen(split_char);
+      if(_redact_params.redact_password == NULL ||
+        strncmp(_redact_params.redact_password, RedactPassword, auth_len-suffix_len) ) {
+        // no password or wrong password
+        _use_sys_params = true;
+        if(out != NULL) {
+          out->print_cr("not correct password, use the default redact mode when stared");
+        }
+    }
+  }
+
+  if(_redact_params.redact_password != NULL) {
+      size_t password_Len = strlen(_redact_params.redact_password);
+      memset(_redact_params.redact_password, '\0', password_Len);
+  }
+
+  if (_redact_level == REDACT_UNKNOWN) {
+    init_heapdump_redact_level();
+  }
+  return;
+}
+
+void HeapRedactor::init_redact_map() {
+  const char* map_param = NULL;
+  const char* map_file_param = NULL;
+  if (_use_sys_params) {
+    map_param = RedactMap;
+    map_file_param = RedactMapFile;
+  } else {
+    map_param = _redact_params.redact_map;
+    map_file_param = _redact_params.redact_map_file;
+  }
+  if (map_file_param != NULL) {
+    read_redact_map_from_file(map_file_param);
+  }
+  if (map_param != NULL) {
+    size_t length = strlen(map_param);
+    _name_map_list = NEW_C_HEAP_ARRAY(char, length + 1, mtInternal);
+    strncpy(_name_map_list, map_param, length + 1);
+    read_redact_map_dependon_mode(_name_map_list, _redact_level);
+  }
+}
+
+void HeapRedactor::read_redact_map_dependon_mode(char* name_map_list, HeapDumpRedactLevel redact_level) {
+  if(redact_level == REDACT_DIYRULES) {
+    parse_redact_diy_rules(name_map_list);
+  } else {
+    parse_redact_map_string(name_map_list);
+  }
+}
+
+void HeapRedactor::parse_redact_map_string(char *name_map_list) {
+#ifdef LINUX
+  size_t token_start = 0;
+  size_t step = 0;
+  size_t length = strlen(name_map_list);
+
+  while (step < length) {
+    bool is_seperator = false;
+    if ((is_seperator = (name_map_list[step] == ',' || name_map_list[step] == ';' || name_map_list[step] == '\n' ||
+                         name_map_list[step] == ' ')) ||
+        step == length - 1) {
+      if (is_seperator) {
+        name_map_list[step] = '\0';
+      } else {
+        step++;
+      }
+
+      if (token_start >= step) {
+        // to reduce the depth of the method
+        token_start = step + 1;
+        continue;
+      }
+
+      char *token = name_map_list + token_start;
+      size_t i = 0;
+      size_t token_length = strlen(token);
+      while (i < token_length && token[i] != ':') {
+        i++;
+      }
+      if (i < token_length - 1) {
+        token[i] = '\0';
+        _redact_name_table = os::Linux::heap_dict_add(token, token + i + 1, _redact_name_table, 0);
+      }
+      token_start = step + 1;
+    }
+    step++;
+  }
+#endif
+}
+
+void HeapRedactor::read_redact_map_from_file(const char *path) {
+  char base_path[JVM_MAXPATHLEN] = {'\0'};
+  char buffer[MAX_MAP_FILE_LENGTH + 1] = {'\0'};
+  if (path == NULL || path[0] == '\0') {
+    // RedactMapFile=<file> not specified
+  } else {
+    if (strlen(path) >= JVM_MAXPATHLEN) {
+      warning("RedactMap File path is too long ");
+      return;
+    }
+    strncpy(base_path, path, sizeof(base_path));
+    // check if the path is a directory (must exist)
+    FILE* fm = NULL;
+    fm = fopen(base_path, "r");
+    if (fm == NULL) {
+      return;
+    }
+    size_t num_read = fread((char *)buffer, 1, MAX_MAP_FILE_LENGTH, fm);
+    if((int)num_read != -1){
+      _file_name_map_list = NEW_C_HEAP_ARRAY(char, (size_t)num_read + 1, mtInternal);
+      strncpy(_file_name_map_list, buffer, num_read + 1);
+      read_redact_map_dependon_mode(_file_name_map_list, _redact_level);
+    }
+
+    fclose(fm);
+  }
+}
+
+void HeapRedactor::parse_redact_diy_rules(char* name_map_list) {
+    size_t token_start = 0;
+    size_t step = 0;
+    size_t length = strlen(name_map_list);
+
+    while (step < length) {
+        bool is_seperator = false;
+        if ((is_seperator = (name_map_list[step] == ',' || name_map_list[step] == ';' || name_map_list[step] == '\n' ||
+                             name_map_list[step] == ' ')) ||
+            step == length - 1) {
+            if (is_seperator) {
+                name_map_list[step] = '\0';
+            } else {
+                step++;
+            }
+
+            if (token_start >= step) {
+                // to reduce the depth of the method
+                token_start = step + 1;
+                continue;
+            }
+
+            char *token = name_map_list + token_start;
+            parse_token(token);
+            token_start = step + 1;
+        }
+        step++;
+    }
+
+    // clear _redact_class_full_name, encase RedactMap has an unformatted value(without class name),
+    // will rewrite  the last class's value_map
+    _redact_class_full_name = NULL;
+}
+
+void HeapRedactor::parse_token(char* token) {
+#ifdef LINUX
+    size_t i = 0;
+    size_t token_length = strlen(token);
+    while (i < token_length && token[i] != ':') {
+        if(token[i] == '.' ) {
+            token[i] = '/';
+        }
+        i++;
+    }
+
+    void* _redact_rules_sub_table = _redact_class_full_name == NULL ? NULL :
+                                    os::Linux::heap_dict_lookup(_redact_class_full_name, _redact_rules_table, false);
+    if (i < token_length - 1 && _redact_rules_sub_table != NULL) {
+        token[i] = '\0';
+        os::Linux::heap_dict_add(token, token + i + 1, _redact_rules_sub_table, 0);
+    } else if( i == token_length) {
+        _redact_class_full_name = token;
+        _redact_rules_sub_table = os::Linux::heap_dict_lookup(token, _redact_rules_table, false);
+        if (_redact_rules_sub_table == NULL) {
+            _redact_rules_sub_table = os::Linux::heap_dict_add(token, NULL, _redact_rules_sub_table, 0);
+            _redact_rules_table = os::Linux::heap_dict_add(token, _redact_rules_sub_table, _redact_rules_table, 0);
+        }
+    }
+#endif
+}
+
+HeapDumpRedactLevel HeapRedactor::init_heapdump_redact_level() {
+  const char* redact_string = NULL;
+  if (_use_sys_params) {
+    redact_string = HeapDumpRedact;
+  } else {
+    redact_string = _redact_params.heap_dump_redact;
+  }
+  if (redact_string == NULL) {
+    _redact_level = REDACT_OFF;
+  } else {
+#ifdef LINUX
+    if (strcmp(redact_string, "basic") == 0) {
+      _redact_level = REDACT_BASIC;
+    } else if (strcmp(redact_string, "names") == 0) {
+      _redact_level = REDACT_NAMES;
+      init_redact_map();
+    } else if (strcmp(redact_string, "full") == 0) {
+      _redact_level = REDACT_FULL;
+      init_redact_map();
+    } else if (strcmp(redact_string, "diyrules") == 0) {
+      _redact_level = REDACT_DIYRULES;
+      init_redact_map();
+    } else if (strcmp(redact_string, "annotation") == 0) {
+      _redact_level = REDACT_ANNOTATION;
+      init_class_path();
+      if(_annotation_class_path == NULL) {
+          _redact_level = REDACT_OFF;
+      }
+    } else {
+      _redact_level = REDACT_OFF;
+    }
+#else
+    if (strcmp(redact_string, "basic") == 0) {
+      _redact_level = REDACT_BASIC;
+    } else if (strcmp(redact_string, "full") == 0) {
+      _redact_level = REDACT_BASIC;
+    } else {
+        _redact_level = REDACT_OFF;
+    }
+#endif
+
+  }
+
+  if (_redact_params.params_string != NULL) {
+    FREE_C_HEAP_ARRAY(char, _redact_params.params_string);
+  }
+  return _redact_level;
+}
+
+void HeapRedactor::init_class_path() {
+  const char* class_path = NULL;
+  if (_use_sys_params) {
+    class_path = RedactClassPath;
+  } else {
+    class_path = _redact_params.annotation_class_path;
+  }
+
+  if(class_path != NULL) {
+      size_t class_path_len = strlen(class_path);
+      _annotation_class_path = NEW_C_HEAP_ARRAY(char, class_path_len + 3, mtInternal);
+      _annotation_class_path[0] = 'L';
+      strncpy(_annotation_class_path + 1, class_path, class_path_len + 1);
+      _annotation_class_path[class_path_len + 1] = ';';
+      _annotation_class_path[class_path_len + 2] = '\0';
+  }
+}
+
+void HeapRedactor::insert_anonymous_value(void* key, void* value, uint index){
+#ifdef LINUX
+  _annotation_value_tables[index] = os::Linux::heap_dict_add(key, value, _annotation_value_tables[index], 1);
+#endif
+}
+
+bool HeapRedactor::recursion_cp_refs_in_annotation_struct(
+        AnnotationArray* annotations_typeArray, int &byte_i_ref) {
+  if ((byte_i_ref + 2 + 2) > annotations_typeArray->length()) {
+    // not enough room for smallest annotation_struct
+    if (log_is_enabled(Debug, cds, heap)) {
+      log_debug(cds, heap)("length() is too small for annotation_struct");
+    }
+    return false;
+  }
+
+  u2 type_index = Bytes::get_Java_u2((address)annotations_typeArray->adr_at(byte_i_ref));
+  byte_i_ref += 2;
+
+  u2 num_element_value_pairs = Bytes::get_Java_u2((address) annotations_typeArray->adr_at(byte_i_ref));
+  byte_i_ref += 2;
+
+  if (log_is_enabled(Debug, cds, heap)) {
+    log_debug(cds, heap)("type_index=%d  num_element_value_pairs=%d", type_index, num_element_value_pairs);
+  }
+
+  int calc_num_element_value_pairs = 0;
+  for (; calc_num_element_value_pairs < num_element_value_pairs;
+         calc_num_element_value_pairs++) {
+    if ((byte_i_ref + 2) > annotations_typeArray->length()) {
+      // not enough room for another element_name_index, let alone
+      // the rest of another component
+      log_debug(cds, heap)("length() is too small for element_name_index");
+      return false;
+    }
+
+    u2 element_name_index = Bytes::get_Java_u2((address) annotations_typeArray->adr_at(byte_i_ref));
+    byte_i_ref += 2;
+
+    log_debug(cds, heap)("element_name_index=%d", element_name_index);
+
+    if (!recursion_cp_refs_in_element_value(annotations_typeArray, byte_i_ref)) {
+      log_debug(cds, heap)("bad element_value at %d", calc_num_element_value_pairs);
+      // propagate failure back to caller
+      return false;
+    }
+  } // end for each component
+  assert(num_element_value_pairs == calc_num_element_value_pairs, "sanity check");
+
+  return true;
+} // end recursion_cp_refs_in_annotation_struct()
+
+bool HeapRedactor::lookup_annotation_index_in_constant_pool(AnnotationArray* field_annotations, ConstantPool *cp, int &byte_i_ref) {
+    u2 num_annotations = 0;
+    bool has_anonymous_annotation = false;
+
+    if ((byte_i_ref + 2) > field_annotations->length()) {
+        // not enough room for num_annotations field
+        log_debug(cds, heap)("length() is too small for num_annotations field");
+        return false;
+    } else {
+        num_annotations = Bytes::get_Java_u2((address) field_annotations->adr_at(byte_i_ref));
+    }
+
+    byte_i_ref += 2;
+
+    for (int calc_num_annotations = 0; calc_num_annotations < num_annotations; calc_num_annotations++) {
+
+        if ((byte_i_ref + 2 + 2) > field_annotations->length()) {
+            // not enough room for smallest annotation_struct
+            log_debug(cds, heap)("length() is too small for annotation_struct");
+            return false;
+        }
+
+        // get constants pool index
+        address cp_index_addr = (address) field_annotations->adr_at(byte_i_ref);
+        byte_i_ref += 2;
+        u2 cp_index = Bytes::get_Java_u2(cp_index_addr);
+        Symbol *annotate_class_symbol = cp->symbol_at(cp_index);
+        if (!Symbol::is_valid(annotate_class_symbol)) {
+            return false;
+        }
+        char *annotate_class_name = annotate_class_symbol->as_C_string();
+
+        u2 num_element_value_pairs = Bytes::get_Java_u2((address) field_annotations->adr_at(byte_i_ref));
+        byte_i_ref += 2;
+        if ((byte_i_ref + 2 + 1) > field_annotations->length()) {
+            // not enough room for smallest annotation_struct
+            log_debug(cds, heap)("length() is too small for element_name_index");
+            return false;
+        }
+
+        const char *annotation_class_path = get_annotation_class_path();
+        has_anonymous_annotation = (strcmp(annotation_class_path, annotate_class_name) == 0);
+        if (has_anonymous_annotation) {
+            address element_name_addr = (address) field_annotations->adr_at(byte_i_ref);
+            byte_i_ref += 2;
+            u2 cp_name_index = Bytes::get_Java_u2(element_name_addr);
+            Symbol *element_name_symbol = cp->symbol_at(cp_name_index);
+            char *element_name = element_name_symbol->as_C_string();
+            if(element_name == NULL || strcmp(element_name, "value")) {
+                // expected annotation has only one field "value"
+                return false;
+            }
+            // skip element tag
+            byte_i_ref++;
+            return true;
+        }
+
+        int calc_num_element_value_pairs = 0;
+        // skip element_name_index
+        byte_i_ref += 2;
+        for (; calc_num_element_value_pairs < num_element_value_pairs; calc_num_element_value_pairs++) {
+            if (!recursion_cp_refs_in_element_value(field_annotations, byte_i_ref)) {
+                return false;
+            }
+        }
+    }
+    return false;
+}
+
+bool HeapRedactor::recursion_cp_refs_in_element_value(AnnotationArray* field_annotations, int &byte_i_ref) {
+  if ((byte_i_ref + 1) > field_annotations->length()) {
+    // not enough room for a tag let alone the rest of an element_value
+    if (log_is_enabled(Debug, cds, heap)) {
+      log_debug(cds, heap)("length() is too small for a tag");
+    }
+    return false;
+  }
+
+  u1 tag = field_annotations->at(byte_i_ref);
+  byte_i_ref++;
+  switch (tag) {
+    case JVM_SIGNATURE_BYTE:
+    case JVM_SIGNATURE_CHAR:
+    case JVM_SIGNATURE_DOUBLE:
+    case JVM_SIGNATURE_FLOAT:
+    case JVM_SIGNATURE_INT:
+    case JVM_SIGNATURE_LONG:
+    case JVM_SIGNATURE_SHORT:
+    case JVM_SIGNATURE_BOOLEAN:
+    case 's':
+    case 'c':
+    {
+      if ((byte_i_ref + 2) > field_annotations->length()) {
+        if (log_is_enabled(Debug, cds, heap)) {
+          log_debug(cds, heap)("length() is too small for a const_value_index");
+        }
+        break;
+      }
+      byte_i_ref += 2;
+    } break;
+    case 'e':
+    {
+      if ((byte_i_ref + 4) > field_annotations->length()) {
+        if (log_is_enabled(Debug, cds, heap)) {
+          log_debug(cds, heap)("length() is too small for a enum_const_value");
+        }
+        break;
+      }
+      byte_i_ref += 4;
+    } break;
+
+    case '@':
+      // For the above tag value, value.attr_value is the right union
+      // field. This is a nested annotation.
+      if (!recursion_cp_refs_in_annotation_struct(field_annotations, byte_i_ref)) {
+        // propagate failure back to caller
+        return false;
+      }
+      break;
+
+    case JVM_SIGNATURE_ARRAY:
+    {
+      if ((byte_i_ref + 2) > field_annotations->length()) {
+        // not enough room for a num_values field
+        if (log_is_enabled(Debug, cds, heap)) {
+            log_debug(cds, heap)("length() is too small for a num_values field");
+        }
+        return false;
+      }
+
+      // For the above tag value, value.array_value is the right union
+      // field. This is an array of nested element_value.
+      u2 num_values = Bytes::get_Java_u2((address) field_annotations->adr_at(byte_i_ref));
+      byte_i_ref += 2;
+      if (log_is_enabled(Debug, cds, heap)) {
+          log_debug(cds, heap)("num_values=%d", num_values);
+      }
+
+      int calc_num_values = 0;
+      for (; calc_num_values < num_values; calc_num_values++) {
+        if (!recursion_cp_refs_in_element_value(field_annotations, byte_i_ref)) {
+          if (log_is_enabled(Debug, cds, heap)) {
+            log_debug(cds, heap)("bad nested element_value at %d", calc_num_values);
+          }
+          // propagate failure back to caller
+          return false;
+        }
+      }
+    } break;
+
+    default:
+      if (log_is_enabled(Debug, cds, heap)) {
+        log_debug(cds, heap)("bad tag=0x%x", tag);
+      }
+      return false;
+  }
+
+  return true;
+}
+
+bool HeapRedactor::record_typeArrayOop(typeArrayOop array, uint index) {
+    bool _inserted = false;
+#ifdef LINUX
+    _redact_records[index] = os::Linux::heap_vector_add(array, _redact_records[index], _inserted);
+#endif
+    return _inserted;
+}
+
+void HeapRedactor::insert_class_field_value(void* class_key, void* field_key, void* value) {
+#ifdef LINUX
+    void* _redact_sub_table = os::Linux::heap_dict_lookup(class_key, _redact_class_field_table, false);
+    _redact_sub_table = os::Linux::heap_dict_add(field_key, value, _redact_sub_table, 1);
+    _redact_class_field_table = os::Linux::heap_dict_add(class_key, _redact_sub_table, _redact_class_field_table, 1);
+#endif
+}
+
+void HeapRedactor::init_containers(uint nums) {
+  _container_nums = (nums == 0 ? 1 : nums);
+  _annotation_value_tables = NEW_C_HEAP_ARRAY(void*, _container_nums, mtInternal);
+  memset(_annotation_value_tables, 0, sizeof(void*)*_container_nums);
+  _redact_records = NEW_C_HEAP_ARRAY(void*, _container_nums, mtInternal);
+  memset(_redact_records, 0, sizeof(void*)*_container_nums);
+}
\ No newline at end of file
diff --git a/src/hotspot/share/services/heapRedactor.hpp b/src/hotspot/share/services/heapRedactor.hpp
new file mode 100644
index 000000000..467baa39d
--- /dev/null
+++ b/src/hotspot/share/services/heapRedactor.hpp
@@ -0,0 +1,225 @@
+/*
+ * Copyright (c) 2020, 2023, Huawei Technologies Co., Ltd. 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.  Huawei designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Huawei in the LICENSE file that accompanied this code.
+ *
+ * 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 visit https://gitee.com/openeuler/bishengjdk-8 if you need additional
+ * information or have any questions.
+ */
+
+#ifndef SHARE_SERVICES_HEAPREDACTOR_HPP
+#define SHARE_SERVICES_HEAPREDACTOR_HPP
+#include "memory/allocation.hpp"
+#include "oops/annotations.hpp"
+#include "oops/constantPool.hpp"
+#ifdef LINUX
+#include "os_linux.hpp"
+#endif
+
+#define MAX_MAP_FILE_LENGTH 1024
+#define SALT_LEN 9
+
+enum HeapDumpRedactLevel {
+    REDACT_UNKNOWN,
+    REDACT_OFF,
+    REDACT_NAMES,
+    REDACT_BASIC,
+    REDACT_DIYRULES,
+    REDACT_ANNOTATION,
+    REDACT_FULL
+};
+
+struct RedactParams {
+    char* params_string;
+    char* heap_dump_redact;
+    char* redact_map;
+    char* redact_map_file;
+    char* annotation_class_path;
+    char* redact_password;
+};
+
+class HeapRedactor : public StackObj {
+public:
+    static const char* REDACT_UNKNOWN_STR;
+    static const char* REDACT_OFF_STR;
+    static const char* REDACT_NAMES_STR;
+    static const char* REDACT_BASIC_STR;
+    static const char* REDACT_DIYRULES_STR;
+    static const char* REDACT_ANNOTATION_STR;
+    static const char* REDACT_FULL_STR;
+    HeapRedactor(outputStream* out);
+    HeapRedactor(const char* redact_params, outputStream* out);
+    ~HeapRedactor();
+    static bool check_launcher_heapdump_redact_support(const char* value);
+    HeapDumpRedactLevel redact_level() {
+      if(_redact_level == REDACT_UNKNOWN) {
+        _redact_level = init_heapdump_redact_level();
+      }
+
+      return _redact_level;
+    }
+
+    const char* get_redact_level_string() const {
+#ifdef LINUX
+      switch (_redact_level) {
+        case REDACT_OFF:
+          return REDACT_OFF_STR;
+        case REDACT_NAMES:
+          return REDACT_NAMES_STR;
+        case REDACT_BASIC:
+          return REDACT_BASIC_STR;
+        case REDACT_DIYRULES:
+          return REDACT_DIYRULES_STR;
+        case REDACT_ANNOTATION:
+          return REDACT_ANNOTATION_STR;
+        case REDACT_FULL:
+          return REDACT_FULL_STR;
+        case REDACT_UNKNOWN:
+        default:
+          return REDACT_UNKNOWN_STR;
+      }
+#else
+      switch (_redact_level) {
+        case REDACT_OFF:
+            return REDACT_OFF_STR;
+        case REDACT_BASIC:
+            return REDACT_BASIC_STR;
+        case REDACT_UNKNOWN:
+        default:
+            return REDACT_UNKNOWN_STR;
+      }
+#endif
+
+    }
+
+    char* lookup_redact_name(const void* name) {
+        void* val = NULL;
+#ifdef LINUX
+        val = os::Linux::heap_dict_lookup(const_cast<void*>(name), _redact_name_table, false);
+#endif
+        if(val != NULL) {
+            return (char*)val;
+        }
+        return NULL;
+    }
+
+    void* lookup_class_rules(const void* name) {
+        void* val = NULL;
+#ifdef LINUX
+        val = os::Linux::heap_dict_lookup(const_cast<void*>(name), _redact_rules_table, false);
+#endif
+        return val;
+    }
+
+    const char* get_annotation_class_path(){
+      return _annotation_class_path;
+    }
+
+    void insert_anonymous_value(void* key, void* value, uint index);
+
+    template<typename T>
+    T lookup_replace_value(void* key) {
+        void* val = NULL;
+#ifdef LINUX
+        for(uint i = 0; i < _container_nums; i++) {
+          if(_annotation_value_tables[i] == NULL) {
+            continue;
+          }
+          val = os::Linux::heap_dict_lookup(key, _annotation_value_tables[i], true);
+          if(val != NULL) {
+            break;
+          }
+        }
+#endif
+        if(val != NULL) {
+            return (T)val;
+        }
+        return NULL;
+    }
+
+    bool lookup_annotation_index_in_constant_pool(AnnotationArray* field_annotations, ConstantPool *cp, int &byte_i_ref);
+    bool recursion_cp_refs_in_element_value(AnnotationArray* field_annotations, int &byte_i_ref);
+    bool recursion_cp_refs_in_annotation_struct(AnnotationArray* field_annotations, int &byte_i_ref);
+
+    bool record_typeArrayOop(typeArrayOop array, uint index);
+    void* get_vector_node_next(void* node, int &_cnt, void** &_items, uint index) {
+        void* val = NULL;
+#ifdef LINUX
+        val = os::Linux::heap_vector_get_next(_redact_records[index], node, _cnt, _items);
+#endif
+        return val;
+    }
+
+    void insert_class_field_value(void* class_key, void* field_key, void* value);
+    void* lookup_class_value(void* key) {
+        void* val = NULL;
+#ifdef LINUX
+        if(_redact_class_field_table == NULL) {
+          return val;
+        }
+        val = os::Linux::heap_dict_lookup(key, _redact_class_field_table, false);
+#endif
+        return val;
+    }
+
+    void* lookup_value(void* key, void* heap_dict, bool deletable) {
+        void* val = NULL;
+#ifdef LINUX
+        val = os::Linux::heap_dict_lookup(key, heap_dict, deletable);
+#endif
+        return val;
+    }
+
+    void init_containers(uint nums);
+    const uint get_container_nums() {
+      return _container_nums;
+    }
+
+private:
+    HeapDumpRedactLevel _redact_level;
+    RedactParams _redact_params;
+    bool _use_sys_params;
+    void* _redact_name_table;
+    void* _redact_rules_table;
+    void** _annotation_value_tables;
+    // void* _annotation_value_table;
+    void* _redact_class_field_table;
+    char* _file_name_map_list;
+    char* _name_map_list;
+    char* _annotation_class_path;
+    char* _redact_class_full_name;
+    void** _redact_records;
+    //void* _redact_record;
+    // safety: every dump thread has one map and one vector
+    uint _container_nums;
+
+    HeapDumpRedactLevel init_heapdump_redact_level();
+    void read_redact_map_from_file(const char* path);
+    void read_redact_map_dependon_mode(char* name_map_list, HeapDumpRedactLevel redact_level);
+    void parse_redact_map_string(char* name_map_list);
+    void parse_redact_diy_rules(char* name_map_list);
+    void parse_token(char* token);
+    void parse_redact_params(const char *redact_params_string);
+    char* parse_redact_child_param(char *redact_params_sub_string, const char* redact_param_prefix, const char* next_redact_param_prefix);
+    void init(outputStream* out);
+    void init_fields();
+    void init_redact_map();
+    void init_class_path();
+
+};
+#endif // SHARE_SERVICES_HEAPREDACTOR_HPP
\ No newline at end of file
diff --git a/src/hotspot/share/services/writeableFlags.cpp b/src/hotspot/share/services/writeableFlags.cpp
index d4f601ed8..6e8924c86 100644
--- a/src/hotspot/share/services/writeableFlags.cpp
+++ b/src/hotspot/share/services/writeableFlags.cpp
@@ -235,6 +235,13 @@ JVMFlag::Error WriteableFlags::set_flag(const char* name, const void* value, JVM
 
   JVMFlag* f = JVMFlag::find_flag(name);
   if (f) {
+    if(VerifyRedactPassword) {
+        if(strcmp(name, "HeapDumpRedact") == 0 || strcmp(name, "RedactMap") == 0 || strcmp(name, "RedactMapFile") == 0
+          || strcmp(name, "RedactClassPath") == 0) {
+          err_msg.print("has no authority to reset redact params");
+          return JVMFlag::NON_WRITABLE;
+        }
+    }
     // only writeable flags are allowed to be set
     if (f->is_writeable()) {
       return setter(f, value, origin, err_msg);
diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/HSDB.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/HSDB.java
index 9cc51934d..80d64ea97 100644
--- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/HSDB.java
+++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/HSDB.java
@@ -41,15 +41,16 @@ import sun.jvm.hotspot.gc.g1.*;
 import sun.jvm.hotspot.gc.x.*;
 import sun.jvm.hotspot.gc.z.*;
 import sun.jvm.hotspot.interpreter.*;
-import sun.jvm.hotspot.oops.*;
 import sun.jvm.hotspot.runtime.*;
 import sun.jvm.hotspot.ui.*;
+import sun.jvm.hotspot.ui.Annotation;
 import sun.jvm.hotspot.ui.tree.*;
 import sun.jvm.hotspot.ui.classbrowser.*;
 import sun.jvm.hotspot.utilities.*;
 import sun.jvm.hotspot.utilities.Observable;
 import sun.jvm.hotspot.utilities.Observer;
-
+import sun.jvm.hotspot.oops.*;
+ 
 /** The top-level HotSpot Debugger. FIXME: make this an embeddable
     component! (Among other things, figure out what to do with the
     menu bar...) */
@@ -1003,7 +1004,7 @@ public class HSDB implements ObjectHistogramPanel.Listener, SAListener {
             }
 
             if (curFrame.getFP() != null) {
-              annoPanel.addAnnotation(new Annotation(curFrame.getSP(),
+              annoPanel.addAnnotation(new sun.jvm.hotspot.ui.Annotation(curFrame.getSP(),
                                                      curFrame.getFP(),
                                                      anno));
             } else {
@@ -1013,14 +1014,14 @@ public class HSDB implements ObjectHistogramPanel.Listener, SAListener {
               if (Assert.ASSERTS_ENABLED) {
                 Assert.that(cb.getFrameSize() > 0, "CodeBlob must have non-zero frame size");
               }
-              annoPanel.addAnnotation(new Annotation(sp,
+              annoPanel.addAnnotation(new sun.jvm.hotspot.ui.Annotation(sp,
                                                      sp.addOffsetTo(cb.getFrameSize()),
                                                      anno));
             }
 
             // Add interpreter frame annotations
             if (curFrame.isInterpretedFrame()) {
-              annoPanel.addAnnotation(new Annotation(curFrame.addressOfInterpreterFrameExpressionStack(),
+              annoPanel.addAnnotation(new sun.jvm.hotspot.ui.Annotation(curFrame.addressOfInterpreterFrameExpressionStack(),
                                                      curFrame.addressOfInterpreterFrameTOS(),
                                                      "Interpreter expression stack"));
               Address monBegin = curFrame.interpreterFrameMonitorBegin().address();
@@ -1032,7 +1033,7 @@ public class HSDB implements ObjectHistogramPanel.Listener, SAListener {
               if (interpreterFrameMethod != null) {
                 // The offset is just to get the right stack slots highlighted in the output
                 int offset = 1;
-                annoPanel.addAnnotation(new Annotation(curFrame.addressOfInterpreterFrameLocal(offset),
+                annoPanel.addAnnotation(new sun.jvm.hotspot.ui.Annotation(curFrame.addressOfInterpreterFrameLocal(offset),
                                                        curFrame.addressOfInterpreterFrameLocal((int) interpreterFrameMethod.getMaxLocals() + offset),
                                                        "Interpreter locals area for frame with SP = " + curFrame.getSP()));
               }
@@ -1041,9 +1042,9 @@ public class HSDB implements ObjectHistogramPanel.Listener, SAListener {
                 methodAnno += " (BAD OOP)";
               }
               Address a = curFrame.addressOfInterpreterFrameMethod();
-              annoPanel.addAnnotation(new Annotation(a, a.addOffsetTo(addressSize), methodAnno));
+              annoPanel.addAnnotation(new sun.jvm.hotspot.ui.Annotation(a, a.addOffsetTo(addressSize), methodAnno));
               a = curFrame.addressOfInterpreterFrameCPCache();
-              annoPanel.addAnnotation(new Annotation(a, a.addOffsetTo(addressSize), "Interpreter constant pool cache"));
+              annoPanel.addAnnotation(new sun.jvm.hotspot.ui.Annotation(a, a.addOffsetTo(addressSize), "Interpreter constant pool cache"));
             }
 
             RegisterMap rm = (RegisterMap) vf.getRegisterMap().clone();
@@ -1160,7 +1161,7 @@ public class HSDB implements ObjectHistogramPanel.Listener, SAListener {
                         }
                       }
 
-                      annoPanel.addAnnotation(new Annotation(addr, addr.addOffsetTo(addressSize), anno));
+                      annoPanel.addAnnotation(new sun.jvm.hotspot.ui.Annotation(addr, addr.addOffsetTo(addressSize), anno));
                     }
                   }, rm);
               } catch (Exception e) {
diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/SALauncher.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/SALauncher.java
index b884058a3..1adabf833 100644
--- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/SALauncher.java
+++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/SALauncher.java
@@ -130,6 +130,10 @@ public class SALauncher {
         System.out.println("    --histo                 To print histogram of java object heap.");
         System.out.println("    --clstats               To print class loader statistics.");
         System.out.println("    --finalizerinfo         To print information on objects awaiting finalization.");
+        System.out.println("    --HeapDumpRedact <basic|names|full|annotation|diyrules|off>         redact the heapdump information to remove sensitive data.");
+        System.out.println("    --RedactMap <name1:value1;name2:value2;...>     Redact the class and field names to other strings.");
+        System.out.println("    --RedactMapFile <file>                          file path of the redact map.");
+        System.err.println("    --RedactClassPath <classpath>                   full path of the redact annotation");
         return commonHelpWithConnect("jmap");
     }
 
@@ -302,8 +306,8 @@ public class SALauncher {
         jstack.runWithArgs(buildAttachArgs(newArgMap, false));
     }
 
-    private static void runJMAP(String[] oldArgs) {
-        Map<String, String> longOptsMap = Map.ofEntries(
+    private static Map<String, String> getLongOptsMap() {
+        return Map.ofEntries(
                 Map.entry("exe=", "exe"),
                 Map.entry("core=", "core"),
                 Map.entry("pid=", "pid"),
@@ -314,13 +318,27 @@ public class SALauncher {
                 Map.entry("gz=", "gz"),
                 Map.entry("histo", "-histo"),
                 Map.entry("clstats", "-clstats"),
-                Map.entry("finalizerinfo", "-finalizerinfo"));
+                Map.entry("finalizerinfo", "-finalizerinfo"),
+                Map.entry("HeapDumpRedact=", "HeapDumpRedact"),
+                Map.entry("RedactMap=", "RedactMap"),
+                Map.entry("RedactMapFile=", "RedactMapFile"),
+                Map.entry("RedactClassPath=", "RedactClassPath"),
+                Map.entry("RedactPassword", "RedactPassword"));
+    }
+
+    private static void runJMAP(String[] oldArgs) {
+        Map<String, String> longOptsMap = getLongOptsMap();
         Map<String, String> newArgMap = parseOptions(oldArgs, longOptsMap);
 
         boolean requestHeapdump = newArgMap.containsKey("binaryheap");
         String dumpfile = newArgMap.get("dumpfile");
         String gzLevel = newArgMap.get("gz");
         String command = "-heap:format=b";
+        String heapDumpRedact = newArgMap.get("HeapDumpRedact");
+        String redactMap = newArgMap.get("RedactMap");
+        String redactMapFile = newArgMap.get("RedactMapFile");
+        String redactClassPath = newArgMap.get("RedactClassPath");
+        boolean hasRedactPassword = newArgMap.containsKey("RedactPassword");
         if (!requestHeapdump && (dumpfile != null)) {
             throw new IllegalArgumentException("Unexpected argument: dumpfile");
         }
@@ -331,15 +349,37 @@ public class SALauncher {
             if (dumpfile != null) {
                 command += ",file=" + dumpfile;
             }
+            if (heapDumpRedact != null) {
+                command += ",HeapDumpRedact=" + heapDumpRedact;
+            }
+            if (redactMap != null) {
+                command += ",RedactMap=" + redactMap;
+            }
+            if (redactMapFile != null) {
+                command += ",RedactMapFile=" + redactMapFile;
+            }
+            if (redactClassPath != null) {
+                command += ",RedactClassPath=" + redactClassPath;
+            }
+            if(hasRedactPassword) {
+                command += ",RedactPassword";
+            }
             newArgMap.put(command, null);
         }
 
         newArgMap.remove("binaryheap");
         newArgMap.remove("dumpfile");
         newArgMap.remove("gz");
+        newArgMap.remove("HeapDumpRedact");
+        newArgMap.remove("RedactMap");
+        newArgMap.remove("RedactMapFile");
+        newArgMap.remove("RedactClassPath");
+        newArgMap.remove("RedactPassword");
         JMap.main(buildAttachArgs(newArgMap, false));
     }
 
+
+
     private static void runJINFO(String[] oldArgs) {
         Map<String, String> longOptsMap = Map.of("exe=", "exe",
                                                  "core=", "core",
diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/Annotation.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/Annotation.java
new file mode 100644
index 000000000..617e8952b
--- /dev/null
+++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/Annotation.java
@@ -0,0 +1,70 @@
+/*
+ * Copyright (c) 2000, 2020, 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.
+ *
+ */
+
+package sun.jvm.hotspot.oops;
+
+import sun.jvm.hotspot.debugger.Address;
+import sun.jvm.hotspot.runtime.VM;
+import sun.jvm.hotspot.runtime.VMObject;
+import sun.jvm.hotspot.types.AddressField;
+import sun.jvm.hotspot.types.Type;
+import sun.jvm.hotspot.types.TypeDataBase;
+import sun.jvm.hotspot.types.WrongTypeException;
+import sun.jvm.hotspot.utilities.AnnotationArray2D;
+import sun.jvm.hotspot.utilities.Observable;
+import sun.jvm.hotspot.utilities.Observer;
+
+// An Annotation is an oop containing class annotations
+
+public class Annotation extends VMObject {
+    private static AddressField class_annotations;
+    private static AddressField class_type_annotations;
+    private static AddressField fields_annotations;
+    private static AddressField fields_type_annotations;
+
+    static {
+        VM.registerVMInitializedObserver(new Observer() {
+            public void update(Observable o, Object data) {
+                initialize(VM.getVM().getTypeDataBase());
+            }
+        });
+    }
+
+    private static synchronized void initialize(TypeDataBase db) throws WrongTypeException {
+        Type type   = db.lookupType("Annotations");
+        class_annotations = type.getAddressField("_class_annotations");
+        class_type_annotations = type.getAddressField("_class_type_annotations");
+        fields_annotations = type.getAddressField("_fields_annotations");
+        fields_type_annotations = type.getAddressField("_fields_type_annotations");
+    }
+
+    public Annotation(Address addr) {
+        super(addr);
+    }
+
+    public AnnotationArray2D getFieldsAnnotations() {
+        Address addr = getAddress().getAddressAt(fields_annotations.getOffset());
+        return new AnnotationArray2D(addr);
+    }
+}
\ No newline at end of file
diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/Field.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/Field.java
index ebf571c7b..98cb416c9 100644
--- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/Field.java
+++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/Field.java
@@ -131,6 +131,8 @@ public class Field {
   private Symbol          genericSignature;
   private AccessFlags     accessFlags;
   private int             fieldIndex;
+  // java field redact annotation
+  private U1Array         fieldAnnotations;
 
   /** Returns the byte offset of the field within the object or klass */
   public long getOffset() { return offset; }
@@ -182,6 +184,14 @@ public class Field {
   public boolean hasInitialValue()           { return holder.getFieldInitialValueIndex(fieldIndex) != 0;    }
   public int getInitialValueIndex()        { return values.initialValueIndex; }
 
+  public void setFieldAnnotations(U1Array fieldAnnotations){
+    this.fieldAnnotations = fieldAnnotations;
+  }
+
+  public U1Array getFieldAnnotations(){
+    return fieldAnnotations;
+  }
+
   //
   // Following accessors are for named, non-VM fields only
   //
diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/InstanceKlass.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/InstanceKlass.java
index cec603be2..719aa8435 100644
--- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/InstanceKlass.java
+++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/InstanceKlass.java
@@ -75,6 +75,7 @@ public class InstanceKlass extends Klass {
     constants            = new MetadataField(type.getAddressField("_constants"), 0);
     sourceDebugExtension = type.getAddressField("_source_debug_extension");
     innerClasses         = type.getAddressField("_inner_classes");
+    annotate             = type.getAddressField("_annotations");
     nonstaticFieldSize   = new CIntField(type.getCIntegerField("_nonstatic_field_size"), 0);
     staticFieldSize      = new CIntField(type.getCIntegerField("_static_field_size"), 0);
     staticOopFieldCount  = new CIntField(type.getCIntegerField("_static_oop_field_count"), 0);
@@ -145,6 +146,7 @@ public class InstanceKlass extends Klass {
   private static CIntField initState;
   private static CIntField itableLen;
   private static AddressField breakpoints;
+  private static AddressField annotate;
 
   // type safe enum for ClassState from instanceKlass.hpp
   public static class ClassState {
@@ -854,6 +856,10 @@ public class InstanceKlass extends Klass {
     return VMObjectFactory.newObject(U2Array.class, addr);
   }
 
+  public Annotation getAnnotation() {
+      Address addr = getAddress().getAddressAt(annotate.getOffset());
+      return VMObjectFactory.newObject(Annotation.class, addr);
+  }
 
   //----------------------------------------------------------------------
   // Internals only below this point
diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/tools/JMap.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/tools/JMap.java
index 4c80ecd6c..fbead3ce4 100644
--- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/tools/JMap.java
+++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/tools/JMap.java
@@ -25,6 +25,9 @@
 package sun.jvm.hotspot.tools;
 
 import java.io.*;
+import java.nio.CharBuffer;
+import java.util.regex.Pattern;
+
 import sun.jvm.hotspot.debugger.JVMDebugger;
 import sun.jvm.hotspot.utilities.*;
 
@@ -78,6 +81,7 @@ public class JMap extends Tool {
 
     private static String dumpfile = "heap.bin";
     private static int gzLevel = 0;
+    private static HeapRedactor heapRedactor;
 
     public void run() {
         Tool tool = null;
@@ -123,6 +127,7 @@ public class JMap extends Tool {
 
     public static void main(String[] args) {
         int mode = MODE_PMAP;
+        HeapRedactor.RedactParams redactParams = new HeapRedactor.RedactParams();
         if (args.length > 1 ) {
             String modeFlag = args[0];
             boolean copyArgs = true;
@@ -177,6 +182,19 @@ public class JMap extends Tool {
                                 System.err.println("compression level out of range (1-9): " + level);
                                 System.exit(1);
                             }
+                        } else if (keyValue[0].equals("HeapDumpRedact")) {
+                            if (!redactParams.setAndCheckHeapDumpRedact(keyValue[1])) {
+                                System.exit(1);
+                            }
+                        } else if (keyValue[0].equals("RedactMap")) {
+                            redactParams.setRedactMap(keyValue[1]);
+                        } else if (keyValue[0].equals("RedactMapFile")) {
+                            redactParams.setRedactMapFile(keyValue[1]);
+                        } else if (keyValue[0].equals("RedactClassPath")) {
+                            redactParams.setRedactClassPath(keyValue[1]);
+                        } else if (keyValue[0].equals("RedactPassword")) {
+                            redactParams.setRedactPassword(getRedactPassword());
+
                         } else {
                             System.err.println("unknown option:" + keyValue[0]);
 
@@ -189,12 +207,24 @@ public class JMap extends Tool {
                 }
             }
 
+            if (redactParams.getHeapDumpRedact() == null) {
+                if (redactParams.getRedactMap() == null && redactParams.getRedactMapFile() == null
+                    && redactParams.getRedactClassPath() == null) {
+                    redactParams.setEnableRedact(false);
+                } else {
+                    System.err.println("Error: HeapDumpRedact must be specified to enable heap-dump-redacting");
+                    copyArgs = false;
+                    System.exit(1);
+                }
+            }
+
             if (copyArgs) {
                 String[] newArgs = new String[args.length - 1];
                 for (int i = 0; i < newArgs.length; i++) {
                     newArgs[i] = args[i + 1];
                 }
                 args = newArgs;
+                heapRedactor = new HeapRedactor(redactParams);
             }
         }
 
@@ -202,9 +232,39 @@ public class JMap extends Tool {
         jmap.execute(args);
     }
 
+    private static CharBuffer getRedactPassword() {
+        CharBuffer redactPassword = CharBuffer.wrap("");
+        // heap dump may need a password
+        Console console = System.console();
+        char[] passwords = null;
+        if (console == null) {
+            return redactPassword;
+        }
+
+        try {
+            passwords = console.readPassword("redact authority password:");
+        } catch (Exception e) {
+        }
+        if(passwords == null) {
+            return redactPassword;
+        }
+
+        try {
+            CharBuffer cb = CharBuffer.wrap(passwords);
+            String passwordPattern = "^[0-9a-zA-Z!@#$]{1,9}$";
+            if(!Pattern.matches(passwordPattern, cb)) {
+                return redactPassword;
+            }
+            redactPassword = cb;
+        } catch (Exception e) {
+        }
+
+        return redactPassword;
+    }
+
     public boolean writeHeapHprofBin(String fileName, int gzLevel) {
         try {
-            HeapGraphWriter hgw;
+            HeapHprofBinWriter hgw;
             if (gzLevel == 0) {
                 hgw = new HeapHprofBinWriter();
             } else if (gzLevel >=1 && gzLevel <= 9) {
@@ -213,6 +273,7 @@ public class JMap extends Tool {
                 System.err.println("Illegal compression level: " + gzLevel);
                 return false;
             }
+            hgw.setHeapRedactor(heapRedactor);
             hgw.write(fileName);
             System.out.println("heap written to " + fileName);
             return true;
diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/AnnotationArray2D.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/AnnotationArray2D.java
new file mode 100644
index 000000000..fa2b06776
--- /dev/null
+++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/AnnotationArray2D.java
@@ -0,0 +1,62 @@
+/*
+ * Copyright (c) 2023, Huawei Technologies Co., Ltd. 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.  Huawei designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Huawei in the LICENSE file that accompanied this code.
+ *
+ * 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 visit https://gitee.com/openeuler/bishengjdk-8 if you need additional
+ * information or have any questions.
+ */
+
+package sun.jvm.hotspot.utilities;
+
+import sun.jvm.hotspot.debugger.Address;
+import sun.jvm.hotspot.runtime.VM;
+import sun.jvm.hotspot.types.Type;
+import sun.jvm.hotspot.types.TypeDataBase;
+import sun.jvm.hotspot.types.WrongTypeException;
+
+public class AnnotationArray2D extends GenericArray {
+    static {
+        VM.registerVMInitializedObserver(new Observer() {
+            public void update(Observable o, Object data) {
+                initialize(VM.getVM().getTypeDataBase());
+            }
+        });
+    }
+
+    private static synchronized void initialize(TypeDataBase db) throws WrongTypeException {
+        elemType = db.lookupType("Array<u1>*");
+
+        Type type = db.lookupType("Array<Array<u1>*>");
+        dataFieldOffset = type.getAddressField("_data").getOffset();
+    }
+
+    private static long dataFieldOffset;
+    protected static Type elemType;
+
+    public AnnotationArray2D(Address addr) {
+        super(addr, dataFieldOffset);
+    }
+
+    public U1Array getAt(int i) {
+        return new U1Array(getAddressAt(i));
+    }
+    public Type getElemType() {
+        return elemType;
+    }
+}
\ No newline at end of file
diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/HeapHprofBinWriter.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/HeapHprofBinWriter.java
index c9ffca89e..8501f4d93 100644
--- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/HeapHprofBinWriter.java
+++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/HeapHprofBinWriter.java
@@ -28,6 +28,10 @@ import java.io.*;
 import java.nio.ByteBuffer;
 import java.nio.ByteOrder;
 import java.nio.channels.*;
+import java.nio.CharBuffer;
+import java.security.NoSuchAlgorithmException;
+import java.security.spec.InvalidKeySpecException;
+import java.security.spec.KeySpec;
 import java.util.*;
 import java.util.zip.*;
 import sun.jvm.hotspot.debugger.*;
@@ -36,6 +40,10 @@ import sun.jvm.hotspot.oops.*;
 import sun.jvm.hotspot.runtime.*;
 import sun.jvm.hotspot.classfile.*;
 
+import javax.crypto.SecretKey;
+import javax.crypto.SecretKeyFactory;
+import javax.crypto.spec.PBEKeySpec;
+
 import static java.nio.charset.StandardCharsets.UTF_8;
 
 /*
@@ -387,6 +395,71 @@ public class HeapHprofBinWriter extends AbstractHeapGraphWriter {
     private static final long MAX_U4_VALUE = 0xFFFFFFFFL;
     int serialNum = 1;
 
+    // encrypt
+    private static int SALT_MIN_LENGTH = 8;
+    private static int HASH_BIT_SIZE = 256;
+    private static int HASH_ITERATIONS_COUNT = 10000;
+
+    // Heap Redact
+    private HeapRedactor heapRedactor;
+
+    public HeapRedactor getHeapRedactor() {
+        return heapRedactor;
+    }
+
+    public void setHeapRedactor(HeapRedactor heapRedactor) {
+        this.heapRedactor = heapRedactor;
+    }
+
+    public HeapRedactor.HeapDumpRedactLevel getHeapDumpRedactLevel(){
+        if(heapRedactor==null){
+            return HeapRedactor.HeapDumpRedactLevel.REDACT_OFF;
+        }
+        return heapRedactor.getHeapDumpRedactLevel();
+    }
+
+    public Optional<CharBuffer> getHeapDumpRedactPassword() {
+        return heapRedactor == null ? Optional.empty() : Optional.ofNullable(heapRedactor.getRedactPassword());
+    }
+
+    private Optional<String> lookupRedactName(String name){
+        return heapRedactor == null ? Optional.empty() : heapRedactor.lookupRedactName(name);
+    }
+
+    private void resetRedactParams(){
+        Optional<String> redactOption = getVMRedactParameter("HeapDumpRedact");
+        String redactStr= redactOption.isPresent() ?  redactOption.get() : null;
+        if(redactStr!=null && !redactStr.isEmpty()){
+            HeapRedactor.RedactParams redactParams = new HeapRedactor.RedactParams();
+            if(HeapRedactor.REDACT_ANNOTATION_OPTION.equals(redactStr)){
+                Optional<String> classPathOption = getVMRedactParameter("RedactClassPath");
+                String classPathStr = classPathOption.isPresent() ? classPathOption.get() : null;
+                redactStr = classPathOption.isPresent() ? redactStr : HeapRedactor.REDACT_OFF_OPTION;
+                redactParams.setRedactClassPath(classPathStr);
+            } else {
+                Optional<String> redactMapOption = getVMRedactParameter("RedactMap");
+                String redactMapStr = redactMapOption.isPresent() ? redactMapOption.get() : null;
+                redactParams.setRedactMap(redactMapStr);
+                Optional<String> redactMapFileOption = getVMRedactParameter("RedactMapFile");
+                String redactMapFileStr = redactMapFileOption.isPresent() ? redactMapFileOption.get() : null;
+                redactParams.setRedactMapFile(redactMapFileStr);
+            }
+            if(!redactParams.setAndCheckHeapDumpRedact(redactStr)){
+                redactParams.setAndCheckHeapDumpRedact(HeapRedactor.REDACT_OFF_OPTION);
+            }
+            setHeapRedactor(new HeapRedactor(redactParams));
+        }
+    }
+
+    private Optional<String>  getVMRedactParameter(String name) {
+        VM vm = VM.getVM();
+        VM.Flag flag = vm.getCommandLineFlag(name);
+        if(flag == null){
+            return Optional.empty();
+        }
+        return Optional.ofNullable(flag.getCcstr());
+    }
+
     public HeapHprofBinWriter() {
         this.KlassMap = new ArrayList<Klass>();
         this.names = new HashSet<Symbol>();
@@ -399,9 +472,69 @@ public class HeapHprofBinWriter extends AbstractHeapGraphWriter {
         this.gzLevel = gzLevel;
     }
 
+    private boolean checkPassword() {
+        Optional<String> redactAuthOption = getVMRedactParameter("RedactPassword");
+        String redactAuth = redactAuthOption.isPresent() ? redactAuthOption.get() : null;
+        boolean redactAuthFlag = true;
+        if(redactAuth != null) {
+            String[] auths = redactAuth.split(",");
+            if(auths.length != 2) {
+                return redactAuthFlag;
+            }
+
+            Optional<CharBuffer> passwordOption = getHeapDumpRedactPassword();
+            CharBuffer password = passwordOption.isPresent() ? passwordOption.get() : CharBuffer.wrap("");
+            char[] passwordChars = null;
+            try {
+                passwordChars = password.array();
+
+                byte[] saltBytes = auths[1].getBytes("UTF-8");
+                if(saltBytes.length < SALT_MIN_LENGTH) {
+                    return redactAuthFlag;
+                }
+
+                String digestStr = getEncryptValue(passwordChars, saltBytes);
+                redactAuthFlag = auths[0].equals(digestStr);
+            } catch (Exception e) {
+                // ignore
+                redactAuthFlag = false;
+            } finally {
+                // clear all password
+                if(passwordChars != null) {
+                    Arrays.fill(passwordChars, '0');
+                }
+            }
+        }
+
+        return redactAuthFlag;
+    }
+
+    private String getEncryptValue(char[] passwordValue, byte[] saltBytes) throws InvalidKeySpecException, NoSuchAlgorithmException {
+        StringBuilder digestStrBuilder = new StringBuilder();
+
+        KeySpec spec = new PBEKeySpec(passwordValue, saltBytes, HASH_ITERATIONS_COUNT, HASH_BIT_SIZE);
+        SecretKeyFactory secretKeyFactory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA256");
+        SecretKey secretKey = secretKeyFactory.generateSecret(spec);
+        byte[] digestBytes = secretKey.getEncoded();
+        for (byte b : digestBytes) {
+            String hex = Integer.toHexString(0xff & b);
+            if (hex.length() == 1) {
+                digestStrBuilder.append('0');
+            }
+            digestStrBuilder.append(hex);
+        }
+        String digestStr = digestStrBuilder.toString();
+
+        return digestStr;
+    }
+
     public synchronized void write(String fileName) throws IOException {
         VM vm = VM.getVM();
 
+        if(getHeapDumpRedactLevel() == HeapRedactor.HeapDumpRedactLevel.REDACT_UNKNOWN || !checkPassword()) {
+            resetRedactParams();
+        }
+
         // Check whether we should dump the heap as segments
         useSegmentedHeapDump = isCompression() ||
                 (vm.getUniverse().heap().used() > HPROF_SEGMENTED_HEAP_DUMP_THRESHOLD);
@@ -465,6 +598,9 @@ public class HeapHprofBinWriter extends AbstractHeapGraphWriter {
         // this will write heap data into the buffer stream
         super.write();
 
+        // write redacted String Field record
+        writeAnnotateFieldValue();
+
         // flush buffer stream.
         out.flush();
         if (!useSegmentedHeapDump) {
@@ -725,6 +861,68 @@ public class HeapHprofBinWriter extends AbstractHeapGraphWriter {
         }
     }
 
+    private void writeAnnotateFieldValue() throws IOException {
+        HeapRedactor.HeapDumpRedactLevel level = getHeapDumpRedactLevel();
+        if(level != HeapRedactor.HeapDumpRedactLevel.REDACT_ANNOTATION
+                && level != HeapRedactor.HeapDumpRedactLevel.REDACT_DIYRULES) {
+            return;
+        }
+
+        HeapRedactor.RedactVectorNode redactVector = heapRedactor.getHeaderNode();
+        if(redactVector == null) {
+            return;
+        }
+
+        while(redactVector != null) {
+            List<TypeArray> typeArrayList = redactVector.getTypeArrayList();
+            for(int i = 0; i < redactVector.getCurrentIndex(); i++) {
+                TypeArray array = typeArrayList.get(i);
+                TypeArrayKlass tak = (TypeArrayKlass) array.getKlass();
+                final int type = (int) tak.getElementType();
+
+                if(type != TypeArrayKlass.T_BYTE) {
+                    continue;
+                }
+
+                OopHandle handle = (array != null)? array.getHandle() : null;
+                long address = getAddressValue(handle);
+                Optional<String> annotateValueOptional = heapRedactor.lookupRedactAnnotationValue(address);
+                String annotateValue = annotateValueOptional.isPresent() ? annotateValueOptional.get() : null;
+                long expectLength = array.getLength();
+                if(annotateValue != null) {
+                    expectLength = annotateValue.length();
+                }
+
+                int headerSize = getArrayHeaderSize(false);
+                final String typeName = tak.getElementTypeName();
+                final long typeSize = getSizeForType(type);
+                final int length = calculateArrayMaxLength(expectLength,
+                        headerSize,
+                        typeSize,
+                        typeName);
+                out.writeByte((byte) HPROF_GC_PRIM_ARRAY_DUMP);
+                writeObjectID(array);
+                out.writeInt(DUMMY_STACK_TRACE_ID);
+                out.writeInt(length);
+                out.writeByte((byte) type);
+
+                if (annotateValue != null) {
+                    for(int index = 0; index < expectLength; index++) {
+                        out.writeByte(annotateValue.charAt(index));
+                    }
+                } else {
+                    for (int index = 0; index < length; index++) {
+                        long offset = BYTE_BASE_OFFSET + index * BYTE_SIZE;
+                        out.writeByte(array.getHandle().getJByteAt(offset));
+                    }
+                }
+            }
+
+            HeapRedactor.RedactVectorNode tempVector = redactVector.getNext();
+            redactVector = tempVector;
+        }
+    }
+
     protected void writeClass(Instance instance) throws IOException {
         Klass reflectedKlass = java_lang_Class.asKlass(instance);
         // dump instance record only for primitive type Class objects.
@@ -958,9 +1156,18 @@ public class HeapHprofBinWriter extends AbstractHeapGraphWriter {
     }
 
     protected void writePrimitiveArray(TypeArray array) throws IOException {
+        HeapRedactor.HeapDumpRedactLevel level = getHeapDumpRedactLevel();
+
         int headerSize = getArrayHeaderSize(false);
         TypeArrayKlass tak = (TypeArrayKlass) array.getKlass();
         final int type = tak.getElementType();
+
+        if(type == TypeArrayKlass.T_BYTE && (level == HeapRedactor.HeapDumpRedactLevel.REDACT_ANNOTATION
+            || level == HeapRedactor.HeapDumpRedactLevel.REDACT_DIYRULES)) {
+            heapRedactor.recordTypeArray(array);
+            return;
+        }
+
         final String typeName = tak.getElementTypeName();
         final long typeSize = getSizeForType(type);
         final int length = calculateArrayMaxLength(array.getLength(),
@@ -972,12 +1179,16 @@ public class HeapHprofBinWriter extends AbstractHeapGraphWriter {
         out.writeInt(DUMMY_STACK_TRACE_ID);
         out.writeInt(length);
         out.writeByte((byte) type);
+
+        boolean shouldRedact = ( level == HeapRedactor.HeapDumpRedactLevel.REDACT_BASIC
+                || level == HeapRedactor.HeapDumpRedactLevel.REDACT_FULL);
+
         switch (type) {
             case TypeArrayKlass.T_BOOLEAN:
                 writeBooleanArray(array, length);
                 break;
             case TypeArrayKlass.T_CHAR:
-                writeCharArray(array, length);
+                writeCharArray(array, length, shouldRedact);
                 break;
             case TypeArrayKlass.T_FLOAT:
                 writeFloatArray(array, length);
@@ -986,13 +1197,13 @@ public class HeapHprofBinWriter extends AbstractHeapGraphWriter {
                 writeDoubleArray(array, length);
                 break;
             case TypeArrayKlass.T_BYTE:
-                writeByteArray(array, length);
+                writeByteArray(array, length, shouldRedact);
                 break;
             case TypeArrayKlass.T_SHORT:
                 writeShortArray(array, length);
                 break;
             case TypeArrayKlass.T_INT:
-                writeIntArray(array, length);
+                writeIntArray(array, length, shouldRedact);
                 break;
             case TypeArrayKlass.T_LONG:
                 writeLongArray(array, length);
@@ -1010,10 +1221,16 @@ public class HeapHprofBinWriter extends AbstractHeapGraphWriter {
         }
     }
 
-    private void writeByteArray(TypeArray array, int length) throws IOException {
-        for (int index = 0; index < length; index++) {
-             long offset = BYTE_BASE_OFFSET + index * BYTE_SIZE;
-             out.writeByte(array.getHandle().getJByteAt(offset));
+    private void writeByteArray(TypeArray array, int length, boolean shouldRedact) throws IOException {
+        if (shouldRedact) {
+            for(int index = 0; index < length; index++) {
+                out.writeByte(0);
+            }
+        } else {
+            for (int index = 0; index < length; index++) {
+                 long offset = BYTE_BASE_OFFSET + index * BYTE_SIZE;
+                 out.writeByte(array.getHandle().getJByteAt(offset));
+            }
         }
     }
 
@@ -1024,10 +1241,16 @@ public class HeapHprofBinWriter extends AbstractHeapGraphWriter {
         }
     }
 
-    private void writeIntArray(TypeArray array, int length) throws IOException {
-        for (int index = 0; index < length; index++) {
-             long offset = INT_BASE_OFFSET + index * INT_SIZE;
-             out.writeInt(array.getHandle().getJIntAt(offset));
+    private void writeIntArray(TypeArray array, int length, boolean shouldRedact) throws IOException {
+        if (shouldRedact) {
+            for(int index = 0; index < length; index++) {
+                out.writeInt(0);
+            }
+        } else {
+            for (int index = 0; index < length; index++) {
+                 long offset = INT_BASE_OFFSET + index * INT_SIZE;
+                 out.writeInt(array.getHandle().getJIntAt(offset));
+            }
         }
     }
 
@@ -1038,10 +1261,16 @@ public class HeapHprofBinWriter extends AbstractHeapGraphWriter {
         }
     }
 
-    private void writeCharArray(TypeArray array, int length) throws IOException {
-        for (int index = 0; index < length; index++) {
-             long offset = CHAR_BASE_OFFSET + index * CHAR_SIZE;
-             out.writeChar(array.getHandle().getJCharAt(offset));
+    private void writeCharArray(TypeArray array, int length, boolean shouldRedact) throws IOException {
+        if (shouldRedact) {
+            for(int index = 0; index < length; index++) {
+                out.writeChar(0);
+            }
+        } else {
+            for (int index = 0; index < length; index++) {
+                 long offset = CHAR_BASE_OFFSET + index * CHAR_SIZE;
+                 out.writeChar(array.getHandle().getJCharAt(offset));
+            }
         }
     }
 
@@ -1083,6 +1312,16 @@ public class HeapHprofBinWriter extends AbstractHeapGraphWriter {
         for (Iterator<Field> itr = fields.iterator(); itr.hasNext();) {
             writeField(itr.next(), instance);
         }
+
+        // record the anonymous value for every field
+        if(klass instanceof InstanceKlass && heapRedactor != null) {
+            if(heapRedactor.getHeapDumpRedactLevel() == HeapRedactor.HeapDumpRedactLevel.REDACT_ANNOTATION
+                    && heapRedactor.getRedactAnnotationClassPath() != null && !heapRedactor.getRedactAnnotationClassPath().isEmpty()) {
+                recordAnnotationValueMap(fields, instance);
+            } else if( heapRedactor.getHeapDumpRedactLevel() == HeapRedactor.HeapDumpRedactLevel.REDACT_DIYRULES) {
+                recordDiyRulesValueMap(fields, instance);
+            }
+        }
     }
 
     //-- Internals only below this point
@@ -1105,6 +1344,131 @@ public class HeapHprofBinWriter extends AbstractHeapGraphWriter {
         }
     }
 
+    private void recordAnnotationValueMap(List<Field> fields, Instance instance) {
+        Klass klass = instance.getKlass();
+        boolean inJavaPackage = false;
+        Symbol classNameSymbol = klass.getName();
+        if(classNameSymbol != null) {
+            String className = classNameSymbol.asString();
+            inJavaPackage = (className != null && className.startsWith("java/"));
+        }
+        if(inJavaPackage){
+            return;
+        }
+        for (Field field : fields) {
+            Symbol fieldSignature = field.getSignature();
+            if(fieldSignature == null || fieldSignature.asString() == null
+                    || !"Ljava/lang/String;".equals(fieldSignature.asString())) {
+                continue;
+            }
+            try {
+                InstanceKlass fieldHolder = field.getFieldHolder();
+                U1Array fieldAnnotations = field.getFieldAnnotations();
+                Optional<String> anonymousValueOption = getAnonymousValue(fieldAnnotations, fieldHolder.getConstants());
+                if(!anonymousValueOption.isPresent()) {
+                    continue;
+                }
+                long address = getStringFieldAddress(field, instance);
+                if(address > 0L) {
+                    heapRedactor.recordRedactAnnotationValue(address, anonymousValueOption.get());
+                }
+            } catch (Exception e) {
+            }
+        }
+    }
+
+    private Optional<String> getAnonymousValue(U1Array fieldAnnotations, ConstantPool cp) {
+        Optional<String> anonymousValueOption = Optional.empty();
+        if (fieldAnnotations.getAddress() == null) {
+            return anonymousValueOption;
+        }
+
+        int fieldAnnotationsTagsLen = fieldAnnotations.length();
+        boolean isAnonymousAnnotation = false;
+        int annotationStart = 0;
+        int annotationEnd = 0;
+        for (int j = 0; j < fieldAnnotationsTagsLen; j++) {
+            int cpIndex = fieldAnnotations.at(j);
+            if (cpIndex >= cp.getLength() || cpIndex < 0) {
+                continue;
+            }
+            byte cpConstType = cp.getTags().at(cpIndex);
+            if (cpConstType == ConstantPool.JVM_CONSTANT_Utf8) {
+                annotationStart += (isAnonymousAnnotation ? 0 : 1);
+                annotationEnd++;
+                Symbol symbol = cp.getSymbolAt(cpIndex);
+                if (symbol.asString() == null || symbol.asString().isEmpty()) {
+                    continue;
+                }
+                if (symbol.asString().equals("L" + heapRedactor.getRedactAnnotationClassPath() + ";")) {
+                    isAnonymousAnnotation = true;
+                }
+                if(annotationEnd - annotationStart == 1 && !"value".equals(symbol.asString())) {
+                    break;
+                }
+                if(annotationEnd - annotationStart == 2) {
+                    anonymousValueOption = Optional.ofNullable(cp.getSymbolAt(cpIndex).asString());
+                    break;
+                }
+            }
+        }
+        return anonymousValueOption;
+    }
+
+    private void recordDiyRulesValueMap(List<Field> fields, Instance instance) {
+        Klass klass = instance.getKlass();
+        boolean diyRulesFlag = false;
+        Symbol classNameSymbol = klass.getName();
+        Map<String, String> redactRulesMap = null;
+        if(classNameSymbol != null) {
+            String className = classNameSymbol.asString();
+            Optional<Map<String, String>> redactRulesMapOptional = className == null ? Optional.empty() : heapRedactor.getRedactRulesTable(className);
+            redactRulesMap = redactRulesMapOptional.isPresent() ? redactRulesMapOptional.get() : null;
+            diyRulesFlag = (redactRulesMap != null);
+        }
+        if(!diyRulesFlag){
+            return;
+        }
+        for (Field field : fields) {
+            Symbol fieldSignature = field.getSignature();
+            if(fieldSignature == null || fieldSignature.asString() == null || !"Ljava/lang/String;".equals(fieldSignature.asString())) {
+                continue;
+            }
+
+            try {
+                Symbol filedNameSymbol = field.getName();
+                if(filedNameSymbol == null) {
+                    continue;
+                }
+
+                String filedName = filedNameSymbol.asString();
+                String replaceValue = filedName == null ? null : redactRulesMap.get(filedName);
+                long address = getStringFieldAddress(field, instance);
+                if(address > 0L && replaceValue != null) {
+                    heapRedactor.recordRedactAnnotationValue(address, replaceValue);
+                }
+            } catch (Exception e) {
+            }
+        }
+    }
+
+    private long getStringFieldAddress(Field field, Instance instance) {
+        long address = 0L;
+        if(field instanceof OopField) {
+            Oop fieldOop = ((OopField) field).getValue(instance);
+            Field stringField = null;
+            if (fieldOop != null && fieldOop.getKlass() instanceof InstanceKlass) {
+                List<Field> oopFiledSubs = ((InstanceKlass) fieldOop.getKlass()).getAllFields();
+                stringField = oopFiledSubs.iterator().next();
+            }
+            if (stringField != null && stringField instanceof OopField) {
+                OopHandle handle = ((OopField) stringField).getValueAsOopHandle(fieldOop);
+                address = getAddressValue(handle);
+            }
+        }
+        return address;
+    }
+
     public static int signatureToHprofKind(char ch) {
         switch (ch) {
         case JVM_SIGNATURE_CLASS:
@@ -1221,7 +1585,18 @@ public class HeapHprofBinWriter extends AbstractHeapGraphWriter {
         // If name is already written don't write it again.
         if (names.add(sym)) {
             if(sym != null) {
-              byte[] buf = sym.asString().getBytes(UTF_8);
+              String symbolStr = sym.asString();
+              HeapRedactor.HeapDumpRedactLevel level = getHeapDumpRedactLevel();
+              boolean shouldRedact = (level == HeapRedactor.HeapDumpRedactLevel.REDACT_NAMES ||
+                    level == HeapRedactor.HeapDumpRedactLevel.REDACT_FULL);
+              byte[] buf = null;
+              if(shouldRedact) {
+                Optional<String> redactField = lookupRedactName(symbolStr);
+                buf = redactField.isPresent() ? redactField.get().getBytes("UTF-8") : null;
+              }
+              if(buf == null) {
+                buf = symbolStr.getBytes(UTF_8);
+              }
               writeHeader(HPROF_UTF8, buf.length + OBJ_ID_SIZE);
               writeSymbolID(sym);
               out.write(buf);
@@ -1301,11 +1676,23 @@ public class HeapHprofBinWriter extends AbstractHeapGraphWriter {
         List<Field> res = new ArrayList<>();
         while (klass != null) {
             List<Field> curFields = klass.getImmediateFields();
+            Annotation annotation = klass.getAnnotation();
+            AnnotationArray2D fieldsAnnotations = (annotation == null) ? null : annotation.getFieldsAnnotations();
+            boolean hasAnnotations = false;
+            if(fieldsAnnotations != null && fieldsAnnotations.getAddress() != null) {
+                hasAnnotations = true;
+            }
+            int fieldIndex = 0;
             for (Iterator<Field> itr = curFields.iterator(); itr.hasNext();) {
                 Field f = itr.next();
                 if (! f.isStatic()) {
                     res.add(f);
+                    // record annotation for class Field
+                    if(hasAnnotations) {
+                        f.setFieldAnnotations(fieldsAnnotations.getAt(fieldIndex));
+                    }
                 }
+                fieldIndex++;
             }
             klass = (InstanceKlass) klass.getSuper();
         }
diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/HeapRedactor.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/HeapRedactor.java
new file mode 100644
index 000000000..5c442b2bb
--- /dev/null
+++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/HeapRedactor.java
@@ -0,0 +1,454 @@
+/*
+ * Copyright (c) 2023, Huawei Technologies Co., Ltd. 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.  Huawei designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Huawei in the LICENSE file that accompanied this code.
+ *
+ * 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 visit https://gitee.com/openeuler/bishengjdk-8 if you need additional
+ * information or have any questions.
+ */
+
+package sun.jvm.hotspot.utilities;
+
+import sun.jvm.hotspot.oops.TypeArray;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileReader;
+import java.io.IOException;
+import java.nio.CharBuffer;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Locale;
+import java.util.Optional;
+
+public class HeapRedactor {
+    public enum HeapDumpRedactLevel {
+        REDACT_UNKNOWN,
+        REDACT_OFF,
+        REDACT_NAMES,
+        REDACT_BASIC,
+        REDACT_DIYRULES,
+        REDACT_ANNOTATION,
+        REDACT_FULL
+    }
+
+    private HeapDumpRedactLevel redactLevel;
+    private Map<String, String> redactNameTable;
+    private Map<String, Map<String, String>> redactClassTable;
+    private String redactClassFullName = null;
+    private Map<Long, String> redactValueTable;
+    private RedactVectorNode headerNode;
+    private RedactVectorNode currentNode;
+
+    private RedactParams redactParams;
+
+    public static final String HEAP_DUMP_REDACT_PREFIX = "HeapDumpRedact=";
+    public static final String REDACT_MAP_PREFIX = "RedactMap=";
+    public static final String REDACT_MAP_FILE_PREFIX = "RedactMapFile=";
+    public static final String REDACT_CLASS_PATH_PREFIX = "RedactClassPath=";
+    public static final String REDACT_PASSWORD_PREFIX = "RedactPassword=";
+
+    public static final String REDACT_UNKNOWN_STR = "UNKNOWN";
+    public static final String REDACT_OFF_STR = "OFF";
+    public static final String REDACT_NAME_STR = "NAMES";
+    public static final String REDACT_BASIC_STR = "BASIC";
+    public static final String REDACT_DIYRULES_STR = "DIYRULES";
+    public static final String REDACT_ANNOTATION_STR = "ANNOTATION";
+    public static final String REDACT_FULL_STR = "FULL";
+
+    public static final String REDACT_UNKNOWN_OPTION = REDACT_UNKNOWN_STR.toLowerCase(Locale.ROOT);
+    public static final String REDACT_OFF_OPTION = REDACT_OFF_STR.toLowerCase(Locale.ROOT);
+    public static final String REDACT_NAME_OPTION = REDACT_NAME_STR.toLowerCase(Locale.ROOT);
+    public static final String REDACT_BASIC_OPTION = REDACT_BASIC_STR.toLowerCase(Locale.ROOT);
+    public static final String REDACT_DIYRULES_OPTION = REDACT_DIYRULES_STR.toLowerCase(Locale.ROOT);
+    public static final String REDACT_ANNOTATION_OPTION = REDACT_ANNOTATION_STR.toLowerCase(Locale.ROOT);
+    public static final String REDACT_FULL_OPTION = REDACT_FULL_STR.toLowerCase(Locale.ROOT);
+
+    public static final int PATH_MAX = 4096;
+    public static final int REDACT_VECTOR_SIZE = 1024;
+
+    public HeapRedactor(RedactParams redactParams) {
+        this.redactParams = redactParams;
+        redactLevel = HeapDumpRedactLevel.REDACT_UNKNOWN;
+        redactNameTable = null;
+        redactClassTable = null;
+        redactValueTable = null;
+        init(null);
+    }
+
+    private void init(String options) {
+        if (redactLevel == HeapDumpRedactLevel.REDACT_UNKNOWN) {
+            initHeapdumpRedactLevel(options);
+        }
+    }
+
+    public HeapDumpRedactLevel getHeapDumpRedactLevel() {
+        return redactLevel;
+    }
+
+    public String getRedactLevelString() {
+        switch (redactLevel) {
+            case REDACT_BASIC:
+                return REDACT_BASIC_STR;
+            case REDACT_NAMES:
+                return REDACT_NAME_STR;
+            case REDACT_FULL:
+                return REDACT_FULL_STR;
+            case REDACT_DIYRULES:
+                return REDACT_DIYRULES_STR;
+            case REDACT_ANNOTATION:
+                return REDACT_ANNOTATION_STR;
+            case REDACT_OFF:
+                return REDACT_OFF_STR;
+            case REDACT_UNKNOWN:
+            default:
+                return REDACT_UNKNOWN_STR;
+        }
+    }
+
+    public Optional<String> lookupRedactName(String name){
+        return Optional.ofNullable(redactNameTable == null ? null : redactNameTable.get(name));
+    }
+
+    public void recordTypeArray(TypeArray oop) {
+        int tmp_index = currentNode.getCurrentIndex();
+        if(tmp_index == REDACT_VECTOR_SIZE){
+            RedactVectorNode newNode = new RedactVectorNode();
+            List<TypeArray> list = new ArrayList<>(REDACT_VECTOR_SIZE);
+            newNode.setTypeArrayList(list);
+            newNode.setNext(null);
+            newNode.setCurrentIndex(0);
+            tmp_index = 0;
+            currentNode.setNext(newNode);
+            currentNode = newNode;
+        }
+        currentNode.getTypeArrayList().add(tmp_index, oop);
+        tmp_index++;
+        currentNode.setCurrentIndex(tmp_index);
+
+    }
+
+    public RedactVectorNode getHeaderNode(){
+        return headerNode;
+    }
+
+    public void recordRedactAnnotationValue(Long addr, String value) {
+        redactValueTable.put(addr, value);
+    }
+
+    public Optional<String> lookupRedactAnnotationValue(Long addr){
+        return Optional.ofNullable(redactValueTable == null ? null : redactValueTable.get(addr));
+    }
+
+    public String getRedactAnnotationClassPath(){
+        return redactParams.getRedactClassPath();
+    }
+
+    public CharBuffer getRedactPassword(){
+        return redactParams.getRedactPassword();
+    }
+
+    public Optional<Map<String, String>> getRedactRulesTable(String key) {
+        return Optional.ofNullable(redactClassTable == null ? null: redactClassTable.get(key));
+    }
+
+    private HeapDumpRedactLevel initHeapdumpRedactLevel(String options) {
+        RedactParams customizedParams = parseRedactOptions(options);
+
+        if (customizedParams.isEnableRedact() || this.redactParams == null) {
+            this.redactParams = customizedParams;
+        }
+
+        if (redactParams.heapDumpRedact == null) {
+            redactLevel = HeapDumpRedactLevel.REDACT_UNKNOWN;
+        } else {
+            if (REDACT_BASIC_OPTION.equals(redactParams.heapDumpRedact)) {
+                redactLevel = HeapDumpRedactLevel.REDACT_BASIC;
+            } else if (REDACT_NAME_OPTION.equals(redactParams.heapDumpRedact)) {
+                redactLevel = HeapDumpRedactLevel.REDACT_NAMES;
+                initRedactMap();
+            } else if (REDACT_FULL_OPTION.equals(redactParams.heapDumpRedact)) {
+                redactLevel = HeapDumpRedactLevel.REDACT_FULL;
+                initRedactMap();
+            } else if (REDACT_DIYRULES_OPTION.equals(redactParams.heapDumpRedact)) {
+                redactLevel = HeapDumpRedactLevel.REDACT_DIYRULES;
+                initRedactMap();
+                initRedactVector();
+            } else if (REDACT_ANNOTATION_OPTION.equals(redactParams.heapDumpRedact)) {
+                redactLevel = HeapDumpRedactLevel.REDACT_ANNOTATION;
+                initRedactVector();
+            } else {
+                redactLevel = HeapDumpRedactLevel.REDACT_OFF;
+            }
+        }
+        return redactLevel;
+    }
+
+    private void initRedactVector(){
+        if(redactValueTable == null) {
+            redactValueTable = new HashMap<>();
+        }
+        if(headerNode == null) {
+            headerNode = new RedactVectorNode();
+            List<TypeArray> list = new ArrayList<>(REDACT_VECTOR_SIZE);
+            headerNode.setTypeArrayList(list);
+            headerNode.setNext(null);
+            headerNode.setCurrentIndex(0);
+            currentNode = headerNode;
+        }
+    }
+
+    private RedactParams parseRedactOptions(String optionStr) {
+        RedactParams params = new RedactParams(REDACT_OFF_OPTION, null, null, null, null);
+        if (optionStr != null) {
+            String[] options = optionStr.split(",");
+            for (String option : options) {
+                if (option.startsWith(HEAP_DUMP_REDACT_PREFIX)) {
+                    params.setAndCheckHeapDumpRedact(option.substring(HEAP_DUMP_REDACT_PREFIX.length()));
+                } else if (option.startsWith(REDACT_MAP_PREFIX)) {
+                    params.setRedactMap(option.substring(REDACT_MAP_PREFIX.length()));
+                } else if (option.startsWith(REDACT_MAP_FILE_PREFIX)) {
+                    params.setRedactMapFile(option.substring(REDACT_MAP_FILE_PREFIX.length()));
+                } else if (option.startsWith(REDACT_CLASS_PATH_PREFIX)) {
+                    params.setRedactClassPath(option.substring(REDACT_CLASS_PATH_PREFIX.length()));
+                } else {
+                    continue;
+                }
+            }
+        }
+        return params;
+    }
+
+    private void initRedactMap() {
+        if (redactParams.redactMapFile != null) {
+            readRedactMapFromFile(redactParams.redactMapFile);
+        }
+        if (redactParams.redactMap != null) {
+            parseRedactMapStringDependOnMode(redactParams.redactMap, redactLevel);
+        }
+    }
+
+    private void readRedactMapFromFile(String path) {
+        if (path == null || path.isEmpty()) {
+            // RedactMapFile=<file> not specified
+            return;
+        } else {
+            if (path.length() >= PATH_MAX) {
+                System.err.println("RedactMap File path is too long");
+                return;
+            }
+            File file = new File(path);
+            if (!file.exists() || !file.isFile()) {
+                System.err.println("RedactMap File does not exist");
+            }
+            try (BufferedReader reader = new BufferedReader(new FileReader(path))) {
+                String line;
+                while ((line = reader.readLine()) != null) {
+                    parseRedactMapStringDependOnMode(line, redactLevel);
+                }
+            } catch (IOException e) {
+                System.err.println("Encounter an error when reading " + path + " , skip processing RedactMap File.");
+                e.printStackTrace();
+                return;
+            }
+        }
+    }
+
+    private void parseRedactMapStringDependOnMode(String nameMapList, HeapDumpRedactLevel redactLevel) {
+        if(redactLevel == HeapDumpRedactLevel.REDACT_DIYRULES) {
+            parseRedactDiyRulesString(nameMapList);
+        } else {
+            parseRedactMapString(nameMapList);
+        }
+    }
+
+    private void parseRedactMapString(String nameMapList) {
+        if (redactNameTable == null) {
+            redactNameTable = new HashMap<>();
+        }
+        String[] tokens = nameMapList.split("[,;\\s+]");
+        for (String token : tokens) {
+            String[] pair = token.split(":");
+            if (pair.length == 2) {
+                redactNameTable.put(pair[0], pair[1]);
+            }
+        }
+    }
+
+    private void parseRedactDiyRulesString(String nameMapList) {
+        if (redactClassTable == null) {
+            redactClassTable = new HashMap<>();
+        }
+        Map<String, String> redactRulesTable = redactClassFullName == null ? null : redactClassTable.get(redactClassFullName);
+        String[] tokens = nameMapList.split("[,;\\s+]");
+        for (String token : tokens) {
+            String[] pair = token.split(":");
+            if (pair.length == 1) {
+                redactClassFullName = pair[0].replace(".", "/");
+                redactRulesTable = redactClassTable.get(redactClassFullName);
+                if(redactRulesTable == null) {
+                    redactRulesTable = new HashMap<>();
+                    redactClassTable.put(redactClassFullName, redactRulesTable);
+                }
+            }
+            if (pair.length == 2 && redactRulesTable != null) {
+                redactRulesTable.put(pair[0], pair[1]);
+            }
+        }
+    }
+
+    public static class RedactParams {
+        private String heapDumpRedact;
+        private String redactMap;
+        private String redactMapFile;
+        private String redactClassPath;
+        private CharBuffer redactPassword;
+        private boolean enableRedact = false;
+
+        public RedactParams() {
+        }
+
+        public RedactParams(String heapDumpRedact, String redactMap, String redactMapFile, String redactClassPath, CharBuffer redactPassword) {
+            this.heapDumpRedact = heapDumpRedact;
+            this.redactMap = redactMap;
+            this.redactMapFile = redactMapFile;
+            this.redactClassPath = redactClassPath;
+            this.redactPassword = redactPassword;
+        }
+
+        @Override
+        public String toString() {
+            StringBuilder builder = new StringBuilder();
+            if (heapDumpRedact != null) {
+                builder.append(HEAP_DUMP_REDACT_PREFIX);
+                builder.append(heapDumpRedact);
+                builder.append(",");
+            }
+            if (redactMap != null) {
+                builder.append(REDACT_MAP_PREFIX);
+                builder.append(redactMap);
+                builder.append(",");
+            }
+            if (redactMapFile != null) {
+                builder.append(REDACT_MAP_FILE_PREFIX);
+                builder.append(redactMapFile);
+                builder.append(",");
+            }
+            if (redactClassPath != null) {
+                builder.append(REDACT_CLASS_PATH_PREFIX);
+                builder.append(redactClassPath);
+            }
+            return builder.toString();
+        }
+
+        public String getHeapDumpRedact() {
+            return heapDumpRedact;
+        }
+
+        public boolean setAndCheckHeapDumpRedact(String heapDumpRedact) {
+            if (!checkLauncherHeapdumpRedactSupport(heapDumpRedact)) {
+                return false;
+            }
+            this.heapDumpRedact = heapDumpRedact;
+            this.enableRedact = true;
+            return true;
+        }
+
+        public String getRedactMap() {
+            return redactMap;
+        }
+
+        public void setRedactMap(String redactMap) {
+            this.redactMap = redactMap;
+        }
+
+        public String getRedactMapFile() {
+            return redactMapFile;
+        }
+
+        public void setRedactMapFile(String redactMapFile) {
+            this.redactMapFile = redactMapFile;
+        }
+
+        public String getRedactClassPath() {
+            return redactClassPath;
+        }
+
+        public void setRedactClassPath(String redactClassPath) {
+            this.redactClassPath = redactClassPath;
+        }
+
+        public CharBuffer getRedactPassword() {
+            return redactPassword;
+        }
+
+        public void setRedactPassword(CharBuffer redactPassword) {
+            this.redactPassword = redactPassword;
+        }
+
+        public static boolean checkLauncherHeapdumpRedactSupport(String value) {
+            String[] validValues = {REDACT_BASIC_OPTION, REDACT_NAME_OPTION, REDACT_FULL_OPTION, REDACT_DIYRULES_OPTION, REDACT_ANNOTATION_OPTION, REDACT_OFF_OPTION};
+            for (String validValue : validValues) {
+                if (validValue.equals(value)) {
+                    return true;
+                }
+            }
+            return false;
+        }
+
+        public boolean isEnableRedact() {
+            return enableRedact;
+        }
+
+        public void setEnableRedact(boolean enableRedact) {
+            this.enableRedact = enableRedact;
+        }
+    }
+
+    public class RedactVectorNode{
+        private List<TypeArray> typeArrayList;
+        private RedactVectorNode next;
+        private int currentIndex;
+
+        public List<TypeArray> getTypeArrayList() {
+            return typeArrayList;
+        }
+
+        public void setTypeArrayList(List<TypeArray> list) {
+            this.typeArrayList = list;
+        }
+
+        public RedactVectorNode getNext() {
+            return next;
+        }
+
+        public void setNext(RedactVectorNode next) {
+            this.next = next;
+        }
+
+        public int getCurrentIndex() {
+            return currentIndex;
+        }
+
+        public void setCurrentIndex(int index) {
+            this.currentIndex = index;
+        }
+    }
+}
\ No newline at end of file
diff --git a/src/jdk.jcmd/share/classes/sun/tools/jmap/JMap.java b/src/jdk.jcmd/share/classes/sun/tools/jmap/JMap.java
index 8939d6093..50757d2d7 100644
--- a/src/jdk.jcmd/share/classes/sun/tools/jmap/JMap.java
+++ b/src/jdk.jcmd/share/classes/sun/tools/jmap/JMap.java
@@ -25,16 +25,29 @@
 
 package sun.tools.jmap;
 
+import java.io.BufferedInputStream;
+import java.io.Console;
 import java.io.File;
 import java.io.IOException;
 import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.nio.CharBuffer;
+import java.security.NoSuchAlgorithmException;
+import java.security.spec.InvalidKeySpecException;
+import java.security.spec.KeySpec;
+import java.util.Arrays;
 import java.util.Collection;
+import java.util.regex.Pattern;
 
 import com.sun.tools.attach.VirtualMachine;
 import com.sun.tools.attach.AttachNotSupportedException;
 import sun.tools.attach.HotSpotVirtualMachine;
 import sun.tools.common.ProcessArgumentMatcher;
 
+import javax.crypto.SecretKey;
+import javax.crypto.SecretKeyFactory;
+import javax.crypto.spec.PBEKeySpec;
+
 import static java.nio.charset.StandardCharsets.UTF_8;
 
 /*
@@ -45,6 +58,10 @@ import static java.nio.charset.StandardCharsets.UTF_8;
  * options are mapped to SA tools.
  */
 public class JMap {
+    // encrypt
+    private static int SALT_MIN_LENGTH = 8;
+    private static int HASH_BIT_SIZE = 256;
+    private static int HASH_ITERATIONS_COUNT = 10000;
 
     public static void main(String[] args) throws Exception {
         if (args.length == 0) {
@@ -206,6 +223,8 @@ public class JMap {
         String filename = null;
         String liveopt = "-all";
         String compress_level = null;
+        RedactParams redactParams = new RedactParams();
+        String redactPassword = ",RedactPassword=";
 
         for (String subopt : subopts) {
             if (subopt.equals("") || subopt.equals("all")) {
@@ -226,6 +245,18 @@ public class JMap {
                     System.err.println("Fail: no number provided in option: '" + subopt + "'");
                     usage(1);
                 }
+            } else if (subopt.startsWith("HeapDumpRedact=")) {
+                if (!redactParams.setAndCheckHeapDumpRedact(subopt.substring("HeapDumpRedact=".length()))) {
+                    usage(1);
+                }
+            } else if (subopt.startsWith("RedactMap=")) {
+                redactParams.setRedactMap(subopt.substring("RedactMap=".length()));
+            } else if (subopt.startsWith("RedactMapFile=")) {
+                redactParams.setRedactMapFile(subopt.substring("RedactMapFile=".length()));
+            } else if (subopt.startsWith("RedactClassPath")) {
+                redactParams.setRedactClassPath(subopt.substring("RedactClassPath=".length()));
+            }  else if (subopt.startsWith("RedactPassword")) {
+                redactPassword = getRedactPassword(pid);
             } else {
                 System.err.println("Fail: invalid option: '" + subopt + "'");
                 usage(1);
@@ -237,10 +268,121 @@ public class JMap {
             usage(1);
         }
 
+        checkRedactParams(redactParams);
+
         System.out.flush();
 
         // dumpHeap is not the same as jcmd GC.heap_dump
-        executeCommandForPid(pid, "dumpheap", filename, liveopt, compress_level);
+        String heapDumpRedactParams = redactParams.isEnableRedact() ? ";" + redactParams.toDumpArgString() + redactPassword : "";
+        executeCommandForPid(pid, "dumpheap", filename + heapDumpRedactParams, liveopt, compress_level);
+    }
+
+    private static void checkRedactParams(RedactParams redactParams) {
+        if (redactParams.getHeapDumpRedact() == null) {
+            if (redactParams.getRedactMap() == null && redactParams.getRedactMapFile() == null) {
+                redactParams.setEnableRedact(false);
+            } else {
+                System.err.println("Error: HeapDumpRedact must be specified to enable heap-dump-redacting");
+                usage(1);
+            }
+        }
+    }
+
+    private static String getRedactPassword(String pid) {
+        String redactPassword = ",RedactPassword=";
+        // heap dump may need a password
+        Console console = System.console();
+        char[] passwords = null;
+        if (console == null) {
+            return redactPassword;
+        }
+
+        try {
+            passwords = console.readPassword("redact authority password:");
+        } catch (Exception e) {
+        }
+        if(passwords == null) {
+            return redactPassword;
+        }
+
+        String digestStr = null;
+        try {
+            CharBuffer cb = CharBuffer.wrap(passwords);
+            String passwordPattern = "^[0-9a-zA-Z!@#$]{1,9}$";
+            if(!Pattern.matches(passwordPattern, cb)) {
+                return redactPassword;
+            }
+
+            String salt = getSalt(pid);
+            if(salt == null) {
+                return redactPassword;
+            }
+            byte[] saltBytes = salt.getBytes("UTF-8");
+            if(saltBytes.length < SALT_MIN_LENGTH) {
+                return redactPassword;
+            }
+            digestStr = getEncryptValue(passwords, saltBytes);
+        } catch (Exception e) {
+        }finally {
+            // clear all password
+            if(passwords != null) {
+                Arrays.fill(passwords, '0');
+            }
+        }
+
+        redactPassword += (digestStr == null ? "" : digestStr);
+        return redactPassword;
+    }
+
+    private static String getSalt(String pid) throws Exception {
+        String salt = null;
+        StringBuilder redactAuth = new StringBuilder();
+
+        VirtualMachine vm = VirtualMachine.attach(pid);
+        HotSpotVirtualMachine hvm = (HotSpotVirtualMachine) vm;
+        String flag = "RedactPassword";
+        try (InputStream in = hvm.printFlag(flag); BufferedInputStream bis = new BufferedInputStream(in);
+            InputStreamReader isr = new InputStreamReader(bis, "UTF-8")) {
+            char c[] = new char[256];
+            int n;
+            do {
+                n = isr.read(c);
+
+                if (n > 0) {
+                    redactAuth.append(n == c.length ? c : Arrays.copyOf(c, n));
+                }
+            } while (n > 0);
+        }
+        vm.detach();
+
+        if(redactAuth.length() > 0) {
+            String[] auths = redactAuth.toString().split(",");
+            if(auths.length != 2) {
+                return salt;
+            }
+            return auths[1].trim();
+        }
+
+        return salt;
+    }
+
+    private static String getEncryptValue(char[] passwordValue, byte[] saltBytes) throws InvalidKeySpecException, NoSuchAlgorithmException {
+        StringBuilder digestStrBuilder = new StringBuilder();
+
+        KeySpec spec = new PBEKeySpec(passwordValue, saltBytes, HASH_ITERATIONS_COUNT, HASH_BIT_SIZE);
+        SecretKeyFactory secretKeyFactory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA256");
+        SecretKey secretKey = secretKeyFactory.generateSecret(spec);
+        byte[] digestBytes = secretKey.getEncoded();
+        for (byte b : digestBytes) {
+            String hex = Integer.toHexString(0xff & b);
+            if (hex.length() == 1) {
+                digestStrBuilder.append('0');
+            }
+            digestStrBuilder.append(hex);
+        }
+        String digestStr = digestStrBuilder.toString();
+
+        return digestStr;
     }
 
     private static void checkForUnsupportedOptions(String[] args) {
@@ -307,6 +449,12 @@ public class JMap {
         System.err.println("      file=<file>  dump heap to <file>");
         System.err.println("      gz=<number>  If specified, the heap dump is written in gzipped format using the given compression level.");
         System.err.println("                   1 (recommended) is the fastest, 9 the strongest compression.");
+        System.err.println("      HeapDumpRedact=<basic|names|full|diyrules|annotation|off>     redact the heapdump information to remove sensitive data,");
+        System.err.println("      RedactMap=<name1:value1;name2:value2;...>            Redact the class and field names to other strings");
+        System.err.println("      RedactMapFile=<file>                                 file path of the redact map");
+        System.err.println("      RedactClassPath=<classpath>                          full path of the redact annotation");
+        System.err.println("      RedactPassword                                       maybe redact feature has an authority, will wait for a password, ");
+        System.err.println("                                                           without a correct password, heap dump with default redact level");
         System.err.println("");
         System.err.println("    Example: jmap -dump:live,format=b,file=heap.bin <pid>");
         System.err.println("");
@@ -322,4 +470,112 @@ public class JMap {
         System.err.println("    Example: jmap -histo:live,file=/tmp/histo.data <pid>");
         System.exit(exit);
     }
+
+    public static class RedactParams {
+        private boolean enableRedact = false;
+        private String heapDumpRedact;
+        private String redactMap;
+        private String redactMapFile;
+        private String redactClassPath;
+
+        public RedactParams() {
+        }
+
+        public RedactParams(String heapDumpRedact, String redactMap, String redactMapFile, String redactClassPath) {
+            if (heapDumpRedact != null && checkLauncherHeapdumpRedactSupport(heapDumpRedact)) {
+                enableRedact = true;
+            }
+            this.heapDumpRedact = heapDumpRedact;
+            this.redactMap = redactMap;
+            this.redactMapFile = redactMapFile;
+            this.redactClassPath = redactClassPath;
+        }
+
+        @Override
+        public String toString() {
+            StringBuilder builder = new StringBuilder();
+            if (heapDumpRedact != null) {
+                builder.append("HeapDumpRedact=");
+                builder.append(heapDumpRedact);
+                builder.append(",");
+            }
+            if (redactMap != null) {
+                builder.append("RedactMap=");
+                builder.append(redactMap);
+                builder.append(",");
+            }
+            if (redactMapFile != null) {
+                builder.append("RedactMapFile=");
+                builder.append(redactMapFile);
+                builder.append(",");
+            }
+            if (redactClassPath != null) {
+                builder.append("RedactClassPath=");
+                builder.append(redactClassPath);
+            }
+            return builder.toString();
+        }
+
+        public String toDumpArgString() {
+            return "-HeapDumpRedact=" + (heapDumpRedact == null ? "off" : heapDumpRedact) +
+                    ",RedactMap=" + (redactMap == null ? "" : redactMap) +
+                    ",RedactMapFile=" + (redactMapFile == null ? "" : redactMapFile) +
+                    ",RedactClassPath=" + (redactClassPath == null ? "" : redactClassPath);
+        }
+
+        public static boolean checkLauncherHeapdumpRedactSupport(String value) {
+            String[] validValues = {"basic", "names", "full", "diyrules", "annotation", "off"};
+            for (String validValue : validValues) {
+                if (validValue.equals(value)) {
+                    return true;
+                }
+            }
+            return false;
+        }
+
+        public boolean isEnableRedact() {
+            return enableRedact;
+        }
+
+        public void setEnableRedact(boolean enableRedact) {
+            this.enableRedact = enableRedact;
+        }
+
+        public String getHeapDumpRedact() {
+            return heapDumpRedact;
+        }
+
+        public boolean setAndCheckHeapDumpRedact(String heapDumpRedact) {
+            if (!checkLauncherHeapdumpRedactSupport(heapDumpRedact)) {
+                return false;
+            }
+            this.heapDumpRedact = heapDumpRedact;
+            this.enableRedact = true;
+            return true;
+        }
+
+        public String getRedactMap() {
+            return redactMap;
+        }
+
+        public void setRedactMap(String redactMap) {
+            this.redactMap = redactMap;
+        }
+
+        public String getRedactMapFile() {
+            return redactMapFile;
+        }
+
+        public void setRedactMapFile(String redactMapFile) {
+            this.redactMapFile = redactMapFile;
+        }
+
+        public String getRedactClassPath() {
+            return redactClassPath;
+        }
+
+        public void setRedactClassPath(String redactClassPath) {
+            this.redactClassPath = redactClassPath;
+        }
+    }
 }
-- 
2.47.0.windows.2