Internal changes

The NamePool (used to allocate integer codes to the names of elements and attributes, for fast comparison) has been redesigned to improve scaleability. The new design has less contention when being updated by multiple threads in parallel, and performance degrades less as the number of names in the pool increases, though the absolute capacity is unchanged at 2^20 names.

Use of integer namecodes and fingerprints on the PullProvider interface (supporting Saxon's pull pipeline) has been dropped, further reducing unnecessary use of the NamePool and thus reducing potential for contention in applications that use pull processing.

The LinkedTree structure (used for schemas and stylesheets and also available for source documents) now holds element and attribute names as NodeName objects rather than integer name codes. Name codes will be allocated lazily within the NodeName objects if required, but not otherwise. This is all part of a trend to reduce dependence on the shared NamePool.

The multi-threading on xsl:for-each has been rewritten to reduce contention. In one test, elapsed time reduced from 240 seconds to 40 seconds, but at the cost of a memory increase from 80Mb to 650Mb. The threads implementing the body of the xsl:for-each instruction now accumulate their results in memory and pass them over to the master thread in a single go, rather than passing them incrementally one item at a time.

A new optimization has been introduced to reorder predicates within an expression or pattern based on a rough estimate of the cost of evaluation. This affects filter expressions with more than one (non-positional) predicate, such as A[following::X][@Y] (where the aim is to evaluate the cheapest predicate first), and match patterns of the form A[P]/B[Q] (where in effect parent::A[P] is taken as an additional predicate that can be evaluated before or after evaluating [Q]). The cost metrics are very simple, and have no knowledge of data volumes or distribution, but they are adequate to distinguish a very expensive predicate from a very cheap one, and in some cases this can make a huge difference. (Note: ideally the calculation should also assess the probability of the predicate returning true, but we make no attempt to do this.)