xref: /haiku/src/kits/debugger/debug_managers/ValueNodeManager.cpp (revision b31cb92f29fe89eaca84d173d0f70d38bf0c6a3d)
1 /*
2  * Copyright 2012-2016, Rene Gollent, rene@gollent.com.
3  * Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de.
4  * Distributed under the terms of the MIT License.
5  */
6 
7 #include "ValueNodeManager.h"
8 
9 #include "AutoLocker.h"
10 
11 #include "model/Thread.h"
12 #include "StackFrame.h"
13 #include "Team.h"
14 #include "TypeHandlerRoster.h"
15 #include "ValueNode.h"
16 #include "Variable.h"
17 #include "VariableValueNodeChild.h"
18 
19 
20 ValueNodeManager::ValueNodeManager(bool addFrameNodes)
21 	:
22 	fAddFrameNodes(addFrameNodes),
23 	fContainer(NULL),
24 	fStackFrame(NULL),
25 	fThread(NULL)
26 {
27 	SetStackFrame(NULL, NULL);
28 }
29 
30 
31 ValueNodeManager::~ValueNodeManager()
32 {
33 	SetStackFrame(NULL, NULL);
34 }
35 
36 
37 status_t
38 ValueNodeManager::SetStackFrame(Thread* thread,
39 	StackFrame* stackFrame)
40 {
41 	if (fContainer != NULL) {
42 		AutoLocker<ValueNodeContainer> containerLocker(fContainer);
43 
44 		fContainer->RemoveListener(this);
45 
46 		fContainer->RemoveAllChildren();
47 		containerLocker.Unlock();
48 		fContainer->ReleaseReference();
49 		fContainer = NULL;
50 	}
51 
52 	fStackFrame = stackFrame;
53 	fThread = thread;
54 
55 	if (fStackFrame == NULL)
56 		return B_OK;
57 
58 	fContainer = new(std::nothrow) ValueNodeContainer;
59 	if (fContainer == NULL)
60 		return B_NO_MEMORY;
61 
62 	status_t error = fContainer->Init();
63 	if (error != B_OK) {
64 		delete fContainer;
65 		fContainer = NULL;
66 		return error;
67 	}
68 
69 	AutoLocker<ValueNodeContainer> containerLocker(fContainer);
70 
71 	fContainer->AddListener(this);
72 
73 	if (fStackFrame != NULL && fAddFrameNodes) {
74 		for (int32 i = 0; Variable* variable = fStackFrame->ParameterAt(i);
75 				i++) {
76 			_AddNode(variable);
77 		}
78 
79 		for (int32 i = 0; Variable* variable
80 				= fStackFrame->LocalVariableAt(i); i++) {
81 			_AddNode(variable);
82 		}
83 	}
84 
85 	return B_OK;
86 }
87 
88 
89 bool
90 ValueNodeManager::AddListener(ValueNodeContainer::Listener* listener)
91 {
92 	return fListeners.AddItem(listener);
93 }
94 
95 
96 void
97 ValueNodeManager::RemoveListener(ValueNodeContainer::Listener* listener)
98 {
99 	fListeners.RemoveItem(listener);
100 }
101 
102 
103 void
104 ValueNodeManager::ValueNodeChanged(ValueNodeChild* nodeChild,
105 	ValueNode* oldNode, ValueNode* newNode)
106 {
107 	if (fContainer == NULL)
108 		return;
109 
110 	AutoLocker<ValueNodeContainer> containerLocker(fContainer);
111 
112 	for (int32 i = fListeners.CountItems() - 1; i >= 0; i--)
113 		fListeners.ItemAt(i)->ValueNodeChanged(nodeChild, oldNode, newNode);
114 
115 	if (oldNode != NULL && !newNode->ChildCreationNeedsValue())
116 		newNode->CreateChildren(fThread->GetTeam()->GetTeamTypeInformation());
117 }
118 
119 
120 void
121 ValueNodeManager::ValueNodeChildrenCreated(ValueNode* node)
122 {
123 	if (fContainer == NULL)
124 		return;
125 
126 	for (int32 i = fListeners.CountItems() - 1; i >= 0; i--)
127 		fListeners.ItemAt(i)->ValueNodeChildrenCreated(node);
128 }
129 
130 
131 void
132 ValueNodeManager::ValueNodeChildrenDeleted(ValueNode* node)
133 {
134 	if (fContainer == NULL)
135 		return;
136 
137 	for (int32 i = fListeners.CountItems() - 1; i >= 0; i--)
138 		fListeners.ItemAt(i)->ValueNodeChildrenDeleted(node);
139 }
140 
141 
142 void
143 ValueNodeManager::ValueNodeValueChanged(ValueNode* valueNode)
144 {
145 	if (fContainer == NULL)
146 		return;
147 
148 	AutoLocker<ValueNodeContainer> containerLocker(fContainer);
149 
150 	// check whether we know the node
151 	ValueNodeChild* nodeChild = valueNode->NodeChild();
152 	if (nodeChild == NULL)
153 		return;
154 
155 	if (valueNode->ChildCreationNeedsValue()
156 		&& !valueNode->ChildrenCreated()) {
157 		status_t error = valueNode->CreateChildren(
158 			fThread->GetTeam()->GetTeamTypeInformation());
159 		if (error == B_OK) {
160 			for (int32 i = 0; i < valueNode->CountChildren(); i++) {
161 				ValueNodeChild* child = valueNode->ChildAt(i);
162 				_CreateValueNode(child);
163 				AddChildNodes(child);
164 			}
165 		}
166 	}
167 
168 	for (int32 i = fListeners.CountItems() - 1; i >= 0; i--)
169 		fListeners.ItemAt(i)->ValueNodeValueChanged(valueNode);
170 }
171 
172 
173 void
174 ValueNodeManager::_AddNode(Variable* variable)
175 {
176 	// create the node child for the variable
177 	ValueNodeChild* nodeChild = new (std::nothrow) VariableValueNodeChild(
178 		variable);
179 	BReference<ValueNodeChild> nodeChildReference(nodeChild, true);
180 	if (nodeChild == NULL || !fContainer->AddChild(nodeChild)) {
181 		delete nodeChild;
182 		return;
183 	}
184 
185 	// automatically add child nodes for the top level nodes
186 	AddChildNodes(nodeChild);
187 }
188 
189 
190 status_t
191 ValueNodeManager::_CreateValueNode(ValueNodeChild* nodeChild)
192 {
193 	if (nodeChild->Node() != NULL)
194 		return B_OK;
195 
196 	// create the node
197 	ValueNode* valueNode;
198 	status_t error;
199 	if (nodeChild->IsInternal()) {
200 		error = nodeChild->CreateInternalNode(valueNode);
201 	} else {
202 		error = TypeHandlerRoster::Default()->CreateValueNode(nodeChild,
203 			nodeChild->GetType(), NULL, valueNode);
204 	}
205 
206 	if (error != B_OK)
207 		return error;
208 
209 	nodeChild->SetNode(valueNode);
210 	valueNode->ReleaseReference();
211 
212 	return B_OK;
213 }
214 
215 
216 status_t
217 ValueNodeManager::AddChildNodes(ValueNodeChild* nodeChild)
218 {
219 	AutoLocker<ValueNodeContainer> containerLocker(fContainer);
220 
221 	// create a value node for the value node child, if doesn't have one yet
222 	ValueNode* valueNode = nodeChild->Node();
223 	if (valueNode == NULL) {
224 		status_t error = _CreateValueNode(nodeChild);
225 		if (error != B_OK)
226 			return error;
227 		valueNode = nodeChild->Node();
228 	}
229 
230 	// check if this node requires child creation
231 	// to be deferred until after its location/value have been resolved
232 	if (valueNode->ChildCreationNeedsValue())
233 		return B_OK;
234 
235 	// create the children, if not done yet
236 	if (valueNode->ChildrenCreated())
237 		return B_OK;
238 
239 	return valueNode->CreateChildren(
240 		fThread->GetTeam()->GetTeamTypeInformation());
241 }
242