diff --git a/src/java.desktop/macosx/classes/sun/lwawt/macosx/CAccessibility.java b/src/java.desktop/macosx/classes/sun/lwawt/macosx/CAccessibility.java
index 19ac4818928cc9904a40556f800674d4caba55fa..0ab38fc06b4ecd050817df298aa7792b5630984b 100644
--- a/src/java.desktop/macosx/classes/sun/lwawt/macosx/CAccessibility.java
+++ b/src/java.desktop/macosx/classes/sun/lwawt/macosx/CAccessibility.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2011, 2021, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011, 2024, 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
@@ -35,10 +35,11 @@ import java.awt.event.KeyEvent;
 import java.beans.PropertyChangeEvent;
 import java.beans.PropertyChangeListener;
 import java.lang.annotation.Native;
-import java.lang.reflect.Constructor;
 import java.lang.reflect.InvocationTargetException;
 import java.util.ArrayList;
+import java.util.HashMap;
 import java.util.HashSet;
+import java.util.List;
 import java.util.Set;
 import java.util.concurrent.Callable;
 import java.util.Arrays;
@@ -64,7 +65,6 @@ import javax.swing.JTextArea;
 import javax.swing.JList;
 import javax.swing.JTree;
 import javax.swing.KeyStroke;
-import javax.swing.tree.TreePath;
 
 import sun.awt.AWTAccessor;
 import sun.lwawt.LWWindowPeer;
@@ -742,21 +742,6 @@ class CAccessibility implements PropertyChangeListener {
         return new Object[]{childrenAndRoles.get(whichChildren * 2), childrenAndRoles.get((whichChildren * 2) + 1)};
     }
 
-    private static Accessible createAccessibleTreeNode(JTree t, TreePath p) {
-        Accessible a = null;
-
-        try {
-            Class<?> accessibleJTreeNodeClass = Class.forName("javax.swing.JTree$AccessibleJTree$AccessibleJTreeNode");
-            Constructor<?> constructor = accessibleJTreeNodeClass.getConstructor(t.getAccessibleContext().getClass(), JTree.class, TreePath.class, Accessible.class);
-            constructor.setAccessible(true);
-            a = ((Accessible) constructor.newInstance(t.getAccessibleContext(), t, p, null));
-        } catch (Exception e) {
-            e.printStackTrace();
-        }
-
-        return a;
-    }
-
     // This method is called from the native
     // Each child takes up three entries in the array: one for itself, one for its role, and one for the recursion level
     private static Object[] getChildrenAndRolesRecursive(final Accessible a, final Component c, final int whichChildren, final boolean allowIgnored, final int level) {
@@ -764,62 +749,21 @@ class CAccessibility implements PropertyChangeListener {
         return invokeAndWait(new Callable<Object[]>() {
             public Object[] call() throws Exception {
                 ArrayList<Object> allChildren = new ArrayList<Object>();
-
-                Accessible at = null;
-                if (a instanceof CAccessible) {
-                    at = CAccessible.getSwingAccessible(a);
-                } else {
-                    at = a;
-                }
-
-                if (at instanceof JTree) {
-                    JTree tree = ((JTree) at);
-
-                    if (whichChildren == JAVA_AX_ALL_CHILDREN) {
-                        int count = tree.getRowCount();
-                        for (int i = 0; i < count; i++) {
-                            TreePath path = tree.getPathForRow(i);
-                            Accessible an = createAccessibleTreeNode(tree, path);
-                            if (an != null) {
-                                AccessibleContext ac = an.getAccessibleContext();
-                                if (ac != null) {
-                                    allChildren.add(an);
-                                    allChildren.add(ac.getAccessibleRole());;
-                                    allChildren.add(String.valueOf((tree.isRootVisible() ? path.getPathCount() : path.getPathCount() - 1)));
-                                }
-                            }
-                        }
-                    }
-
-                    if (whichChildren == JAVA_AX_SELECTED_CHILDREN) {
-                        int count = tree.getSelectionCount();
-                        for (int i = 0; i < count; i++) {
-                            TreePath path = tree.getSelectionPaths()[i];
-                            Accessible an = createAccessibleTreeNode(tree, path);
-                            if (an != null) {
-                                AccessibleContext ac = an.getAccessibleContext();
-                                if (ac != null) {
-                                    allChildren.add(an);
-                                    allChildren.add(ac.getAccessibleRole());
-                                    allChildren.add(String.valueOf((tree.isRootVisible() ? path.getPathCount() : path.getPathCount() - 1)));
-                                }
-                            }
-                        }
-                    }
-
-                    return allChildren.toArray();
-                }
-
                 ArrayList<Object> currentLevelChildren = new ArrayList<Object>();
                 ArrayList<Accessible> parentStack = new ArrayList<Accessible>();
+                HashMap<Accessible, List<Object>> childrenOfParent = new HashMap<>();
                 parentStack.add(a);
                 ArrayList<Integer> indexses = new ArrayList<Integer>();
                 Integer index = 0;
                 int currentLevel = level;
                 while (!parentStack.isEmpty()) {
                     Accessible p = parentStack.get(parentStack.size() - 1);
-
-                    currentLevelChildren.addAll(Arrays.asList(getChildrenAndRolesImpl(p, c, JAVA_AX_ALL_CHILDREN, allowIgnored, ChildrenOperations.COMMON)));
+                    if (!childrenOfParent.containsKey(p)) {
+                        childrenOfParent.put(p, Arrays.asList(getChildrenAndRolesImpl(p,
+                                c, JAVA_AX_ALL_CHILDREN, allowIgnored,
+                                ChildrenOperations.COMMON)));
+                    }
+                    currentLevelChildren.addAll(childrenOfParent.get(p));
                     if ((currentLevelChildren.size() == 0) || (index >= currentLevelChildren.size())) {
                         if (!parentStack.isEmpty()) parentStack.remove(parentStack.size() - 1);
                         if (!indexses.isEmpty()) index = indexses.remove(indexses.size() - 1);
@@ -862,7 +806,6 @@ class CAccessibility implements PropertyChangeListener {
                         currentLevel += 1;
                         continue;
                     }
-
                 }
 
                 return allChildren.toArray();
diff --git a/src/java.desktop/macosx/native/libawt_lwawt/awt/a11y/OutlineAccessibility.h b/src/java.desktop/macosx/native/libawt_lwawt/awt/a11y/OutlineAccessibility.h
index 2992d82cbe4f521ebf444979f287897b5a6579f5..8281f0b0213db9f14aa4994aeb80a615f1c5748a 100644
--- a/src/java.desktop/macosx/native/libawt_lwawt/awt/a11y/OutlineAccessibility.h
+++ b/src/java.desktop/macosx/native/libawt_lwawt/awt/a11y/OutlineAccessibility.h
@@ -1,6 +1,6 @@
 /*
- * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved.
- * Copyright (c) 2021, JetBrains s.r.o.. All rights reserved.
+ * Copyright (c) 2021, 2024, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2021, 2024, JetBrains s.r.o.. 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
@@ -29,7 +29,12 @@
 // This is a tree representation. See: https://developer.apple.com/documentation/appkit/nsoutlineview
 
 @interface OutlineAccessibility : ListAccessibility <NSAccessibilityOutline>
-
+{
+    NSMutableArray<id<NSAccessibilityRow>> *rowCache;
+    BOOL rowCacheValid;
+    NSMutableArray<id<NSAccessibilityRow>> *selectedRowCache;
+    BOOL selectedRowCacheValid;
+}
 @property(readonly) BOOL isTreeRootVisible;
 
 @end
diff --git a/src/java.desktop/macosx/native/libawt_lwawt/awt/a11y/OutlineAccessibility.m b/src/java.desktop/macosx/native/libawt_lwawt/awt/a11y/OutlineAccessibility.m
index cdf6dbbd4ab7783d393246ded05d6a5911038ebd..08240614bf774312d6d7e7219db39643dc7e50ef 100644
--- a/src/java.desktop/macosx/native/libawt_lwawt/awt/a11y/OutlineAccessibility.m
+++ b/src/java.desktop/macosx/native/libawt_lwawt/awt/a11y/OutlineAccessibility.m
@@ -1,6 +1,6 @@
 /*
- * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved.
- * Copyright (c) 2021, JetBrains s.r.o.. All rights reserved.
+ * Copyright (c) 2021, 2024, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2021, 2024, JetBrains s.r.o.. 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
@@ -55,4 +55,88 @@ static jmethodID sjm_isTreeRootVisible = NULL;
     return [[super accessibilityLabel] isEqualToString:@"list"] ? @"tree" : [super accessibilityLabel];
 }
 
+- (nullable NSArray<id<NSAccessibilityRow>> *)accessibilityRows
+{
+    return [self accessibilityChildren];
+}
+
+- (nullable NSArray<id<NSAccessibilityRow>> *)accessibilitySelectedRows
+{
+    return [self accessibilitySelectedChildren];
+}
+
+- (nullable  NSArray<id<NSAccessibilityRow>> *)accessibilityChildren
+{
+    if (![self isCacheValid]) {
+        NSArray *t = [super accessibilityChildren];
+        if (t != nil) {
+            rowCache = [[NSMutableArray arrayWithArray:t] retain];
+        } else {
+            rowCache = nil;
+        }
+        rowCacheValid = YES;
+    }
+    return rowCache;
+}
+
+- (nullable NSArray<id<NSAccessibilityRow>> *)accessibilitySelectedChildren
+{
+    if (!selectedRowCacheValid) {
+        NSArray *t = [super accessibilitySelectedChildren];
+        if (t != nil) {
+            selectedRowCache = [[NSMutableArray arrayWithArray:t] retain];
+        } else {
+            selectedRowCache = nil;
+        }
+        selectedRowCacheValid = YES;
+    }
+    return selectedRowCache;
+}
+
+- (BOOL)isCacheValid
+{
+    if (rowCacheValid && [[self parent] respondsToSelector:NSSelectorFromString(@"isCacheValid")]) {
+        return [[self parent] isCacheValid];
+    }
+    return rowCacheValid;
+}
+
+- (void)invalidateCache
+{
+    rowCacheValid = NO;
+}
+
+- (void)invalidateSelectionCache
+{
+    selectedRowCacheValid = NO;
+}
+
+- (void)postSelectionChanged
+{
+    AWT_ASSERT_APPKIT_THREAD;
+    [self invalidateSelectionCache];
+    [super postSelectionChanged];
+}
+
+- (void)postTreeNodeCollapsed
+{
+    AWT_ASSERT_APPKIT_THREAD;
+    [self invalidateCache];
+    [super postTreeNodeCollapsed];
+}
+
+- (void)postTreeNodeExpanded
+{
+    AWT_ASSERT_APPKIT_THREAD;
+    [self invalidateCache];
+    [super postTreeNodeExpanded];
+}
+
+- (void)postSelectedCellsChanged
+{
+    AWT_ASSERT_APPKIT_THREAD;
+    [self invalidateSelectionCache];
+    [super postSelectedCellsChanged];
+}
+
 @end