Bug #4448

Local variables in xsl:key definition: Internal error: Cannot set local variable: no slot allocated

Added by Johan Gheys over 1 year ago. Updated over 1 year ago.

Start date:
Due date:
% Done:


Estimated time:
Legacy ID:
Applies to branch:
9.9, trunk
Fix Committed on Branch:
9.9, trunk
Fixed in Maintenance Release:


When transforming a primary input file with Saxon-EE- thereby looking up information in a secondary input file with the key() function, we have the following error:

Exception in thread "main" java.lang.AssertionError: Internal error: Cannot set local variable: no slot allocated at net.sf.saxon.expr.XPathContextMinor.setLocalVariable( at net.sf.saxon.expr.LetExpression.iterate( at at at net.sf.saxon.expr.CardinalityChecker.evaluateItem( at net.sf.saxon.expr.parser.Evaluator$6.evaluate( at net.sf.saxon.expr.SystemFunctionCall.evaluateArguments( at net.sf.saxon.expr.FunctionCall.iterate( at net.sf.saxon.trans.KeyIndex.processNode( at net.sf.saxon.trans.KeyIndex.lambda$constructIndex$0( at at net.sf.saxon.trans.KeyIndex.constructIndex( at net.sf.saxon.trans.KeyIndex.buildIndex( at net.sf.saxon.trans.KeyManager.buildIndex( at net.sf.saxon.trans.KeyManager.obtainLocalIndex( at net.sf.saxon.trans.KeyManager.obtainIndex( at net.sf.saxon.trans.KeyManager.selectByKey( at at at net.sf.saxon.expr.FunctionCall.iterate( at net.sf.saxon.expr.SlashExpression.iterate( at at net.sf.saxon.expr.FirstItemExpression.evaluateItem( at net.sf.saxon.expr.parser.Evaluator$6.evaluate( at net.sf.saxon.expr.LetExpression.eval( at net.sf.saxon.expr.LetExpression.processLeavingTail( at net.sf.saxon.expr.instruct.TemplateRule.applyLeavingTail( at net.sf.saxon.trans.Mode.applyTemplates( at net.sf.saxon.expr.instruct.ApplyTemplates.apply( at net.sf.saxon.expr.instruct.ApplyTemplates.process( at net.sf.saxon.expr.instruct.ElementCreator.processLeavingTail( at net.sf.saxon.expr.instruct.Copy.processLeavingTail( at net.sf.saxon.expr.instruct.TemplateRule.applyLeavingTail( at net.sf.saxon.trans.Mode.applyTemplates( at net.sf.saxon.trans.rules.TextOnlyCopyRuleSet.process( at net.sf.saxon.trans.Mode.applyTemplates( at net.sf.saxon.trans.XsltController.applyTemplates( at net.sf.saxon.s9api.AbstractXsltTransformer.applyTemplatesToSource( at net.sf.saxon.s9api.Xslt30Transformer.applyTemplates( at net.sf.saxon.Transform.processFile( at net.sf.saxon.Transform.doTransform( at net.sf.saxon.Transform.main(

See a simplified example in attachment. No problem with Saxon-EE- (4.62 KB) Johan Gheys, 2020-01-29 15:26


#1 Updated by Michael Kay over 1 year ago

  • Category set to Internals
  • Status changed from New to In Progress
  • Assignee set to Michael Kay

For the xsl:key declaration, slots for local variables are being allocated during the call on compileDeclaration, which is too early; this is followed by a call on opttimize(), which in this instance is triggering inlining of the stylesheet function call. Inlining the call introduces new variables, and this therefore needs to happen before slot allocation.

Will need to give some thought about how best to fix this.

I don't think has introduced a new bug here; I think there's probably been a change which enables deeper optimization and this exposes the bug that was already there.

#2 Updated by Johan Gheys over 1 year ago

Thank you for your quick response (even in the middle of the night).

#3 Updated by Michael Kay over 1 year ago

  • Status changed from In Progress to Resolved
  • Applies to branch 9.9, trunk added
  • Fix Committed on Branch 9.9, trunk added

For other kinds of component, we allocate slots at the end of the optimize() phase rather than during compileDeclaration(), so I have changed XSLkey to do the same.

#4 Updated by Michael Kay over 1 year ago

  • Status changed from Resolved to In Progress

The fix appears to have side-effects, see test case key-058. It seems that on this path we are allocating slots to a variable used in the "use" expression (actually the implicit variable used for the current() function) but the stack frame size isn't being properly communicated to the run-time.

The code for building the index (KeyIndex#164) appears to be using the same context object, and therefore the same stack frame, for evaluating both the match pattern and the use expression. This is held as KeyDefinition.stackFrameMap. In XSLKey we are setting this during the compileDeclaration() processing (which is too early for new slot allocation in the use expression, which happens during optimize()).

KeyDefinition.setStackFrameMap() is called during compileDeclaration processing, and does nothing if the stack frame is empty, that is if there are no variables in the match pattern. The stack frame is then updated during optimize() processing, but it has not been registered with the key definition, so this has no effect. The solution seems to be for KeyDefinition.setStackFrameMap() to have effect even if the stack frame map is empty at the time.

This solves the problem for key-058, but we still get a slot allocation problem with key-073 and key-074. In both these tests (a) we have multiple xsl:key declarations with the same name, and (b) one of them uses a sequence constructor rather than a select expression for the "use" expression.

The problem here seems to be that we have optimized the use expression and inlined the local variables, so it no longer needs any slots, but we haven't updated the KeyDefinition with the optimized use expression, so at run-time it is executing the unoptimized form, which needs slots for variables.

#5 Updated by Michael Kay over 1 year ago

  • Status changed from In Progress to Resolved

Applied these two further changes to XSLKey.optimize() and to KeyDefinition.setStackFrameMap()

#6 Updated by Michael Kay over 1 year ago

  • Subject changed from Internal error: Cannot set local variable: no slot allocated to Local variables in xsl:key definition: Internal error: Cannot set local variable: no slot allocated

The changes have led to another regression; test case backwards-039. When there are several xsl:key definitions with the same name, and at least one has an effective version="1.0", the entire key is supposed to operate in backwards compatibility mode. We add key definitions to the key definition set during compileDeclaration(), and the key definition set is marked as backwards compatible as soon as we add a key definition with effective version="1.0". At this point, if backwards compatibility is set, we modify the "use" expression to convert the keys to strings. But in optimize(), it seems we are picking up the original use expression, not the modified one.

Fixed with a further change to XSLKey.optimize() - it now picks up the use expression from the key definition, rather than from its own remembered value.

#7 Updated by O'Neil Delpratt over 1 year ago

  • Status changed from Resolved to Closed
  • % Done changed from 0 to 100
  • Fixed in Maintenance Release added

Patch applied in the maintenance release.

Please register to edit this issue

Also available in: Atom PDF