This is an automated email from the ASF dual-hosted git repository.
joshtynjala pushed a commit to branch develop
in repository https://gitbox.apache.org/repos/asf/royale-compiler.git
The following commit(s) were added to refs/heads/develop by this push:
new bad8386b0 FunctionNode: fix missing definitions in FunctionScope when
emitting methods as JavaScript (references #249)
bad8386b0 is described below
commit bad8386b0555df1b6304cec79267d67ce56bc32f
Author: Josh Tynjala <[email protected]>
AuthorDate: Fri Jun 12 12:20:07 2026 -0700
FunctionNode: fix missing definitions in FunctionScope when emitting
methods as JavaScript (references #249)
Uses the existing deferredBodyParsingLock that is already used by
parseFunctionBody() and discardFunctionBody() to ensure thread safety when
reconnecting the scope to the ScopedBlockNode, and also when removing stale
definitions when the function body needs to be re-parsed and will create new
definitions to replace them.
I ended up moving the changes from 35eed62f13519c659e6346d26cca3f44afe3170f
from FunctionScope to FunctionNode. FunctionNode is the only place where the
scope is reconnected, and it's the only place where definitions are already
added to and removed from the FunctionScope. So it's better to remove stale
definitions in the same place.
This issue is very difficult to reproduce (although building MXRoyaleBaseJS
usually does it eventually... sometimes dozens or hundreds of compiles!). My
best guess is that reconnecting the scope node while the body is currently
being parsed, or while the definitions are currently being added to the scope,
is where it leaves the scope without any definitions at all. I see that in
analyze(), PostProcessStep.POPULATE_SCOPE creates a new FunctionScope, and
PostProcessStep.RECONNECT_DEFINI [...]
---
RELEASE_NOTES.md | 1 +
.../compiler/internal/scopes/FunctionScope.java | 46 ----------------------
.../compiler/internal/tree/as/FunctionNode.java | 39 +++++++++++++++++-
3 files changed, 39 insertions(+), 47 deletions(-)
diff --git a/RELEASE_NOTES.md b/RELEASE_NOTES.md
index 9b224eec2..3c26ff715 100644
--- a/RELEASE_NOTES.md
+++ b/RELEASE_NOTES.md
@@ -85,6 +85,7 @@ Apache Royale Compiler 1.0.0
- compiler: Fixed parsing of namespace uri and manifest mappings to allow
multiple manifest paths per URI.
- compiler: Fixed missing require for package-level functions or variables in
some situations.
- compiler: Fixed missing binding data caused by thread conflicts.
+- compiler: Fixed lost typing information in method bodies when emitting
JavaScript in some circumstances.
- debugger: Added missing isolate ID to SWF load and unload events.
- debugger: Fixed debugger targeting the current JDK version instead of the
intended minimum JDK version.
- debugger: Fixed localized messages appearing as unprocessed tokens.
diff --git
a/compiler/src/main/java/org/apache/royale/compiler/internal/scopes/FunctionScope.java
b/compiler/src/main/java/org/apache/royale/compiler/internal/scopes/FunctionScope.java
index b734781f3..c6ccbf297 100644
---
a/compiler/src/main/java/org/apache/royale/compiler/internal/scopes/FunctionScope.java
+++
b/compiler/src/main/java/org/apache/royale/compiler/internal/scopes/FunctionScope.java
@@ -19,14 +19,7 @@
package org.apache.royale.compiler.internal.scopes;
-import java.util.Collection;
-
-import org.apache.royale.compiler.definitions.IDefinition;
-import org.apache.royale.compiler.definitions.IParameterDefinition;
-import org.apache.royale.compiler.internal.tree.as.FunctionNode;
import org.apache.royale.compiler.internal.tree.as.ScopedBlockNode;
-import org.apache.royale.compiler.tree.as.IASNode;
-import org.apache.royale.compiler.tree.as.IScopedNode;
/**
* Sub-class of ASScope used for function scopes. all definition in scope of
@@ -45,43 +38,4 @@ public class FunctionScope extends ASScope
super(containingScope);
}
- @Override
- public void reconnectScopeNode(IScopedNode node)
- {
- IASNode parentNode = node.getParent();
- if (parentNode instanceof FunctionNode)
- {
- FunctionNode functionNode = (FunctionNode) parentNode;
- if (!functionNode.hasBeenParsed())
- {
- // the compiler holds weak references to nodes in certain
places
- // which allows them to be garbage collected. however, from
time
- // to time, the compiler may need the node again later, after
it
- // has been garbage collected, so that node needs to be
- // recreated.
- // when a function node is recreated, its scope may still be
- // populated with definitions from the old function node's
body,
- // such as local variables. upon recreation, those local
- // definitions should be considered invalid because they will
- // be replaced with new definitions after parsing the new
- // function node's body.
- // to reiterate, removing the definitions below is not the same
- // case where a function node's discardFunctionBody() method is
- // called and the local definitions need to be removed.
instead,
- // this is a separate case where a function node is garbage
- // collected and the body was never discarded, so the scope
- // still contains definitions from the old function node.
- Collection<IDefinition> localDefs = getAllLocalDefinitions();
- for (IDefinition def : localDefs)
- {
- if (! (def instanceof IParameterDefinition))
- {
- removeDefinition(def);
- }
- }
- }
- }
- super.reconnectScopeNode(node);
- }
-
}
diff --git
a/compiler/src/main/java/org/apache/royale/compiler/internal/tree/as/FunctionNode.java
b/compiler/src/main/java/org/apache/royale/compiler/internal/tree/as/FunctionNode.java
index 51751d73c..f003f154b 100644
---
a/compiler/src/main/java/org/apache/royale/compiler/internal/tree/as/FunctionNode.java
+++
b/compiler/src/main/java/org/apache/royale/compiler/internal/tree/as/FunctionNode.java
@@ -278,7 +278,44 @@ public class FunctionNode extends BaseTypedDefinitionNode
implements IFunctionNo
// getters and setters
if (contents != null && scope != null)
{
- contents.reconnectScope(scope);
+ deferredBodyParsingLock.lock();
+ try
+ {
+ // the compiler holds weak references to nodes in
certain places
+ // which allows them to be garbage collected. however,
from time
+ // to time, the compiler may need the node again
later, after it
+ // has been garbage collected, so that node needs to be
+ // recreated.
+ // when a function node is recreated, its scope may
still be
+ // populated with definitions from the old function
node's body,
+ // such as local variables. upon recreation, those
local
+ // definitions should be considered invalid because
they will
+ // be replaced with new definitions after parsing the
new
+ // function node's body.
+ // to reiterate, removing the definitions below is not
the same
+ // case where a function node's discardFunctionBody()
method is
+ // called and the local definitions need to be
removed. instead,
+ // this is a separate case where a function node is
garbage
+ // collected and the body was never discarded, so the
scope
+ // still contains definitions from the old function
node.
+ if (!hasBeenParsed())
+ {
+ Collection<IDefinition> localDefs =
scope.getAllLocalDefinitions();
+ for (IDefinition def : localDefs)
+ {
+ if (! (def instanceof IParameterDefinition))
+ {
+ scope.removeDefinition(def);
+ }
+ }
+ }
+
+ contents.reconnectScope(scope);
+ }
+ finally
+ {
+ deferredBodyParsingLock.unlock();
+ }
}
}
}