Skip to content

Commit 55a6e38

Browse files
committed
Share types of CrossSiteObject<ScriptFunction> objects
1 parent cb90e11 commit 55a6e38

File tree

9 files changed

+221
-52
lines changed

9 files changed

+221
-52
lines changed

lib/Common/ConfigFlagsList.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -386,6 +386,7 @@ PHASE(All)
386386
PHASE(ShareTypesWithAttributes)
387387
PHASE(ShareAccessorTypes)
388388
PHASE(ShareFuncTypes)
389+
PHASE(ShareCrossSiteFuncTypes)
389390
PHASE(ConditionalCompilation)
390391
PHASE(InterpreterProfile)
391392
PHASE(InterpreterAutoProfile)

lib/Runtime/Base/FunctionBody.cpp

Lines changed: 43 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1484,6 +1484,8 @@ namespace Js
14841484

14851485
#define CopyDeferParseField(field) other->field = this->field;
14861486
CopyDeferParseField(flags);
1487+
CopyDeferParseField(crossSiteDeferredFunctionType);
1488+
CopyDeferParseField(crossSiteUndeferredFunctionType);
14871489
CopyDeferParseField(m_isDeclaration);
14881490
CopyDeferParseField(m_isAccessor);
14891491
CopyDeferParseField(m_isStrictMode);
@@ -1598,6 +1600,8 @@ namespace Js
15981600
LocalFunctionId functionId, Utf8SourceInfo* sourceInfo, ScriptContext* scriptContext, uint functionNumber,
15991601
const char16* displayName, uint displayNameLength, uint displayShortNameOffset, FunctionInfo::Attributes attributes, FunctionBodyFlags flags) :
16001602
FunctionProxy(scriptContext, sourceInfo, functionNumber),
1603+
crossSiteDeferredFunctionType(nullptr),
1604+
crossSiteUndeferredFunctionType(nullptr),
16011605
#if DYNAMIC_INTERPRETER_THUNK
16021606
m_dynamicInterpreterThunk(nullptr),
16031607
#endif
@@ -2085,6 +2089,28 @@ namespace Js
20852089
undeferredFunctionType = type;
20862090
}
20872091

2092+
ScriptFunctionType * FunctionProxy::GetCrossSiteDeferredFunctionType() const
2093+
{
2094+
return HasParseableInfo() ? GetParseableFunctionInfo()->GetCrossSiteDeferredFunctionType() : nullptr;
2095+
}
2096+
2097+
void FunctionProxy::SetCrossSiteDeferredFunctionType(ScriptFunctionType * type)
2098+
{
2099+
Assert(HasParseableInfo());
2100+
GetParseableFunctionInfo()->SetCrossSiteDeferredFunctionType(type);
2101+
}
2102+
2103+
ScriptFunctionType * FunctionProxy::GetCrossSiteUndeferredFunctionType() const
2104+
{
2105+
return HasParseableInfo() ? GetParseableFunctionInfo()->GetCrossSiteUndeferredFunctionType() : nullptr;
2106+
}
2107+
2108+
void FunctionProxy::SetCrossSiteUndeferredFunctionType(ScriptFunctionType * type)
2109+
{
2110+
Assert(HasParseableInfo());
2111+
GetParseableFunctionInfo()->SetCrossSiteUndeferredFunctionType(type);
2112+
}
2113+
20882114
JavascriptMethod FunctionProxy::GetDirectEntryPoint(ProxyEntryPointInfo* entryPoint) const
20892115
{
20902116
Assert(entryPoint->jsMethod != nullptr);
@@ -4975,6 +5001,14 @@ namespace Js
49755001
this->undeferredFunctionType->SetEntryPoint(this->GetDefaultEntryPointInfo()->jsMethod);
49765002
this->undeferredFunctionType->SetEntryPointInfo(this->GetDefaultEntryPointInfo());
49775003
}
5004+
if (this->crossSiteDeferredFunctionType)
5005+
{
5006+
this->crossSiteDeferredFunctionType->SetEntryPointInfo(this->GetDefaultEntryPointInfo());
5007+
}
5008+
if (this->crossSiteUndeferredFunctionType)
5009+
{
5010+
this->crossSiteUndeferredFunctionType->SetEntryPointInfo(this->GetDefaultEntryPointInfo());
5011+
}
49785012

49795013
#if DBG
49805014
if (!this->HasValidEntryPoint())
@@ -5266,7 +5300,7 @@ namespace Js
52665300
if (this->deferredPrototypeType)
52675301
{
52685302
// Update old entry points on the deferred prototype type,
5269-
// as they may point to old native code gen regions which age gone now.
5303+
// as they may point to old native code gen regions which are gone now.
52705304
this->deferredPrototypeType->SetEntryPoint(this->GetDefaultEntryPointInfo()->jsMethod);
52715305
this->deferredPrototypeType->SetEntryPointInfo(this->GetDefaultEntryPointInfo());
52725306
}
@@ -5275,6 +5309,14 @@ namespace Js
52755309
this->undeferredFunctionType->SetEntryPoint(this->GetDefaultEntryPointInfo()->jsMethod);
52765310
this->undeferredFunctionType->SetEntryPointInfo(this->GetDefaultEntryPointInfo());
52775311
}
5312+
if (this->crossSiteDeferredFunctionType)
5313+
{
5314+
this->crossSiteDeferredFunctionType->SetEntryPointInfo(this->GetDefaultEntryPointInfo());
5315+
}
5316+
if (this->crossSiteUndeferredFunctionType)
5317+
{
5318+
this->crossSiteUndeferredFunctionType->SetEntryPointInfo(this->GetDefaultEntryPointInfo());
5319+
}
52785320
ReinitializeExecutionModeAndLimits();
52795321
}
52805322

lib/Runtime/Base/FunctionBody.h

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1022,6 +1022,7 @@ namespace Js
10221022
void SetEnclosedByGlobalFunc();
10231023
bool CanBeDeferred() const;
10241024
BOOL IsDeferredDeserializeFunction() const;
1025+
BOOL HasParseableInfo() const;
10251026
BOOL IsDeferredParseFunction() const;
10261027
FunctionInfo::Attributes GetAttributes() const;
10271028
void SetAttributes(FunctionInfo::Attributes attributes);
@@ -1057,6 +1058,10 @@ namespace Js
10571058
ScriptFunctionType * EnsureDeferredPrototypeType();
10581059
ScriptFunctionType * GetUndeferredFunctionType() const;
10591060
void SetUndeferredFunctionType(ScriptFunctionType * type);
1061+
ScriptFunctionType * GetCrossSiteDeferredFunctionType() const;
1062+
void SetCrossSiteDeferredFunctionType(ScriptFunctionType * type);
1063+
ScriptFunctionType * GetCrossSiteUndeferredFunctionType() const;
1064+
void SetCrossSiteUndeferredFunctionType(ScriptFunctionType * type);
10601065
JavascriptMethod GetDirectEntryPoint(ProxyEntryPointInfo* entryPoint) const;
10611066

10621067
// Function object type list methods
@@ -1302,6 +1307,13 @@ namespace Js
13021307
return GetFunctionInfo()->IsDeferredDeserializeFunction();
13031308
}
13041309

1310+
inline BOOL FunctionProxy::HasParseableInfo() const
1311+
{
1312+
Assert(GetFunctionInfo());
1313+
Assert(GetFunctionInfo()->GetFunctionProxy() == this);
1314+
return GetFunctionInfo()->HasParseableInfo();
1315+
}
1316+
13051317
inline BOOL FunctionProxy::IsDeferredParseFunction() const
13061318
{
13071319
Assert(GetFunctionInfo());
@@ -1578,6 +1590,11 @@ namespace Js
15781590
uint32 GetGrfscr() const;
15791591
void SetGrfscr(uint32 grfscr);
15801592

1593+
ScriptFunctionType * GetCrossSiteDeferredFunctionType() const { return crossSiteDeferredFunctionType; }
1594+
void SetCrossSiteDeferredFunctionType(ScriptFunctionType * type) { Assert(!crossSiteDeferredFunctionType); crossSiteDeferredFunctionType = type; }
1595+
ScriptFunctionType * GetCrossSiteUndeferredFunctionType() const { return crossSiteUndeferredFunctionType; }
1596+
void SetCrossSiteUndeferredFunctionType(ScriptFunctionType * type) { Assert(!crossSiteUndeferredFunctionType); crossSiteUndeferredFunctionType = type; }
1597+
15811598
///----------------------------------------------------------------------------
15821599
///
15831600
/// ParseableFunctionInfo::GetInParamsCount
@@ -1807,6 +1824,9 @@ namespace Js
18071824
#if DYNAMIC_INTERPRETER_THUNK
18081825
FieldNoBarrier(void*) m_dynamicInterpreterThunk; // Unique 'thunk' for every interpreted function - used for ETW symbol decoding.
18091826
#endif
1827+
FieldWithBarrier(ScriptFunctionType*) crossSiteDeferredFunctionType;
1828+
FieldWithBarrier(ScriptFunctionType*) crossSiteUndeferredFunctionType;
1829+
18101830
FieldWithBarrier(uint) m_cbStartOffset; // pUtf8Source is this many bytes from the start of the scriptContext's source buffer.
18111831
// This is generally the same as m_cchStartOffset unless the buffer has a BOM or other non-ascii characters
18121832
FieldWithBarrier(uint) m_cbStartPrintOffset; // pUtf8Source is this many bytes from the start of the toString-relevant part of the scriptContext's source buffer.

lib/Runtime/Library/JavascriptLibrary.cpp

Lines changed: 91 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -569,7 +569,7 @@ namespace Js
569569
functionWithPrototypeTypeHandler->SetHasKnownSlot0();
570570

571571
externalFunctionWithDeferredPrototypeType = CreateDeferredPrototypeFunctionTypeNoProfileThunk(JavascriptExternalFunction::ExternalFunctionThunk, true /*isShared*/);
572-
externalFunctionWithLengthAndDeferredPrototypeType = CreateDeferredPrototypeFunctionTypeNoProfileThunk(JavascriptExternalFunction::ExternalFunctionThunk, true /*isShared*/, /* isLengthAvailable */ true);
572+
externalFunctionWithLengthAndDeferredPrototypeType = CreateDeferredLengthPrototypeFunctionTypeNoProfileThunk(JavascriptExternalFunction::ExternalFunctionThunk, true /*isShared*/);
573573
wrappedFunctionWithDeferredPrototypeType = CreateDeferredPrototypeFunctionTypeNoProfileThunk(JavascriptExternalFunction::WrappedFunctionThunk, true /*isShared*/);
574574
stdCallFunctionWithDeferredPrototypeType = CreateDeferredPrototypeFunctionTypeNoProfileThunk(JavascriptExternalFunction::StdCallExternalFunctionThunk, true /*isShared*/);
575575
idMappedFunctionWithPrototypeType = DynamicType::New(scriptContext, TypeIds_Function, functionPrototype, JavascriptExternalFunction::ExternalFunctionThunk,
@@ -581,6 +581,8 @@ namespace Js
581581

582582
boundFunctionType = DynamicType::New(scriptContext, TypeIds_Function, functionPrototype, BoundFunction::NewInstance,
583583
GetDeferredFunctionTypeHandler(), true, true);
584+
crossSiteDeferredFunctionType = CreateDeferredFunctionTypeNoProfileThunk(
585+
scriptContext->CurrentCrossSiteThunk, true /*isShared*/);
584586
crossSiteDeferredPrototypeFunctionType = CreateDeferredPrototypeFunctionTypeNoProfileThunk(
585587
scriptContext->CurrentCrossSiteThunk, true /*isShared*/);
586588
crossSiteIdMappedFunctionWithPrototypeType = DynamicType::New(scriptContext, TypeIds_Function, functionPrototype, scriptContext->CurrentCrossSiteThunk,
@@ -1008,20 +1010,51 @@ namespace Js
10081010
isAnonymousFunction ? GetDeferredAnonymousPrototypeAsyncFunctionTypeHandler() : GetDeferredPrototypeAsyncFunctionTypeHandler(scriptContext), isShared, isShared);
10091011
}
10101012

1013+
DynamicType * JavascriptLibrary::CreateDeferredFunctionType(JavascriptMethod entrypoint)
1014+
{
1015+
return CreateDeferredFunctionTypeNoProfileThunk(this->inDispatchProfileMode ? ProfileEntryThunk : entrypoint);
1016+
}
1017+
10111018
DynamicType * JavascriptLibrary::CreateDeferredPrototypeFunctionType(JavascriptMethod entrypoint)
10121019
{
10131020
return CreateDeferredPrototypeFunctionTypeNoProfileThunk(this->inDispatchProfileMode ? ProfileEntryThunk : entrypoint);
10141021
}
10151022

1016-
DynamicType * JavascriptLibrary::CreateDeferredPrototypeFunctionTypeNoProfileThunk(JavascriptMethod entrypoint, bool isShared, bool isLengthAvailable)
1023+
DynamicType * JavascriptLibrary::CreateDeferredFunctionTypeNoProfileThunk(JavascriptMethod entryPoint, bool isShared)
1024+
{
1025+
return CreateDeferredFunctionTypeNoProfileThunk_Internal<false, false>(entryPoint, isShared);
1026+
}
1027+
1028+
DynamicType * JavascriptLibrary::CreateDeferredLengthFunctionTypeNoProfileThunk(JavascriptMethod entryPoint, bool isShared)
1029+
{
1030+
return CreateDeferredFunctionTypeNoProfileThunk_Internal<true, false>(entryPoint, isShared);
1031+
}
1032+
1033+
DynamicType * JavascriptLibrary::CreateDeferredPrototypeFunctionTypeNoProfileThunk(JavascriptMethod entryPoint, bool isShared)
1034+
{
1035+
return CreateDeferredFunctionTypeNoProfileThunk_Internal<false, true>(entryPoint, isShared);
1036+
}
1037+
1038+
DynamicType * JavascriptLibrary::CreateDeferredLengthPrototypeFunctionTypeNoProfileThunk(JavascriptMethod entryPoint, bool isShared)
1039+
{
1040+
return CreateDeferredFunctionTypeNoProfileThunk_Internal<true, true>(entryPoint, isShared);
1041+
}
1042+
1043+
template<bool isLengthAvailable, bool isPrototypeAvailable>
1044+
DynamicType * JavascriptLibrary::CreateDeferredFunctionTypeNoProfileThunk_Internal(JavascriptMethod entrypoint, bool isShared)
10171045
{
10181046
// Note: the lack of TypeHandler switching here based on the isAnonymousFunction flag is intentional.
10191047
// We can't switch shared typeHandlers and RuntimeFunctions do not produce script code for us to know if a function is Anonymous.
10201048
// As a result we may have an issue where hasProperty would say you have a name property but getProperty returns undefined
1021-
return DynamicType::New(scriptContext, TypeIds_Function, functionPrototype, entrypoint,
1022-
isLengthAvailable ? GetDeferredPrototypeFunctionWithLengthTypeHandler(scriptContext) : GetDeferredPrototypeFunctionTypeHandler(scriptContext),
1023-
isShared, isShared);
1049+
DynamicTypeHandler * typeHandler =
1050+
isLengthAvailable ?
1051+
(isPrototypeAvailable ?
1052+
GetDeferredPrototypeFunctionWithLengthTypeHandler(scriptContext) : GetDeferredFunctionWithLengthTypeHandler()) :
1053+
(isPrototypeAvailable ?
1054+
GetDeferredPrototypeFunctionTypeHandler(scriptContext) : GetDeferredFunctionTypeHandler());
1055+
return DynamicType::New(scriptContext, TypeIds_Function, functionPrototype, entrypoint, typeHandler, isShared, isShared);
10241056
}
1057+
10251058
DynamicType * JavascriptLibrary::CreateFunctionType(JavascriptMethod entrypoint, RecyclableObject* prototype)
10261059
{
10271060
if (prototype == nullptr)
@@ -5200,11 +5233,7 @@ namespace Js
52005233
{
52015234
Assert(function->GetDynamicType()->GetIsLocked());
52025235

5203-
if (VarIs<ScriptFunction>(function))
5204-
{
5205-
this->SetCrossSiteForLockedNonBuiltInFunctionType(function);
5206-
}
5207-
else if (VarIs<BoundFunction>(function))
5236+
if (VarIs<ScriptFunction>(function) || VarIs<BoundFunction>(function))
52085237
{
52095238
this->SetCrossSiteForLockedNonBuiltInFunctionType(function);
52105239
}
@@ -5216,6 +5245,11 @@ namespace Js
52165245
{
52175246
function->ReplaceType(crossSiteDeferredPrototypeFunctionType);
52185247
}
5248+
else if (typeHandler == JavascriptLibrary::GetDeferredFunctionTypeHandler()
5249+
|| typeHandler == JavascriptLibrary::GetDeferredFunctionWithLengthTypeHandler())
5250+
{
5251+
function->ReplaceType(crossSiteDeferredFunctionType);
5252+
}
52195253
else if (typeHandler == Js::DeferredTypeHandler<Js::JavascriptExternalFunction::DeferredConstructorInitializer>::GetDefaultInstance())
52205254
{
52215255
function->ReplaceType(crossSiteExternalConstructFunctionWithPrototypeType);
@@ -5233,16 +5267,58 @@ namespace Js
52335267

52345268
void JavascriptLibrary::SetCrossSiteForLockedNonBuiltInFunctionType(JavascriptFunction * function)
52355269
{
5270+
FunctionProxy * functionProxy = function->GetFunctionProxy();
52365271
DynamicTypeHandler *typeHandler = function->GetTypeHandler();
5237-
if (typeHandler->IsPathTypeHandler())
5272+
if (typeHandler->IsDeferredTypeHandler())
52385273
{
5239-
PathTypeHandlerBase::FromTypeHandler(typeHandler)->ConvertToNonShareableTypeHandler(function);
5274+
if (functionProxy && functionProxy->GetCrossSiteDeferredFunctionType())
5275+
{
5276+
function->ReplaceType(functionProxy->GetCrossSiteDeferredFunctionType());
5277+
}
5278+
else
5279+
{
5280+
function->ChangeType();
5281+
function->SetEntryPoint(scriptContext->CurrentCrossSiteThunk);
5282+
if (functionProxy && functionProxy->HasParseableInfo() && !PHASE_OFF1(ShareCrossSiteFuncTypesPhase))
5283+
{
5284+
function->ShareType();
5285+
functionProxy->SetCrossSiteDeferredFunctionType(UnsafeVarTo<ScriptFunction>(function)->GetScriptFunctionType());
5286+
}
5287+
}
52405288
}
5241-
else
5289+
else
52425290
{
5243-
function->ChangeType();
5291+
if (functionProxy && functionProxy->GetCrossSiteUndeferredFunctionType())
5292+
{
5293+
function->ReplaceType(functionProxy->GetCrossSiteUndeferredFunctionType());
5294+
}
5295+
else
5296+
{
5297+
if (typeHandler->IsPathTypeHandler())
5298+
{
5299+
if (!PHASE_OFF1(ShareCrossSiteFuncTypesPhase))
5300+
{
5301+
DynamicType *type = function->DuplicateType();
5302+
PathTypeHandlerBase::FromTypeHandler(typeHandler)->BuildPathTypeFromNewRoot(function, &type);
5303+
function->ReplaceType(type);
5304+
}
5305+
else
5306+
{
5307+
PathTypeHandlerBase::FromTypeHandler(typeHandler)->ConvertToNonShareableTypeHandler(function);
5308+
}
5309+
}
5310+
else
5311+
{
5312+
function->ChangeType();
5313+
}
5314+
function->SetEntryPoint(scriptContext->CurrentCrossSiteThunk);
5315+
if (functionProxy && functionProxy->HasParseableInfo() && function->GetTypeHandler()->GetMayBecomeShared() && !PHASE_OFF1(ShareCrossSiteFuncTypesPhase))
5316+
{
5317+
function->ShareType();
5318+
functionProxy->SetCrossSiteUndeferredFunctionType(UnsafeVarTo<ScriptFunction>(function)->GetScriptFunctionType());
5319+
}
5320+
}
52445321
}
5245-
function->SetEntryPoint(scriptContext->CurrentCrossSiteThunk);
52465322
}
52475323

52485324
JavascriptExternalFunction*

lib/Runtime/Library/JavascriptLibrary.h

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -298,6 +298,7 @@ namespace Js
298298
Field(DynamicType *) defaultExternalConstructorFunctionWithDeferredPrototypeType;
299299
Field(DynamicType *) boundFunctionType;
300300
Field(DynamicType *) regexConstructorType;
301+
Field(DynamicType *) crossSiteDeferredFunctionType;
301302
Field(DynamicType *) crossSiteDeferredPrototypeFunctionType;
302303
Field(DynamicType *) crossSiteIdMappedFunctionWithPrototypeType;
303304
Field(DynamicType *) crossSiteExternalConstructFunctionWithPrototypeType;
@@ -933,8 +934,13 @@ namespace Js
933934
template<bool isNameAvailable>
934935
static DynamicTypeHandler * GetDeferredAsyncFunctionTypeHandlerBase();
935936

937+
DynamicType * CreateDeferredFunctionType(JavascriptMethod entrypoint);
936938
DynamicType * CreateDeferredPrototypeFunctionType(JavascriptMethod entrypoint);
937-
DynamicType * CreateDeferredPrototypeFunctionTypeNoProfileThunk(JavascriptMethod entrypoint, bool isShared = false, bool isLengthAvailable = false);
939+
DynamicType * CreateDeferredPrototypeFunctionTypeNoProfileThunk(JavascriptMethod entrypoint, bool isShared = false);
940+
DynamicType * CreateDeferredFunctionTypeNoProfileThunk(JavascriptMethod entrypoint, bool isShared = false);
941+
DynamicType * CreateDeferredLengthPrototypeFunctionTypeNoProfileThunk(JavascriptMethod entrypoint, bool isShared = false);
942+
DynamicType * CreateDeferredLengthFunctionTypeNoProfileThunk(JavascriptMethod entrypoint, bool isShared = false);
943+
template<bool isLengthAvailable, bool isPrototypeAvailable> DynamicType * CreateDeferredFunctionTypeNoProfileThunk_Internal(JavascriptMethod entrypoint, bool isShared);
938944
DynamicType * CreateFunctionType(JavascriptMethod entrypoint, RecyclableObject* prototype = nullptr);
939945
DynamicType * CreateFunctionWithConfigurableLengthType(FunctionInfo * functionInfo);
940946
DynamicType * CreateFunctionWithLengthType(FunctionInfo * functionInfo);

0 commit comments

Comments
 (0)