xref: /haiku/src/kits/debugger/debug_managers/ValueNodeManager.cpp (revision 3995592cdf304335132305e27c40cbb0b1ac46e3)
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)
116 		newNode->CreateChildren(fThread->GetTeam()->GetTeamTypeInformation());
117 
118 }
119 
120 
121 void
122 ValueNodeManager::ValueNodeChildrenCreated(ValueNode* node)
123 {
124 	if (fContainer == NULL)
125 		return;
126 
127 	for (int32 i = fListeners.CountItems() - 1; i >= 0; i--)
128 		fListeners.ItemAt(i)->ValueNodeChildrenCreated(node);
129 }
130 
131 
132 void
133 ValueNodeManager::ValueNodeChildrenDeleted(ValueNode* node)
134 {
135 	if (fContainer == NULL)
136 		return;
137 
138 	for (int32 i = fListeners.CountItems() - 1; i >= 0; i--)
139 		fListeners.ItemAt(i)->ValueNodeChildrenDeleted(node);
140 }
141 
142 
143 void
144 ValueNodeManager::ValueNodeValueChanged(ValueNode* valueNode)
145 {
146 	if (fContainer == NULL)
147 		return;
148 
149 	AutoLocker<ValueNodeContainer> containerLocker(fContainer);
150 
151 	// check whether we know the node
152 	ValueNodeChild* nodeChild = valueNode->NodeChild();
153 	if (nodeChild == NULL)
154 		return;
155 
156 	if (valueNode->ChildCreationNeedsValue()
157 		&& !valueNode->ChildrenCreated()) {
158 		status_t error = valueNode->CreateChildren(
159 			fThread->GetTeam()->GetTeamTypeInformation());
160 		if (error == B_OK) {
161 			for (int32 i = 0; i < valueNode->CountChildren(); i++) {
162 				ValueNodeChild* child = valueNode->ChildAt(i);
163 				_CreateValueNode(child);
164 				AddChildNodes(child);
165 			}
166 		}
167 	}
168 
169 	for (int32 i = fListeners.CountItems() - 1; i >= 0; i--)
170 		fListeners.ItemAt(i)->ValueNodeValueChanged(valueNode);
171 }
172 
173 
174 void
175 ValueNodeManager::_AddNode(Variable* variable)
176 {
177 	// create the node child for the variable
178 	ValueNodeChild* nodeChild = new (std::nothrow) VariableValueNodeChild(
179 		variable);
180 	BReference<ValueNodeChild> nodeChildReference(nodeChild, true);
181 	if (nodeChild == NULL || !fContainer->AddChild(nodeChild)) {
182 		delete nodeChild;
183 		return;
184 	}
185 
186 	// automatically add child nodes for the top level nodes
187 	AddChildNodes(nodeChild);
188 }
189 
190 
191 status_t
192 ValueNodeManager::_CreateValueNode(ValueNodeChild* nodeChild)
193 {
194 	if (nodeChild->Node() != NULL)
195 		return B_OK;
196 
197 	// create the node
198 	ValueNode* valueNode;
199 	status_t error;
200 	if (nodeChild->IsInternal()) {
201 		error = nodeChild->CreateInternalNode(valueNode);
202 	} else {
203 		error = TypeHandlerRoster::Default()->CreateValueNode(nodeChild,
204 			nodeChild->GetType(), valueNode);
205 	}
206 
207 	if (error != B_OK)
208 		return error;
209 
210 	nodeChild->SetNode(valueNode);
211 	valueNode->ReleaseReference();
212 
213 	return B_OK;
214 }
215 
216 
217 status_t
218 ValueNodeManager::AddChildNodes(ValueNodeChild* nodeChild)
219 {
220 	AutoLocker<ValueNodeContainer> containerLocker(fContainer);
221 
222 	// create a value node for the value node child, if doesn't have one yet
223 	ValueNode* valueNode = nodeChild->Node();
224 	if (valueNode == NULL) {
225 		status_t error = _CreateValueNode(nodeChild);
226 		if (error != B_OK)
227 			return error;
228 		valueNode = nodeChild->Node();
229 	}
230 
231 	// check if this node requires child creation
232 	// to be deferred until after its location/value have been resolved
233 	if (valueNode->ChildCreationNeedsValue())
234 		return B_OK;
235 
236 	// create the children, if not done yet
237 	if (valueNode->ChildrenCreated())
238 		return B_OK;
239 
240 	return valueNode->CreateChildren(
241 		fThread->GetTeam()->GetTeamTypeInformation());
242 }
243