Debugger: Adjust VariablesView for new expression API.

- Simplify handling of expression nodes. For primitive results, we now
  construct a Variable object that represents the expression result, and
  then add that as we would any other local variable. This simplifies handling,
  and also allows saving/restoration of their view state to be handled the
  same as other nodes. Complex expression results aren't yet handled properly,
  pending some further work in progress on the evaluator.
This commit is contained in:
Rene Gollent
2014-11-22 17:08:51 -05:00
parent 81c848a14a
commit b4a861136b
3 changed files with 211 additions and 171 deletions
@@ -26,7 +26,6 @@
#include "ActionMenuItem.h" #include "ActionMenuItem.h"
#include "Architecture.h" #include "Architecture.h"
#include "ExpressionInfo.h" #include "ExpressionInfo.h"
#include "ExpressionValueNode.h"
#include "ExpressionValues.h" #include "ExpressionValues.h"
#include "FileSourceCode.h" #include "FileSourceCode.h"
#include "Function.h" #include "Function.h"
@@ -41,6 +40,8 @@
#include "StackTrace.h" #include "StackTrace.h"
#include "StackFrame.h" #include "StackFrame.h"
#include "StackFrameValues.h" #include "StackFrameValues.h"
#include "StringUtils.h"
#include "StringValue.h"
#include "SyntheticPrimitiveType.h" #include "SyntheticPrimitiveType.h"
#include "TableCellValueRenderer.h" #include "TableCellValueRenderer.h"
#include "Team.h" #include "Team.h"
@@ -205,6 +206,47 @@ private:
}; };
// #pragma mark - ExpressionVariableID
class VariablesView::ExpressionVariableID : public ObjectID {
public:
ExpressionVariableID(ExpressionInfo* info)
:
fInfo(info)
{
fInfo->AcquireReference();
}
virtual ~ExpressionVariableID()
{
fInfo->ReleaseReference();
}
virtual bool operator==(const ObjectID& other) const
{
const ExpressionVariableID* otherID
= dynamic_cast<const ExpressionVariableID*>(&other);
if (otherID == NULL)
return false;
return fInfo == otherID->fInfo;
}
protected:
virtual uint32 ComputeHashValue() const
{
uint32 hash = *(uint32*)(&fInfo);
hash = hash * 19 + StringUtils::HashValue(fInfo->Expression());
return hash;
}
private:
ExpressionInfo* fInfo;
};
// #pragma mark - ModelNode // #pragma mark - ModelNode
@@ -593,7 +635,8 @@ public:
const TreeTablePath& path, const TreeTablePath& path,
int32 columnIndex, BToolTip** _tip); int32 columnIndex, BToolTip** _tip);
status_t AddSyntheticNode(ModelNode* node); status_t AddSyntheticNode(Variable* variable,
ValueNodeChild*& _child);
void RemoveSyntheticNode(ModelNode* node); void RemoveSyntheticNode(ModelNode* node);
private: private:
@@ -1467,24 +1510,50 @@ VariablesView::VariableTableModel::GetToolTipForTablePath(
status_t status_t
VariablesView::VariableTableModel::AddSyntheticNode(ModelNode* node) VariablesView::VariableTableModel::AddSyntheticNode(Variable* variable,
ValueNodeChild*& _child)
{ {
status_t error = node->Init(); ValueNodeContainer* container = fNodeManager->GetContainer();
AutoLocker<ValueNodeContainer> containerLocker(container);
_child = new(std::nothrow) VariableValueNodeChild(variable);
if (_child == NULL)
return B_NO_MEMORY;
BReference<ValueNodeChild> childReference(_child, true);
ValueNode* valueNode;
status_t error;
if (_child->IsInternal())
error = _child->CreateInternalNode(valueNode);
else {
error = TypeHandlerRoster::Default()->CreateValueNode(_child,
_child->GetType(), valueNode);
}
if (error != B_OK) if (error != B_OK)
return error; return error;
int32 index = fNodes.CountItems(); _child->SetNode(valueNode);
valueNode->ReleaseReference();
container->AddChild(_child);
if (!fNodes.AddItem(node)) { error = _AddNode(variable, NULL, _child);
return B_NO_MEMORY; if (error != B_OK) {
// NB: we take over the caller's reference container->RemoveChild(_child);
return error;
} }
fNodeTable.Insert(node); // since we're injecting these nodes synthetically,
// we have to manually ask the node manager to create any
// applicable children; this would normally be done implicitly
// for top level nodes, as they're added from the parameters/locals,
// but not here.
fNodeManager->AddChildNodes(_child);
node->NodeChild()->Node()->SetContainer(fNodeManager->GetContainer()); ModelNode* childNode = fNodeTable.Lookup(_child);
if (childNode != NULL)
NotifyNodesAdded(TreeTablePath(), index, 1); fContainerListener->ModelNodeValueRequested(childNode);
ValueNodeChildrenCreated(_child->Node());
return B_OK; return B_OK;
} }
@@ -1615,6 +1684,7 @@ VariablesView::VariablesView(Listener* listener)
fPreviousViewState(NULL), fPreviousViewState(NULL),
fViewStateHistory(NULL), fViewStateHistory(NULL),
fExpressions(NULL), fExpressions(NULL),
fExpressionChildren(10, false),
fTableCellContextMenuTracker(NULL), fTableCellContextMenuTracker(NULL),
fFrameClearPending(false), fFrameClearPending(false),
fListener(listener) fListener(listener)
@@ -1676,6 +1746,10 @@ VariablesView::SetStackFrame(Thread* thread, StackFrame* stackFrame)
_FinishContextMenu(true); _FinishContextMenu(true);
for (int32 i = 0; i < fExpressionChildren.CountItems(); i++)
fExpressionChildren.ItemAt(i)->ReleaseReference();
fExpressionChildren.MakeEmpty();
if (fThread != NULL) if (fThread != NULL)
fThread->ReleaseReference(); fThread->ReleaseReference();
if (fStackFrame != NULL) if (fStackFrame != NULL)
@@ -1975,7 +2049,7 @@ VariablesView::MessageReceived(BMessage* message)
valueReference.SetTo(value, true); valueReference.SetTo(value, true);
} }
_SetExpressionNodeValue(info, result, value); _AddExpressionNode(info, result, value);
break; break;
} }
case MSG_VALUE_NODE_CHANGED: case MSG_VALUE_NODE_CHANGED:
@@ -2410,20 +2484,18 @@ VariablesView::_GetContextActionsForNode(ModelNode* node,
BPrivate::ObjectDeleter<ContextActionList> postActionListDeleter( BPrivate::ObjectDeleter<ContextActionList> postActionListDeleter(
_postActions); _postActions);
#if 0
result = _AddContextAction("Add watch expression" B_UTF8_ELLIPSIS, result = _AddContextAction("Add watch expression" B_UTF8_ELLIPSIS,
MSG_ADD_WATCH_EXPRESSION, _postActions, message); MSG_ADD_WATCH_EXPRESSION, _postActions, message);
if (result != B_OK) if (result != B_OK)
return result; return result;
if (dynamic_cast<ExpressionValueNodeChild*>(node->NodeChild()) != NULL) { if (fExpressionChildren.HasItem(node->NodeChild())) {
result = _AddContextAction("Remove watch expression", result = _AddContextAction("Remove watch expression",
MSG_REMOVE_WATCH_EXPRESSION, _postActions, message); MSG_REMOVE_WATCH_EXPRESSION, _postActions, message);
if (result != B_OK) if (result != B_OK)
return result; return result;
message->AddPointer("node", node); message->AddPointer("node", node);
} }
#endif
preActionListDeleter.Detach(); preActionListDeleter.Detach();
postActionListDeleter.Detach(); postActionListDeleter.Detach();
@@ -2599,7 +2671,6 @@ VariablesView::_AddViewStateDescendentNodeInfos(VariablesViewState* viewState,
Value* value = node->GetValue(); Value* value = node->GetValue();
Variable* variable = node->GetVariable(); Variable* variable = node->GetVariable();
if (variable != NULL) {
TypeComponentPath* componentPath = node->GetPath(); TypeComponentPath* componentPath = node->GetPath();
ObjectID* id = variable->ID(); ObjectID* id = variable->ID();
@@ -2621,24 +2692,6 @@ VariablesView::_AddViewStateDescendentNodeInfos(VariablesViewState* viewState,
updateValues); updateValues);
if (error != B_OK) if (error != B_OK)
return error; return error;
} else {
ExpressionValueNodeChild* child
= dynamic_cast<ExpressionValueNodeChild*>(node->NodeChild());
if (child != NULL && value != NULL && updateValues) {
BVariant variableValueData;
if (value->ToVariant(variableValueData)) {
FunctionID* id = fStackFrame->Function()->GetFunctionID();
if (id == NULL)
return B_NO_MEMORY;
BReference<FunctionID> functionReference(id, true);
status_t error = viewState->GetExpressionValues()
->SetValue(id, fThread, child->GetExpression(),
variableValueData);
if (error != B_OK)
return error;
}
}
}
path.RemoveLastComponent(); path.RemoveLastComponent();
} }
@@ -2658,8 +2711,6 @@ VariablesView::_ApplyViewStateDescendentNodeInfos(VariablesViewState* viewState,
return B_NO_MEMORY; return B_NO_MEMORY;
// apply the node's info, if any // apply the node's info, if any
Variable* variable = node->GetVariable();
if (variable != NULL) {
ObjectID* objectID = node->GetVariable()->ID(); ObjectID* objectID = node->GetVariable()->ID();
TypeComponentPath* componentPath = node->GetPath(); TypeComponentPath* componentPath = node->GetPath();
const VariablesViewNodeInfo* nodeInfo = viewState->GetNodeInfo( const VariablesViewNodeInfo* nodeInfo = viewState->GetNodeInfo(
@@ -2693,21 +2744,6 @@ VariablesView::_ApplyViewStateDescendentNodeInfos(VariablesViewState* viewState,
node->SetPreviousValue(previousValue); node->SetPreviousValue(previousValue);
} }
} }
} else {
ExpressionValueNodeChild* child
= dynamic_cast<ExpressionValueNodeChild*>(node->NodeChild());
if (child != NULL) {
BVariant previousValue;
FunctionID* id = fStackFrame->Function()->GetFunctionID();
if (id == NULL)
return B_NO_MEMORY;
BReference<FunctionID> idReference(id, true);
if (viewState->GetExpressionValues()->GetValue(id, fThread,
child->GetExpression(), previousValue)) {
node->SetPreviousValue(previousValue);
}
}
}
// recurse // recurse
status_t error = _ApplyViewStateDescendentNodeInfos(viewState, node, status_t error = _ApplyViewStateDescendentNodeInfos(viewState, node,
@@ -2776,10 +2812,6 @@ VariablesView::_AddExpression(const char* expression, ExpressionInfo*& _info)
BReference<ExpressionInfo> infoReference(info, true); BReference<ExpressionInfo> infoReference(info, true);
status_t error = _AddExpressionNode(info);
if (error != B_OK)
return error;
if (!entry->AddItem(info)) if (!entry->AddItem(info))
return B_NO_MEMORY; return B_NO_MEMORY;
@@ -2793,9 +2825,7 @@ VariablesView::_AddExpression(const char* expression, ExpressionInfo*& _info)
void void
VariablesView::_RemoveExpression(ModelNode* node) VariablesView::_RemoveExpression(ModelNode* node)
{ {
ExpressionValueNodeChild* child if (!fExpressionChildren.HasItem(node->NodeChild()))
= dynamic_cast<ExpressionValueNodeChild*>(node->NodeChild());
if (child == NULL)
return; return;
FunctionID* id = fStackFrame->Function()->GetFunctionID(); FunctionID* id = fStackFrame->Function()->GetFunctionID();
@@ -2807,7 +2837,7 @@ VariablesView::_RemoveExpression(ModelNode* node)
for (int32 i = 0; i < entry->CountItems(); i++) { for (int32 i = 0; i < entry->CountItems(); i++) {
ExpressionInfo* info = entry->ItemAt(i); ExpressionInfo* info = entry->ItemAt(i);
if (info->Expression() == child->GetExpression()) { if (info->Expression() == node->Name()) {
entry->RemoveItemAt(i); entry->RemoveItemAt(i);
info->RemoveListener(this); info->RemoveListener(this);
info->ReleaseReference(); info->ReleaseReference();
@@ -2819,46 +2849,6 @@ VariablesView::_RemoveExpression(ModelNode* node)
} }
status_t
VariablesView::_AddExpressionNode(ExpressionInfo* info)
{
#if 0
ExpressionValueNodeChild* child
= new(std::nothrow) ExpressionValueNodeChild(info->Expression(), type);
if (child == NULL)
return B_NO_MEMORY;
BReference<ValueNodeChild> childReference(child, true);
ExpressionValueNode* expressionNode
= new(std::nothrow) ExpressionValueNode(child, type);
if (expressionNode == NULL)
return B_NO_MEMORY;
BReference<ValueNode> expressionNodeReference(expressionNode, true);
child->SetNode(expressionNode);
ModelNode* modelNode = new(std::nothrow) ModelNode(NULL, NULL,
child, true);
if (modelNode == NULL)
return B_NO_MEMORY;
BReference<ModelNode> modelNodeReference(modelNode, true);
status_t error = fVariableTableModel->AddSyntheticNode(modelNode);
if (error != B_OK)
return error;
expressionNodeReference.Detach();
modelNodeReference.Detach();
return B_OK;
#endif
return B_NOT_SUPPORTED;
}
void void
VariablesView::_RestoreExpressionNodes() VariablesView::_RestoreExpressionNodes()
{ {
@@ -2878,45 +2868,90 @@ VariablesView::_RestoreExpressionNodes()
for (int32 i = 0; i < entry->CountItems(); i++) { for (int32 i = 0; i < entry->CountItems(); i++) {
ExpressionInfo* info = entry->ItemAt(i); ExpressionInfo* info = entry->ItemAt(i);
_AddExpressionNode(info);
fListener->ExpressionEvaluationRequested(info, fStackFrame, fThread); fListener->ExpressionEvaluationRequested(info, fStackFrame, fThread);
} }
} }
void void
VariablesView::_SetExpressionNodeValue(ExpressionInfo* info, status_t result, VariablesView::_AddExpressionNode(ExpressionInfo* info, status_t result,
ExpressionResult* value) ExpressionResult* value)
{ {
FunctionInstance* instance = fStackFrame->Function(); Variable* variable = NULL;
if (instance == NULL) BReference<Variable> variableReference;
return; BVariant valueData;
FunctionID* id = instance->GetFunctionID(); Value* primitive = value->PrimitiveValue();
if (primitive != NULL) {
if (!primitive->ToVariant(valueData))
return;
} else
valueData.SetTo("Unsupported expression result type.");
ExpressionVariableID* id
= new(std::nothrow) ExpressionVariableID(info);
if (id == NULL) if (id == NULL)
return; return;
BReference<ObjectID> idReference(id, true);
BReference<FunctionID> idReference(id, true); Type* type = NULL;
if (_GetTypeForTypeCode(valueData.Type(), type) != B_OK)
return;
BReference<Type> typeReference(type, true);
ExpressionInfoEntry* entry = fExpressions->Lookup(FunctionKey(id)); ValueLocation* location = new(std::nothrow) ValueLocation();
if (entry == NULL) if (location == NULL)
return;
BReference<ValueLocation> locationReference(location, true);
if (valueData.IsNumber()) {
ValuePieceLocation piece;
if (!piece.SetToValue(valueData.Bytes(), valueData.Size())
|| !location->AddPiece(piece)) {
return;
}
}
variable = new(std::nothrow) Variable(id,
info->Expression(), type, location);
if (variable == NULL)
return;
variableReference.SetTo(variable, true);
ValueNodeChild* child = NULL;
status_t error = fVariableTableModel->AddSyntheticNode(variable, child);
if (error != B_OK)
return; return;
void* rootNode = fVariableTableModel->Root(); // In the case of either an evaluation error, or an unsupported result
for (int32 i = 0; i < fVariableTableModel->CountChildren(rootNode); i++) { // type, set an explanatory string for the result directly.
ModelNode* node = (ModelNode*)fVariableTableModel->ChildAt(rootNode, if (result != B_OK || valueData.Type() == B_STRING_TYPE) {
i); StringValue* explicitValue = new(std::nothrow) StringValue(
ExpressionValueNodeChild* child valueData.ToString());
= dynamic_cast<ExpressionValueNodeChild*>(node->NodeChild()); if (explicitValue == NULL)
if (child == NULL)
continue;
if (child->GetExpression() != info->Expression())
continue;
child->Node()->SetLocationAndValue(NULL, value->PrimitiveValue(),
result);
return; return;
child->Node()->SetLocationAndValue(NULL, explicitValue, B_OK);
}
if (fExpressionChildren.AddItem(child)) {
child->AcquireReference();
// attempt to restore our newly added node's view state,
// if applicable.
FunctionID* functionID = fStackFrame->Function()
->GetFunctionID();
if (functionID == NULL)
return;
BReference<FunctionID> functionIDReference(functionID,
true);
VariablesViewState* viewState = fViewStateHistory
->GetState(fThread->ID(), functionID);
if (viewState != NULL) {
TreeTablePath path;
_ApplyViewStateDescendentNodeInfos(viewState,
fVariableTableModel->Root(), path);
}
} }
} }
@@ -2924,7 +2959,7 @@ VariablesView::_SetExpressionNodeValue(ExpressionInfo* info, status_t result,
status_t status_t
VariablesView::_GetTypeForTypeCode(int32 type, Type*& _resultType) const VariablesView::_GetTypeForTypeCode(int32 type, Type*& _resultType) const
{ {
if (BVariant::TypeIsNumber(type)) { if (BVariant::TypeIsNumber(type) || type == B_STRING_TYPE) {
_resultType = new(std::nothrow) SyntheticPrimitiveType(type); _resultType = new(std::nothrow) SyntheticPrimitiveType(type);
if (_resultType == NULL) if (_resultType == NULL)
return B_NO_MEMORY; return B_NO_MEMORY;
@@ -23,6 +23,7 @@ class Thread;
class Type; class Type;
class TypeComponentPath; class TypeComponentPath;
class ValueNode; class ValueNode;
class ValueNodeChild;
class ValueNodeContainer; class ValueNodeContainer;
class Value; class Value;
class Variable; class Variable;
@@ -70,6 +71,7 @@ private:
private: private:
class ContainerListener; class ContainerListener;
class ExpressionVariableID;
class ModelNode; class ModelNode;
class VariableValueColumn; class VariableValueColumn;
class VariableTableModel; class VariableTableModel;
@@ -77,6 +79,7 @@ private:
class TableCellContextMenuTracker; class TableCellContextMenuTracker;
typedef BObjectList<ActionMenuItem> ContextActionList; typedef BObjectList<ActionMenuItem> ContextActionList;
typedef BObjectList<ExpressionInfo> ExpressionInfoList; typedef BObjectList<ExpressionInfo> ExpressionInfoList;
typedef BObjectList<ValueNodeChild> ExpressionChildList;
struct FunctionKey; struct FunctionKey;
struct ExpressionInfoEntry; struct ExpressionInfoEntry;
@@ -113,10 +116,9 @@ private:
ExpressionInfo*& _info); ExpressionInfo*& _info);
void _RemoveExpression(ModelNode* node); void _RemoveExpression(ModelNode* node);
status_t _AddExpressionNode(ExpressionInfo* info);
void _RestoreExpressionNodes(); void _RestoreExpressionNodes();
void _SetExpressionNodeValue(ExpressionInfo* info, void _AddExpressionNode(ExpressionInfo* info,
status_t result, ExpressionResult* value); status_t result, ExpressionResult* value);
status_t _GetTypeForTypeCode(int32 typeCode, status_t _GetTypeForTypeCode(int32 typeCode,
@@ -131,6 +133,7 @@ private:
VariablesViewState* fPreviousViewState; VariablesViewState* fPreviousViewState;
VariablesViewStateHistory* fViewStateHistory; VariablesViewStateHistory* fViewStateHistory;
ExpressionInfoTable* fExpressions; ExpressionInfoTable* fExpressions;
ExpressionChildList fExpressionChildren;
TableCellContextMenuTracker* fTableCellContextMenuTracker; TableCellContextMenuTracker* fTableCellContextMenuTracker;
bool fFrameClearPending; bool fFrameClearPending;
Listener* fListener; Listener* fListener;
@@ -479,6 +479,8 @@ UiUtils::TypeCodeToString(type_code type)
return "float"; return "float";
case B_DOUBLE_TYPE: case B_DOUBLE_TYPE:
return "double"; return "double";
case B_STRING_TYPE:
return "string";
default: default:
return "unknown"; return "unknown";
} }