Skip to content

Commit c8740cc

Browse files
committed
inline JsBuiltIn helper CallInstanceFunction
JsBuiltIns cannot do ```callback.call(thisArg, ...)``` because ```.call``` is loaded off the function prototype which could be changed a user. CallInstanceFunction performs the same operation, taking the form ```CallInstanceFunction(callback, thisArg, ...)```. This commit results in ```callback``` being directly inlined.
1 parent b45b70b commit c8740cc

22 files changed

+3222
-3427
lines changed

lib/Backend/Inline.cpp

Lines changed: 90 additions & 35 deletions
Large diffs are not rendered by default.

lib/Backend/Inline.h

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ class Inline
6262
#endif
6363
IR::Instr * InlineGetterSetterFunction(IR::Instr *accessorInstr, const FunctionJITTimeInfo *const inlineeData, const StackSym *symCallerThis, const uint inlineCacheIndex, bool isGetter, bool *pIsInlined, uint recursiveInlineDepth);
6464
IR::Instr * InlineFunctionCommon(IR::Instr *callInstr, bool originalCallTargetOpndIsJITOpt, StackSym* originalCallTargetStackSym, const FunctionJITTimeInfo *funcInfo, Func *inlinee, IR::Instr *instrNext,
65-
IR::RegOpnd * returnValueOpnd, IR::Instr *inlineBailoutChecksBeforeInstr, const StackSym *symCallerThis, uint recursiveInlineDepth, bool safeThis = false, bool isApplyTarget = false, bool isCallbackCallApplyTarget = false);
65+
IR::RegOpnd * returnValueOpnd, IR::Instr *inlineBailoutChecksBeforeInstr, const StackSym *symCallerThis, uint recursiveInlineDepth, bool safeThis = false, bool isApplyTarget = false);
6666
IR::Instr * SimulateCallForGetterSetter(IR::Instr *accessorInstr, IR::Instr* insertInstr, IR::PropertySymOpnd* methodOpnd, bool isGetter);
6767

6868
IR::Instr * InlineApply(IR::Instr *callInstr, const FunctionJITTimeInfo * applyData, const FunctionJITTimeInfo * inlinerData, const StackSym *symThis, bool* pIsInlined, uint callSiteId, uint recursiveInlineDepth, uint argsCount);
@@ -73,11 +73,12 @@ class Inline
7373
const StackSym *symThis, IR::Instr ** returnInstr, uint recursiveInlineDepth, bool isArrayOpndArgumentsObject, uint argsCount);
7474
void GetArgInstrsForCallAndApply(IR::Instr* callInstr, IR::Instr** implicitThisArgOut, IR::Instr** explicitThisArgOut, IR::Instr** argumentsOrArrayArgOut, uint &argOutCount);
7575
_Success_(return != false) bool TryGetCallApplyAndTargetLdInstrs(IR::Instr * callInstr, _Outptr_result_nullonfailure_ IR::Instr ** callApplyLdInstr, _Outptr_result_nullonfailure_ IR::Instr ** callApplyTargetLdInstr);
76-
IR::Instr * InlineCall(IR::Instr *callInstr, const FunctionJITTimeInfo * inlineeData, const FunctionJITTimeInfo * inlinerData, const StackSym *symThis, bool* pIsInlined, uint callSiteId, uint recursiveInlineDepth);
76+
IR::Instr * InlineCall(IR::Instr *callInstr, const FunctionJITTimeInfo * inlineeData, const FunctionJITTimeInfo * inlinerData, const StackSym *symThis, bool* pIsInlined, uint callSiteId, uint recursiveInlineDepth, bool isCallInstanceFunction);
7777
bool InlineCallTarget(IR::Instr *callInstr, const FunctionJITTimeInfo* inlinerData, const FunctionJITTimeInfo** pInlineeData, const FunctionJITTimeInfo *callFuncInfo,
78-
const StackSym *symThis, IR::Instr ** returnInstr, uint recursiveInlineDepth);
78+
const StackSym *symThis, IR::Instr ** returnInstr, uint recursiveInlineDepth, bool isCallInstanceFunction);
7979

80-
bool TryGetCallApplyInlineeData(const FunctionJITTimeInfo* inlinerData, IR::Instr * callApplyLdInstr, IR::Instr * callApplyTargetLdInstr, const FunctionJITTimeInfo ** inlineeData, Js::InlineCacheIndex * inlineCacheIndex, IR::Instr ** callbackDefInstr);
80+
bool TryGetCallApplyInlineeData(const FunctionJITTimeInfo* inlinerData, IR::Instr * callInstr, IR::Instr * callApplyLdInstr, IR::Instr * callApplyTargetLdInstr, const FunctionJITTimeInfo ** inlineeData, Js::InlineCacheIndex * inlineCacheIndex,
81+
IR::Instr ** callbackDefInstr, bool isCallInstanceFunction);
8182

8283
bool InlConstFoldArg(IR::Instr *instr, __in_ecount_opt(callerArgOutCount) IR::Instr *callerArgOuts[], Js::ArgSlot callerArgOutCount);
8384
bool InlConstFold(IR::Instr *instr, IntConstType *pValue, __in_ecount_opt(callerArgOutCount) IR::Instr *callerArgOuts[], Js::ArgSlot callerArgOutCount);
@@ -100,6 +101,7 @@ class Inline
100101
IR::Instr * TryGetCallbackDefInstr(StackSym * callbackSym);
101102
IR::Instr * TryGetCallbackDefInstrForCallInstr(IR::Instr * callInstr);
102103
IR::Instr * TryGetCallbackDefInstrForCallApplyTarget(IR::Instr * callApplyLdInstr);
104+
IR::Instr * TryGetCallbackDefInstrForCallInstanceFunction(IR::Instr * callInstr);
103105

104106
IR::Instr * InlineSpread(IR::Instr *spreadCall);
105107

@@ -108,7 +110,7 @@ class Inline
108110
void SetupInlineeFrame(Func *inlinee, IR::Instr *inlineeStart, Js::ArgSlot actualCount, IR::Opnd *functionObject);
109111
void FixupExtraActualParams(IR::Instr * instr, IR::Instr *argOuts[], IR::Instr *argOutsExtra[], uint index, uint actualCount, Js::ProfileId callSiteId);
110112
void RemoveExtraFixupArgouts(IR::Instr* instr, uint argoutRemoveCount, Js::ProfileId callSiteId);
111-
IR::Instr* PrepareInsertionPoint(IR::Instr *callInstr, const FunctionJITTimeInfo *funcInfo, IR::Instr *insertBeforeInstr, bool isCallbackCallApplyTarget = false);
113+
IR::Instr* PrepareInsertionPoint(IR::Instr *callInstr, const FunctionJITTimeInfo *funcInfo, IR::Instr *insertBeforeInstr);
112114
IR::ByteCodeUsesInstr* EmitFixedMethodOrFunctionObjectChecksForBuiltIns(IR::Instr *callInstr, IR::Instr * funcObjCheckInsertInstr, const FunctionJITTimeInfo * inlineeInfo, bool isPolymorphic, bool isBuiltIn, bool isCtor, bool isInlined);
113115
Js::ArgSlot MapActuals(IR::Instr *callInstr, __out_ecount(maxParamCount) IR::Instr *argOuts[], Js::ArgSlot formalCount, Func *inlinee, Js::ProfileId callSiteId, bool *stackArgsArgOutExpanded, IR::Instr *argOutsExtra[] = nullptr, Js::ArgSlot maxParamCount = Js::InlineeCallInfo::MaxInlineeArgoutCount);
114116
uint32 CountActuals(IR::Instr *callIntr);

lib/Backend/InliningDecider.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -553,6 +553,9 @@ bool InliningDecider::GetBuiltInInfoCommon(
553553
case Js::JavascriptBuiltInFunction::JavascriptFunction_Call:
554554
*inlineCandidateOpCode = Js::OpCode::InlineFunctionCall;
555555
break;
556+
case Js::JavascriptBuiltInFunction::EngineInterfaceObject_CallInstanceFunction:
557+
*inlineCandidateOpCode = Js::OpCode::InlineCallInstanceFunction;
558+
break;
556559

557560
// The following are not currently inlined, but are tracked for their return type
558561
// TODO: Add more built-ins that return objects. May consider tracking all built-ins.

lib/Common/ConfigFlagsList.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -586,6 +586,7 @@ PHASE(All)
586586
#endif
587587
#define DEFAULT_CONFIG_JitRepro (false)
588588
#define DEFAULT_CONFIG_LdChakraLib (false)
589+
#define DEFAULT_CONFIG_TestChakraLib (false)
589590
#define DEFAULT_CONFIG_EntryPointInfoRpcData (false)
590591

591592
// ES6 DEFAULT BEHAVIOR
@@ -1074,6 +1075,7 @@ FLAGNR(Boolean, JitRepro , "Add Function.invokeJit to execute codeg
10741075
FLAGNR(Boolean, EntryPointInfoRpcData , "Keep encoded rpc buffer for jitted function on EntryPointInfo until cleanup", DEFAULT_CONFIG_EntryPointInfoRpcData)
10751076

10761077
FLAGNR(Boolean, LdChakraLib , "Access to the Chakra internal library with the __chakraLibrary keyword", DEFAULT_CONFIG_LdChakraLib)
1078+
FLAGNR(Boolean, TestChakraLib , "Access to the Chakra internal library with the __chakraLibrary keyword without global access restriction", DEFAULT_CONFIG_TestChakraLib)
10771079
// ES6 (BLUE+1) features/flags
10781080

10791081
// Master ES6 flag to enable STABLE ES6 features/flags

lib/Runtime/ByteCode/ByteCodeEmitter.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5128,7 +5128,8 @@ void ByteCodeGenerator::EmitPropLoad(Js::RegSlot lhsLocation, Symbol *sym, Ident
51285128
opcode = Js::OpCode::LdUndef;
51295129
break;
51305130
case Js::PropertyIds::__chakraLibrary:
5131-
if (CONFIG_FLAG(LdChakraLib)) {
5131+
if (CONFIG_FLAG(LdChakraLib) || CONFIG_FLAG(TestChakraLib))
5132+
{
51325133
opcode = Js::OpCode::LdChakraLib;
51335134
}
51345135
break;

lib/Runtime/ByteCode/OpCodes.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -765,6 +765,7 @@ MACRO_BACKEND_ONLY( InlineArrayPop, Empty, OpSideEffect|OpInli
765765
MACRO_BACKEND_ONLY( InlineArrayPush, Empty, OpSideEffect|OpInlinableBuiltIn|OpHasImplicitCall)
766766
MACRO_BACKEND_ONLY( InlineFunctionApply, Empty, OpSideEffect|OpInlinableBuiltIn)
767767
MACRO_BACKEND_ONLY( InlineFunctionCall, Empty, OpSideEffect|OpInlinableBuiltIn)
768+
MACRO_BACKEND_ONLY( InlineCallInstanceFunction, Empty, OpSideEffect|OpInlinableBuiltIn)
768769
MACRO_BACKEND_ONLY( InlineRegExpExec, Empty, OpSideEffect|OpInlinableBuiltIn)
769770

770771
MACRO_BACKEND_ONLY( CallIFixed, Empty, OpSideEffect|OpUseAllFields|OpCallInstr|OpInlineCallInstr)

lib/Runtime/Library/EngineInterfaceObject.cpp

Lines changed: 5 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -107,7 +107,6 @@ namespace Js
107107
NoProfileFunctionInfo EngineInterfaceObject::EntryInfo::SetPrototype(FORCE_NO_WRITE_BARRIER_TAG(EngineInterfaceObject::Entry_SetPrototype));
108108
NoProfileFunctionInfo EngineInterfaceObject::EntryInfo::GetArrayLength(FORCE_NO_WRITE_BARRIER_TAG(EngineInterfaceObject::Entry_GetArrayLength));
109109
NoProfileFunctionInfo EngineInterfaceObject::EntryInfo::RegexMatch(FORCE_NO_WRITE_BARRIER_TAG(EngineInterfaceObject::Entry_RegexMatch));
110-
NoProfileFunctionInfo EngineInterfaceObject::EntryInfo::CallInstanceFunction(FORCE_NO_WRITE_BARRIER_TAG(EngineInterfaceObject::Entry_CallInstanceFunction));
111110

112111
#ifndef GlobalBuiltIn
113112
#define GlobalBuiltIn(global, method) \
@@ -426,8 +425,7 @@ namespace Js
426425
{
427426
EngineInterfaceObject_CommonFunctionProlog(function, callInfo);
428427

429-
Assert(args.Info.Count <= 5);
430-
if (callInfo.Count < 3 || args.Info.Count > 5 || !JavascriptConversion::IsCallable(args.Values[1]) || !RecyclableObject::Is(args.Values[2]))
428+
if (callInfo.Count < 3 || !JavascriptConversion::IsCallable(args.Values[1]) || !RecyclableObject::Is(args.Values[2]))
431429
{
432430
return scriptContext->GetLibrary()->GetUndefined();
433431
}
@@ -437,19 +435,16 @@ namespace Js
437435
AssertOrFailFastMsg(func != scriptContext->GetLibrary()->GetUndefined(), "Trying to callInstanceFunction(undefined, ...)");
438436

439437
//Shift the arguments by 2 so argument at index 2 becomes the 'this' argument at index 0
440-
Var newVars[3];
441-
Js::Arguments newArgs(callInfo, newVars);
442-
443-
for (uint i = 0; i<args.Info.Count - 2; ++i)
438+
for (uint i = 0; i < args.Info.Count - 2; ++i)
444439
{
445-
newArgs.Values[i] = args.Values[i + 2];
440+
args.Values[i] = args.Values[i + 2];
446441
}
447442

448-
newArgs.Info.Count = args.Info.Count - 2;
443+
args.Info.Count -= 2;
449444

450445
BEGIN_SAFE_REENTRANT_CALL(scriptContext->GetThreadContext())
451446
{
452-
return JavascriptFunction::CallFunction<true>(func, func->GetEntryPoint(), newArgs);
447+
return JavascriptFunction::CallFunction<true>(func, func->GetEntryPoint(), args);
453448
}
454449
END_SAFE_REENTRANT_CALL
455450
}

lib/Runtime/Library/EngineInterfaceObject.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -97,7 +97,7 @@ namespace Js
9797
static NoProfileFunctionInfo SetPrototype;
9898
static NoProfileFunctionInfo GetArrayLength;
9999
static NoProfileFunctionInfo RegexMatch;
100-
static NoProfileFunctionInfo CallInstanceFunction;
100+
static FunctionInfo CallInstanceFunction;
101101

102102
#ifndef GlobalBuiltIn
103103
#define GlobalBuiltIn(global, method) \

lib/Runtime/Library/JavascriptBuiltInFunctionList.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -505,4 +505,6 @@ BUILTIN(AtomicsObject, Wait, EntryWait, FunctionInfo::ErrorOnNew)
505505
BUILTIN(AtomicsObject, Notify, EntryNotify, FunctionInfo::ErrorOnNew)
506506
BUILTIN(AtomicsObject, Xor, EntryXor, FunctionInfo::ErrorOnNew)
507507

508+
BUILTIN(EngineInterfaceObject, CallInstanceFunction, Entry_CallInstanceFunction, FunctionInfo::ErrorOnNew | FunctionInfo::DoNotProfile)
509+
508510
#undef BUILTIN_TEMPLATE

lib/Runtime/Library/JavascriptBuiltInFunctions.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
// Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
44
//-------------------------------------------------------------------------------------------------------
55
#include "RuntimeLibraryPch.h"
6+
#include "EngineInterfaceObject.h"
67

78
namespace Js
89
{

0 commit comments

Comments
 (0)