Skip to content

Commit 9b49b23

Browse files
committed
With equivalent obj type spec on by default, certain operations still require monomorphic type checks. We've handled this in the dead store pass by locating any equivalent type check that protects an operation that requires a specific type and changing it to use a monomorphic check. But because of the vagaries of inline cache sharing, the operation that does the check may not appear to be monomorphic. Deal with this by having the dead store pass indicate the required type on the checking instruction.
1 parent 4ecb778 commit 9b49b23

File tree

7 files changed

+93
-19
lines changed

7 files changed

+93
-19
lines changed

lib/Backend/BackwardPass.cpp

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1069,10 +1069,17 @@ BackwardPass::MergeGuardedProperties(ObjTypeGuardBucket bucket1, ObjTypeGuardBuc
10691069

10701070
ObjTypeGuardBucket bucket;
10711071
bucket.SetGuardedPropertyOps(mergedPropertyOps);
1072-
if (bucket1.NeedsMonoCheck() || bucket2.NeedsMonoCheck())
1072+
Js::Type *monoGuardType = bucket1.GetMonoGuardType();
1073+
if (monoGuardType != nullptr)
10731074
{
1074-
bucket.SetNeedsMonoCheck(true);
1075+
Assert(!bucket2.NeedsMonoCheck() || monoGuardType == bucket2.GetMonoGuardType());
10751076
}
1077+
else
1078+
{
1079+
monoGuardType = bucket2.GetMonoGuardType();
1080+
}
1081+
bucket.SetMonoGuardType(monoGuardType);
1082+
10761083
return bucket;
10771084
}
10781085

@@ -3988,7 +3995,8 @@ BackwardPass::TrackObjTypeSpecProperties(IR::PropertySymOpnd *opnd, BasicBlock *
39883995
if (opnd->NeedsMonoCheck())
39893996
{
39903997
Assert(opnd->IsMono());
3991-
bucket->SetNeedsMonoCheck(true);
3998+
Js::Type *monoGuardType = opnd->HasInitialType() ? opnd->GetInitialType() : opnd->GetType();
3999+
bucket->SetMonoGuardType(monoGuardType);
39924000
}
39934001

39944002
if (opnd->NeedsPrimaryTypeCheck())
@@ -4013,11 +4021,10 @@ BackwardPass::TrackObjTypeSpecProperties(IR::PropertySymOpnd *opnd, BasicBlock *
40134021
{
40144022
// Some instr protected by this one requires a monomorphic type check. (E.g., final type opt,
40154023
// fixed field not loaded from prototype.)
4016-
Assert(opnd->IsMono());
4017-
opnd->SetMustDoMonoCheck(true);
4024+
opnd->SetMonoGuardType(bucket->GetMonoGuardType());
40184025
this->currentInstr->ChangeEquivalentToMonoTypeCheckBailOut();
40194026
}
4020-
bucket->SetNeedsMonoCheck(false);
4027+
bucket->SetMonoGuardType(nullptr);
40214028
}
40224029

40234030
bucket->SetGuardedPropertyOps(nullptr);

lib/Backend/FlowGraph.h

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -71,28 +71,29 @@ class ObjTypeGuardBucket
7171
{
7272
private:
7373
BVSparse<JitArenaAllocator>* guardedPropertyOps;
74-
bool needsMonoCheck;
74+
Js::Type * monoGuardType;
7575

7676
public:
77-
ObjTypeGuardBucket() : guardedPropertyOps(nullptr), needsMonoCheck(false) {}
77+
ObjTypeGuardBucket() : guardedPropertyOps(nullptr), monoGuardType(nullptr) {}
7878

79-
ObjTypeGuardBucket(BVSparse<JitArenaAllocator>* guardedPropertyOps) : needsMonoCheck(false)
79+
ObjTypeGuardBucket(BVSparse<JitArenaAllocator>* guardedPropertyOps) : monoGuardType(nullptr)
8080
{
8181
this->guardedPropertyOps = (guardedPropertyOps != nullptr ? guardedPropertyOps->CopyNew() : nullptr);
8282
}
8383

8484
void Copy(ObjTypeGuardBucket *pNew) const
8585
{
8686
pNew->guardedPropertyOps = this->guardedPropertyOps ? this->guardedPropertyOps->CopyNew() : nullptr;
87-
pNew->needsMonoCheck = this->needsMonoCheck;
87+
pNew->monoGuardType = this->monoGuardType;
8888
}
8989

9090
BVSparse<JitArenaAllocator> *GetGuardedPropertyOps() const { return this->guardedPropertyOps; }
9191
void SetGuardedPropertyOps(BVSparse<JitArenaAllocator> *guardedPropertyOps) { this->guardedPropertyOps = guardedPropertyOps; }
9292
void AddToGuardedPropertyOps(uint propertyOpId) { Assert(this->guardedPropertyOps != nullptr); this->guardedPropertyOps->Set(propertyOpId); }
9393

94-
bool NeedsMonoCheck() const { return this->needsMonoCheck; }
95-
void SetNeedsMonoCheck(bool value) { this->needsMonoCheck = value; }
94+
bool NeedsMonoCheck() const { return this->monoGuardType != nullptr; }
95+
void SetMonoGuardType(Js::Type *type) { this->monoGuardType = type; }
96+
Js::Type * GetMonoGuardType() const { return this->monoGuardType; }
9697

9798
#if DBG_DUMP
9899
void Dump() const;

lib/Backend/Lower.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6762,7 +6762,8 @@ Lowerer::GenerateCachedTypeCheck(IR::Instr *instrChk, IR::PropertySymOpnd *prope
67626762
(propertySymOpnd->IsPoly() || instrChk->HasTypeCheckBailOut());
67636763
Assert(doEquivTypeCheck || !instrChk->HasEquivalentTypeCheckBailOut());
67646764

6765-
Js::Type* type = doEquivTypeCheck ? propertySymOpnd->GetFirstEquivalentType() : propertySymOpnd->GetType();
6765+
Js::Type* type = propertySymOpnd->MustDoMonoCheck() ? propertySymOpnd->GetMonoGuardType() :
6766+
doEquivTypeCheck ? propertySymOpnd->GetFirstEquivalentType() : propertySymOpnd->GetType();
67666767

67676768
Js::PropertyGuard* typeCheckGuard = doEquivTypeCheck ?
67686769
(Js::PropertyGuard*)CreateEquivalentTypeGuardAndLinkToGuardedProperties(type, propertySymOpnd) :

lib/Backend/Opnd.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -715,6 +715,7 @@ PropertySymOpnd::New(PropertySym *propertySym, IRType type, Func *func)
715715
newOpnd->m_type = type;
716716
newOpnd->SetObjTypeSpecFldInfo(nullptr);
717717
newOpnd->finalType = nullptr;
718+
newOpnd->monoGuardType = nullptr;
718719
newOpnd->guardedPropOps = nullptr;
719720
newOpnd->writeGuards = nullptr;
720721
newOpnd->objTypeSpecFlags = 0;

lib/Backend/Opnd.h

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -506,6 +506,7 @@ class PropertySymOpnd sealed : public SymOpnd
506506
Js::ObjTypeSpecFldInfo* objTypeSpecFldInfo;
507507
public:
508508
Js::Type* finalType;
509+
Js::Type* monoGuardType;
509510
BVSparse<JitArenaAllocator>* guardedPropOps;
510511
BVSparse<JitArenaAllocator>* writeGuards;
511512
byte m_polyCacheUtil;
@@ -534,7 +535,6 @@ class PropertySymOpnd sealed : public SymOpnd
534535
bool typeDead: 1;
535536
bool typeChecked: 1;
536537
bool initialTypeChecked: 1;
537-
bool mustDoMonoCheck: 1;
538538
bool typeMismatch: 1;
539539
bool writeGuardChecked: 1;
540540
};
@@ -667,14 +667,17 @@ class PropertySymOpnd sealed : public SymOpnd
667667

668668
bool MustDoMonoCheck() const
669669
{
670-
// Question: does this property access need to do a monomorphic check because of some other access
671-
// that this check protects?
672-
return this->mustDoMonoCheck;
670+
return this->monoGuardType != nullptr;
673671
}
674672

675-
void SetMustDoMonoCheck(bool value)
673+
Js::Type * GetMonoGuardType() const
676674
{
677-
this->mustDoMonoCheck = value;
675+
return this->monoGuardType;
676+
}
677+
678+
void SetMonoGuardType(Js::Type *type)
679+
{
680+
this->monoGuardType = type;
678681
}
679682

680683
bool NeedsMonoCheck() const
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
//-------------------------------------------------------------------------------------------------------
2+
// Copyright (C) Microsoft. All rights reserved.
3+
// Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
4+
//-------------------------------------------------------------------------------------------------------
5+
6+
function test0() {
7+
var GiantPrintArray = [];
8+
var obj0 = {};
9+
var protoObj0 = {};
10+
var protoObj1 = {};
11+
var obj2 = {};
12+
var protoObj2 = {};
13+
var func0 = function () {
14+
if ({} instanceof EvalError ^ (parseInt()) * (ary - protoObj2.prop6)) {
15+
var uniqobj1 = uniqobj0;
16+
} else {
17+
protoObj0.prop4 = uic8;
18+
({ b: { n: protoObj1.prop0 } });
19+
for (var v0 = 0; v0 < 3; v0++) {
20+
protoObj1.prop4 = protoObj1.prop1 === protoObj1 && obj2 === protoObj1.prop6;
21+
}
22+
}
23+
GiantPrintArray.push(protoObj1.prop5);
24+
};
25+
var func1 = function () {
26+
(function () {
27+
Math.sin(new func0()) ? -(argMath10 * -921543659 - -1139958822.9) : prop4 = ui16;
28+
func0(func0());
29+
}(new func0()));
30+
};
31+
var func3 = function () {
32+
var uniqobj6 = { 33: func1((new func0())) };
33+
};
34+
obj0.method0 = func3;
35+
method1 = obj0.method0;
36+
var ui16 = new Uint16Array();
37+
var uic8 = new Uint8ClampedArray();
38+
var VarArr0 = Array();
39+
ary = 856134889;
40+
protoObj0.prop0 = 194709012;
41+
protoObj0.prop1 = -377120002;
42+
protoObj0.prop2 = -1996023131.9;
43+
protoObj0.prop3 = 114;
44+
protoObj1.prop0 = -3;
45+
protoObj1.prop1 = -1824894349.9;
46+
protoObj1.prop2 = 1469720302881920000;
47+
protoObj1.prop3 = -1231853442;
48+
protoObj1.prop4 = -563681667;
49+
protoObj1.prop5 = 1;
50+
protoObj2.prop6 = -7120587829494880000;
51+
method1(typeof (--protoObj2.prop6 >= (VarArr0[false ? VarArr0[17] = 'x' : undefined, 17] instanceof (typeof Object == 'function' ? Object : Object))));
52+
}
53+
test0();
54+
55+
WScript.Echo('pass');

test/fieldopts/rlexe.xml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -836,4 +836,10 @@
836836
<compile-flags>-force:fieldhoist -off:inlinegetters -off:fixedmethods</compile-flags>
837837
</default>
838838
</test>
839+
<test>
840+
<default>
841+
<files>fixedfieldmonocheck.js</files>
842+
<compile-flags>-force:fixdataprops</compile-flags>
843+
</default>
844+
</test>
839845
</regress-exe>

0 commit comments

Comments
 (0)