Bug #4448
closedLocal variables in xsl:key definition: Internal error: Cannot set local variable: no slot allocated
100%
Description
When transforming a primary input file with Saxon-EE-9.9.1.6 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(XPathContextMinor.java:348) at net.sf.saxon.expr.LetExpression.iterate(LetExpression.java:507) at net.sf.saxon.expr.instruct.ForEach.map(ForEach.java:518) at net.sf.saxon.expr.ContextMappingIterator.next(ContextMappingIterator.java:62) at net.sf.saxon.expr.CardinalityChecker.evaluateItem(CardinalityChecker.java:277) at net.sf.saxon.expr.parser.Evaluator$6.evaluate(Evaluator.java:213) at net.sf.saxon.expr.SystemFunctionCall.evaluateArguments(SystemFunctionCall.java:446) at net.sf.saxon.expr.FunctionCall.iterate(FunctionCall.java:530) at net.sf.saxon.trans.KeyIndex.processNode(KeyIndex.java:198) at net.sf.saxon.trans.KeyIndex.lambda$constructIndex$0(KeyIndex.java:164) at net.sf.saxon.om.SequenceIterator.forEachOrFail(SequenceIterator.java:128) at net.sf.saxon.trans.KeyIndex.constructIndex(KeyIndex.java:164) at net.sf.saxon.trans.KeyIndex.buildIndex(KeyIndex.java:127) at net.sf.saxon.trans.KeyManager.buildIndex(KeyManager.java:263) at net.sf.saxon.trans.KeyManager.obtainLocalIndex(KeyManager.java:471) at net.sf.saxon.trans.KeyManager.obtainIndex(KeyManager.java:369) at net.sf.saxon.trans.KeyManager.selectByKey(KeyManager.java:314) at net.sf.saxon.functions.KeyFn.search(KeyFn.java:267) at net.sf.saxon.functions.KeyFn.call(KeyFn.java:192) at net.sf.saxon.expr.FunctionCall.iterate(FunctionCall.java:532) at net.sf.saxon.expr.SlashExpression.iterate(SlashExpression.java:922) at net.sf.saxon.expr.instruct.BlockIterator.next(BlockIterator.java:49) at net.sf.saxon.expr.FirstItemExpression.evaluateItem(FirstItemExpression.java:113) at net.sf.saxon.expr.parser.Evaluator$6.evaluate(Evaluator.java:213) at net.sf.saxon.expr.LetExpression.eval(LetExpression.java:532) at net.sf.saxon.expr.LetExpression.processLeavingTail(LetExpression.java:714) at net.sf.saxon.expr.instruct.TemplateRule.applyLeavingTail(TemplateRule.java:352) at net.sf.saxon.trans.Mode.applyTemplates(Mode.java:533) at net.sf.saxon.expr.instruct.ApplyTemplates.apply(ApplyTemplates.java:300) at net.sf.saxon.expr.instruct.ApplyTemplates.process(ApplyTemplates.java:251) at net.sf.saxon.expr.instruct.ElementCreator.processLeavingTail(ElementCreator.java:352) at net.sf.saxon.expr.instruct.Copy.processLeavingTail(Copy.java:431) at net.sf.saxon.expr.instruct.TemplateRule.applyLeavingTail(TemplateRule.java:352) at net.sf.saxon.trans.Mode.applyTemplates(Mode.java:533) at net.sf.saxon.trans.rules.TextOnlyCopyRuleSet.process(TextOnlyCopyRuleSet.java:71) at net.sf.saxon.trans.Mode.applyTemplates(Mode.java:495) at net.sf.saxon.trans.XsltController.applyTemplates(XsltController.java:746) at net.sf.saxon.s9api.AbstractXsltTransformer.applyTemplatesToSource(AbstractXsltTransformer.java:347) at net.sf.saxon.s9api.Xslt30Transformer.applyTemplates(Xslt30Transformer.java:311) at net.sf.saxon.Transform.processFile(Transform.java:1283) at net.sf.saxon.Transform.doTransform(Transform.java:815) at net.sf.saxon.Transform.main(Transform.java:80)
See a simplified example in attachment. No problem with Saxon-EE-9.9.1.5.
Files
Updated by Michael Kay almost 5 years 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 9.9.1.6 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.
Updated by Johan Gheys almost 5 years ago
Thank you for your quick response (even in the middle of the night).
Updated by Michael Kay almost 5 years 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.
Updated by Michael Kay almost 5 years 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.
Updated by Michael Kay almost 5 years ago
- Status changed from In Progress to Resolved
Applied these two further changes to XSLKey.optimize()
and to KeyDefinition.setStackFrameMap()
Updated by Michael Kay almost 5 years 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.
Updated by O'Neil Delpratt over 4 years ago
- Status changed from Resolved to Closed
- % Done changed from 0 to 100
- Fixed in Maintenance Release 9.9.1.7 added
Patch applied in the 9.9.1.7 maintenance release.
Please register to edit this issue