Skip to main content
summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMikhail Khodjaiants2012-01-26 11:59:27 -0500
committerMikhail Khodjaiants2012-01-26 11:59:27 -0500
commit15ab0165f1bfae5ff780536d134902ff7592ff8e (patch)
treed70e19d0d8c83c0933f61f6501531df046bd9632
parentee0eb1bb4811d40bb9380f743421122d9cafa635 (diff)
downloadorg.eclipse.cdt-15ab0165f1bfae5ff780536d134902ff7592ff8e.tar.gz
org.eclipse.cdt-15ab0165f1bfae5ff780536d134902ff7592ff8e.tar.xz
org.eclipse.cdt-15ab0165f1bfae5ff780536d134902ff7592ff8e.zip
Bug 365541 - View an array variable whose length is very long (such as
10000) in the editor or Variable View, will cause the interface to die.
-rwxr-xr-xdebug/org.eclipse.cdt.debug.ui/icons/obj16/arraypartition_obj.gifbin0 -> 370 bytes
-rw-r--r--debug/org.eclipse.cdt.debug.ui/src/org/eclipse/cdt/debug/internal/ui/CDebugImages.java2
-rw-r--r--dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/mi/service/MIExpressions.java417
-rw-r--r--dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/mi/service/MIVariableManager.java4
-rw-r--r--dsf-gdb/org.eclipse.cdt.tests.dsf.gdb/data/launch/src/ExpressionTestApp.cc9
-rw-r--r--dsf-gdb/org.eclipse.cdt.tests.dsf.gdb/src/org/eclipse/cdt/tests/dsf/gdb/tests/MIExpressionsTest.java169
-rw-r--r--dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/viewmodel/DsfCastToTypeSupport.java4
-rw-r--r--dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/variable/VariableVMNode.java61
-rw-r--r--dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/debug/service/IExpressions.java24
9 files changed, 590 insertions, 100 deletions
diff --git a/debug/org.eclipse.cdt.debug.ui/icons/obj16/arraypartition_obj.gif b/debug/org.eclipse.cdt.debug.ui/icons/obj16/arraypartition_obj.gif
new file mode 100755
index 0000000000..052915a19b
--- /dev/null
+++ b/debug/org.eclipse.cdt.debug.ui/icons/obj16/arraypartition_obj.gif
Binary files differ
diff --git a/debug/org.eclipse.cdt.debug.ui/src/org/eclipse/cdt/debug/internal/ui/CDebugImages.java b/debug/org.eclipse.cdt.debug.ui/src/org/eclipse/cdt/debug/internal/ui/CDebugImages.java
index 5387b5e2d1..26c89c64e3 100644
--- a/debug/org.eclipse.cdt.debug.ui/src/org/eclipse/cdt/debug/internal/ui/CDebugImages.java
+++ b/debug/org.eclipse.cdt.debug.ui/src/org/eclipse/cdt/debug/internal/ui/CDebugImages.java
@@ -104,6 +104,7 @@ public class CDebugImages {
public static final String IMG_OBJS_PATH_MAPPING = NAME_PREFIX + "mapping_obj.gif"; //$NON-NLS-1$
public static final String IMG_OBJS_PATH_MAP_ENTRY = NAME_PREFIX + "mapentry_obj.gif"; //$NON-NLS-1$
public static final String IMG_OBJS_COMMON_TAB = NAME_PREFIX + "common_tab.gif"; //$NON-NLS-1$
+ public static final String IMG_OBJS_ARRAY_PARTITION = NAME_PREFIX + "arraypartition_obj.gif"; //$NON-NLS-1$
public static final String IMG_LCL_TYPE_NAMES = NAME_PREFIX + "tnames_co.gif"; //$NON-NLS-1$
public static final String IMG_LCL_CHANGE_REGISTER_VALUE = NAME_PREFIX + "change_reg_value_co.gif"; //$NON-NLS-1$
@@ -188,6 +189,7 @@ public class CDebugImages {
public static final ImageDescriptor DESC_OBJS_PATH_MAPPING = createManaged(T_OBJ, IMG_OBJS_PATH_MAPPING);
public static final ImageDescriptor DESC_OBJS_PATH_MAP_ENTRY = createManaged(T_OBJ, IMG_OBJS_PATH_MAP_ENTRY);
public static final ImageDescriptor DESC_OBJS_COMMON_TAB = createManaged(T_OBJ, IMG_OBJS_COMMON_TAB);
+ public static final ImageDescriptor DESC_OBJS_ARRAY_PARTITION = createManaged(T_OBJ, IMG_OBJS_ARRAY_PARTITION);
public static final ImageDescriptor DESC_WIZBAN_ADD_SOURCE = createManaged(T_WIZBAN, IMG_WIZBAN_ADD_SOURCE);
public static final ImageDescriptor DESC_WIZBAN_PATH_MAPPING = createManaged(T_WIZBAN, IMG_WIZBAN_PATH_MAPPING);
public static final ImageDescriptor DESC_WIZBAN_PATH_MAP_ENTRY = createManaged(T_WIZBAN, IMG_WIZBAN_PATH_MAP_ENTRY);
diff --git a/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/mi/service/MIExpressions.java b/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/mi/service/MIExpressions.java
index 9f978a8a27..9b518666d0 100644
--- a/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/mi/service/MIExpressions.java
+++ b/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/mi/service/MIExpressions.java
@@ -13,12 +13,14 @@
*******************************************************************************/
package org.eclipse.cdt.dsf.mi.service;
+import java.util.Arrays;
import java.util.HashMap;
import java.util.Hashtable;
import java.util.Map;
import org.eclipse.cdt.core.IAddress;
import org.eclipse.cdt.dsf.concurrent.DataRequestMonitor;
+import org.eclipse.cdt.dsf.concurrent.ImmediateExecutor;
import org.eclipse.cdt.dsf.concurrent.ImmediateRequestMonitor;
import org.eclipse.cdt.dsf.concurrent.RequestMonitor;
import org.eclipse.cdt.dsf.datamodel.AbstractDMContext;
@@ -71,6 +73,8 @@ import org.osgi.framework.BundleContext;
*/
public class MIExpressions extends AbstractDsfService implements IMIExpressions, ICachingService {
+ private static final int PARTITION_LENGTH = 100;
+
/**
* A format that gives more details about an expression and supports pretty-printing
* provided by the backend.
@@ -381,7 +385,7 @@ public class MIExpressions extends AbstractDsfService implements IMIExpressions,
this.exprInfo = info;
}
}
-
+
protected static class InvalidContextExpressionDMC extends AbstractDMContext
implements IExpressionDMContext
{
@@ -413,6 +417,86 @@ public class MIExpressions extends AbstractDsfService implements IMIExpressions,
return expression;
}
}
+
+ /**
+ * @since 4.1
+ */
+ protected static class IndexedPartitionDMC extends MIExpressionDMC implements IIndexedPartitionDMContext {
+
+ final private ExpressionInfo fParentInfo;
+ private final int fIndex;
+ private final int fLength;
+
+ public IndexedPartitionDMC(
+ String sessionId,
+ ExpressionInfo parentInfo,
+ IFrameDMContext frameCtx,
+ int index,
+ int length) {
+ this(sessionId, parentInfo, (IDMContext)frameCtx, index, length);
+ }
+
+ private IndexedPartitionDMC(
+ String sessionId,
+ ExpressionInfo parentInfo,
+ IDMContext parent,
+ int index,
+ int length) {
+ super(sessionId, createExpressionInfo(parentInfo, index, length), parent);
+ fIndex = index;
+ fLength = length;
+ fParentInfo = parentInfo;
+ }
+
+ public ExpressionInfo getParentInfo() {
+ return fParentInfo;
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.cdt.dsf.debug.service.IExpressions4.IIndexedPartitionDMContext#getParentExpression()
+ */
+ @Override
+ public String getParentExpression() {
+ return getParentInfo().getFullExpr();
+ }
+
+ @Override
+ public int getIndex() {
+ return fIndex;
+ }
+
+ @Override
+ public int getLength() {
+ return fLength;
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ return super.baseEquals(other) &&
+ ((IndexedPartitionDMC) other).getParentInfo().equals(getParentInfo()) &&
+ ((IndexedPartitionDMC) other).getIndex() == getIndex() &&
+ ((IndexedPartitionDMC) other).getLength() == getLength();
+ }
+
+ @Override
+ public int hashCode() {
+ return super.baseHashCode() + 17*getIndex() + 31*getLength();
+ }
+
+ @Override
+ public String toString() {
+ return String.format( "%s[%d-%d]", baseToString(), Integer.valueOf( getIndex() ), Integer.valueOf( getIndex() + getLength() ) ); //$NON-NLS-1$
+ }
+
+ private static ExpressionInfo createExpressionInfo(ExpressionInfo parentInfo, int index, int length) {
+ String expression = String.format(
+ "*((%s)+%d)@%d", //$NON-NLS-1$
+ parentInfo.getFullExpr(),
+ Integer.valueOf(index),
+ Integer.valueOf(length));
+ return new ExpressionInfo(expression, expression);
+ }
+ }
/**
@@ -1064,33 +1148,8 @@ public class MIExpressions extends AbstractDsfService implements IMIExpressions,
* The data request monitor that will contain the requested data
*/
@Override
- public void getSubExpressions(final IExpressionDMContext dmc,
- final DataRequestMonitor<IExpressionDMContext[]> rm)
- {
- if (dmc instanceof MIExpressionDMC) {
- fExpressionCache.execute(
- new ExprMetaGetChildren(dmc),
- new DataRequestMonitor<ExprMetaGetChildrenInfo>(getExecutor(), rm) {
- @Override
- protected void handleSuccess() {
- ExpressionInfo[] childrenExpr = getData().getChildrenExpressions();
- IExpressionDMContext[] childArray = new IExpressionDMContext[childrenExpr.length];
- for (int i=0; i<childArray.length; i++) {
- childArray[i] = createExpression(
- dmc.getParents()[0], childrenExpr[i]);
- }
-
- rm.setData(childArray);
- rm.done();
- }
- });
- } else if (dmc instanceof InvalidContextExpressionDMC) {
- rm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, INVALID_HANDLE, "Invalid context for evaluating expressions.", null)); //$NON-NLS-1$
- rm.done();
- } else {
- rm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, INTERNAL_ERROR, "Invalid expression context.", null)); //$NON-NLS-1$
- rm.done();
- }
+ public void getSubExpressions(IExpressionDMContext dmc, DataRequestMonitor<IExpressionDMContext[]> rm) {
+ getSubExpressions(dmc, -1, -1, rm);
}
/**
@@ -1112,37 +1171,48 @@ public class MIExpressions extends AbstractDsfService implements IMIExpressions,
public void getSubExpressions(final IExpressionDMContext exprCtx, final int startIndex,
final int length, final DataRequestMonitor<IExpressionDMContext[]> rm) {
- if (startIndex < 0 || length < 0) {
- rm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, INTERNAL_ERROR, "Invalid range for evaluating sub expressions.", null)); //$NON-NLS-1$
- rm.done();
- return;
+ if (exprCtx instanceof IndexedPartitionDMC) {
+ getIndexedPartitionChildren((IndexedPartitionDMC)exprCtx, startIndex, length, rm);
}
-
- if (exprCtx instanceof MIExpressionDMC) {
- fExpressionCache.execute(
- new ExprMetaGetChildren(exprCtx, startIndex + length),
- new DataRequestMonitor<ExprMetaGetChildrenInfo>(getExecutor(), rm) {
- @Override
- protected void handleSuccess() {
- ExpressionInfo[] childrenExpr = getData().getChildrenExpressions();
-
- if (startIndex >= childrenExpr.length) {
- rm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, REQUEST_FAILED, "Invalid range for evaluating sub expressions.", null)); //$NON-NLS-1$
- rm.done();
- return;
- }
-
- int numChildren = childrenExpr.length - startIndex;
- numChildren = Math.min(length, numChildren);
- IExpressionDMContext[] childrenArray = new IExpressionDMContext[numChildren];
- for (int i=0; i < numChildren; i++) {
- childrenArray[i] = createExpression(
- exprCtx.getParents()[0], childrenExpr[startIndex + i]);
- }
- rm.setData(childrenArray);
+ else if (exprCtx instanceof MIExpressionDMC) {
+ getRealSubExpressionCount(
+ exprCtx,
+ IMIExpressions.CHILD_COUNT_LIMIT_UNSPECIFIED,
+ new DataRequestMonitor<Integer>(getExecutor(), rm) {
+ /* (non-Javadoc)
+ * @see org.eclipse.cdt.dsf.concurrent.RequestMonitor#handleSuccess()
+ */
+ @Override
+ protected void handleSuccess() {
+ final int realNumChildren = getData().intValue();
+ if (realNumChildren == 0) {
+ rm.setData(new IExpressionDMContext[0]);
rm.done();
+ return;
}
- });
+
+ if (realNumChildren <= getArrayPartitionLength()) {
+ getRealSubExpressions(exprCtx, startIndex, length, rm);
+ }
+ else {
+ getExpressionData(
+ exprCtx,
+ new DataRequestMonitor<IExpressionDMData>(ImmediateExecutor.getInstance(), rm) {
+
+ @Override
+ protected void handleSuccess() {
+ if (IExpressionDMData.BasicType.array.equals(getData().getBasicType())) {
+ rm.setData(getTopLevelIndexedPartitions((MIExpressionDMC)exprCtx, realNumChildren, startIndex, length ));
+ rm.done();
+ }
+ else {
+ getRealSubExpressions(exprCtx, startIndex, length, rm);
+ }
+ }
+ });
+ }
+ }
+ });
} else if (exprCtx instanceof InvalidContextExpressionDMC) {
rm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, INVALID_HANDLE, "Invalid context for evaluating expressions.", null)); //$NON-NLS-1$
rm.done();
@@ -1183,19 +1253,48 @@ public class MIExpressions extends AbstractDsfService implements IMIExpressions,
* @since 4.0
*/
@Override
- public void getSubExpressionCount(IExpressionDMContext dmc,
+ public void getSubExpressionCount(final IExpressionDMContext dmc,
final int numChildLimit, final DataRequestMonitor<Integer> rm) {
if (dmc instanceof MIExpressionDMC) {
- fExpressionCache.execute(
- new ExprMetaGetChildCount(dmc, numChildLimit),
- new DataRequestMonitor<ExprMetaGetChildCountInfo>(getExecutor(), rm) {
+ if (dmc instanceof IndexedPartitionDMC) {
+ int length = ((IndexedPartitionDMC)dmc).getLength();
+ rm.setData(computeNumberOfChildren(length));
+ rm.done();
+ }
+ else {
+ getRealSubExpressionCount(
+ dmc,
+ numChildLimit,
+ new DataRequestMonitor<Integer>(getExecutor(), rm) {
+
@Override
protected void handleSuccess() {
- rm.setData(getData().getChildNum());
- rm.done();
- }
+ final int realNum = getData().intValue();
+ if (realNum <= getArrayPartitionLength()) {
+ rm.setData(Integer.valueOf(realNum));
+ rm.done();
+ }
+ else {
+ getExpressionData(
+ dmc,
+ new DataRequestMonitor<IExpressionDMData>(ImmediateExecutor.getInstance(), rm) {
+
+ @Override
+ protected void handleSuccess() {
+ if (IExpressionDMData.BasicType.array.equals(getData().getBasicType())) {
+ rm.setData(computeNumberOfChildren(realNum));
+ }
+ else {
+ rm.setData(Integer.valueOf(realNum));
+ }
+ rm.done();
+ }
+ });
+ }
+ }
});
+ }
} else if (dmc instanceof InvalidContextExpressionDMC) {
rm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, INVALID_HANDLE, "Invalid context for evaluating expressions.", null)); //$NON-NLS-1$
rm.done();
@@ -1442,4 +1541,196 @@ public class MIExpressions extends AbstractDsfService implements IMIExpressions,
}
});
}
+
+ private IndexedPartitionDMC[] getTopLevelIndexedPartitions(
+ MIExpressionDMC exprCtx,
+ int realNumChildren,
+ int startIndex,
+ int length) {
+
+ int numChildren = computeNumberOfChildren(realNumChildren);
+ if (startIndex >= numChildren)
+ return new IndexedPartitionDMC[0];
+ int startIndex1 = (startIndex < 0) ? 0 : startIndex;
+ int length1 = (length < 0) ? numChildren - startIndex1 : Math.min(length, numChildren - startIndex1);
+
+ IndexedPartitionDMC[] children = new IndexedPartitionDMC[numChildren];
+ int index = 0;
+ for(int i = 0; i < children.length; ++i) {
+ int partLength = computePartitionLength(realNumChildren, i);
+ children[i] = createIndexedPartition(
+ exprCtx.getParents()[0],
+ exprCtx.getExpressionInfo(),
+ index,
+ partLength);
+ index += partLength;
+ }
+ return Arrays.copyOfRange(children, startIndex1, startIndex1 + length1 );
+ }
+
+ private void getIndexedPartitionChildren(
+ final IndexedPartitionDMC partDmc,
+ final int startIndex,
+ final int length,
+ final DataRequestMonitor<IExpressionDMContext[]> rm) {
+
+ final int startIndex1 = (startIndex < 0) ? 0 : startIndex;
+ final int length1 = (length < 0) ? Integer.MAX_VALUE : length;
+
+ final int partStartIndex = partDmc.getIndex();
+ final int partLength = partDmc.getLength();
+ if (partLength > getArrayPartitionLength()) {
+ // create subpartitions
+ int numChildren = computeNumberOfChildren(partLength);
+
+ if (startIndex1 >= numChildren) {
+ rm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, REQUEST_FAILED, "Invalid range for evaluating sub expressions.", null)); //$NON-NLS-1$
+ rm.done();
+ return;
+ }
+
+ int numPart = Math.min(numChildren, length1);
+ IndexedPartitionDMC[] children = new IndexedPartitionDMC[numPart];
+ int index = partStartIndex;
+ for (int i = 0; i < startIndex1; ++i)
+ index += computePartitionLength(partLength, i);
+ for (int i = 0; i < children.length; ++i) {
+ int childPartLength = computePartitionLength(partLength, i + startIndex1);
+ children[i] = createIndexedPartition(
+ partDmc,
+ partDmc.getParentInfo(),
+ index,
+ childPartLength);
+ index += childPartLength;
+ }
+ rm.setData(children);
+ rm.done();
+ }
+ else {
+ // this is the last partition level, create "real" children
+ if (startIndex1 > partLength) {
+ rm.setData(new IExpressionDMContext[0]);
+ rm.done();
+ }
+ else {
+ getRealSubExpressions(
+ createExpression(partDmc.getParents()[0], partDmc.getParentInfo()),
+ partStartIndex + startIndex1,
+ Math.min(length1, partLength - startIndex1),
+ rm);
+ }
+ }
+ }
+
+ void getRealSubExpressions(
+ final IExpressionDMContext exprCtx,
+ int startIndex,
+ int length,
+ final DataRequestMonitor<IExpressionDMContext[]> rm) {
+
+ ExprMetaGetChildren getChildren = (startIndex < 0 || length < 0) ?
+ new ExprMetaGetChildren(exprCtx) : new ExprMetaGetChildren(exprCtx, startIndex + length);
+ final int startIndex1 = (startIndex < 0) ? 0 : startIndex;
+ final int length1 = (length < 0) ? Integer.MAX_VALUE : length;
+ fExpressionCache.execute(
+ getChildren,
+ new DataRequestMonitor<ExprMetaGetChildrenInfo>(getExecutor(), rm) {
+ @Override
+ protected void handleSuccess() {
+ ExpressionInfo[] childrenExpr = getData().getChildrenExpressions();
+
+ if (startIndex1 >= childrenExpr.length) {
+ rm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, REQUEST_FAILED, "Invalid range for evaluating sub expressions.", null)); //$NON-NLS-1$
+ rm.done();
+ return;
+ }
+
+ int numChildren = childrenExpr.length - startIndex1;
+ numChildren = Math.min(length1, numChildren);
+ IExpressionDMContext[] childrenArray = new IExpressionDMContext[numChildren];
+ for (int i=0; i < numChildren; i++) {
+ childrenArray[i] = createExpression(exprCtx.getParents()[0], childrenExpr[startIndex1 + i]);
+ }
+ rm.setData(childrenArray);
+ rm.done();
+ }
+ });
+ }
+
+ /**
+ * Returns the number of "real" children if it is less or equal to the partition size,
+ * otherwise returns the number of partitions.
+ */
+ private int computeNumberOfChildren(int realNumberOfChildren) {
+ int childNum = realNumberOfChildren;
+ int partLength = getArrayPartitionLength();
+ while (childNum > partLength) {
+ childNum /= partLength;
+ }
+ if (childNum*partLength < realNumberOfChildren)
+ ++childNum;
+ return childNum;
+ }
+
+ private int computePartitionLength(int realNumberOfChildren, int index) {
+ int childNum = realNumberOfChildren;
+ int depth = 0;
+ int partLength = getArrayPartitionLength();
+ int length = partLength;
+ while (childNum > partLength) {
+ childNum /= partLength;
+ if (depth > 0)
+ length *= partLength;
+ ++depth;
+ }
+ int diff = realNumberOfChildren - length*index;
+ return ( diff > length ) ? length : diff ;
+ }
+
+ private IndexedPartitionDMC createIndexedPartition(IDMContext ctx, ExpressionInfo info, int index, int length) {
+ IFrameDMContext frameDmc = DMContexts.getAncestorOfType(ctx, IFrameDMContext.class);
+ if (frameDmc != null) {
+ return new IndexedPartitionDMC(getSession().getId(), info, frameDmc, index, length);
+ }
+
+ IMIExecutionDMContext execCtx = DMContexts.getAncestorOfType(ctx, IMIExecutionDMContext.class);
+ if (execCtx != null) {
+ // If we have a thread context but not a frame context, we give the user
+ // the expression as per the top-most frame of the specified thread.
+ // To do this, we create our own frame context.
+ MIStack stackService = getServicesTracker().getService(MIStack.class);
+ if (stackService != null) {
+ frameDmc = stackService.createFrameDMContext(execCtx, 0);
+ return new IndexedPartitionDMC(getSession().getId(), info, frameDmc, index, length);
+ }
+ }
+
+ return new IndexedPartitionDMC(getSession().getId(), info, ctx, index, length);
+ }
+
+ private void getRealSubExpressionCount(IExpressionDMContext dmc, int numChildLimit, final DataRequestMonitor<Integer> rm) {
+ if (dmc instanceof MIExpressionDMC) {
+ fExpressionCache.execute(
+ new ExprMetaGetChildCount(dmc, numChildLimit),
+ new DataRequestMonitor<ExprMetaGetChildCountInfo>(getExecutor(), rm) {
+ @Override
+ protected void handleSuccess() {
+ rm.setData(getData().getChildNum());
+ rm.done();
+ }
+ });
+ } else if (dmc instanceof InvalidContextExpressionDMC) {
+ rm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, INVALID_HANDLE, "Invalid context for evaluating expressions.", null)); //$NON-NLS-1$
+ rm.done();
+ } else {
+ rm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, INTERNAL_ERROR, "Invalid expression context.", null)); //$NON-NLS-1$
+ rm.done();
+ }
+ }
+
+ private int getArrayPartitionLength() {
+ // Replace this in case we or the platform decide to add a user preference.
+ // See org.eclipse.debug.internal.ui.model.elements.VariableContentProvider.
+ return PARTITION_LENGTH;
+ }
}
diff --git a/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/mi/service/MIVariableManager.java b/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/mi/service/MIVariableManager.java
index 1636f919ed..2aa69e0d21 100644
--- a/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/mi/service/MIVariableManager.java
+++ b/dsf-gdb/org.eclipse.cdt.dsf.gdb/src/org/eclipse/cdt/dsf/mi/service/MIVariableManager.java
@@ -31,6 +31,7 @@ import org.eclipse.cdt.dsf.concurrent.RequestMonitor;
import org.eclipse.cdt.dsf.datamodel.DMContexts;
import org.eclipse.cdt.dsf.debug.service.IExpressions;
import org.eclipse.cdt.dsf.debug.service.IExpressions.IExpressionDMContext;
+import org.eclipse.cdt.dsf.debug.service.IExpressions.IIndexedPartitionDMContext;
import org.eclipse.cdt.dsf.debug.service.IExpressions2.ICastedExpressionDMContext;
import org.eclipse.cdt.dsf.debug.service.IFormattedValues;
import org.eclipse.cdt.dsf.debug.service.IFormattedValues.FormattedValueDMContext;
@@ -1274,6 +1275,9 @@ public class MIVariableManager implements ICommandControl {
exprName = '(' + exprName + ')';
castingIndex = ((ICastedExpressionDMContext)exprDmc).getCastInfo().getArrayStartIndex();
}
+ if (exprDmc instanceof IIndexedPartitionDMContext) {
+ castingIndex = ((IIndexedPartitionDMContext)exprDmc).getIndex();
+ }
for (int i= 0; i < childrenOfArray.length; i++) {
String fullExpr = exprName + "[" + i + "]";//$NON-NLS-1$//$NON-NLS-2$
String relExpr = exprDmc.getRelativeExpression() + "[" + (castingIndex + i) + "]";//$NON-NLS-1$//$NON-NLS-2$
diff --git a/dsf-gdb/org.eclipse.cdt.tests.dsf.gdb/data/launch/src/ExpressionTestApp.cc b/dsf-gdb/org.eclipse.cdt.tests.dsf.gdb/data/launch/src/ExpressionTestApp.cc
index 54b4fec842..88c10cd9eb 100644
--- a/dsf-gdb/org.eclipse.cdt.tests.dsf.gdb/data/launch/src/ExpressionTestApp.cc
+++ b/dsf-gdb/org.eclipse.cdt.tests.dsf.gdb/data/launch/src/ExpressionTestApp.cc
@@ -293,6 +293,14 @@ int testCanWrite() {
return 1;
}
+int testArrays() {
+ int array_simple[10];
+ int array_int[24321];
+ foo array_foo[1200];
+
+ return 1;
+}
+
int main() {
printf("Running ExpressionTest App\n");
@@ -317,6 +325,7 @@ int main() {
testConcurrentUpdateOutOfScopeChildThenParent();
testUpdateOfPointer();
testCanWrite();
+ testArrays();
// For bug 320277
BaseTest b; b.test();
diff --git a/dsf-gdb/org.eclipse.cdt.tests.dsf.gdb/src/org/eclipse/cdt/tests/dsf/gdb/tests/MIExpressionsTest.java b/dsf-gdb/org.eclipse.cdt.tests.dsf.gdb/src/org/eclipse/cdt/tests/dsf/gdb/tests/MIExpressionsTest.java
index 61934dbb88..ca68a7e736 100644
--- a/dsf-gdb/org.eclipse.cdt.tests.dsf.gdb/src/org/eclipse/cdt/tests/dsf/gdb/tests/MIExpressionsTest.java
+++ b/dsf-gdb/org.eclipse.cdt.tests.dsf.gdb/src/org/eclipse/cdt/tests/dsf/gdb/tests/MIExpressionsTest.java
@@ -26,6 +26,7 @@ import org.eclipse.cdt.dsf.debug.service.IExpressions.IExpressionChangedDMEvent;
import org.eclipse.cdt.dsf.debug.service.IExpressions.IExpressionDMAddress;
import org.eclipse.cdt.dsf.debug.service.IExpressions.IExpressionDMContext;
import org.eclipse.cdt.dsf.debug.service.IExpressions.IExpressionDMData;
+import org.eclipse.cdt.dsf.debug.service.IExpressions.IIndexedPartitionDMContext;
import org.eclipse.cdt.dsf.debug.service.IExpressions3.IExpressionDMDataExtension;
import org.eclipse.cdt.dsf.debug.service.IFormattedValues;
import org.eclipse.cdt.dsf.debug.service.IFormattedValues.FormattedValueDMContext;
@@ -320,37 +321,10 @@ public class MIExpressionsTest extends BaseTestCase {
final IFrameDMContext frameDmc = SyncUtil.getStackFrame(stoppedEvent.getDMContext(), 0);
- final AsyncCompletionWaitor wait = new AsyncCompletionWaitor();
-
// First we get the expected value of the array pointer.
final IExpressionDMContext exprDmc = SyncUtil.createExpression(frameDmc, "f");
- fExpService.getExecutor().submit(new Runnable() {
- @Override
- public void run() {
- fExpService.getSubExpressionCount(
- exprDmc,
- new DataRequestMonitor<Integer>(fExpService.getExecutor(), null) {
- @Override
- protected void handleCompleted() {
- if (!isSuccess()) {
- wait.waitFinished(getStatus());
- } else {
- int count = getData();
- if (count != 5) {
- wait.waitFinished(new Status(IStatus.ERROR, TestsPlugin.PLUGIN_ID,
- "Failed getting count for children. Got " + count + " instead of 5", null));
- } else {
- wait.waitFinished();
- }
- }
- }
- });
- }
- });
-
- wait.waitUntilDone(AsyncCompletionWaitor.WAIT_FOREVER);
- assertTrue(wait.getMessage(), wait.isOK());
+ getChildrenCount(exprDmc, 5);
}
/**
@@ -3263,8 +3237,14 @@ public class MIExpressionsTest extends BaseTestCase {
getExprChangedCount() == 0);
}
+ private IExpressionDMContext[] getChildren(IExpressionDMContext parentDmc, String[] expectedValues) throws Throwable {
+ return getChildren(parentDmc, -1, -1, expectedValues );
+ }
+
private IExpressionDMContext[] getChildren(
- final IExpressionDMContext parentDmc,
+ final IExpressionDMContext parentDmc,
+ final int startIndex,
+ final int length,
String[] expectedValues) throws Throwable {
final AsyncCompletionWaitor wait = new AsyncCompletionWaitor();
@@ -3273,7 +3253,10 @@ public class MIExpressionsTest extends BaseTestCase {
@Override
public void run() {
- fExpService.getSubExpressions(parentDmc,
+ fExpService.getSubExpressions(
+ parentDmc,
+ startIndex,
+ length,
new DataRequestMonitor<IExpressionDMContext[]>(fExpService.getExecutor(), null) {
@Override
protected void handleCompleted() {
@@ -3311,4 +3294,130 @@ public class MIExpressionsTest extends BaseTestCase {
return childDmcs;
}
+
+ /**
+ * This test verifies that large arrays are properly partitioned and
+ * the handling of "small" arrays is not affected.
+ */
+ @Test
+ public void testArrays() throws Throwable {
+ MIStoppedEvent stoppedEvent = SyncUtil.runToLocation("testArrays");
+
+ IFrameDMContext frameDmc = SyncUtil.getStackFrame(stoppedEvent.getDMContext(), 0);
+
+ // int array_simple[10];
+ IExpressionDMContext arraySimpleExprDMC = SyncUtil.createExpression(frameDmc, "array_simple");
+
+ getChildrenCount(arraySimpleExprDMC, 10);
+
+ // get all children
+ String[] expectedValues = new String[10];
+ for (int i = 0; i < expectedValues.length; ++i) {
+ expectedValues[i] = String.format("array_simple[%d]", i);
+ }
+ IExpressionDMContext[] arraySimpleChildren = getChildren(arraySimpleExprDMC, expectedValues);
+ for (IExpressionDMContext ctx : arraySimpleChildren)
+ getChildren(ctx, new String[0]);
+
+ // get some parts of the children array
+ getChildren(arraySimpleExprDMC, 3, 2, new String[] { "array_simple[3]", "array_simple[4]" });
+ getChildren(arraySimpleExprDMC, 9, 3, new String[] { "array_simple[9]" });
+
+ // int array_int[24321];
+ IExpressionDMContext arrayIntExprDMC = SyncUtil.createExpression(frameDmc, "array_int");
+ getChildrenCount(arrayIntExprDMC, 3);
+
+ // get top level partitions: [0-9999], [10000-19999], [20000-24321]
+ IExpressionDMContext[] arrayIntPartitions =
+ getChildren(arrayIntExprDMC, new String[] {"*((array_int)+0)@10000", "*((array_int)+10000)@10000", "*((array_int)+20000)@4321"});
+ assertTrue(String.format("Invalid number of partition: expected 3 got %d", arrayIntPartitions.length), arrayIntPartitions.length == 3);
+
+ // get children of the last partition: [20000-24321]
+ expectedValues = new String[44];
+ for(int i = 0; i < expectedValues.length - 1; ++i) {
+ expectedValues[i] = String.format("*((array_int)+%d)@100", 20000 + i*100);
+ }
+ expectedValues[expectedValues.length - 1] = "*((array_int)+24300)@21";
+ IExpressionDMContext[] arrayIntPartitions1 = getChildren(arrayIntPartitions[2], expectedValues);
+ expectedValues = new String[21];
+ for(int i = 0; i < expectedValues.length; ++i) {
+ expectedValues[i] = String.format("array_int[%d]", 24300 + i);
+ }
+ getChildren(arrayIntPartitions1[arrayIntPartitions1.length - 1], expectedValues);
+
+ // foo array_foo[1200];
+ IExpressionDMContext arrayFooExprDMC = SyncUtil.createExpression(frameDmc, "array_foo");
+ getChildrenCount(arrayFooExprDMC, 12);
+ expectedValues = new String[12];
+ for (int i = 0; i < expectedValues.length; ++i) {
+ expectedValues[i] = String.format("*((array_foo)+%d)@%d", i*100, 100);
+ }
+ IExpressionDMContext[] arrayFooPartitions = getChildren(arrayFooExprDMC, expectedValues);
+ for (int i = 0; i < arrayFooPartitions.length; ++i) {
+ IExpressionDMContext ctx = arrayFooPartitions[i];
+ assertTrue(String.format("Invalid DM context type: expected '%s' got '%s'",
+ IIndexedPartitionDMContext.class.getName(), ctx.getClass().getName()),
+ ctx instanceof IIndexedPartitionDMContext);
+ expectedValues = new String[100];
+ for (int j = 0; j < expectedValues.length; ++j) {
+ expectedValues[j] = String.format("array_foo[%d]", i*100 + j);
+ }
+ IExpressionDMContext[] arrayFooChildren = getChildren(ctx, expectedValues);
+ for (IExpressionDMContext fooCtx : arrayFooChildren) {
+ getChildren(fooCtx, new String[] {"bar", "bar2", "a", "b", "c"});
+ }
+
+ // get parts of the children array
+ expectedValues = new String[] { String.format("array_foo[%d]", i*100 + 3), String.format("array_foo[%d]", i*100 + 4) };
+ getChildren(ctx, 3, 2, expectedValues);
+ getChildren(ctx, 99, 3, new String[] { String.format("array_foo[%d]", i*100 + 99) });
+ }
+ }
+
+ private int getChildrenCount(final IExpressionDMContext parentDmc, final int expectedCount) throws Throwable {
+
+ final AsyncCompletionWaitor wait = new AsyncCompletionWaitor();
+
+ fExpService.getExecutor().submit(new Runnable() {
+ @Override
+ public void run() {
+
+ fExpService.getSubExpressionCount(
+ parentDmc,
+ new DataRequestMonitor<Integer>(fExpService.getExecutor(), null) {
+ @Override
+ protected void handleCompleted() {
+ if (isSuccess()) {
+ wait.setReturnInfo(getData());
+ if (getData() != expectedCount) {
+ wait.waitFinished(
+ new Status(
+ IStatus.ERROR,
+ TestsPlugin.PLUGIN_ID,
+ String.format(
+ "Failed getting count for children. Got %d instead of %d.",
+ getData(),
+ expectedCount)));
+ }
+ else {
+ wait.waitFinished(getStatus());
+ }
+ }
+ else {
+ wait.waitFinished(getStatus());
+ }
+ }
+ });
+ }
+ });
+
+ wait.waitUntilDone(AsyncCompletionWaitor.WAIT_FOREVER);
+ assertTrue(wait.getMessage(), wait.isOK());
+
+ int count = ((Integer)wait.getReturnInfo()).intValue();
+
+ assertTrue(String.format("Expected %d but got %d", expectedCount, count), count == expectedCount);
+
+ return count;
+ }
}
diff --git a/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/viewmodel/DsfCastToTypeSupport.java b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/viewmodel/DsfCastToTypeSupport.java
index e625c17d03..458f1829e1 100644
--- a/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/viewmodel/DsfCastToTypeSupport.java
+++ b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/internal/ui/viewmodel/DsfCastToTypeSupport.java
@@ -25,6 +25,7 @@ import org.eclipse.cdt.dsf.datamodel.DMContexts;
import org.eclipse.cdt.dsf.debug.service.IExpressions.IExpressionChangedDMEvent;
import org.eclipse.cdt.dsf.debug.service.IExpressions.IExpressionDMContext;
import org.eclipse.cdt.dsf.debug.service.IExpressions.IExpressionDMData;
+import org.eclipse.cdt.dsf.debug.service.IExpressions.IIndexedPartitionDMContext;
import org.eclipse.cdt.dsf.debug.service.IExpressions2;
import org.eclipse.cdt.dsf.debug.service.IExpressions2.CastInfo;
import org.eclipse.cdt.dsf.debug.service.IExpressions2.ICastedExpressionDMContext;
@@ -90,6 +91,9 @@ public class DsfCastToTypeSupport {
}
private boolean isValid() {
+ if (exprDMC instanceof IIndexedPartitionDMContext)
+ return false;
+
TestExpressions2Query query = new TestExpressions2Query();
dmvmProvider.getSession().getExecutor().execute(query);
diff --git a/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/variable/VariableVMNode.java b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/variable/VariableVMNode.java
index f5bc8e0356..9163bb86cc 100644
--- a/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/variable/VariableVMNode.java
+++ b/dsf/org.eclipse.cdt.dsf.ui/src/org/eclipse/cdt/dsf/debug/ui/viewmodel/variable/VariableVMNode.java
@@ -37,6 +37,7 @@ import org.eclipse.cdt.dsf.debug.service.IExpressions.IExpressionDMAddress;
import org.eclipse.cdt.dsf.debug.service.IExpressions.IExpressionDMContext;
import org.eclipse.cdt.dsf.debug.service.IExpressions.IExpressionDMData;
import org.eclipse.cdt.dsf.debug.service.IExpressions.IExpressionDMLocation;
+import org.eclipse.cdt.dsf.debug.service.IExpressions.IIndexedPartitionDMContext;
import org.eclipse.cdt.dsf.debug.service.IExpressions2;
import org.eclipse.cdt.dsf.debug.service.IExpressions3;
import org.eclipse.cdt.dsf.debug.service.IExpressions3.IExpressionDMDataExtension;
@@ -135,6 +136,11 @@ public class VariableVMNode extends AbstractExpressionVMNode
*/
public static final String PROP_VARIABLE_ADDRESS_CHANGED = ICachingVMProvider.PROP_IS_CHANGED_PREFIX + PROP_VARIABLE_ADDRESS;
+ /**
+ * 'PROP_VARIABLE_BASIC_TYPE' property value for indexed partitions
+ */
+ private static final String INDEXED_PARTITION_TYPE = "indexed_partition_type"; //$NON-NLS-1$
+
private final SyncVariableDataAccess fSyncVariableDataAccess;
/**
@@ -330,6 +336,16 @@ public class VariableVMNode extends AbstractExpressionVMNode
};
};
+ public final static LabelImage PARTITION_LABEL_IMAGE = new LabelImage(CDebugImages.DESC_OBJS_ARRAY_PARTITION) {
+ { setPropertyNames(new String[] { PROP_VARIABLE_BASIC_TYPE }); }
+
+ @Override
+ public boolean isEnabled(IStatus status, java.util.Map<String,Object> properties) {
+ String type = (String)properties.get(PROP_VARIABLE_BASIC_TYPE);
+ return INDEXED_PARTITION_TYPE.equals(type);
+ };
+ };
+
protected IElementLabelProvider createLabelProvider() {
//
@@ -407,6 +423,7 @@ public class VariableVMNode extends AbstractExpressionVMNode
new String[] { PROP_NAME }),
POINTER_LABEL_IMAGE,
AGGREGATE_LABEL_IMAGE,
+ PARTITION_LABEL_IMAGE,
SIMPLE_LABEL_IMAGE,
new StaleDataLabelForeground(),
new VariableLabelFont(),
@@ -422,6 +439,7 @@ public class VariableVMNode extends AbstractExpressionVMNode
new String[] { PROP_ELEMENT_EXPRESSION }),
POINTER_LABEL_IMAGE,
AGGREGATE_LABEL_IMAGE,
+ PARTITION_LABEL_IMAGE,
SIMPLE_LABEL_IMAGE,
new StaleDataLabelForeground(),
new VariableLabelFont(),
@@ -770,10 +788,13 @@ public class VariableVMNode extends AbstractExpressionVMNode
// In case of an error fill in the expression text in the name column and expressions columns.
IExpressionDMContext dmc = findDmcInPath(update.getViewerInput(), update.getElementPath(), IExpressions.IExpressionDMContext.class);
if (dmc != null && dmc.getExpression() != null) {
- update.setProperty(PROP_NAME, dmc.getExpression());
+ String displayName = getExpressionDisplayName(dmc, dmc.getExpression());
+ update.setProperty(PROP_NAME, displayName);
if (expression == null) {
- update.setProperty(PROP_ELEMENT_EXPRESSION, dmc.getExpression());
+ update.setProperty(PROP_ELEMENT_EXPRESSION, displayName);
}
+ if (dmc instanceof IIndexedPartitionDMContext)
+ update.setProperty(PROP_VARIABLE_BASIC_TYPE, INDEXED_PARTITION_TYPE);
}
update.setStatus(getStatus());
}
@@ -814,11 +835,23 @@ public class VariableVMNode extends AbstractExpressionVMNode
@ConfinedToDsfExecutor("getSession().getExecutor()")
protected void fillExpressionDataProperties(IPropertiesUpdate update, IExpressionDMData data)
{
- update.setProperty(PROP_NAME, data.getName());
+ IExpressionDMContext dmc = findDmcInPath(update.getViewerInput(), update.getElementPath(), IExpressions.IExpressionDMContext.class);
+ String displayName = data.getName();
+ if (dmc != null) {
+ displayName = getExpressionDisplayName(dmc, displayName);
+ }
+ update.setProperty(PROP_NAME, displayName);
update.setProperty(PROP_VARIABLE_TYPE_NAME, data.getTypeName());
- IExpressionDMData.BasicType type = data.getBasicType();
- if (type != null) {
- update.setProperty(PROP_VARIABLE_BASIC_TYPE, type.name());
+ String typeValue = null;
+ if (dmc instanceof IIndexedPartitionDMContext)
+ typeValue = INDEXED_PARTITION_TYPE;
+ else {
+ IExpressionDMData.BasicType type = data.getBasicType();
+ if (type != null)
+ typeValue = type.name();
+ }
+ if (typeValue != null) {
+ update.setProperty(PROP_VARIABLE_BASIC_TYPE, typeValue);
}
//
@@ -828,7 +861,7 @@ public class VariableVMNode extends AbstractExpressionVMNode
//
IExpression expression = (IExpression)DebugPlugin.getAdapter(update.getElement(), IExpression.class);
if (expression == null) {
- update.setProperty(AbstractExpressionVMNode.PROP_ELEMENT_EXPRESSION, data.getName());
+ update.setProperty(AbstractExpressionVMNode.PROP_ELEMENT_EXPRESSION, displayName);
}
}
@@ -1344,4 +1377,18 @@ public class VariableVMNode extends AbstractExpressionVMNode
request.done();
}
}
+
+ /**
+ * Returns the label for the element with the given context.
+ */
+ protected String getExpressionDisplayName(IExpressionDMContext dmc, String name) {
+ if (dmc instanceof IIndexedPartitionDMContext) {
+ IIndexedPartitionDMContext ipDmc = (IIndexedPartitionDMContext)dmc;
+ name = String.format(
+ "[%d...%d]", //$NON-NLS-1$
+ ipDmc.getIndex(),
+ ipDmc.getIndex() + ipDmc.getLength() - 1);
+ }
+ return name;
+ }
}
diff --git a/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/debug/service/IExpressions.java b/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/debug/service/IExpressions.java
index ba32cdcdd4..fac33c4a85 100644
--- a/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/debug/service/IExpressions.java
+++ b/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/debug/service/IExpressions.java
@@ -44,6 +44,30 @@ public interface IExpressions extends IFormattedValues {
}
/**
+ * To avoid SWT performance issues large arrays are divided into partitions.
+ * This interface represents the context of such a partition.
+ *
+ * @since 2.3
+ */
+ public interface IIndexedPartitionDMContext extends IExpressionDMContext {
+
+ /**
+ * Returns the expression string of the parent array.
+ */
+ public String getParentExpression();
+
+ /**
+ * Returns the index of the partition's first element in the parent array.
+ */
+ public int getIndex();
+
+ /**
+ * Returns the number of array's elements in the partition.
+ */
+ public int getLength();
+ }
+
+ /**
* The address and size of an expression.
*/
public interface IExpressionDMAddress {

Back to the top