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 fContainer = new(std::nothrow) ValueNodeContainer; 56 if (fContainer == NULL) 57 return B_NO_MEMORY; 58 59 status_t error = fContainer->Init(); 60 if (error != B_OK) { 61 delete fContainer; 62 fContainer = NULL; 63 return error; 64 } 65 66 AutoLocker<ValueNodeContainer> containerLocker(fContainer); 67 68 fContainer->AddListener(this); 69 70 if (fStackFrame != NULL && fAddFrameNodes) { 71 for (int32 i = 0; Variable* variable = fStackFrame->ParameterAt(i); 72 i++) { 73 _AddNode(variable); 74 } 75 76 for (int32 i = 0; Variable* variable 77 = fStackFrame->LocalVariableAt(i); i++) { 78 _AddNode(variable); 79 } 80 } 81 82 return B_OK; 83 } 84 85 86 bool 87 ValueNodeManager::AddListener(ValueNodeContainer::Listener* listener) 88 { 89 return fListeners.AddItem(listener); 90 } 91 92 93 void 94 ValueNodeManager::RemoveListener(ValueNodeContainer::Listener* listener) 95 { 96 fListeners.RemoveItem(listener); 97 } 98 99 100 void 101 ValueNodeManager::ValueNodeChanged(ValueNodeChild* nodeChild, 102 ValueNode* oldNode, ValueNode* newNode) 103 { 104 if (fContainer == NULL) 105 return; 106 107 AutoLocker<ValueNodeContainer> containerLocker(fContainer); 108 109 for (int32 i = fListeners.CountItems() - 1; i >= 0; i--) 110 fListeners.ItemAt(i)->ValueNodeChanged(nodeChild, oldNode, newNode); 111 112 if (oldNode != NULL) 113 newNode->CreateChildren(fThread->GetTeam()->GetTeamTypeInformation()); 114 115 } 116 117 118 void 119 ValueNodeManager::ValueNodeChildrenCreated(ValueNode* node) 120 { 121 if (fContainer == NULL) 122 return; 123 124 for (int32 i = fListeners.CountItems() - 1; i >= 0; i--) 125 fListeners.ItemAt(i)->ValueNodeChildrenCreated(node); 126 } 127 128 129 void 130 ValueNodeManager::ValueNodeChildrenDeleted(ValueNode* node) 131 { 132 if (fContainer == NULL) 133 return; 134 135 for (int32 i = fListeners.CountItems() - 1; i >= 0; i--) 136 fListeners.ItemAt(i)->ValueNodeChildrenDeleted(node); 137 } 138 139 140 void 141 ValueNodeManager::ValueNodeValueChanged(ValueNode* valueNode) 142 { 143 if (fContainer == NULL) 144 return; 145 146 AutoLocker<ValueNodeContainer> containerLocker(fContainer); 147 148 // check whether we know the node 149 ValueNodeChild* nodeChild = valueNode->NodeChild(); 150 if (nodeChild == NULL) 151 return; 152 153 if (valueNode->ChildCreationNeedsValue() 154 && !valueNode->ChildrenCreated()) { 155 status_t error = valueNode->CreateChildren( 156 fThread->GetTeam()->GetTeamTypeInformation()); 157 if (error == B_OK) { 158 for (int32 i = 0; i < valueNode->CountChildren(); i++) { 159 ValueNodeChild* child = valueNode->ChildAt(i); 160 _CreateValueNode(child); 161 AddChildNodes(child); 162 } 163 } 164 } 165 166 for (int32 i = fListeners.CountItems() - 1; i >= 0; i--) 167 fListeners.ItemAt(i)->ValueNodeValueChanged(valueNode); 168 } 169 170 171 void 172 ValueNodeManager::_AddNode(Variable* variable) 173 { 174 // create the node child for the variable 175 ValueNodeChild* nodeChild = new (std::nothrow) VariableValueNodeChild( 176 variable); 177 BReference<ValueNodeChild> nodeChildReference(nodeChild, true); 178 if (nodeChild == NULL || !fContainer->AddChild(nodeChild)) { 179 delete nodeChild; 180 return; 181 } 182 183 // automatically add child nodes for the top level nodes 184 AddChildNodes(nodeChild); 185 } 186 187 188 status_t 189 ValueNodeManager::_CreateValueNode(ValueNodeChild* nodeChild) 190 { 191 if (nodeChild->Node() != NULL) 192 return B_OK; 193 194 // create the node 195 ValueNode* valueNode; 196 status_t error; 197 if (nodeChild->IsInternal()) { 198 error = nodeChild->CreateInternalNode(valueNode); 199 } else { 200 error = TypeHandlerRoster::Default()->CreateValueNode(nodeChild, 201 nodeChild->GetType(), valueNode); 202 } 203 204 if (error != B_OK) 205 return error; 206 207 nodeChild->SetNode(valueNode); 208 valueNode->ReleaseReference(); 209 210 return B_OK; 211 } 212 213 214 status_t 215 ValueNodeManager::AddChildNodes(ValueNodeChild* nodeChild) 216 { 217 AutoLocker<ValueNodeContainer> containerLocker(fContainer); 218 219 // create a value node for the value node child, if doesn't have one yet 220 ValueNode* valueNode = nodeChild->Node(); 221 if (valueNode == NULL) { 222 status_t error = _CreateValueNode(nodeChild); 223 if (error != B_OK) 224 return error; 225 valueNode = nodeChild->Node(); 226 } 227 228 // check if this node requires child creation 229 // to be deferred until after its location/value have been resolved 230 if (valueNode->ChildCreationNeedsValue()) 231 return B_OK; 232 233 // create the children, if not done yet 234 if (valueNode->ChildrenCreated()) 235 return B_OK; 236 237 return valueNode->CreateChildren( 238 fThread->GetTeam()->GetTeamTypeInformation()); 239 } 240