Skip to content

Commit 1f6cd8e

Browse files
committed
[MERGE #5689 @wyrichte] Fixes #5477 - Forces computed property names within classes to be executed in strict mode
Merge pull request #5689 from wyrichte:bug_5477_fixed Forces computed property names within classes to be executed in strict mode. The ECMA spec requires that a class definition is always strict mode code, this includes computed property names within classes. A flag, forceStrictModeForClassComputedPropertyName, is added into ByteCodeGenerator.h. When set, this flag will force bytecode opcodes to be emitted in strict mode when avaliable. This flag is set outside of emit calls under the condition that the bytecode being emitted corresponds to computed property names within classes.
2 parents 9976ab2 + 4f3f3bf commit 1f6cd8e

File tree

7 files changed

+298
-17
lines changed

7 files changed

+298
-17
lines changed

lib/Runtime/ByteCode/ByteCodeEmitter.cpp

Lines changed: 28 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4733,7 +4733,7 @@ void ByteCodeGenerator::EmitPropStore(Js::RegSlot rhsLocation, Symbol *sym, Iden
47334733
}
47344734
else
47354735
{
4736-
this->EmitPatchableRootProperty(GetStFldOpCode(funcInfo, true, isLetDecl, isConstDecl, false), rhsLocation, propertyId, false, true, funcInfo);
4736+
this->EmitPatchableRootProperty(GetStFldOpCode(funcInfo, true, isLetDecl, isConstDecl, false, forceStrictModeForClassComputedPropertyName), rhsLocation, propertyId, false, true, funcInfo);
47374737
}
47384738
}
47394739
else if (sym->GetIsFuncExpr())
@@ -5320,7 +5320,7 @@ void ByteCodeGenerator::EmitPropDelete(Js::RegSlot lhsLocation, Symbol *sym, Ide
53205320
if (this->flags & (fscrEval | fscrImplicitThis))
53215321
{
53225322
this->m_writer.ScopedProperty(Js::OpCode::ScopedDeleteFld, lhsLocation,
5323-
funcInfo->FindOrAddReferencedPropertyId(propertyId));
5323+
funcInfo->FindOrAddReferencedPropertyId(propertyId), forceStrictModeForClassComputedPropertyName);
53245324
}
53255325
else
53265326
{
@@ -6931,7 +6931,7 @@ void EmitAssignment(
69316931
{
69326932
uint cacheId = funcInfo->FindOrAddInlineCacheId(lhs->AsParseNodeBin()->pnode1->location, propertyId, false, true);
69336933
byteCodeGenerator->Writer()->PatchableProperty(
6934-
ByteCodeGenerator::GetStFldOpCode(funcInfo, false, false, false, false), rhsLocation, lhs->AsParseNodeBin()->pnode1->location, cacheId);
6934+
ByteCodeGenerator::GetStFldOpCode(funcInfo, false, false, false, false, byteCodeGenerator->forceStrictModeForClassComputedPropertyName), rhsLocation, lhs->AsParseNodeBin()->pnode1->location, cacheId);
69356935
}
69366936

69376937
break;
@@ -8347,7 +8347,19 @@ void EmitMemberNode(ParseNode *memberNode, Js::RegSlot objectLocation, ByteCodeG
83478347
// Transparently pass the name expr
83488348
// The Emit will replace this with a temp register if necessary to preserve the value.
83498349
nameNode->location = nameNode->AsParseNodeUni()->pnode1->location;
8350+
8351+
// Save the previous value of the flag to be restored later.
8352+
bool prevFlag = byteCodeGenerator->forceStrictModeForClassComputedPropertyName;
8353+
8354+
// Strict mode must be enforced on the evaluation of computed property names inside
8355+
// classes, thus enable the flag if the computed property name is a class member.
8356+
byteCodeGenerator->forceStrictModeForClassComputedPropertyName = isClassMember || prevFlag;
8357+
83508358
EmitBinaryOpnds(nameNode, exprNode, byteCodeGenerator, funcInfo);
8359+
8360+
// Restore the flag's previous value.
8361+
byteCodeGenerator->forceStrictModeForClassComputedPropertyName = prevFlag;
8362+
83518363
if (isFncDecl && !exprNode->AsParseNodeFnc()->IsClassConstructor())
83528364
{
83538365
EmitComputedFunctionNameVar(nameNode, exprNode->AsParseNodeFnc(), byteCodeGenerator);
@@ -8374,7 +8386,18 @@ void EmitMemberNode(ParseNode *memberNode, Js::RegSlot objectLocation, ByteCodeG
83748386
(isClassMember ? Js::OpCode::InitClassMemberSetComputedName : Js::OpCode::InitSetElemI) :
83758387
(isClassMember ? Js::OpCode::InitClassMemberComputedName : Js::OpCode::InitComputedProperty);
83768388

8377-
byteCodeGenerator->Writer()->Element(setOp, exprNode->location, objectLocation, nameNode->location, true);
8389+
// Save the previous value of the flag to be restored later.
8390+
bool prevFlag = byteCodeGenerator->forceStrictModeForClassComputedPropertyName;
8391+
byteCodeGenerator->forceStrictModeForClassComputedPropertyName = isClassMember || prevFlag;
8392+
8393+
// Strict mode must be enforced on the evaluation of computed property names inside
8394+
// classes, thus enable the flag if the computed property name is a class member.
8395+
byteCodeGenerator->Writer()->Element(setOp, exprNode->location, objectLocation, nameNode->location, true,
8396+
byteCodeGenerator->forceStrictModeForClassComputedPropertyName);
8397+
8398+
// Restore the flag's previous value.
8399+
byteCodeGenerator->forceStrictModeForClassComputedPropertyName = prevFlag;
8400+
83788401

83798402
funcInfo->ReleaseLoc(exprNode);
83808403
funcInfo->ReleaseLoc(nameNode);
@@ -10634,7 +10657,7 @@ void Emit(ParseNode *pnode, ByteCodeGenerator *byteCodeGenerator, FuncInfo *func
1063410657
Js::PropertyId propertyId = pexpr->AsParseNodeBin()->pnode2->AsParseNodeName()->PropertyIdFromNameNode();
1063510658
funcInfo->AcquireLoc(pnode);
1063610659
byteCodeGenerator->Writer()->Property(Js::OpCode::DeleteFld, pnode->location, pexpr->AsParseNodeBin()->pnode1->location,
10637-
funcInfo->FindOrAddReferencedPropertyId(propertyId));
10660+
funcInfo->FindOrAddReferencedPropertyId(propertyId), byteCodeGenerator->forceStrictModeForClassComputedPropertyName);
1063810661
}
1063910662

1064010663
break;

lib/Runtime/ByteCode/ByteCodeGenerator.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1923,9 +1923,9 @@ Scope * ByteCodeGenerator::FindScopeForSym(Scope *symScope, Scope *scope, Js::Pr
19231923
}
19241924

19251925
/* static */
1926-
Js::OpCode ByteCodeGenerator::GetStFldOpCode(FuncInfo* funcInfo, bool isRoot, bool isLetDecl, bool isConstDecl, bool isClassMemberInit)
1926+
Js::OpCode ByteCodeGenerator::GetStFldOpCode(FuncInfo* funcInfo, bool isRoot, bool isLetDecl, bool isConstDecl, bool isClassMemberInit, bool forceStrictModeForClassComputedPropertyName)
19271927
{
1928-
return GetStFldOpCode(funcInfo->GetIsStrictMode(), isRoot, isLetDecl, isConstDecl, isClassMemberInit);
1928+
return GetStFldOpCode(funcInfo->GetIsStrictMode() || forceStrictModeForClassComputedPropertyName, isRoot, isLetDecl, isConstDecl, isClassMemberInit);
19291929
}
19301930

19311931
/* static */

lib/Runtime/ByteCode/ByteCodeGenerator.h

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,13 @@ class ByteCodeGenerator
6565
static const unsigned int MinArgumentsForCallOptimization = 16;
6666
bool forceNoNative;
6767

68+
// A flag that when set will force bytecode opcodes to be emitted in strict mode when avaliable.
69+
// This flag is set outside of emit calls under the condition that the bytecode being emitted
70+
// corresponds to computed property names within classes. This fixes a bug where computed property
71+
// names would not enforce strict mode when inside a class even though the spec requires that
72+
// all code within a class must be strict.
73+
bool forceStrictModeForClassComputedPropertyName = false;
74+
6875
ByteCodeGenerator(Js::ScriptContext* scriptContext, Js::ScopeInfo* parentScopeInfo);
6976

7077
#if DBG_DUMP
@@ -326,7 +333,7 @@ class ByteCodeGenerator
326333
isStrictMode ? (isRoot ? Js::OpCode::StRootFldStrict : Js::OpCode::StFldStrict) :
327334
isRoot ? Js::OpCode::StRootFld : Js::OpCode::StFld;
328335
}
329-
static Js::OpCode GetStFldOpCode(FuncInfo* funcInfo, bool isRoot, bool isLetDecl, bool isConstDecl, bool isClassMemberInit);
336+
static Js::OpCode GetStFldOpCode(FuncInfo* funcInfo, bool isRoot, bool isLetDecl, bool isConstDecl, bool isClassMemberInit, bool forceStrictModeForClassComputedPropertyName = false);
330337
static Js::OpCode GetScopedStFldOpCode(bool isStrictMode, bool isConsoleScope = false)
331338
{
332339
return isStrictMode ?

lib/Runtime/ByteCode/ByteCodeWriter.cpp

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1301,7 +1301,7 @@ namespace Js
13011301
return false;
13021302
}
13031303

1304-
void ByteCodeWriter::Element(OpCode op, RegSlot Value, RegSlot Instance, RegSlot Element, bool instanceAtReturnRegOK)
1304+
void ByteCodeWriter::Element(OpCode op, RegSlot Value, RegSlot Instance, RegSlot Element, bool instanceAtReturnRegOK, bool forceStrictMode)
13051305
{
13061306
CheckOpen();
13071307
CheckOp(op, OpLayoutType::ElementI);
@@ -1311,7 +1311,7 @@ namespace Js
13111311
Instance = ConsumeReg(Instance);
13121312
Element = ConsumeReg(Element);
13131313

1314-
if (this->m_functionWrite->GetIsStrictMode())
1314+
if (this->m_functionWrite->GetIsStrictMode() || forceStrictMode)
13151315
{
13161316
if (op == OpCode::DeleteElemI_A)
13171317
{
@@ -1401,7 +1401,7 @@ namespace Js
14011401
return false;
14021402
}
14031403

1404-
void ByteCodeWriter::ScopedProperty(OpCode op, RegSlot value, PropertyIdIndexType propertyIdIndex)
1404+
void ByteCodeWriter::ScopedProperty(OpCode op, RegSlot value, PropertyIdIndexType propertyIdIndex, bool forceStrictMode)
14051405
{
14061406
CheckOpen();
14071407
CheckOp(op, OpLayoutType::ElementScopedC);
@@ -1424,7 +1424,7 @@ namespace Js
14241424
}
14251425
#endif
14261426

1427-
if (this->m_functionWrite->GetIsStrictMode())
1427+
if (this->m_functionWrite->GetIsStrictMode() || forceStrictMode)
14281428
{
14291429
if (op == OpCode::ScopedDeleteFld)
14301430
{
@@ -1448,7 +1448,7 @@ namespace Js
14481448
return false;
14491449
}
14501450

1451-
void ByteCodeWriter::Property(OpCode op, RegSlot value, RegSlot instance, PropertyIdIndexType propertyIdIndex)
1451+
void ByteCodeWriter::Property(OpCode op, RegSlot value, RegSlot instance, PropertyIdIndexType propertyIdIndex, bool forceStrictMode)
14521452
{
14531453
CheckOpen();
14541454
CheckOp(op, OpLayoutType::ElementC);
@@ -1477,7 +1477,7 @@ namespace Js
14771477
}
14781478
#endif
14791479

1480-
if (this->m_functionWrite->GetIsStrictMode())
1480+
if (this->m_functionWrite->GetIsStrictMode() || forceStrictMode)
14811481
{
14821482
if (op == OpCode::DeleteFld)
14831483
{

lib/Runtime/ByteCode/ByteCodeWriter.h

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -269,10 +269,10 @@ namespace Js
269269
void CallI(OpCode op, RegSlot returnValueRegister, RegSlot functionRegister, ArgSlot givenArgCount, ProfileId callSiteId, CallFlags callFlags = CallFlags_None);
270270
void CallIExtended(OpCode op, RegSlot returnValueRegister, RegSlot functionRegister, ArgSlot givenArgCount, CallIExtendedOptions options, const void *buffer, uint byteCount, ProfileId callSiteId, CallFlags callFlags = CallFlags_None);
271271
void RemoveEntryForRegSlotFromCacheIdMap(RegSlot functionRegister);
272-
void Element(OpCode op, RegSlot value, RegSlot instance, RegSlot element, bool instanceAtReturnRegOK = false);
272+
void Element(OpCode op, RegSlot value, RegSlot instance, RegSlot element, bool instanceAtReturnRegOK = false, bool forceStrictMode = false);
273273
void ElementUnsigned1(OpCode op, RegSlot value, RegSlot instance, uint32 element);
274-
void Property(OpCode op, RegSlot Value, RegSlot Instance, PropertyIdIndexType propertyIdIndex);
275-
void ScopedProperty(OpCode op, RegSlot Value, PropertyIdIndexType propertyIdIndex);
274+
void Property(OpCode op, RegSlot Value, RegSlot Instance, PropertyIdIndexType propertyIdIndex, bool forceStrictMode = false);
275+
void ScopedProperty(OpCode op, RegSlot Value, PropertyIdIndexType propertyIdIndex, bool forceStrictMode = false);
276276
void Slot(OpCode op, RegSlot value, RegSlot instance, uint32 slotId);
277277
void Slot(OpCode op, RegSlot value, RegSlot instance, uint32 slotId, ProfileId profileId);
278278
void SlotI1(OpCode op, RegSlot value, uint32 slotId1);

0 commit comments

Comments
 (0)