Skip to content

Commit 75e62ad

Browse files
committed
Fix module export symbols should not be marked as having non-local references
When we do BindPidRefsInScope, we walk the PidRef stack and check to see if any ref is non-local. Global and module export symbols should never be marked as non-local. Problem is that not all refs in the PidRef stack are necessarily marked to indicate that the symbol is a module export. If a symbol which is an export has a non-local ref which does not indicate it is a module export, we will erroneously set the hasNonLocalReference flag on that symbol. Here's an example of how this can happen: function foo() { }; export { foo }; In this case, the top ref to symbol foo does not say that foo is a module export so we might set the hasNonLocalReference flag on symbol foo when we look at the top ref. The next ref in the PidRef stack would indicate that foo is a symbol but by then we've already marked it. A fix is to move the module export flag out of PidRef and into the Ident itself. Then we can check to see if the pid is a module export before we walk the PidRef stack in BindPidRefsInScope.
1 parent 7365761 commit 75e62ad

File tree

3 files changed

+27
-23
lines changed

3 files changed

+27
-23
lines changed

lib/Parser/Hash.h

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -27,23 +27,24 @@ ULONG CaseInsensitiveComputeHash(LPCOLESTR posz);
2727

2828
enum
2929
{
30-
fidNil = 0x0000,
31-
fidKwdRsvd = 0x0001, // the keyword is a reserved word
32-
fidKwdFutRsvd = 0x0002, // a future reserved word, but only in strict mode
30+
fidNil = 0x0000,
31+
fidKwdRsvd = 0x0001, // the keyword is a reserved word
32+
fidKwdFutRsvd = 0x0002, // a future reserved word, but only in strict mode
3333

3434
// Flags to identify tracked aliases of "eval"
35-
fidEval = 0x0008,
35+
fidEval = 0x0008,
3636
// Flags to identify tracked aliases of "let"
3737
fidLetOrConst = 0x0010, // ID has previously been used in a block-scoped declaration
3838

3939
// This flag is used by the Parser CountDcls and FillDcls methods.
4040
// CountDcls sets the bit as it walks through the var decls so that
4141
// it can skip duplicates. FillDcls clears the bit as it walks through
4242
// again to skip duplicates.
43-
fidGlobalDcl = 0x2000,
43+
fidGlobalDcl = 0x2000,
4444

45-
fidUsed = 0x4000 // name referenced by source code
45+
fidUsed = 0x4000, // name referenced by source code
4646

47+
fidModuleExport = 0x8000 // name is module export
4748
};
4849

4950
struct BlockIdsStack
@@ -84,8 +85,6 @@ struct PidRefStack
8485
bool IsAssignment() const { return isAsg; }
8586
bool IsDynamicBinding() const { return isDynamic; }
8687
void SetDynamicBinding() { isDynamic = true; }
87-
bool IsModuleExport() const { return isModuleExport; }
88-
void SetModuleExport() { isModuleExport = true; }
8988

9089
Symbol **GetSymRef()
9190
{
@@ -283,6 +282,9 @@ struct Ident
283282

284283
void SetIsLetOrConst() { m_grfid |= fidLetOrConst; }
285284
BOOL GetIsLetOrConst() const { return m_grfid & fidLetOrConst; }
285+
286+
void SetIsModuleExport() { m_grfid |= fidModuleExport; }
287+
BOOL GetIsModuleExport() const { return m_grfid & fidModuleExport; }
286288
};
287289

288290

lib/Parser/Parse.cpp

Lines changed: 6 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1368,15 +1368,6 @@ ParseNodePtr Parser::CreateModuleImportDeclNode(IdentPtr localName)
13681368
return declNode;
13691369
}
13701370

1371-
void Parser::MarkIdentifierReferenceIsModuleExport(IdentPtr localName)
1372-
{
1373-
PidRefStack* pidRef = this->PushPidRef(localName);
1374-
1375-
Assert(pidRef != nullptr);
1376-
1377-
pidRef->SetModuleExport();
1378-
}
1379-
13801371
ParseNodePtr Parser::CreateVarDeclNode(IdentPtr pid, SymbolType symbolType, bool autoArgumentsObject, ParseNodePtr pnodeFnc, bool errorOnRedecl)
13811372
{
13821373
ParseNodePtr pnode = CreateDeclNode(knopVarDecl, pid, symbolType, errorOnRedecl);
@@ -1679,6 +1670,11 @@ void Parser::BindPidRefsInScope(IdentPtr pid, Symbol *sym, int blockId, uint max
16791670
Js::LocalFunctionId funcId = GetCurrentFunctionNode()->sxFnc.functionId;
16801671
Assert(sym);
16811672

1673+
if (pid->GetIsModuleExport())
1674+
{
1675+
sym->SetIsModuleExportStorage(true);
1676+
}
1677+
16821678
for (ref = pid->GetTopRef(); ref && ref->GetScopeId() >= blockId; ref = nextRef)
16831679
{
16841680
// Fix up sym* on PID ref.
@@ -1702,11 +1698,6 @@ void Parser::BindPidRefsInScope(IdentPtr pid, Symbol *sym, int blockId, uint max
17021698
}
17031699
}
17041700

1705-
if (ref->IsModuleExport())
1706-
{
1707-
sym->SetIsModuleExportStorage(true);
1708-
}
1709-
17101701
if (ref->GetFuncScopeId() != funcId && !sym->GetIsGlobal() && !sym->GetIsModuleExportStorage())
17111702
{
17121703
Assert(ref->GetFuncScopeId() > funcId);
@@ -2129,7 +2120,7 @@ void Parser::ParseNamedImportOrExportClause(ModuleImportOrExportEntryList* impor
21292120
}
21302121
else
21312122
{
2132-
MarkIdentifierReferenceIsModuleExport(identifierName);
2123+
identifierName->SetIsModuleExport();
21332124
AddModuleImportOrExportEntry(importOrExportEntryList, nullptr, identifierName, identifierAs, nullptr);
21342125
}
21352126
}

test/es6/module-functionality.js

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -291,6 +291,17 @@ var tests = [
291291
WScript.LoadModule(functionBody, 'samethread');
292292
}
293293
},
294+
{
295+
name: "Nested function in module function body which captures exported symbol doesn't create empty frame object",
296+
body: function() {
297+
let functionBody =
298+
`function foo() { };
299+
export { foo };
300+
function bar() { foo(); };`;
301+
302+
WScript.LoadModule(functionBody, 'samethread');
303+
}
304+
},
294305
];
295306

296307
testRunner.runTests(tests, { verbose: WScript.Arguments[0] != "summary" });

0 commit comments

Comments
 (0)