clazz) {
+ if (!providerMap.containsKey(clazz)) {
+ throw new IllegalArgumentException(String.format("%s has not been registered.", clazz.getName()));
+ }
+ return (T) providerMap.get(clazz);
+ }
+
+ @Override
+ public void registerProvider(Class extends IProvider> clazz, IProvider provider) {
+ if (clazz == null) {
+ throw new IllegalArgumentException("Null provider class is illegal.");
+ }
+
+ if (provider == null) {
+ throw new IllegalArgumentException("Null provider is illegal.");
+ }
+
+ if (providerMap.containsKey(clazz)) {
+ throw new IllegalArgumentException(String.format("%s has already been registered.", clazz.getName()));
+ }
+
+ if (!clazz.isInstance(provider)) {
+ throw new IllegalArgumentException(String.format("The provider doesn't implement interface %s.", clazz.getName()));
+ }
+
+ if (!clazz.isInterface()) {
+ throw new IllegalArgumentException("The provider class should be an interface");
+ }
+
+ providerMap.put(clazz, provider);
+ }
+
+}
diff --git a/src/main/java/com/microsoft/java/debug/core/adapter/RecyclableObjectPool.java b/src/main/java/com/microsoft/java/debug/core/adapter/RecyclableObjectPool.java
new file mode 100755
index 0000000..0d1bdf1
--- /dev/null
+++ b/src/main/java/com/microsoft/java/debug/core/adapter/RecyclableObjectPool.java
@@ -0,0 +1,138 @@
+/*******************************************************************************
+ * Copyright (c) 2017 Microsoft Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Microsoft Corporation - initial API and implementation
+ *******************************************************************************/
+
+package com.microsoft.java.debug.core.adapter;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * An utility object pool class with the following ability:
+ * 1. store an object to get an object id.
+ * 2. remove an object.
+ * 3. remove objects which has specified owner.
+ * 4. remove all objects.
+ *
+ * It is thread-safe, the duplicate object will not be stored, an object can be referenced by multiple owners, it is
+ * removed only when user explicitly calls removeObjectById or all the owners has been removed.
+ *
+ * @param the owner class type
+ * @param the object type
+ */
+public class RecyclableObjectPool {
+ private final IdCollection objectCollection = new IdCollection<>();
+ private final Map> referenceMap = new HashMap<>();
+ private final Map objectIdMap = new HashMap<>();
+
+ /**
+ * Add an object into this pool, if the object is already added, the original id will be used, it will also create a
+ * reference link from the object to its owner.
+ *
+ * @param owner the owner of this object
+ * @param object the object
+ * @return the inner id of this object
+ */
+ public int addObject(O owner, V object) {
+ if (owner == null) {
+ throw new IllegalArgumentException("Owner cannot be null.");
+ }
+ if (object == null) {
+ throw new IllegalArgumentException("Null object cannot be added.");
+ }
+ synchronized (this) {
+ if (!referenceMap.containsKey(object)) {
+ // the object is new
+ Set owners = new HashSet<>(1);
+ owners.add(owner);
+ referenceMap.put(object, owners);
+ int id = objectCollection.create(object);
+ objectIdMap.put(object, id);
+ return id;
+ } else {
+ // the object is already in this pool
+ referenceMap.get(object).add(owner);
+ return objectIdMap.get(object);
+ }
+ }
+ }
+
+ /**
+ * Get the object by object id.
+ *
+ * @param id the object id.
+ * @return the object, null if the object cannot be found.
+ */
+ public V getObjectById(int id) {
+ synchronized (this) {
+ return objectCollection.get(id);
+ }
+ }
+
+ /**
+ * Remove the object by object id.
+ *
+ * @param id the object id.
+ * @return true if the object is removed successfully, false if the object cannot be found.
+ */
+ public boolean removeObjectById(int id) {
+ synchronized (this) {
+ V object = this.objectCollection.remove(id);
+ if (object == null) {
+ return false;
+ }
+ referenceMap.remove(object);
+ objectIdMap.remove(object);
+ return true;
+ }
+ }
+
+ /**
+ * Remove a group of objects with the owner, the objects which only refers this owner will be removed.
+ *
+ * @param owner the owner.
+ * @return true if any object is removed.
+ */
+ public boolean removeObjectsByOwner(O owner) {
+ if (owner == null) {
+ throw new IllegalArgumentException("owner cannot be null.");
+ }
+ synchronized (this) {
+ List recycling = new ArrayList<>();
+ referenceMap.forEach((key, value) -> {
+ if (value.remove(owner)) {
+ if (value.isEmpty()) {
+ recycling.add(key);
+ }
+ }
+ });
+ for (V recycled : recycling) {
+ this.objectCollection.remove(objectIdMap.remove(recycled));
+ referenceMap.remove(recycled);
+ }
+ return !recycling.isEmpty();
+ }
+ }
+
+ /**
+ * Removes all the objects.
+ */
+ public void removeAllObjects() {
+ synchronized (this) {
+ this.objectCollection.reset();
+ this.referenceMap.clear();
+ this.objectIdMap.clear();
+ }
+ }
+}
diff --git a/src/main/java/com/microsoft/java/debug/core/adapter/StackFrameManager.java b/src/main/java/com/microsoft/java/debug/core/adapter/StackFrameManager.java
new file mode 100755
index 0000000..518cc77
--- /dev/null
+++ b/src/main/java/com/microsoft/java/debug/core/adapter/StackFrameManager.java
@@ -0,0 +1,88 @@
+/*******************************************************************************
+ * Copyright (c) 2017-2022 Microsoft Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Microsoft Corporation - initial API and implementation
+ *******************************************************************************/
+
+package com.microsoft.java.debug.core.adapter;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import com.microsoft.java.debug.core.adapter.variables.StackFrameReference;
+import com.sun.jdi.IncompatibleThreadStateException;
+import com.sun.jdi.StackFrame;
+import com.sun.jdi.ThreadReference;
+
+public class StackFrameManager implements IStackFrameManager {
+ private Map