Skip to content

Commit c4db129

Browse files
committed
Fix Optimisation of arguments[-n]
1 parent b521cfe commit c4db129

File tree

6 files changed

+154
-24
lines changed

6 files changed

+154
-24
lines changed

lib/Backend/GlobOpt.cpp

Lines changed: 14 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1586,7 +1586,7 @@ GlobOpt::OptArguments(IR::Instr *instr)
15861586
}
15871587

15881588
SymID id = 0;
1589-
1589+
15901590
switch(instr->m_opcode)
15911591
{
15921592
case Js::OpCode::LdElemI_A:
@@ -13529,16 +13529,19 @@ GlobOpt::OptStackArgLenAndConst(IR::Instr* instr, Value** src1Val)
1352913529
{
1353013530
int argIndex = indirOpndSrc1->GetOffset() + 1;
1353113531
IR::Instr* defInstr = nullptr;
13532-
IR::Instr* inlineeStart = instr->m_func->GetInlineeStart();
13533-
inlineeStart->IterateArgInstrs([&](IR::Instr* argInstr) {
13534-
StackSym *argSym = argInstr->GetDst()->AsSymOpnd()->m_sym->AsStackSym();
13535-
if (argSym->GetArgSlotNum() - 1 == argIndex)
13536-
{
13537-
defInstr = argInstr;
13538-
return true;
13539-
}
13540-
return false;
13541-
});
13532+
if (argIndex > 0)
13533+
{
13534+
IR::Instr* inlineeStart = instr->m_func->GetInlineeStart();
13535+
inlineeStart->IterateArgInstrs([&](IR::Instr* argInstr) {
13536+
StackSym *argSym = argInstr->GetDst()->AsSymOpnd()->m_sym->AsStackSym();
13537+
if (argSym->GetArgSlotNum() - 1 == argIndex)
13538+
{
13539+
defInstr = argInstr;
13540+
return true;
13541+
}
13542+
return false;
13543+
});
13544+
}
1354213545

1354313546
Js::OpCode replacementOpcode;
1354413547
if (instr->m_opcode == Js::OpCode::TypeofElem)

lib/Backend/Lower.cpp

Lines changed: 33 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
//-------------------------------------------------------------------------------------------------------
22
// Copyright (C) Microsoft Corporation and contributors. All rights reserved.
3+
// Copyright (c) 2021 ChakraCore Project Contributors. All rights reserved.
34
// Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
45
//-------------------------------------------------------------------------------------------------------
56
#include "Backend.h"
@@ -22154,10 +22155,14 @@ Lowerer::GenerateFastArgumentsLdElemI(IR::Instr* ldElem, IR::LabelInstr *labelFa
2215422155
// ---GenerateLdValueFromCheckedIndexOpnd
2215522156
// ---LoadInputParamCount
2215622157
// CMP actualParamOpnd, valueOpnd //Compare between the actual count & the index count (say i in arguments[i])
22157-
// JLE $labelCreateHeapArgs
22158+
// JLE $labelReturnUndefined
2215822159
// MOV dst, ebp [(valueOpnd + 5) *4] // 5 for the stack layout
2215922160
// JMP $fallthrough
2216022161
//
22162+
//labelReturnUndefined:
22163+
// MOV dst, undefined
22164+
// JMP $fallthrough
22165+
//
2216122166
//labelCreateHeapArgs:
2216222167
// ---Bail out to create Heap Arguments object
2216322168

@@ -22179,12 +22184,23 @@ Lowerer::GenerateFastArgumentsLdElemI(IR::Instr* ldElem, IR::LabelInstr *labelFa
2217922184

2218022185
bool hasIntConstIndex = indirOpnd->TryGetIntConstIndexValue(true, &value, &isNotInt);
2218122186

22182-
if (isNotInt || (isInlinee && hasIntConstIndex && value >= (ldElem->m_func->actualCount - 1)))
22187+
if (isNotInt)
2218322188
{
22184-
//Outside the range of actuals, skip
22189+
//Not an int disable optimisation and rejit
2218522190
}
22186-
else if (labelFallThru != nullptr && !(hasIntConstIndex && value < 0)) //if index is not a negative int constant
22191+
else if (hasIntConstIndex && (value < 0 || (isInlinee && value >= (ldElem->m_func->actualCount - 1))))
2218722192
{
22193+
// if the index is an int const outside the range then the value must be undefined
22194+
// this is ensured as GlobOpt::OptArguments disables the Arguments optimisation if the arguments object is modified
22195+
IR::Opnd *undef = LoadLibraryValueOpnd(ldElem, LibraryValue::ValueUndefined);
22196+
Lowerer::InsertMove(ldElem->GetDst(), undef, ldElem);
22197+
// JMP $done
22198+
InsertBranch(Js::OpCode::Br, labelFallThru, ldElem);
22199+
emittedFastPath = true;
22200+
}
22201+
else if (labelFallThru != nullptr)
22202+
{
22203+
IR::LabelInstr *labelReturnUndefined = IR::LabelInstr::New(Js::OpCode::Label, func, true);
2218822204
if (isInlinee)
2218922205
{
2219022206
actualParamOpnd = IR::IntConstOpnd::New(ldElem->m_func->actualCount - 1, TyInt32, func);
@@ -22203,7 +22219,7 @@ Lowerer::GenerateFastArgumentsLdElemI(IR::Instr* ldElem, IR::LabelInstr *labelFa
2220322219
}
2220422220
else
2220522221
{
22206-
//Load valueOpnd from the index
22222+
//Load valueOpnd from the index, note this operation includes a bail-out for non-integer indices
2220722223
valueOpnd =
2220822224
m_lowererMD.LoadNonnegativeIndex(
2220922225
indexOpnd,
@@ -22215,22 +22231,22 @@ Lowerer::GenerateFastArgumentsLdElemI(IR::Instr* ldElem, IR::LabelInstr *labelFa
2221522231
true
2221622232
#endif
2221722233
),
22218-
labelCreateHeapArgs,
22219-
labelCreateHeapArgs,
22234+
labelReturnUndefined,
22235+
labelReturnUndefined,
2222022236
ldElem);
2222122237
}
2222222238

2222322239
if (isInlinee)
2222422240
{
2222522241
if (!hasIntConstIndex)
2222622242
{
22227-
//Runtime check if to make sure length is within the arguments.length range.
22228-
GenerateCheckForArgumentsLength(ldElem, labelCreateHeapArgs, valueOpnd, actualParamOpnd, Js::OpCode::BrGe_A);
22243+
//Runtime check to make sure length is within the arguments.length range.
22244+
GenerateCheckForArgumentsLength(ldElem, labelReturnUndefined, valueOpnd, actualParamOpnd, Js::OpCode::BrGe_A);
2222922245
}
2223022246
}
2223122247
else
2223222248
{
22233-
GenerateCheckForArgumentsLength(ldElem, labelCreateHeapArgs, actualParamOpnd, valueOpnd, Js::OpCode::BrLe_A);
22249+
GenerateCheckForArgumentsLength(ldElem, labelReturnUndefined, actualParamOpnd, valueOpnd, Js::OpCode::BrLe_A);
2223422250
}
2223522251

2223622252
IR::Opnd *argIndirOpnd = nullptr;
@@ -22244,9 +22260,16 @@ Lowerer::GenerateFastArgumentsLdElemI(IR::Instr* ldElem, IR::LabelInstr *labelFa
2224422260
}
2224522261

2224622262
Lowerer::InsertMove(ldElem->GetDst(), argIndirOpnd, ldElem);
22263+
// JMP $done
22264+
InsertBranch(Js::OpCode::Br, labelFallThru, ldElem);
2224722265

22266+
// if load is outside of range at runtime return false
22267+
ldElem->InsertBefore(labelReturnUndefined);
22268+
IR::Opnd *undef = LoadLibraryValueOpnd(ldElem, LibraryValue::ValueUndefined);
22269+
Lowerer::InsertMove(ldElem->GetDst(), undef, ldElem);
2224822270
// JMP $done
2224922271
InsertBranch(Js::OpCode::Br, labelFallThru, ldElem);
22272+
2225022273
// $labelCreateHeapArgs:
2225122274
ldElem->InsertBefore(labelCreateHeapArgs);
2225222275
emittedFastPath = true;

test/Function/StackArgsWithFormals.baseline

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,6 @@ StackArgFormals : test16 (22) :Removing Heap Arguments object creation in Lowere
1919
StackArgFormals : test16 (22) :Removing Scope object creation in Lowerer and replacing it with MOV NULL.
2020
StackArgFormals : test16 (22) :Attaching the scope object with the heap arguments object in the bail out path.
2121
StackArgFormals : test17 (23) :Removing Heap Arguments object creation in Lowerer.
22-
StackArgFormals : test17 (23) :Attaching the scope object with the heap arguments object in the bail out path.
2322
StackArgFormals : test19 (25) :Removing Heap Arguments object creation in Lowerer.
2423
StackArgFormals : test20 (26) :Removing Heap Arguments object creation in Lowerer.
2524
PASSED
Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
//-------------------------------------------------------------------------------------------------------
2+
// Copyright (C) Microsoft Corporation and contributors. All rights reserved.
3+
// Copyright (c) 2021 ChakraCore Project Contributors. All rights reserved.
4+
// Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
5+
//-------------------------------------------------------------------------------------------------------
6+
7+
let fail = 0;
8+
9+
// Test 1 inline negative index
10+
function func1() {
11+
return func2(5);
12+
}
13+
14+
function func2() {
15+
return arguments[-1];
16+
}
17+
18+
const obj = { "o" : func2 };
19+
20+
for (i = 0; i < 500; i++) {
21+
if(func1() != undefined) {
22+
++ fail;
23+
}
24+
}
25+
26+
// Test 2 edited negative index
27+
function func3() {
28+
return func4(5);
29+
}
30+
31+
function func4() {
32+
arguments[-1] = 5;
33+
return arguments[-1];
34+
}
35+
36+
for (i = 0; i < 500; i++) {
37+
if(func3() != 5) {
38+
++ fail;
39+
}
40+
}
41+
42+
// Test 3 edit the negative index after jitting
43+
function func5(count) {
44+
if (count > 10) {
45+
arguments[-2] = 5;
46+
}
47+
return arguments[-2];
48+
}
49+
50+
for (let i = 0; i < 20; ++i) {
51+
let val = func5(i);
52+
if (i > 10 && val !== 5 || i <= 10 && val !== undefined) {
53+
++fail;
54+
}
55+
}
56+
57+
function func6(count) {
58+
return func5(count);
59+
}
60+
61+
for (let i = 0; i < 20; ++i) {
62+
let val = func6(i);
63+
if (i > 10 && val !== 5 || i <= 10 && val !== undefined) {
64+
++fail;
65+
}
66+
}
67+
68+
// Test 4 dynamic negative index
69+
function func7(count) {
70+
let n = 0;
71+
if (count > 10) {
72+
n = -1;
73+
}
74+
if (count > 20) {
75+
n = 1;
76+
}
77+
return arguments[n];
78+
}
79+
80+
function func8(count) {
81+
return func7(count);
82+
}
83+
84+
for (let i = 0; i < 40; ++i) {
85+
let val = func7(i);
86+
if (i < 11 && val !== i || i > 10 && val !== undefined) {
87+
++fail;
88+
}
89+
}
90+
91+
for (let i = 0; i < 40; ++i) {
92+
let val = func8(i);
93+
if (i < 11 && val !== i || i > 10 && val !== undefined) {
94+
++fail;
95+
}
96+
}
97+
98+
99+
print (fail > 0 ? "fail" : "pass");

test/Optimizer/rlexe.xml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1641,4 +1641,9 @@
16411641
<tags>exclude_nonative</tags>
16421642
</default>
16431643
</test>
1644+
<test>
1645+
<default>
1646+
<files>StackArgumentsOptNegativeIndex.js</files>
1647+
</default>
1648+
</test>
16441649
</regress-exe>

test/stackfunc/funcexpr_2.js

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
//-------------------------------------------------------------------------------------------------------
2-
// Copyright (C) Microsoft. All rights reserved.
2+
// Copyright (C) Microsoft Corporation and contributors. All rights reserved.
3+
// Copyright (c) 2021 ChakraCore Project Contributors. All rights reserved.
34
// Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
45
//-------------------------------------------------------------------------------------------------------
56

@@ -30,7 +31,7 @@ glo();
3031
function v2() {
3132
}
3233
argMath5 = eval;
33-
})(arguments[0]);
34+
})(arguments[0.5]);
3435
prop1 = argMath5;
3536
}
3637
v0();

0 commit comments

Comments
 (0)