Skip to content

Commit b7eaa8f

Browse files
committed
[MERGE #5867 @wyrichte] CheckIsFuncObj and CheckFuncInfo - Non fixed field bailout hoisting optimization
Merge pull request #5867 from wyrichte:build/wyrichte/non_fixed_field_hoist This optimization groups bailout instrs (created by the inliner when a non fixed field is called) into a single instr (CheckFunctionEntryPoint) which can be hoisted outside of a loop.
2 parents 3ee8e2a + cf09b48 commit b7eaa8f

File tree

8 files changed

+197
-85
lines changed

8 files changed

+197
-85
lines changed

lib/Backend/Inline.cpp

Lines changed: 19 additions & 81 deletions
Original file line numberDiff line numberDiff line change
@@ -4592,35 +4592,14 @@ Inline::SplitConstructorCallCommon(
45924592
}
45934593

45944594
void
4595-
Inline::InsertObjectCheck(IR::RegOpnd * funcOpnd, IR::Instr* insertBeforeInstr, IR::Instr*bailOutIfNotObject)
4595+
Inline::InsertFunctionObjectCheck(IR::RegOpnd * funcOpnd, IR::Instr *insertBeforeInstr, IR::Instr *bailOutInstr, const FunctionJITTimeInfo *funcInfo)
45964596
{
4597-
// Bailout if 'functionRegOpnd' is not an object.
4598-
bailOutIfNotObject->SetSrc1(funcOpnd);
4599-
bailOutIfNotObject->SetByteCodeOffset(insertBeforeInstr);
4600-
insertBeforeInstr->InsertBefore(bailOutIfNotObject);
4601-
}
4597+
Js::BuiltinFunction index = Js::JavascriptLibrary::GetBuiltInForFuncInfo(funcInfo->GetLocalFunctionId());
4598+
AssertMsg(index < Js::BuiltinFunction::Count, "Invalid built-in index on a call target marked as built-in");
46024599

4603-
void
4604-
Inline::InsertFunctionTypeIdCheck(IR::RegOpnd * funcOpnd, IR::Instr* insertBeforeInstr, IR::Instr* bailOutIfNotJsFunction)
4605-
{
4606-
// functionTypeRegOpnd = Ld functionRegOpnd->type
4607-
IR::IndirOpnd *functionTypeIndirOpnd = IR::IndirOpnd::New(funcOpnd, Js::RecyclableObject::GetOffsetOfType(), TyMachPtr, insertBeforeInstr->m_func);
4608-
IR::RegOpnd *functionTypeRegOpnd = IR::RegOpnd::New(TyVar, this->topFunc);
4609-
IR::Instr *instr = IR::Instr::New(Js::OpCode::Ld_A, functionTypeRegOpnd, functionTypeIndirOpnd, insertBeforeInstr->m_func);
4610-
if(instr->m_func->HasByteCodeOffset())
4611-
{
4612-
instr->SetByteCodeOffset(insertBeforeInstr);
4613-
}
4614-
insertBeforeInstr->InsertBefore(instr);
4615-
4616-
CompileAssert(sizeof(Js::TypeId) == sizeof(int32));
4617-
// if (functionTypeRegOpnd->typeId != TypeIds_Function) goto $noInlineLabel
4618-
// BrNeq_I4 $noInlineLabel, functionTypeRegOpnd->typeId, TypeIds_Function
4619-
IR::IndirOpnd *functionTypeIdIndirOpnd = IR::IndirOpnd::New(functionTypeRegOpnd, Js::Type::GetOffsetOfTypeId(), TyInt32, insertBeforeInstr->m_func);
4620-
IR::IntConstOpnd *typeIdFunctionConstOpnd = IR::IntConstOpnd::New(Js::TypeIds_Function, TyInt32, insertBeforeInstr->m_func);
4621-
bailOutIfNotJsFunction->SetSrc1(functionTypeIdIndirOpnd);
4622-
bailOutIfNotJsFunction->SetSrc2(typeIdFunctionConstOpnd);
4623-
insertBeforeInstr->InsertBefore(bailOutIfNotJsFunction);
4600+
bailOutInstr->SetSrc1(funcOpnd);
4601+
bailOutInstr->SetSrc2(IR::IntConstOpnd::New(index, TyInt32, insertBeforeInstr->m_func));
4602+
insertBeforeInstr->InsertBefore(bailOutInstr);
46244603
}
46254604

46264605
void
@@ -4629,74 +4608,33 @@ Inline::InsertJsFunctionCheck(IR::Instr * callInstr, IR::Instr *insertBeforeInst
46294608
// This function only inserts bailout for tagged int & TypeIds_Function.
46304609
// As of now this is only used for polymorphic inlining.
46314610
Assert(bailOutKind == IR::BailOutOnPolymorphicInlineFunction);
4632-
46334611
Assert(insertBeforeInstr);
46344612
Assert(insertBeforeInstr->m_func == callInstr->m_func);
46354613

4636-
IR::RegOpnd * funcOpnd = callInstr->GetSrc1()->AsRegOpnd();
4637-
4638-
// bailOutIfNotFunction is primary bailout instruction
4639-
IR::Instr* bailOutIfNotFunction = IR::BailOutInstr::New(Js::OpCode::BailOnNotEqual, bailOutKind, insertBeforeInstr, callInstr->m_func);
4640-
4641-
IR::Instr *bailOutIfNotObject = IR::BailOutInstr::New(Js::OpCode::BailOnNotObject, bailOutKind, bailOutIfNotFunction->GetBailOutInfo(), callInstr->m_func);
4642-
InsertObjectCheck(funcOpnd, insertBeforeInstr, bailOutIfNotObject);
4643-
4644-
InsertFunctionTypeIdCheck(funcOpnd, insertBeforeInstr, bailOutIfNotFunction);
4645-
4646-
}
4647-
4648-
void
4649-
Inline::InsertFunctionInfoCheck(IR::RegOpnd * funcOpnd, IR::Instr *insertBeforeInstr, IR::Instr* bailoutInstr, const FunctionJITTimeInfo *funcInfo)
4650-
{
4651-
// if (VarTo<JavascriptFunction>(r1)->functionInfo != funcInfo) goto noInlineLabel
4652-
// BrNeq_I4 noInlineLabel, r1->functionInfo, funcInfo
4653-
IR::IndirOpnd* opndFuncInfo = IR::IndirOpnd::New(funcOpnd, Js::JavascriptFunction::GetOffsetOfFunctionInfo(), TyMachPtr, insertBeforeInstr->m_func);
4654-
IR::AddrOpnd* inlinedFuncInfo = IR::AddrOpnd::New(funcInfo->GetFunctionInfoAddr(), IR::AddrOpndKindDynamicFunctionInfo, insertBeforeInstr->m_func);
4655-
bailoutInstr->SetSrc1(opndFuncInfo);
4656-
bailoutInstr->SetSrc2(inlinedFuncInfo);
4657-
4658-
insertBeforeInstr->InsertBefore(bailoutInstr);
4659-
}
4660-
4661-
void
4662-
Inline::InsertFunctionObjectCheck(IR::RegOpnd * funcOpnd, IR::Instr *insertBeforeInstr, IR::Instr *bailOutInstr, const FunctionJITTimeInfo *funcInfo)
4663-
{
4664-
Js::BuiltinFunction index = Js::JavascriptLibrary::GetBuiltInForFuncInfo(funcInfo->GetLocalFunctionId());
4665-
AssertMsg(index < Js::BuiltinFunction::Count, "Invalid built-in index on a call target marked as built-in");
4666-
4667-
bailOutInstr->SetSrc1(funcOpnd);
4668-
bailOutInstr->SetSrc2(IR::IntConstOpnd::New(index, TyInt32, insertBeforeInstr->m_func));
4669-
insertBeforeInstr->InsertBefore(bailOutInstr);
4614+
// Two bailout checks, an object check followed by a function type ID check, are required. These bailout instructions are created
4615+
// when lowering checkFunctionEntryPoint rather than being created here as checkFunctionEntryPoint can be hoisted outside of a loop.
4616+
IR::Instr *checkIsFuncObj = IR::BailOutInstr::New(Js::OpCode::CheckIsFuncObj, bailOutKind, insertBeforeInstr, callInstr->m_func);
4617+
checkIsFuncObj->SetSrc1(callInstr->GetSrc1()->AsRegOpnd());
4618+
checkIsFuncObj->SetByteCodeOffset(insertBeforeInstr);
4619+
insertBeforeInstr->InsertBefore(checkIsFuncObj);
46704620
}
46714621

46724622
IR::Instr *
46734623
Inline::PrepareInsertionPoint(IR::Instr *callInstr, const FunctionJITTimeInfo *funcInfo, IR::Instr *insertBeforeInstr)
46744624
{
46754625
Assert(insertBeforeInstr);
46764626
Assert(insertBeforeInstr->m_func == callInstr->m_func);
4677-
IR::BailOutKind bailOutKind = IR::BailOutOnInlineFunction;
4678-
4679-
IR::RegOpnd * funcOpnd = callInstr->GetSrc1()->AsRegOpnd();
46804627

4681-
// FunctionBody check is the primary bailout instruction, create it first
4682-
IR::BailOutInstr* primaryBailOutInstr = IR::BailOutInstr::New(Js::OpCode::BailOnNotEqual, bailOutKind, insertBeforeInstr, callInstr->m_func);
4683-
primaryBailOutInstr->SetByteCodeOffset(insertBeforeInstr);
4628+
IR::Instr *checkFuncInfo = IR::BailOutInstr::New(Js::OpCode::CheckFuncInfo, IR::BailOutOnInlineFunction, insertBeforeInstr, callInstr->m_func);
4629+
checkFuncInfo->SetSrc1(callInstr->GetSrc1()->AsRegOpnd());
46844630

4685-
// 1. Bailout if function object is not an object.
4686-
IR::Instr *bailOutIfNotObject = IR::BailOutInstr::New(Js::OpCode::BailOnNotObject,
4687-
bailOutKind,
4688-
primaryBailOutInstr->GetBailOutInfo(),
4689-
callInstr->m_func);
4690-
InsertObjectCheck(funcOpnd, insertBeforeInstr, bailOutIfNotObject);
4691-
4692-
// 2. Bailout if function object is not a TypeId_Function
4693-
IR::Instr* bailOutIfNotJsFunction = IR::BailOutInstr::New(Js::OpCode::BailOnNotEqual, bailOutKind, primaryBailOutInstr->GetBailOutInfo(), callInstr->m_func);
4694-
InsertFunctionTypeIdCheck(funcOpnd, insertBeforeInstr, bailOutIfNotJsFunction);
4631+
IR::AddrOpnd* inlinedFuncInfo = IR::AddrOpnd::New(funcInfo->GetFunctionInfoAddr(), IR::AddrOpndKindDynamicFunctionInfo, insertBeforeInstr->m_func);
4632+
checkFuncInfo->SetSrc2(inlinedFuncInfo);
46954633

4696-
// 3. Bailout if function body doesn't match funcInfo
4697-
InsertFunctionInfoCheck(funcOpnd, insertBeforeInstr, primaryBailOutInstr, funcInfo);
4634+
checkFuncInfo->SetByteCodeOffset(insertBeforeInstr);
4635+
insertBeforeInstr->InsertBefore(checkFuncInfo);
46984636

4699-
return primaryBailOutInstr;
4637+
return checkFuncInfo;
47004638
}
47014639

47024640
IR::ByteCodeUsesInstr*

lib/Backend/Inline.h

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -165,10 +165,7 @@ class Inline
165165
void SetInlineeFrameStartSym(Func *inlinee, uint actualCount);
166166
void CloneCallSequence(IR::Instr* callInstr, IR::Instr* clonedCallInstr);
167167

168-
void InsertObjectCheck(IR::RegOpnd * funcOpnd, IR::Instr* insertBeforeInstr, IR::Instr*bailOutInstr);
169-
void InsertFunctionTypeIdCheck(IR::RegOpnd * funcOpnd, IR::Instr* insertBeforeInstr, IR::Instr*bailOutInstr);
170168
void InsertJsFunctionCheck(IR::Instr * callInstr, IR::Instr *insertBeforeInstr, IR::BailOutKind bailOutKind);
171-
void InsertFunctionInfoCheck(IR::RegOpnd * funcOpnd, IR::Instr *insertBeforeInstr, IR::Instr* bailoutInstr, const FunctionJITTimeInfo *funcInfo);
172169
void InsertFunctionObjectCheck(IR::RegOpnd * funcOpnd, IR::Instr *insertBeforeInstr, IR::Instr* bailoutInstr, const FunctionJITTimeInfo *funcInfo);
173170

174171
void TryResetObjTypeSpecFldInfoOn(IR::PropertySymOpnd* propertySymOpnd);

lib/Backend/Lower.cpp

Lines changed: 110 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2715,6 +2715,14 @@ Lowerer::LowerRange(IR::Instr *instrStart, IR::Instr *instrEnd, bool defaultDoFa
27152715
instrPrev = this->LowerBailOnNotObject(instr);
27162716
break;
27172717

2718+
case Js::OpCode::CheckIsFuncObj:
2719+
instrPrev = this->LowerCheckIsFuncObj(instr);
2720+
break;
2721+
2722+
case Js::OpCode::CheckFuncInfo:
2723+
instrPrev = this->LowerCheckIsFuncObj(instr, true);
2724+
break;
2725+
27182726
case Js::OpCode::BailOnNotBuiltIn:
27192727
instrPrev = this->LowerBailOnNotBuiltIn(instr);
27202728
break;
@@ -12510,7 +12518,52 @@ Lowerer::LowerBailOnNotObject(IR::Instr *instr,
1251012518
return prevInstr;
1251112519
}
1251212520

12513-
IR::Instr *
12521+
IR::Instr*
12522+
Lowerer::LowerCheckIsFuncObj(IR::Instr *instr, bool checkFuncInfo)
12523+
{
12524+
// The CheckIsFuncObj instr and CheckFuncInfo instr (checkFuncInfo = true) are used to
12525+
// generate bailout instrs that type check a function (and can also check the func info).
12526+
// Rather than creating these bailout instrs in Inline, they are created in Lower because
12527+
// CheckIsFuncObj and CheckFuncInfo instrs can be hoisted outside of loops and thus the
12528+
// bailout instrs created can exist outside of loops.
12529+
12530+
IR::RegOpnd *funcOpnd = instr->GetSrc1()->AsRegOpnd();
12531+
IR::BailOutKind bailOutKind = instr->GetBailOutKind();
12532+
BailOutInfo *bailOutInfo = instr->GetBailOutInfo();
12533+
12534+
// Check that the property is an object.
12535+
InsertObjectCheck(funcOpnd, instr, bailOutKind, bailOutInfo);
12536+
12537+
// Check that the object is a function with the correct type ID.
12538+
IR::Instr *lastInstr = InsertFunctionTypeIdCheck(funcOpnd, instr, bailOutKind, bailOutInfo);
12539+
12540+
if (checkFuncInfo)
12541+
{
12542+
// Check that the function body matches the func info.
12543+
lastInstr = InsertFunctionInfoCheck(
12544+
funcOpnd, instr, instr->GetSrc2()->AsAddrOpnd(), bailOutKind, bailOutInfo);
12545+
lastInstr->SetByteCodeOffset(instr);
12546+
}
12547+
12548+
if (bailOutInfo->bailOutInstr == instr)
12549+
{
12550+
// bailOutInstr is currently instr. By changing bailOutInstr to point to lastInstr, the next
12551+
// instruction to be lowered (lastInstr) will create the bailout target. This is necessary in
12552+
// cases where instr does not have a shared bailout (ex: instr was not hoisted outside of a loop).
12553+
bailOutInfo->bailOutInstr = lastInstr;
12554+
}
12555+
12556+
// the CheckFunctionEntryPoint instr exists in order to create the instrs above. It does not have
12557+
// any other purpose and thus it is removed. The instr's BailOutInfo continues to be used and thus
12558+
// must not be deleted. Flags are turned off to stop Remove() from deleting instr's BailOutInfo.
12559+
instr->hasBailOutInfo = false;
12560+
instr->hasAuxBailOut = false;
12561+
instr->Remove();
12562+
12563+
return lastInstr;
12564+
}
12565+
12566+
IR::Instr*
1251412567
Lowerer::LowerBailOnTrue(IR::Instr* instr, IR::LabelInstr* labelBailOut /*nullptr*/)
1251512568
{
1251612569
IR::Instr* instrPrev = instr->m_prev;
@@ -28592,6 +28645,62 @@ Lowerer::InsertAndLegalize(IR::Instr * instr, IR::Instr* insertBeforeInstr)
2859228645
LowererMD::Legalize(instr);
2859328646
}
2859428647

28648+
IR::Instr*
28649+
Lowerer::InsertObjectCheck(IR::RegOpnd *funcOpnd, IR::Instr *insertBeforeInstr, IR::BailOutKind bailOutKind, BailOutInfo *bailOutInfo)
28650+
{
28651+
IR::Instr *bailOutIfNotObject = IR::BailOutInstr::New(Js::OpCode::BailOnNotObject, bailOutKind, bailOutInfo, bailOutInfo->bailOutFunc);
28652+
28653+
// Bailout when funcOpnd is not an object.
28654+
bailOutIfNotObject->SetSrc1(funcOpnd);
28655+
bailOutIfNotObject->SetByteCodeOffset(insertBeforeInstr);
28656+
insertBeforeInstr->InsertBefore(bailOutIfNotObject);
28657+
28658+
return bailOutIfNotObject;
28659+
}
28660+
28661+
IR::Instr*
28662+
Lowerer::InsertFunctionTypeIdCheck(IR::RegOpnd * funcOpnd, IR::Instr* insertBeforeInstr, IR::BailOutKind bailOutKind, BailOutInfo *bailOutInfo)
28663+
{
28664+
IR::Instr *bailOutIfNotFunction = IR::BailOutInstr::New(Js::OpCode::BailOnNotEqual, bailOutKind, bailOutInfo, bailOutInfo->bailOutFunc);
28665+
28666+
// functionTypeRegOpnd = Ld functionRegOpnd->type
28667+
IR::IndirOpnd *functionTypeIndirOpnd = IR::IndirOpnd::New(funcOpnd, Js::RecyclableObject::GetOffsetOfType(), TyMachPtr, insertBeforeInstr->m_func);
28668+
IR::RegOpnd *functionTypeRegOpnd = IR::RegOpnd::New(TyVar, insertBeforeInstr->m_func->GetTopFunc());
28669+
IR::Instr *instr = IR::Instr::New(Js::OpCode::Ld_A, functionTypeRegOpnd, functionTypeIndirOpnd, insertBeforeInstr->m_func);
28670+
if (instr->m_func->HasByteCodeOffset())
28671+
{
28672+
instr->SetByteCodeOffset(insertBeforeInstr);
28673+
}
28674+
insertBeforeInstr->InsertBefore(instr);
28675+
28676+
CompileAssert(sizeof(Js::TypeId) == sizeof(int32));
28677+
// if (functionTypeRegOpnd->typeId != TypeIds_Function) goto $noInlineLabel
28678+
// BrNeq_I4 $noInlineLabel, functionTypeRegOpnd->typeId, TypeIds_Function
28679+
IR::IndirOpnd *functionTypeIdIndirOpnd = IR::IndirOpnd::New(functionTypeRegOpnd, Js::Type::GetOffsetOfTypeId(), TyInt32, insertBeforeInstr->m_func);
28680+
IR::IntConstOpnd *typeIdFunctionConstOpnd = IR::IntConstOpnd::New(Js::TypeIds_Function, TyInt32, insertBeforeInstr->m_func);
28681+
bailOutIfNotFunction->SetSrc1(functionTypeIdIndirOpnd);
28682+
bailOutIfNotFunction->SetSrc2(typeIdFunctionConstOpnd);
28683+
insertBeforeInstr->InsertBefore(bailOutIfNotFunction);
28684+
28685+
return bailOutIfNotFunction;
28686+
}
28687+
28688+
IR::Instr*
28689+
Lowerer::InsertFunctionInfoCheck(IR::RegOpnd * funcOpnd, IR::Instr *insertBeforeInstr, IR::AddrOpnd* inlinedFuncInfo, IR::BailOutKind bailOutKind, BailOutInfo *bailOutInfo)
28690+
{
28691+
IR::Instr *bailOutIfWrongFuncInfo = IR::BailOutInstr::New(Js::OpCode::BailOnNotEqual, bailOutKind, bailOutInfo, bailOutInfo->bailOutFunc);
28692+
28693+
// if (VarTo<JavascriptFunction>(r1)->functionInfo != funcInfo) goto noInlineLabel
28694+
// BrNeq_A noInlineLabel, r1->functionInfo, funcInfo
28695+
IR::IndirOpnd* opndFuncInfo = IR::IndirOpnd::New(funcOpnd, Js::JavascriptFunction::GetOffsetOfFunctionInfo(), TyMachPtr, insertBeforeInstr->m_func);
28696+
bailOutIfWrongFuncInfo->SetSrc1(opndFuncInfo);
28697+
bailOutIfWrongFuncInfo->SetSrc2(inlinedFuncInfo);
28698+
28699+
insertBeforeInstr->InsertBefore(bailOutIfWrongFuncInfo);
28700+
28701+
return bailOutIfWrongFuncInfo;
28702+
}
28703+
2859528704
#if DBG
2859628705
void
2859728706
Lowerer::LegalizeVerifyRange(IR::Instr * instrStart, IR::Instr * instrLast)

lib/Backend/Lower.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -565,6 +565,7 @@ class Lowerer
565565
IR::Instr * LowerBailOnNotPolymorphicInlinee(IR::Instr * instr);
566566
IR::Instr * LowerBailOnNotStackArgs(IR::Instr * instr);
567567
IR::Instr * LowerBailOnNotObject(IR::Instr *instr, IR::BranchInstr *branchInstr = nullptr, IR::LabelInstr *labelBailOut = nullptr);
568+
IR::Instr * LowerCheckIsFuncObj(IR::Instr *instr, bool checkFuncInfo = false);
568569
IR::Instr * LowerBailOnTrue(IR::Instr *instr, IR::LabelInstr *labelBailOut = nullptr);
569570
IR::Instr * LowerBailOnNotBuiltIn(IR::Instr *instr, IR::BranchInstr *branchInstr = nullptr, IR::LabelInstr *labelBailOut = nullptr);
570571
IR::Instr * LowerBailOnNotInteger(IR::Instr *instr, IR::BranchInstr *branchInstr = nullptr, IR::LabelInstr *labelBailOut = nullptr);
@@ -799,6 +800,11 @@ class Lowerer
799800

800801
IR::LabelInstr* InsertLoopTopLabel(IR::Instr * insertBeforeInstr);
801802
IR::Instr * AddBailoutToHelperCallInstr(IR::Instr * helperCallInstr, BailOutInfo * bailoutInfo, IR::BailOutKind bailoutKind, IR::Instr * primaryBailoutInstr);
803+
804+
IR::Instr* InsertObjectCheck(IR::RegOpnd *funcOpnd, IR::Instr *insertBeforeInstr, IR::BailOutKind bailOutKind, BailOutInfo *bailOutInfo);
805+
IR::Instr* InsertFunctionTypeIdCheck(IR::RegOpnd *funcOpnd, IR::Instr *insertBeforeInstr, IR::BailOutKind bailOutKind, BailOutInfo *bailOutInfo);
806+
IR::Instr* InsertFunctionInfoCheck(IR::RegOpnd *funcOpnd, IR::Instr *insertBeforeInstr, IR::AddrOpnd *inlinedFuncInfo, IR::BailOutKind bailOutKind, BailOutInfo *bailOutInfo);
807+
802808
public:
803809
static IRType GetImplicitCallFlagsType()
804810
{

lib/Runtime/ByteCode/OpCodes.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -771,6 +771,8 @@ MACRO_BACKEND_ONLY( InlineRegExpExec, Empty, OpSideEffect|OpInli
771771

772772
MACRO_BACKEND_ONLY( CallIFixed, Empty, OpSideEffect|OpUseAllFields|OpCallInstr|OpInlineCallInstr)
773773
MACRO_BACKEND_ONLY( CheckFixedFld, Empty, OpFastFldInstr|OpTempObjectSources|OpCanCSE)
774+
MACRO_BACKEND_ONLY( CheckIsFuncObj, Empty, OpCanCSE | OpBailOutRec)
775+
MACRO_BACKEND_ONLY( CheckFuncInfo, Empty, OpCanCSE | OpBailOutRec)
774776
MACRO_BACKEND_ONLY( CheckPropertyGuardAndLoadType, Empty, OpFastFldInstr|OpTempObjectSources|OpDoNotTransfer)
775777
MACRO_BACKEND_ONLY( CheckObjType, Empty, OpFastFldInstr|OpTempObjectSources|OpCanCSE)
776778
MACRO_BACKEND_ONLY( AdjustObjType, Empty, OpSideEffect)
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
-489500
2+
TypeError: Function expected
3+
TypeError: Object doesn't support property or method 'foo'
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
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 foo(a,b){ return a + b; }
7+
function bar(a,b){ return a - b; }
8+
9+
var obj = {};
10+
obj.foo = foo;
11+
12+
function test(obj)
13+
{
14+
var count = 0;
15+
16+
for (var i = 0; i < 1000; i++)
17+
{
18+
count += obj.foo(10, i);
19+
}
20+
21+
return count;
22+
}
23+
24+
obj.foo = bar;
25+
WScript.Echo(test(obj));
26+
obj.foo = 10;
27+
try
28+
{
29+
WScript.Echo(test(obj));
30+
}
31+
catch(e)
32+
{
33+
WScript.Echo(e);
34+
}
35+
36+
var obj2 = {};
37+
try
38+
{
39+
WScript.Echo(test(obj2));
40+
}
41+
catch(e)
42+
{
43+
WScript.Echo(e);
44+
}

test/FixedFields/rlexe.xml

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,18 @@
11
<?xml version="1.0" encoding="utf-8"?>
22
<regress-exe>
3+
<test>
4+
<default>
5+
<files>NonFixedFieldHoist.js</files>
6+
<baseline>NonFixedFieldHoist.baseline</baseline>
7+
<compile-flags>-maxinterpretcount:1 -bgjit- -off:simplejit</compile-flags>
8+
</default>
9+
</test>
10+
<test>
11+
<default>
12+
<files>NonFixedFieldHoist.js</files>
13+
<baseline>NonFixedFieldHoist.baseline</baseline>
14+
</default>
15+
</test>
316
<test>
417
<default>
518
<files>FixedFieldsOnSingletons.js</files>

0 commit comments

Comments
 (0)