From 8f40df4cb5aca9c028d380fc66bb73439940a5ce Mon Sep 17 00:00:00 2001 From: Paul Leathers Date: Tue, 5 Sep 2017 16:04:12 -0700 Subject: [PATCH] [MSFT 12313182] Detect assignment to const in nested functions that were originally deferred. Add symbol-is-const flag to Symbol and to ScopeInfo to allow us to detect this case. Don't rely on having access to a parse node for the declaration. --- lib/Runtime/ByteCode/ByteCodeEmitter.cpp | 2 +- lib/Runtime/ByteCode/ByteCodeGenerator.cpp | 1 + lib/Runtime/ByteCode/ScopeInfo.cpp | 2 ++ lib/Runtime/ByteCode/ScopeInfo.h | 24 +++++++++++++++++----- lib/Runtime/ByteCode/Symbol.h | 12 +++++++++++ test/LetConst/AssignmentToConst.baseline | 2 ++ test/LetConst/AssignmentToConst.js | 1 + test/LetConst/rlexe.xml | 7 +++++++ 8 files changed, 45 insertions(+), 6 deletions(-) diff --git a/lib/Runtime/ByteCode/ByteCodeEmitter.cpp b/lib/Runtime/ByteCode/ByteCodeEmitter.cpp index 5b031838595..544a7fd1b48 100644 --- a/lib/Runtime/ByteCode/ByteCodeEmitter.cpp +++ b/lib/Runtime/ByteCode/ByteCodeEmitter.cpp @@ -5169,7 +5169,7 @@ void ByteCodeGenerator::EmitPropStore(Js::RegSlot rhsLocation, Symbol *sym, Iden } else if (sym->IsInSlot(funcInfo) || envIndex != -1) { - if (!isConstDecl && sym->GetDecl() && sym->GetDecl()->nop == knopConstDecl) + if (!isConstDecl && sym->GetIsConst()) { // This is a case where const reassignment can't be proven statically (e.g., eval, with) so // we have to catch it at runtime. diff --git a/lib/Runtime/ByteCode/ByteCodeGenerator.cpp b/lib/Runtime/ByteCode/ByteCodeGenerator.cpp index e712fe647af..81cafee75f9 100644 --- a/lib/Runtime/ByteCode/ByteCodeGenerator.cpp +++ b/lib/Runtime/ByteCode/ByteCodeGenerator.cpp @@ -3552,6 +3552,7 @@ void PreVisitBlock(ParseNode *pnodeBlock, ByteCodeGenerator *byteCodeGenerator) #endif sym->SetIsGlobal(isGlobalScope); sym->SetIsBlockVar(true); + sym->SetIsConst(pnode->nop == knopConstDecl); sym->SetNeedDeclaration(true); pnode->sxVar.sym = sym; }; diff --git a/lib/Runtime/ByteCode/ScopeInfo.cpp b/lib/Runtime/ByteCode/ScopeInfo.cpp index 20c73c1ebb7..c7d1b7956b0 100644 --- a/lib/Runtime/ByteCode/ScopeInfo.cpp +++ b/lib/Runtime/ByteCode/ScopeInfo.cpp @@ -33,6 +33,7 @@ namespace Js this->SetSymbolType(scopeSlot, sym->GetSymbolType()); this->SetHasFuncAssignment(scopeSlot, sym->GetHasFuncAssignment()); this->SetIsBlockVariable(scopeSlot, sym->GetIsBlockVar()); + this->SetIsConst(scopeSlot, sym->GetIsConst()); this->SetIsFuncExpr(scopeSlot, sym->GetIsFuncExpr()); this->SetIsModuleExportStorage(scopeSlot, sym->GetIsModuleExportStorage()); this->SetIsModuleImport(scopeSlot, sym->GetIsModuleImport()); @@ -235,6 +236,7 @@ namespace Js sym->SetScopeSlot(static_cast(i)); sym->SetIsBlockVar(GetIsBlockVariable(i)); + sym->SetIsConst(GetIsConst(i)); sym->SetIsFuncExpr(GetIsFuncExpr(i)); sym->SetIsModuleExportStorage(GetIsModuleExportStorage(i)); sym->SetIsModuleImport(GetIsModuleImport(i)); diff --git a/lib/Runtime/ByteCode/ScopeInfo.h b/lib/Runtime/ByteCode/ScopeInfo.h index 4e1de8f14b0..0ca256f9f1f 100644 --- a/lib/Runtime/ByteCode/ScopeInfo.h +++ b/lib/Runtime/ByteCode/ScopeInfo.h @@ -27,11 +27,12 @@ namespace Js { Field(PropertyRecord const*) name; }; Field(SymbolType) symbolType; - Field(bool) hasFuncAssignment; - Field(bool) isBlockVariable; - Field(bool) isFuncExpr; - Field(bool) isModuleExportStorage; - Field(bool) isModuleImport; + Field(bool) hasFuncAssignment : 1; + Field(bool) isBlockVariable : 1; + Field(bool) isConst : 1; + Field(bool) isFuncExpr : 1; + Field(bool) isModuleExportStorage : 1; + Field(bool) isModuleImport : 1; }; private: @@ -86,6 +87,13 @@ namespace Js { symbols[i].isBlockVariable = is; } + void SetIsConst(int i, bool is) + { + Assert(!areNamesCached); + Assert(i >= 0 && i < symbolCount); + symbols[i].isConst = is; + } + void SetIsFuncExpr(int i, bool is) { Assert(!areNamesCached); @@ -151,6 +159,12 @@ namespace Js { return symbols[i].isBlockVariable; } + bool GetIsConst(int i) + { + Assert(i >= 0 && i < symbolCount); + return symbols[i].isConst; + } + bool GetIsFuncExpr(int i) { Assert(i >= 0 && i < symbolCount); diff --git a/lib/Runtime/ByteCode/Symbol.h b/lib/Runtime/ByteCode/Symbol.h index 24edb65a41d..e12e3924412 100644 --- a/lib/Runtime/ByteCode/Symbol.h +++ b/lib/Runtime/ByteCode/Symbol.h @@ -30,6 +30,7 @@ class Symbol BYTE defCount; BYTE needDeclaration : 1; BYTE isBlockVar : 1; + BYTE isConst : 1; BYTE isGlobal : 1; BYTE isEval : 1; BYTE hasNonLocalReference : 1; // if true, then this symbol needs to be heap-allocated @@ -61,6 +62,7 @@ class Symbol location(Js::Constants::NoRegister), needDeclaration(false), isBlockVar(false), + isConst(false), isGlobal(false), hasNonLocalReference(false), isFuncExpr(false), @@ -150,6 +152,16 @@ class Symbol return isBlockVar; } + void SetIsConst(bool is) + { + isConst = is; + } + + bool GetIsConst() const + { + return isConst; + } + void SetIsModuleExportStorage(bool is) { isModuleExportStorage = is; diff --git a/test/LetConst/AssignmentToConst.baseline b/test/LetConst/AssignmentToConst.baseline index 466d08f52e8..9e5ac4fca57 100644 --- a/test/LetConst/AssignmentToConst.baseline +++ b/test/LetConst/AssignmentToConst.baseline @@ -46,3 +46,5 @@ test 23 ReferenceError: Use before declaration test 24 ReferenceError: Use before declaration +test 25 +TypeError: Assignment to const diff --git a/test/LetConst/AssignmentToConst.js b/test/LetConst/AssignmentToConst.js index 101d4bba44f..0b4a8a2e295 100644 --- a/test/LetConst/AssignmentToConst.js +++ b/test/LetConst/AssignmentToConst.js @@ -27,5 +27,6 @@ try { eval("WScript.Echo('test 21'); const x = 1; {const x = 2; x++;}"); WScript try { eval("WScript.Echo('test 22'); const x = 1; {const x = 2;} x++;"); WScript.Echo("passed"); } catch (e) { WScript.Echo(e); } try { eval("WScript.Echo('test 23'); x = 1; {let x = 2;} const x = 10;"); WScript.Echo("passed"); } catch (e) { WScript.Echo(e); } try { eval("WScript.Echo('test 24'); function f() {x = 1; {let x = 2;} const x = 10;} f();"); WScript.Echo("passed"); } catch (e) { WScript.Echo(e); } +try { eval("WScript.Echo('test 25'); const x = 10; function f() {x = 1; {let x = 2;} } f();"); WScript.Echo("passed"); } catch (e) { WScript.Echo(e); } diff --git a/test/LetConst/rlexe.xml b/test/LetConst/rlexe.xml index ea126dc9c3f..f84c9ab3a41 100644 --- a/test/LetConst/rlexe.xml +++ b/test/LetConst/rlexe.xml @@ -141,6 +141,13 @@ AssignmentToConst.baseline + + + AssignmentToConst.js + AssignmentToConst.baseline + -force:deferparse + + DeclOutofBlock.js