Skip to content

Commit 93752a1

Browse files
committed
[MERGE #5794 @pleath] Share types of CrossSiteObject<ScriptFunction> objects
Merge pull request #5794 from pleath:sharecrosssitefunctypes-m Designated a cross-site DeferredTypeHandler type and PathTypeHandler type (if appropriate) for each FunctionProxy.
2 parents ffebc17 + 61b61fd commit 93752a1

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
@@ -388,6 +388,7 @@ PHASE(All)
388388
PHASE(ShareTypesWithAttributes)
389389
PHASE(ShareAccessorTypes)
390390
PHASE(ShareFuncTypes)
391+
PHASE(ShareCrossSiteFuncTypes)
391392
PHASE(ConditionalCompilation)
392393
PHASE(InterpreterProfile)
393394
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);
@@ -4984,6 +5010,14 @@ namespace Js
49845010
this->undeferredFunctionType->SetEntryPoint(this->GetDefaultEntryPointInfo()->jsMethod);
49855011
this->undeferredFunctionType->SetEntryPointInfo(this->GetDefaultEntryPointInfo());
49865012
}
5013+
if (this->crossSiteDeferredFunctionType)
5014+
{
5015+
this->crossSiteDeferredFunctionType->SetEntryPointInfo(this->GetDefaultEntryPointInfo());
5016+
}
5017+
if (this->crossSiteUndeferredFunctionType)
5018+
{
5019+
this->crossSiteUndeferredFunctionType->SetEntryPointInfo(this->GetDefaultEntryPointInfo());
5020+
}
49875021

49885022
#if DBG
49895023
if (!this->HasValidEntryPoint())
@@ -5275,7 +5309,7 @@ namespace Js
52755309
if (this->deferredPrototypeType)
52765310
{
52775311
// Update old entry points on the deferred prototype type,
5278-
// as they may point to old native code gen regions which age gone now.
5312+
// as they may point to old native code gen regions which are gone now.
52795313
this->deferredPrototypeType->SetEntryPoint(this->GetDefaultEntryPointInfo()->jsMethod);
52805314
this->deferredPrototypeType->SetEntryPointInfo(this->GetDefaultEntryPointInfo());
52815315
}
@@ -5284,6 +5318,14 @@ namespace Js
52845318
this->undeferredFunctionType->SetEntryPoint(this->GetDefaultEntryPointInfo()->jsMethod);
52855319
this->undeferredFunctionType->SetEntryPointInfo(this->GetDefaultEntryPointInfo());
52865320
}
5321+
if (this->crossSiteDeferredFunctionType)
5322+
{
5323+
this->crossSiteDeferredFunctionType->SetEntryPointInfo(this->GetDefaultEntryPointInfo());
5324+
}
5325+
if (this->crossSiteUndeferredFunctionType)
5326+
{
5327+
this->crossSiteUndeferredFunctionType->SetEntryPointInfo(this->GetDefaultEntryPointInfo());
5328+
}
52875329
ReinitializeExecutionModeAndLimits();
52885330
}
52895331

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
@@ -583,7 +583,7 @@ namespace Js
583583
functionWithPrototypeTypeHandler->SetHasKnownSlot0();
584584

585585
externalFunctionWithDeferredPrototypeType = CreateDeferredPrototypeFunctionTypeNoProfileThunk(JavascriptExternalFunction::ExternalFunctionThunk, true /*isShared*/);
586-
externalFunctionWithLengthAndDeferredPrototypeType = CreateDeferredPrototypeFunctionTypeNoProfileThunk(JavascriptExternalFunction::ExternalFunctionThunk, true /*isShared*/, /* isLengthAvailable */ true);
586+
externalFunctionWithLengthAndDeferredPrototypeType = CreateDeferredLengthPrototypeFunctionTypeNoProfileThunk(JavascriptExternalFunction::ExternalFunctionThunk, true /*isShared*/);
587587
wrappedFunctionWithDeferredPrototypeType = CreateDeferredPrototypeFunctionTypeNoProfileThunk(JavascriptExternalFunction::WrappedFunctionThunk, true /*isShared*/);
588588
stdCallFunctionWithDeferredPrototypeType = CreateDeferredPrototypeFunctionTypeNoProfileThunk(JavascriptExternalFunction::StdCallExternalFunctionThunk, true /*isShared*/);
589589
idMappedFunctionWithPrototypeType = DynamicType::New(scriptContext, TypeIds_Function, functionPrototype, JavascriptExternalFunction::ExternalFunctionThunk,
@@ -595,6 +595,8 @@ namespace Js
595595

596596
boundFunctionType = DynamicType::New(scriptContext, TypeIds_Function, functionPrototype, BoundFunction::NewInstance,
597597
GetDeferredFunctionTypeHandler(), true, true);
598+
crossSiteDeferredFunctionType = CreateDeferredFunctionTypeNoProfileThunk(
599+
scriptContext->CurrentCrossSiteThunk, true /*isShared*/);
598600
crossSiteDeferredPrototypeFunctionType = CreateDeferredPrototypeFunctionTypeNoProfileThunk(
599601
scriptContext->CurrentCrossSiteThunk, true /*isShared*/);
600602
crossSiteIdMappedFunctionWithPrototypeType = DynamicType::New(scriptContext, TypeIds_Function, functionPrototype, scriptContext->CurrentCrossSiteThunk,
@@ -1022,20 +1024,51 @@ namespace Js
10221024
isAnonymousFunction ? GetDeferredAnonymousPrototypeAsyncFunctionTypeHandler() : GetDeferredPrototypeAsyncFunctionTypeHandler(scriptContext), isShared, isShared);
10231025
}
10241026

1027+
DynamicType * JavascriptLibrary::CreateDeferredFunctionType(JavascriptMethod entrypoint)
1028+
{
1029+
return CreateDeferredFunctionTypeNoProfileThunk(this->inDispatchProfileMode ? ProfileEntryThunk : entrypoint);
1030+
}
1031+
10251032
DynamicType * JavascriptLibrary::CreateDeferredPrototypeFunctionType(JavascriptMethod entrypoint)
10261033
{
10271034
return CreateDeferredPrototypeFunctionTypeNoProfileThunk(this->inDispatchProfileMode ? ProfileEntryThunk : entrypoint);
10281035
}
10291036

1030-
DynamicType * JavascriptLibrary::CreateDeferredPrototypeFunctionTypeNoProfileThunk(JavascriptMethod entrypoint, bool isShared, bool isLengthAvailable)
1037+
DynamicType * JavascriptLibrary::CreateDeferredFunctionTypeNoProfileThunk(JavascriptMethod entryPoint, bool isShared)
1038+
{
1039+
return CreateDeferredFunctionTypeNoProfileThunk_Internal<false, false>(entryPoint, isShared);
1040+
}
1041+
1042+
DynamicType * JavascriptLibrary::CreateDeferredLengthFunctionTypeNoProfileThunk(JavascriptMethod entryPoint, bool isShared)
1043+
{
1044+
return CreateDeferredFunctionTypeNoProfileThunk_Internal<true, false>(entryPoint, isShared);
1045+
}
1046+
1047+
DynamicType * JavascriptLibrary::CreateDeferredPrototypeFunctionTypeNoProfileThunk(JavascriptMethod entryPoint, bool isShared)
1048+
{
1049+
return CreateDeferredFunctionTypeNoProfileThunk_Internal<false, true>(entryPoint, isShared);
1050+
}
1051+
1052+
DynamicType * JavascriptLibrary::CreateDeferredLengthPrototypeFunctionTypeNoProfileThunk(JavascriptMethod entryPoint, bool isShared)
1053+
{
1054+
return CreateDeferredFunctionTypeNoProfileThunk_Internal<true, true>(entryPoint, isShared);
1055+
}
1056+
1057+
template<bool isLengthAvailable, bool isPrototypeAvailable>
1058+
DynamicType * JavascriptLibrary::CreateDeferredFunctionTypeNoProfileThunk_Internal(JavascriptMethod entrypoint, bool isShared)
10311059
{
10321060
// Note: the lack of TypeHandler switching here based on the isAnonymousFunction flag is intentional.
10331061
// We can't switch shared typeHandlers and RuntimeFunctions do not produce script code for us to know if a function is Anonymous.
10341062
// As a result we may have an issue where hasProperty would say you have a name property but getProperty returns undefined
1035-
return DynamicType::New(scriptContext, TypeIds_Function, functionPrototype, entrypoint,
1036-
isLengthAvailable ? GetDeferredPrototypeFunctionWithLengthTypeHandler(scriptContext) : GetDeferredPrototypeFunctionTypeHandler(scriptContext),
1037-
isShared, isShared);
1063+
DynamicTypeHandler * typeHandler =
1064+
isLengthAvailable ?
1065+
(isPrototypeAvailable ?
1066+
GetDeferredPrototypeFunctionWithLengthTypeHandler(scriptContext) : GetDeferredFunctionWithLengthTypeHandler()) :
1067+
(isPrototypeAvailable ?
1068+
GetDeferredPrototypeFunctionTypeHandler(scriptContext) : GetDeferredFunctionTypeHandler());
1069+
return DynamicType::New(scriptContext, TypeIds_Function, functionPrototype, entrypoint, typeHandler, isShared, isShared);
10381070
}
1071+
10391072
DynamicType * JavascriptLibrary::CreateFunctionType(JavascriptMethod entrypoint, RecyclableObject* prototype)
10401073
{
10411074
if (prototype == nullptr)
@@ -5243,11 +5276,7 @@ namespace Js
52435276
{
52445277
Assert(function->GetDynamicType()->GetIsLocked());
52455278

5246-
if (VarIs<ScriptFunction>(function))
5247-
{
5248-
this->SetCrossSiteForLockedNonBuiltInFunctionType(function);
5249-
}
5250-
else if (VarIs<BoundFunction>(function))
5279+
if (VarIs<ScriptFunction>(function) || VarIs<BoundFunction>(function))
52515280
{
52525281
this->SetCrossSiteForLockedNonBuiltInFunctionType(function);
52535282
}
@@ -5259,6 +5288,11 @@ namespace Js
52595288
{
52605289
function->ReplaceType(crossSiteDeferredPrototypeFunctionType);
52615290
}
5291+
else if (typeHandler == JavascriptLibrary::GetDeferredFunctionTypeHandler()
5292+
|| typeHandler == JavascriptLibrary::GetDeferredFunctionWithLengthTypeHandler())
5293+
{
5294+
function->ReplaceType(crossSiteDeferredFunctionType);
5295+
}
52625296
else if (typeHandler == Js::DeferredTypeHandler<Js::JavascriptExternalFunction::DeferredConstructorInitializer>::GetDefaultInstance())
52635297
{
52645298
function->ReplaceType(crossSiteExternalConstructFunctionWithPrototypeType);
@@ -5276,16 +5310,58 @@ namespace Js
52765310

52775311
void JavascriptLibrary::SetCrossSiteForLockedNonBuiltInFunctionType(JavascriptFunction * function)
52785312
{
5313+
FunctionProxy * functionProxy = function->GetFunctionProxy();
52795314
DynamicTypeHandler *typeHandler = function->GetTypeHandler();
5280-
if (typeHandler->IsPathTypeHandler())
5315+
if (typeHandler->IsDeferredTypeHandler())
52815316
{
5282-
PathTypeHandlerBase::FromTypeHandler(typeHandler)->ConvertToNonShareableTypeHandler(function);
5317+
if (functionProxy && functionProxy->GetCrossSiteDeferredFunctionType())
5318+
{
5319+
function->ReplaceType(functionProxy->GetCrossSiteDeferredFunctionType());
5320+
}
5321+
else
5322+
{
5323+
function->ChangeType();
5324+
function->SetEntryPoint(scriptContext->CurrentCrossSiteThunk);
5325+
if (functionProxy && !PHASE_OFF1(ShareCrossSiteFuncTypesPhase))
5326+
{
5327+
function->ShareType();
5328+
functionProxy->SetCrossSiteDeferredFunctionType(UnsafeVarTo<ScriptFunction>(function)->GetScriptFunctionType());
5329+
}
5330+
}
52835331
}
5284-
else
5332+
else
52855333
{
5286-
function->ChangeType();
5334+
if (functionProxy && functionProxy->GetCrossSiteUndeferredFunctionType())
5335+
{
5336+
function->ReplaceType(functionProxy->GetCrossSiteUndeferredFunctionType());
5337+
}
5338+
else
5339+
{
5340+
if (typeHandler->IsPathTypeHandler())
5341+
{
5342+
if (!PHASE_OFF1(ShareCrossSiteFuncTypesPhase))
5343+
{
5344+
DynamicType *type = function->DuplicateType();
5345+
PathTypeHandlerBase::FromTypeHandler(typeHandler)->BuildPathTypeFromNewRoot(function, &type);
5346+
function->ReplaceType(type);
5347+
}
5348+
else
5349+
{
5350+
PathTypeHandlerBase::FromTypeHandler(typeHandler)->ConvertToNonShareableTypeHandler(function);
5351+
}
5352+
}
5353+
else
5354+
{
5355+
function->ChangeType();
5356+
}
5357+
function->SetEntryPoint(scriptContext->CurrentCrossSiteThunk);
5358+
if (functionProxy && function->GetTypeHandler()->GetMayBecomeShared() && !PHASE_OFF1(ShareCrossSiteFuncTypesPhase))
5359+
{
5360+
function->ShareType();
5361+
functionProxy->SetCrossSiteUndeferredFunctionType(UnsafeVarTo<ScriptFunction>(function)->GetScriptFunctionType());
5362+
}
5363+
}
52875364
}
5288-
function->SetEntryPoint(scriptContext->CurrentCrossSiteThunk);
52895365
}
52905366

52915367
JavascriptExternalFunction*

lib/Runtime/Library/JavascriptLibrary.h

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -300,6 +300,7 @@ namespace Js
300300
Field(DynamicType *) defaultExternalConstructorFunctionWithDeferredPrototypeType;
301301
Field(DynamicType *) boundFunctionType;
302302
Field(DynamicType *) regexConstructorType;
303+
Field(DynamicType *) crossSiteDeferredFunctionType;
303304
Field(DynamicType *) crossSiteDeferredPrototypeFunctionType;
304305
Field(DynamicType *) crossSiteIdMappedFunctionWithPrototypeType;
305306
Field(DynamicType *) crossSiteExternalConstructFunctionWithPrototypeType;
@@ -912,8 +913,13 @@ namespace Js
912913
template<bool isNameAvailable>
913914
static DynamicTypeHandler * GetDeferredAsyncFunctionTypeHandlerBase();
914915

916+
DynamicType * CreateDeferredFunctionType(JavascriptMethod entrypoint);
915917
DynamicType * CreateDeferredPrototypeFunctionType(JavascriptMethod entrypoint);
916-
DynamicType * CreateDeferredPrototypeFunctionTypeNoProfileThunk(JavascriptMethod entrypoint, bool isShared = false, bool isLengthAvailable = false);
918+
DynamicType * CreateDeferredPrototypeFunctionTypeNoProfileThunk(JavascriptMethod entrypoint, bool isShared = false);
919+
DynamicType * CreateDeferredFunctionTypeNoProfileThunk(JavascriptMethod entrypoint, bool isShared = false);
920+
DynamicType * CreateDeferredLengthPrototypeFunctionTypeNoProfileThunk(JavascriptMethod entrypoint, bool isShared = false);
921+
DynamicType * CreateDeferredLengthFunctionTypeNoProfileThunk(JavascriptMethod entrypoint, bool isShared = false);
922+
template<bool isLengthAvailable, bool isPrototypeAvailable> DynamicType * CreateDeferredFunctionTypeNoProfileThunk_Internal(JavascriptMethod entrypoint, bool isShared);
917923
DynamicType * CreateFunctionType(JavascriptMethod entrypoint, RecyclableObject* prototype = nullptr);
918924
DynamicType * CreateFunctionWithConfigurableLengthType(FunctionInfo * functionInfo);
919925
DynamicType * CreateFunctionWithLengthType(FunctionInfo * functionInfo);

0 commit comments

Comments
 (0)