blob: d4bc7c8cbf59333242fc1ba0cbca3ac78985d685 [file] [log] [blame]
David Wagnerb76c9d62014-02-05 18:30:24 +01001/*
2 * Copyright (c) 2011-2014, Intel Corporation
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without modification,
6 * are permitted provided that the following conditions are met:
7 *
8 * 1. Redistributions of source code must retain the above copyright notice, this
9 * list of conditions and the following disclaimer.
10 *
11 * 2. Redistributions in binary form must reproduce the above copyright notice,
12 * this list of conditions and the following disclaimer in the documentation and/or
13 * other materials provided with the distribution.
14 *
15 * 3. Neither the name of the copyright holder nor the names of its contributors
16 * may be used to endorse or promote products derived from this software without
17 * specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
21 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
22 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
23 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
24 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
25 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
26 * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
28 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
Patrick Benavoli68a91282011-08-31 11:23:23 +020029 */
30#include "Subsystem.h"
31#include "ComponentLibrary.h"
32#include "InstanceDefinition.h"
33#include "XmlParameterSerializingContext.h"
34#include "ParameterAccessContext.h"
35#include "ConfigurationAccessContext.h"
36#include "SubsystemObjectCreator.h"
Frederic Boisnard6cae0ec2013-05-23 18:48:58 +020037#include "MappingData.h"
Patrick Benavoli68a91282011-08-31 11:23:23 +020038#include <assert.h>
Frederic Boisnard6cae0ec2013-05-23 18:48:58 +020039#include <sstream>
Patrick Benavoli68a91282011-08-31 11:23:23 +020040
41#define base CConfigurableElement
42
43CSubsystem::CSubsystem(const string& strName) : base(strName), _pComponentLibrary(new CComponentLibrary), _pInstanceDefinition(new CInstanceDefinition), _bBigEndian(false)
44{
45 // Note: A subsystem contains instance components
46 // InstanceDefintion and ComponentLibrary objects are then not chosen to be children
47 // They'll be delt with locally
48}
49
50CSubsystem::~CSubsystem()
51{
52 // Remove subsystem objects
53 SubsystemObjectListIterator subsystemObjectIt;
54
55 for (subsystemObjectIt = _subsystemObjectList.begin(); subsystemObjectIt != _subsystemObjectList.end(); ++subsystemObjectIt) {
56
57 delete *subsystemObjectIt;
58 }
59
60 // Remove susbsystem creators
61 uint32_t uiIndex;
62
63 for (uiIndex = 0; uiIndex < _subsystemObjectCreatorArray.size(); uiIndex++) {
64
65 delete _subsystemObjectCreatorArray[uiIndex];
66 }
67
68 // Order matters!
69 delete _pInstanceDefinition;
70 delete _pComponentLibrary;
71}
72
73string CSubsystem::getKind() const
74{
75 return "Subsystem";
76}
77
78// Susbsystem Endianness
79bool CSubsystem::isBigEndian() const
80{
81 return _bBigEndian;
82}
83
Guillaume Denneulinf2fd15a2012-12-20 17:53:29 +010084// Susbsystem sanity
85bool CSubsystem::isAlive() const
86{
87 return true;
88}
89
90// Resynchronization after subsystem restart needed
91bool CSubsystem::needResync(bool bClear)
92{
93 (void)bClear;
94
95 return false;
96}
97
Patrick Benavoli68a91282011-08-31 11:23:23 +020098// From IXmlSink
99bool CSubsystem::fromXml(const CXmlElement& xmlElement, CXmlSerializingContext& serializingContext)
100{
101 // Context
102 CXmlParameterSerializingContext& parameterBuildContext = static_cast<CXmlParameterSerializingContext&>(serializingContext);
103
104 // Install temporary component library for further component creation
105 parameterBuildContext.setComponentLibrary(_pComponentLibrary);
106
107 CXmlElement childElement;
108
109 // XML populate ComponentLibrary
110 xmlElement.getChildElement("ComponentLibrary", childElement);
111
112 if (!_pComponentLibrary->fromXml(childElement, serializingContext)) {
113
114 return false;
115 }
116
117 // XML populate InstanceDefintion
118 xmlElement.getChildElement("InstanceDefintion", childElement);
119 if (!_pInstanceDefinition->fromXml(childElement, serializingContext)) {
120
121 return false;
122 }
123
124 // Create components
125 _pInstanceDefinition->createInstances(this);
126
127 // Execute mapping to create subsystem mapping entities
128 string strError;
129 if (!mapSubsystemElements(strError)) {
130
131 serializingContext.setError(strError);
132
133 return false;
134 }
135
136 // Endianness
137 _bBigEndian = xmlElement.getAttributeBoolean("Endianness", "Big");
138
139 return true;
140}
141
142// XML configuration settings parsing
Patrick Benavoli6ba361d2011-08-31 11:23:24 +0200143bool CSubsystem::serializeXmlSettings(CXmlElement& xmlConfigurationSettingsElementContent, CConfigurationAccessContext& configurationAccessContext) const
Patrick Benavoli68a91282011-08-31 11:23:23 +0200144{
145 // Fix Endianness
146 configurationAccessContext.setBigEndianSubsystem(_bBigEndian);
147
Patrick Benavoli6ba361d2011-08-31 11:23:24 +0200148 return base::serializeXmlSettings(xmlConfigurationSettingsElementContent, configurationAccessContext);
Patrick Benavoli68a91282011-08-31 11:23:23 +0200149}
150
151
152bool CSubsystem::mapSubsystemElements(string& strError)
153{
154 // Default mapping context
155 _contextStack.push(CMappingContext(_contextMappingKeyArray.size()));
156
157 // Map all instantiated subelements in subsystem
158 uint32_t uiNbChildren = getNbChildren();
159 uint32_t uiChild;
160
161 for (uiChild = 0; uiChild < uiNbChildren; uiChild++) {
162
163 CInstanceConfigurableElement* pInstanceConfigurableChildElement = static_cast<CInstanceConfigurableElement*>(getChild(uiChild));
164
165 if (!pInstanceConfigurableChildElement->map(*this, strError)) {
166
167 return false;
168 }
169 }
170 return true;
171}
172
173// Parameter access
Patrick Benavoli065264a2011-11-20 15:46:41 +0100174bool CSubsystem::accessValue(CPathNavigator& pathNavigator, string& strValue, bool bSet, CParameterAccessContext& parameterAccessContext) const
Patrick Benavoli68a91282011-08-31 11:23:23 +0200175{
Patrick Benavoli68a91282011-08-31 11:23:23 +0200176 // Deal with Endianness
Patrick Benavoli065264a2011-11-20 15:46:41 +0100177 parameterAccessContext.setBigEndianSubsystem(_bBigEndian);
Patrick Benavoli68a91282011-08-31 11:23:23 +0200178
Patrick Benavoli065264a2011-11-20 15:46:41 +0100179 return base::accessValue(pathNavigator, strValue, bSet, parameterAccessContext);
Patrick Benavoli68a91282011-08-31 11:23:23 +0200180}
181
Frederic Boisnard6cae0ec2013-05-23 18:48:58 +0200182// Formats the mapping of the ConfigurableElements
183string CSubsystem::formatMappingDataList(
184 const list<const CConfigurableElement*>& configurableElementPath) const
185{
186 // The list is parsed in reverse order because it has been filled from the leaf to the trunk
187 // of the tree. When formatting the mapping, we want to start from the subsystem level
188 ostringstream ossStream;
189 list<const CConfigurableElement*>::const_reverse_iterator it;
190 for (it = configurableElementPath.rbegin(); it != configurableElementPath.rend(); ++it) {
191
192 const CInstanceConfigurableElement* pInstanceConfigurableElement =
193 static_cast<const CInstanceConfigurableElement*>(*it);
194
195 ossStream << pInstanceConfigurableElement->getFormattedMapping() << ", ";
196 }
197 return ossStream.str();
198}
199
200// Find the CSubystemObject containing a specific CInstanceConfigurableElement
201const CSubsystemObject* CSubsystem::findSubsystemObjectFromConfigurableElement(
202 const CInstanceConfigurableElement* pInstanceConfigurableElement) const {
203
204 const CSubsystemObject* pSubsystemObject = NULL;
205
206 list<CSubsystemObject*>::const_iterator it;
207 for (it = _subsystemObjectList.begin(); it != _subsystemObjectList.end(); ++it) {
208
209 // Check if one of the SubsystemObjects is associated with a ConfigurableElement
210 // corresponding to the expected one
211 pSubsystemObject = *it;
212 if (pSubsystemObject->getConfigurableElement() == pInstanceConfigurableElement) {
213
214 break;
215 }
216 }
217
218 return pSubsystemObject;
219}
220
Frédéric Boisnard487ce852013-07-19 17:17:52 +0200221void CSubsystem::findSubsystemLevelMappingKeyValue(
Frederic Boisnard6cae0ec2013-05-23 18:48:58 +0200222 const CInstanceConfigurableElement* pInstanceConfigurableElement,
223 string& strMappingKey,
224 string& strMappingValue) const
225{
226 // Find creator to get key name
227 vector<CSubsystemObjectCreator*>::const_iterator it;
228 for (it = _subsystemObjectCreatorArray.begin();
229 it != _subsystemObjectCreatorArray.end(); ++it) {
230
231 const CSubsystemObjectCreator* pSubsystemObjectCreator = *it;
232
233 strMappingKey = pSubsystemObjectCreator->getMappingKey();
234
235 // Check if the ObjectCreator MappingKey corresponds to the element mapping data
236 const string* pStrValue;
237 if (pInstanceConfigurableElement->getMappingData(strMappingKey, pStrValue)) {
238
239 strMappingValue = *pStrValue;
240 return;
241 }
242 }
243 assert(0);
244}
245
246// Formats the mapping data as a comma separated list of key value pairs
247string CSubsystem::getFormattedSubsystemMappingData(
248 const CInstanceConfigurableElement* pInstanceConfigurableElement) const
249{
250 // Find the SubsystemObject related to pInstanceConfigurableElement
251 const CSubsystemObject* pSubsystemObject = findSubsystemObjectFromConfigurableElement(
252 pInstanceConfigurableElement);
253
254 // Exit if node does not correspond to a SubsystemObject
255 if (pSubsystemObject == NULL) {
256
257 return "";
258 }
259
260 // Find SubsystemCreator mapping key
261 string strMappingKey;
262 string strMappingValue; // mapping value where amends are not replaced by their value
Frédéric Boisnard487ce852013-07-19 17:17:52 +0200263 findSubsystemLevelMappingKeyValue(pInstanceConfigurableElement, strMappingKey, strMappingValue);
Frederic Boisnard6cae0ec2013-05-23 18:48:58 +0200264
265 // Find SubSystemObject mapping value (with amends replaced by their value)
266 return strMappingKey + ":" + pSubsystemObject->getFormattedMappingValue();
267}
268
269string CSubsystem::getMapping(list<const CConfigurableElement*>& configurableElementPath) const
270{
271 if (configurableElementPath.empty()) {
272
273 return "";
274 }
275
276 // Get the first element, which is the element containing the amended mapping
277 const CInstanceConfigurableElement* pInstanceConfigurableElement =
278 static_cast<const CInstanceConfigurableElement*>(configurableElementPath.front());
279 configurableElementPath.pop_front();
280 // Now the list only contains elements whose mapping are related to the context
281
282 // Format context mapping data
283 string strValue = formatMappingDataList(configurableElementPath);
284
285 // Print the mapping of the first node, which corresponds to a SubsystemObject
286 strValue += getFormattedSubsystemMappingData(pInstanceConfigurableElement);
287
288 return strValue;
289}
290
Patrick Benavoli68a91282011-08-31 11:23:23 +0200291void CSubsystem::logValue(string& strValue, CErrorContext& errorContext) const
292{
Patrick Benavoli065264a2011-11-20 15:46:41 +0100293 CParameterAccessContext& parameterAccessContext = static_cast<CParameterAccessContext&>(errorContext);
Patrick Benavoli68a91282011-08-31 11:23:23 +0200294
295 // Deal with Endianness
Patrick Benavoli065264a2011-11-20 15:46:41 +0100296 parameterAccessContext.setBigEndianSubsystem(_bBigEndian);
Patrick Benavoli68a91282011-08-31 11:23:23 +0200297
298 return base::logValue(strValue, errorContext);
299}
300
Patrick Benavoli6ccab9d2011-11-10 23:21:01 +0100301// Used for simulation and virtual subsystems
Patrick Benavoli68a91282011-08-31 11:23:23 +0200302void CSubsystem::setDefaultValues(CParameterAccessContext& parameterAccessContext) const
303{
304 // Deal with Endianness
305 parameterAccessContext.setBigEndianSubsystem(_bBigEndian);
306
307 base::setDefaultValues(parameterAccessContext);
308}
309
310// Belonging subsystem
311const CSubsystem* CSubsystem::getBelongingSubsystem() const
312{
313 return this;
314}
315
316// Subsystem context mapping keys publication
317void CSubsystem::addContextMappingKey(const string& strMappingKey)
318{
319 _contextMappingKeyArray.push_back(strMappingKey);
320}
321
322// Subsystem object creator publication (strong reference)
Patrick Benavoli6ba361d2011-08-31 11:23:24 +0200323void CSubsystem::addSubsystemObjectFactory(CSubsystemObjectCreator* pSubsystemObjectCreator)
Patrick Benavoli68a91282011-08-31 11:23:23 +0200324{
325 _subsystemObjectCreatorArray.push_back(pSubsystemObjectCreator);
326}
327
Frederic Boisnard6cae0ec2013-05-23 18:48:58 +0200328// Generic error handling from derived subsystem classes
329string CSubsystem::getMappingError(const string& strKey,
330 const string& strMessage,
331 const CInstanceConfigurableElement* pInstanceConfigurableElement)
332const
333{
334 return getName() + " " + getKind() + " " +
335 "mapping:\n" + strKey + " " +
336 "error: \"" + strMessage + "\" " +
337 "for element " + pInstanceConfigurableElement->getPath();
338}
339
Patrick Benavoli68a91282011-08-31 11:23:23 +0200340// Mapping generic context handling
Frederic Boisnard6cae0ec2013-05-23 18:48:58 +0200341bool CSubsystem::handleMappingContext(
342 const CInstanceConfigurableElement* pInstanceConfigurableElement,
Frederic Boisnard6cae0ec2013-05-23 18:48:58 +0200343 CMappingContext& context,
344 string& strError) const
Patrick Benavoli68a91282011-08-31 11:23:23 +0200345{
346 // Feed context with found mapping data
347 uint32_t uiItem;
348
Renaud de Chivre46966e02013-09-02 10:48:36 +0200349 for (uiItem = 0; uiItem < _contextMappingKeyArray.size(); uiItem++) {
Patrick Benavoli68a91282011-08-31 11:23:23 +0200350
Renaud de Chivre46966e02013-09-02 10:48:36 +0200351 const string& strKey = _contextMappingKeyArray[uiItem];
Patrick Benavoli6ba361d2011-08-31 11:23:24 +0200352 const string* pStrValue;
Patrick Benavoli68a91282011-08-31 11:23:23 +0200353
Patrick Benavoli6ba361d2011-08-31 11:23:24 +0200354 if (pInstanceConfigurableElement->getMappingData(strKey, pStrValue)) {
Patrick Benavoli68a91282011-08-31 11:23:23 +0200355 // Assign item to context
Renaud de Chivre46966e02013-09-02 10:48:36 +0200356 if (!context.setItem(uiItem, &strKey, pStrValue)) {
Patrick Benavoli68a91282011-08-31 11:23:23 +0200357
Frederic Boisnard6cae0ec2013-05-23 18:48:58 +0200358 strError = getMappingError(strKey, "Already set", pInstanceConfigurableElement);
Patrick Benavoli68a91282011-08-31 11:23:23 +0200359
360 return false;
361 }
362 }
363 }
364 return true;
365}
366
Kevin Rocard084cafb2013-01-28 17:02:08 +0100367// Subsystem object creation handling
368bool CSubsystem::handleSubsystemObjectCreation(
369 CInstanceConfigurableElement* pInstanceConfigurableElement,
370 CMappingContext& context, bool& bHasCreatedSubsystemObject, string& strError)
Patrick Benavoli68a91282011-08-31 11:23:23 +0200371{
372 uint32_t uiItem;
Kevin Rocard084cafb2013-01-28 17:02:08 +0100373 bHasCreatedSubsystemObject = false;
Patrick Benavoli68a91282011-08-31 11:23:23 +0200374
375 for (uiItem = 0; uiItem < _subsystemObjectCreatorArray.size(); uiItem++) {
376
Kevin Rocard3414f992013-04-02 19:49:40 +0200377 const CSubsystemObjectCreator* pSubsystemObjectCreator =
378 _subsystemObjectCreatorArray[uiItem];
Patrick Benavoli68a91282011-08-31 11:23:23 +0200379
380 // Mapping key
381 string strKey = pSubsystemObjectCreator->getMappingKey();
382 // Object id
Patrick Benavoli6ba361d2011-08-31 11:23:24 +0200383 const string* pStrValue;
Patrick Benavoli68a91282011-08-31 11:23:23 +0200384
Patrick Benavoli6ba361d2011-08-31 11:23:24 +0200385 if (pInstanceConfigurableElement->getMappingData(strKey, pStrValue)) {
Patrick Benavoli68a91282011-08-31 11:23:23 +0200386
Kevin Rocard3414f992013-04-02 19:49:40 +0200387 // First check context consistency
388 // (required ancestors must have been set prior to object creation)
Patrick Benavoli68a91282011-08-31 11:23:23 +0200389 uint32_t uiAncestorKey;
390 uint32_t uiAncestorMask = pSubsystemObjectCreator->getAncestorMask();
391
Patrick Benavoli6ba361d2011-08-31 11:23:24 +0200392 for (uiAncestorKey = 0; uiAncestorKey < _contextMappingKeyArray.size(); uiAncestorKey++) {
Patrick Benavoli68a91282011-08-31 11:23:23 +0200393
Patrick Benavoli6ba361d2011-08-31 11:23:24 +0200394 if (!((1 << uiAncestorKey) & uiAncestorMask)) {
395 // Ancestor not required
396 continue;
397 }
398 // Check ancestor was provided
Patrick Benavoli68a91282011-08-31 11:23:23 +0200399 if (!context.iSet(uiAncestorKey)) {
400
Frederic Boisnard6cae0ec2013-05-23 18:48:58 +0200401 strError = getMappingError(strKey, _contextMappingKeyArray[uiAncestorKey] +
402 " not set", pInstanceConfigurableElement);
Patrick Benavoli68a91282011-08-31 11:23:23 +0200403
404 return false;
405 }
406 }
407
Patrick Benavoli6ba361d2011-08-31 11:23:24 +0200408 // Then check configurable element size is correct
Kevin Rocard3414f992013-04-02 19:49:40 +0200409 if (pInstanceConfigurableElement->getFootPrint() >
410 pSubsystemObjectCreator->getMaxConfigurableElementSize()) {
Patrick Benavoli68a91282011-08-31 11:23:23 +0200411
Kevin Rocard3414f992013-04-02 19:49:40 +0200412 string strSizeError = "Size should not exceed " +
413 pSubsystemObjectCreator->getMaxConfigurableElementSize();
Patrick Benavoli68a91282011-08-31 11:23:23 +0200414
Frederic Boisnard6cae0ec2013-05-23 18:48:58 +0200415 strError = getMappingError(strKey, strSizeError, pInstanceConfigurableElement);
Patrick Benavoli68a91282011-08-31 11:23:23 +0200416
417 return false;
418 }
Patrick Benavoli6ba361d2011-08-31 11:23:24 +0200419
420 // Do create object and keep its track
Kevin Rocard3414f992013-04-02 19:49:40 +0200421 _subsystemObjectList.push_back(pSubsystemObjectCreator->objectCreate(
422 *pStrValue, pInstanceConfigurableElement, context));
Patrick Benavoli68a91282011-08-31 11:23:23 +0200423
Kevin Rocard084cafb2013-01-28 17:02:08 +0100424 // Indicate subsytem creation to caller
425 bHasCreatedSubsystemObject = true;
426
427 // The subsystem Object has been instantiated, no need to continue looking for an
428 // instantiation mapping
429 break;
Patrick Benavoli68a91282011-08-31 11:23:23 +0200430 }
431 }
Patrick Benavoli68a91282011-08-31 11:23:23 +0200432
Kevin Rocard084cafb2013-01-28 17:02:08 +0100433 return true;
Patrick Benavoli68a91282011-08-31 11:23:23 +0200434}
435
Patrick Benavoli68a91282011-08-31 11:23:23 +0200436// From IMapper
Kevin Rocard084cafb2013-01-28 17:02:08 +0100437// Handle a configurable element mapping
438bool CSubsystem::mapBegin(CInstanceConfigurableElement* pInstanceConfigurableElement,
439 bool& bKeepDiving, string& strError)
Patrick Benavoli68a91282011-08-31 11:23:23 +0200440{
441 // Get current context
442 CMappingContext context = _contextStack.top();
443
Kevin Rocard084cafb2013-01-28 17:02:08 +0100444 // Add mapping in context
Renaud de Chivre46966e02013-09-02 10:48:36 +0200445 if (!handleMappingContext(pInstanceConfigurableElement, context,
Frederic Boisnard6cae0ec2013-05-23 18:48:58 +0200446 strError)) {
Kevin Rocard084cafb2013-01-28 17:02:08 +0100447
448 return false;
449 }
450
451 // Push context
452 _contextStack.push(context);
453
454 // Assume diving by default
455 bKeepDiving = true;
456
457 // Deal with ambiguous usage of parameter blocks
458 bool bShouldCreateSubsystemObject = true;
459
Patrick Benavoli68a91282011-08-31 11:23:23 +0200460 switch(pInstanceConfigurableElement->getType()) {
461
Kevin Rocard084cafb2013-01-28 17:02:08 +0100462 case CInstanceConfigurableElement::EComponent:
Kevin Rocard084cafb2013-01-28 17:02:08 +0100463 case CInstanceConfigurableElement::EParameterBlock:
464 // Subsystem object creation is optional in parameter blocks
465 bShouldCreateSubsystemObject = false;
466 // No break
467 case CInstanceConfigurableElement::EBitParameterBlock:
468 case CInstanceConfigurableElement::EParameter:
469 case CInstanceConfigurableElement::EStringParameter:
Patrick Benavoli68a91282011-08-31 11:23:23 +0200470
Kevin Rocard084cafb2013-01-28 17:02:08 +0100471 bool bHasCreatedSubsystemObject;
472
473 if (!handleSubsystemObjectCreation(pInstanceConfigurableElement, context,
474 bHasCreatedSubsystemObject, strError)) {
475
476 return false;
477 }
478 // Check for creation error
479 if (bShouldCreateSubsystemObject && !bHasCreatedSubsystemObject) {
480
Frederic Boisnard6cae0ec2013-05-23 18:48:58 +0200481 strError = getMappingError("Not found",
482 "Subsystem object mapping key is missing",
483 pInstanceConfigurableElement);
Kevin Rocard084cafb2013-01-28 17:02:08 +0100484 return false;
485 }
486 // Not created and no error, keep diving
487 bKeepDiving = !bHasCreatedSubsystemObject;
488
489 return true;
490
491 default:
492 assert(0);
Patrick Benavoli68a91282011-08-31 11:23:23 +0200493 return false;
Patrick Benavoli68a91282011-08-31 11:23:23 +0200494 }
Patrick Benavoli68a91282011-08-31 11:23:23 +0200495}
496
497void CSubsystem::mapEnd()
498{
499 // Unstack context
500 _contextStack.pop();
501}