Internal changes

NamePool

The NamePool is no longer used for names such as variable names which are not used at run-time. This change is made to ease pressure on the NamePool as a shared resource which can become a bottleneck for some high-throughput applications, and which can gradually fill for long-running applications. The problem can arise particularly because the Saxon optimizer generates variable names at random for internal variables, meaning that there is a slow but steady increase in the number of entries in the NamePool even under a very stable workload. The name of a variable is now held internally in a StructuredQName object, which holds the prefix, URI, and local name in a structure that is designed for economy in space usage combined with an efficient equals() test.

The same change has been made for other kinds of name such as function names, template names, attribute set names, character map names, mode names, output format names, decimal format names, and key names. In the vast majority of cases these names are resolved at compile time so there was little benefit from using the shared name pool.

Local parameters to XSLT templates, which are matched by name at run-time, still use numeric identifiers for efficient matching, but these are no longer fingerprints allocated from the namepool, they are numbers allocated by the stylesheet compiler locally to a stylesheet.

User applications are unlikely to be affected by the change unless they probe rather deeply into Saxon system-programming interfaces, for example interfaces provided for debuggers, or for defining your own extension function binding factories. But if you provide your own implementation of the StaticContext interface, you will need to change the method bindVariable() to accept a StructuredQName rather than an integer fingerprint.

Expression tree

There have been changes to the internal structure of the expression tree generated by the XSLT, XQuery, and XPath processors, and to the way it is navigated. Most notably, the tree no longer contains any parent pointers linking a subexpression to its containing expression. These have been removed primarily because the code for maintaining the parent pointers was complex and prone to bugs. To compensate for the absence of these pointers, the various traversals of the expression tree (simplify, typeCheck, and optimize), now make use of an ExpressionVisitor object that maintains references to all the containing expressions in the form of a stack.

Expressions now have a link to a Container object that provides access to the outside world, for example to the Configuration and NamePool. However, this is used only for diagnostics, because it is not guaranteed to be available in 100% of cases, especially while the tree is under construction.

There is now an internal diagnostic switch allowing tracing of the decisions made by the optimizer. Not all rewrites are yet traced in this way.

The class IfExpression no longer exists; all conditional expressions including xsl:if, xsl:choose, XPath if-then-else, and XQuery typeswitch are now compiled to a (potentially multi-way) Choose expression.