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
ValueNodeManager(bool addFrameNodes)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
~ValueNodeManager()31 ValueNodeManager::~ValueNodeManager()
32 {
33 SetStackFrame(NULL, NULL);
34 }
35
36
37 status_t
SetStackFrame(Thread * thread,StackFrame * stackFrame)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
AddListener(ValueNodeContainer::Listener * listener)90 ValueNodeManager::AddListener(ValueNodeContainer::Listener* listener)
91 {
92 return fListeners.AddItem(listener);
93 }
94
95
96 void
RemoveListener(ValueNodeContainer::Listener * listener)97 ValueNodeManager::RemoveListener(ValueNodeContainer::Listener* listener)
98 {
99 fListeners.RemoveItem(listener);
100 }
101
102
103 void
ValueNodeChanged(ValueNodeChild * nodeChild,ValueNode * oldNode,ValueNode * newNode)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
ValueNodeChildrenCreated(ValueNode * node)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
ValueNodeChildrenDeleted(ValueNode * node)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
ValueNodeValueChanged(ValueNode * valueNode)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
_AddNode(Variable * variable)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
_CreateValueNode(ValueNodeChild * nodeChild)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
AddChildNodes(ValueNodeChild * nodeChild)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