Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 27 additions & 0 deletions lib/Runtime/Base/FunctionBody.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,8 @@ namespace Js
m_isTopLevel(false),
m_isPublicLibraryCode(false),
m_scriptContext(scriptContext),
deferredPrototypeType(nullptr),
undeferredFunctionType(nullptr),
m_utf8SourceInfo(utf8SourceInfo),
m_functionNumber(functionNumber),
m_defaultEntryPointInfo(nullptr),
Expand Down Expand Up @@ -1472,6 +1474,8 @@ namespace Js
other->SetCachedSourceString(this->GetCachedSourceString());
CopyDeferParseField(m_isAsmjsMode);
CopyDeferParseField(m_isAsmJsFunction);
CopyDeferParseField(deferredPrototypeType);
CopyDeferParseField(undeferredFunctionType);

other->SetFunctionObjectTypeList(this->GetFunctionObjectTypeList());

Expand Down Expand Up @@ -2015,6 +2019,16 @@ namespace Js
return type;
}

ScriptFunctionType * FunctionProxy::GetUndeferredFunctionType() const
{
return undeferredFunctionType;
}

void FunctionProxy::SetUndeferredFunctionType(ScriptFunctionType * type)
{
undeferredFunctionType = type;
}

JavascriptMethod FunctionProxy::GetDirectEntryPoint(ProxyEntryPointInfo* entryPoint) const
{
Assert(entryPoint->jsMethod != nullptr);
Expand Down Expand Up @@ -2055,6 +2069,8 @@ namespace Js
{
func(this->deferredPrototypeType);
}
// NOTE: We deliberately do not map the undeferredFunctionType here, since it's in the list
// of registered function object types we processed above.
}

FunctionProxy::FunctionTypeWeakRefList* FunctionProxy::EnsureFunctionObjectTypeList()
Expand Down Expand Up @@ -4871,6 +4887,11 @@ namespace Js
this->deferredPrototypeType->SetEntryPoint(this->GetDefaultEntryPointInfo()->jsMethod);
this->deferredPrototypeType->SetEntryPointInfo(this->GetDefaultEntryPointInfo());
}
if (this->undeferredFunctionType)
{
this->undeferredFunctionType->SetEntryPoint(this->GetDefaultEntryPointInfo()->jsMethod);
this->undeferredFunctionType->SetEntryPointInfo(this->GetDefaultEntryPointInfo());
}

#if DBG
if (!this->HasValidEntryPoint())
Expand Down Expand Up @@ -5109,6 +5130,7 @@ namespace Js

// Abandon the shared type so a new function will get a new one
this->deferredPrototypeType = nullptr;
this->undeferredFunctionType = nullptr;
this->SetAttributes((FunctionInfo::Attributes) (this->GetAttributes() | FunctionInfo::Attributes::DeferredParse));
}

Expand Down Expand Up @@ -5169,6 +5191,11 @@ namespace Js
this->deferredPrototypeType->SetEntryPoint(this->GetDefaultEntryPointInfo()->jsMethod);
this->deferredPrototypeType->SetEntryPointInfo(this->GetDefaultEntryPointInfo());
}
if (this->undeferredFunctionType)
{
this->undeferredFunctionType->SetEntryPoint(this->GetDefaultEntryPointInfo()->jsMethod);
this->undeferredFunctionType->SetEntryPointInfo(this->GetDefaultEntryPointInfo());
}
ReinitializeExecutionModeAndLimits();
}

Expand Down
3 changes: 3 additions & 0 deletions lib/Runtime/Base/FunctionBody.h
Original file line number Diff line number Diff line change
Expand Up @@ -1290,6 +1290,8 @@ namespace Js
ProxyEntryPointInfo* GetDefaultEntryPointInfo() const;
ScriptFunctionType * GetDeferredPrototypeType() const;
ScriptFunctionType * EnsureDeferredPrototypeType();
ScriptFunctionType * GetUndeferredFunctionType() const;
void SetUndeferredFunctionType(ScriptFunctionType * type);
JavascriptMethod GetDirectEntryPoint(ProxyEntryPointInfo* entryPoint) const;

// Function object type list methods
Expand Down Expand Up @@ -1368,6 +1370,7 @@ namespace Js
FieldNoBarrier(ScriptContext*) m_scriptContext; // Memory context for this function body
FieldWithBarrier(Utf8SourceInfo*) m_utf8SourceInfo;
FieldWithBarrier(ScriptFunctionType*) deferredPrototypeType;
FieldWithBarrier(ScriptFunctionType*) undeferredFunctionType;
FieldWithBarrier(ProxyEntryPointInfo*) m_defaultEntryPointInfo; // The default entry point info for the function proxy

FieldWithBarrier(uint) m_functionNumber; // Per thread global function number
Expand Down
43 changes: 15 additions & 28 deletions lib/Runtime/Library/JavascriptLibrary.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -631,12 +631,13 @@ namespace Js
#endif
}

bool JavascriptLibrary::InitializeGeneratorFunction(DynamicObject *function, DeferredTypeHandlerBase * typeHandler, DeferredInitializeMode mode)
bool JavascriptLibrary::InitializeGeneratorFunction(DynamicObject *instance, DeferredTypeHandlerBase * typeHandler, DeferredInitializeMode mode)
{
bool isAnonymousFunction = JavascriptGeneratorFunction::FromVar(function)->IsAnonymousFunction();
JavascriptGeneratorFunction *function = JavascriptGeneratorFunction::FromVar(instance);
bool isAnonymousFunction = function->IsAnonymousFunction();

JavascriptLibrary* javascriptLibrary = function->GetType()->GetLibrary();
typeHandler->Convert(function, isAnonymousFunction ? javascriptLibrary->anonymousFunctionWithPrototypeTypeHandler : javascriptLibrary->functionWithPrototypeTypeHandler);
typeHandler->ConvertFunction(function, isAnonymousFunction ? javascriptLibrary->anonymousFunctionWithPrototypeTypeHandler : javascriptLibrary->functionWithPrototypeTypeHandler);
function->SetPropertyWithAttributes(PropertyIds::prototype, javascriptLibrary->CreateGeneratorConstructorPrototypeObject(), PropertyWritable, nullptr);

if (!isAnonymousFunction)
Expand Down Expand Up @@ -675,8 +676,9 @@ namespace Js
}

template<bool addPrototype>
bool JavascriptLibrary::InitializeFunction(DynamicObject *function, DeferredTypeHandlerBase * typeHandler, DeferredInitializeMode mode)
bool JavascriptLibrary::InitializeFunction(DynamicObject *instance, DeferredTypeHandlerBase * typeHandler, DeferredInitializeMode mode)
{
JavascriptFunction * function = JavascriptFunction::FromVar(instance);
JavascriptLibrary* javascriptLibrary = function->GetType()->GetLibrary();
ScriptFunction *scriptFunction = nullptr;
bool useAnonymous = false;
Expand All @@ -689,19 +691,19 @@ namespace Js
if (!addPrototype)
{
Assert(!useAnonymous);
typeHandler->Convert(function, javascriptLibrary->functionTypeHandler);
typeHandler->ConvertFunction(function, javascriptLibrary->functionTypeHandler);
}
else
{
typeHandler->Convert(function, useAnonymous ? javascriptLibrary->anonymousFunctionWithPrototypeTypeHandler : javascriptLibrary->functionWithPrototypeTypeHandler);
function->SetProperty(PropertyIds::prototype, javascriptLibrary->CreateConstructorPrototypeObject((Js::JavascriptFunction *)function), PropertyOperation_None, nullptr);
}

if (scriptFunction)
{
if (scriptFunction->GetFunctionInfo()->IsClassConstructor())
typeHandler->ConvertFunction(function, useAnonymous ? javascriptLibrary->anonymousFunctionWithPrototypeTypeHandler : javascriptLibrary->functionWithPrototypeTypeHandler);
DynamicObject *protoObject = javascriptLibrary->CreateConstructorPrototypeObject(function);
if (scriptFunction && scriptFunction->GetFunctionInfo()->IsClassConstructor())
{
function->SetPropertyWithAttributes(PropertyIds::prototype, protoObject, PropertyNone, nullptr);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

SetPropertyWithAttributes [](start = 26, length = 25)

Unless I'm misreading something, isn't this changing the semantics? Previously we were only setting writable to false, now we'll be setting enumerable and configurable to false as well, no?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We've always set the attributes this way for the prototype property of a class constructor. (See the class member defaults.)

}
else
{
scriptFunction->SetWritable(Js::PropertyIds::prototype, FALSE);
function->SetProperty(PropertyIds::prototype, protoObject, PropertyOperation_None, nullptr);
}
}

Expand Down Expand Up @@ -5012,21 +5014,6 @@ namespace Js

if (ScriptFunction::Is(function))
{
#if DEBUG
if (!function->GetFunctionProxy()->GetIsAnonymousFunction())
{
Assert(function->GetFunctionInfo()->IsConstructor() ?
(function->GetDynamicType()->GetTypeHandler() == JavascriptLibrary::GetDeferredPrototypeFunctionTypeHandler(this->GetScriptContext())
|| function->GetDynamicType()->GetTypeHandler() == JavascriptLibrary::GetDeferredPrototypeFunctionWithLengthTypeHandler(this->GetScriptContext()))
: function->GetDynamicType()->GetTypeHandler() == JavascriptLibrary::GetDeferredFunctionTypeHandler());
}
else
{
Assert(function->GetFunctionInfo()->IsConstructor() ?
function->GetDynamicType()->GetTypeHandler() == JavascriptLibrary::GetDeferredAnonymousPrototypeFunctionTypeHandler() :
function->GetDynamicType()->GetTypeHandler() == JavascriptLibrary::GetDeferredAnonymousFunctionTypeHandler());
}
#endif
function->ChangeType();
function->SetEntryPoint(scriptContext->CurrentCrossSiteThunk);
}
Expand Down
14 changes: 1 addition & 13 deletions lib/Runtime/Library/ScriptFunction.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -268,22 +268,10 @@ namespace Js
{
// Update deferred parsed/serialized function to the real function body
Assert(this->functionInfo->HasBody());
Assert(this->functionInfo == newFunctionInfo->GetFunctionInfo());
Assert(this->functionInfo->GetFunctionBody() == newFunctionInfo);
Assert(!newFunctionInfo->IsDeferred());

DynamicType * type = this->GetDynamicType();

// If the type is shared, it must be the shared one in the old function proxy

this->functionInfo = newFunctionInfo->GetFunctionInfo();

if (type->GetIsShared())
{
// the type is still shared, we can't modify it, just migrate to the shared one in the function body
this->ReplaceType(newFunctionInfo->EnsureDeferredPrototypeType());
}

// The type has change from the default, it is not share, just use that one.
JavascriptMethod directEntryPoint = newFunctionInfo->GetDirectEntryPoint(newFunctionInfo->GetDefaultEntryPointInfo());
#if defined(ENABLE_SCRIPT_PROFILING) || defined(ENABLE_SCRIPT_DEBUGGING)
Assert(directEntryPoint != DefaultDeferredParsingThunk
Expand Down
26 changes: 24 additions & 2 deletions lib/Runtime/Types/DeferredTypeHandler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@

namespace Js
{
void DeferredTypeHandlerBase::Convert(DynamicObject * instance, DynamicTypeHandler * typeHandler)
void DeferredTypeHandlerBase::ConvertFunction(JavascriptFunction * instance, DynamicTypeHandler * typeHandler)
{
Assert(instance->GetDynamicType()->GetTypeHandler() == this);
Assert(this->inlineSlotCapacity == typeHandler->inlineSlotCapacity);
Expand All @@ -24,7 +24,29 @@ namespace Js

ScriptContext* scriptContext = instance->GetScriptContext();
instance->EnsureSlots(0, typeHandler->GetSlotCapacity(), scriptContext, typeHandler);
typeHandler->SetInstanceTypeHandler(instance);

FunctionProxy * functionProxy = instance->GetFunctionProxy();
ScriptFunctionType * undeferredFunctionType = nullptr;
if (functionProxy)
{
undeferredFunctionType = functionProxy->GetUndeferredFunctionType();
}
if (undeferredFunctionType && !instance->IsCrossSiteObject())
{
Assert(undeferredFunctionType->GetIsShared());
Assert(!CrossSite::IsThunk(undeferredFunctionType->GetEntryPoint()));
instance->ReplaceType(undeferredFunctionType);
}
else
{
typeHandler->SetInstanceTypeHandler(instance);
if (functionProxy && typeHandler->GetMayBecomeShared() && !CrossSite::IsThunk(instance->GetType()->GetEntryPoint()))
{
Assert(!functionProxy->GetUndeferredFunctionType());
functionProxy->SetUndeferredFunctionType(ScriptFunction::UnsafeFromVar(instance)->GetScriptFunctionType());
instance->ShareType();
}
}

// We may be changing to a type handler that already has some properties. Initialize those to undefined.
const Var undefined = scriptContext->GetLibrary()->GetUndefined();
Expand Down
2 changes: 1 addition & 1 deletion lib/Runtime/Types/DeferredTypeHandler.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ namespace Js
}

public:
void Convert(DynamicObject * instance, DynamicTypeHandler * handler);
void ConvertFunction(JavascriptFunction * instance, DynamicTypeHandler * handler);
void Convert(DynamicObject * instance, DeferredInitializeMode mode, int initSlotCapacity, BOOL hasAccessor = false);

virtual void SetAllPropertiesToUndefined(DynamicObject* instance, bool invalidateFixedFields) override {};
Expand Down
16 changes: 5 additions & 11 deletions lib/Runtime/Types/DynamicObject.h
Original file line number Diff line number Diff line change
Expand Up @@ -67,15 +67,9 @@ namespace Js

friend class JavascriptArray; // for xplat offsetof field access
friend class JavascriptNativeArray; // for xplat offsetof field access
friend class JavascriptOperators; // for ReplaceType
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks like the xplat builds are failing because JavascriptOperators is trying to access a protected member function DynamicObject::BoxStackInstance, so this friend wasn't just for ReplaceType

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

True. So the different compilers are enforcing different rules?

friend class PathTypeHandlerBase; // for ReplaceType
friend class SimplePathTypeHandlerNoAttr;
friend class SimplePathTypeHandlerWithAttr;
friend class PathTypeHandlerNoAttr;
friend class JavascriptLibrary; // for ReplaceType
friend class ScriptFunction; // for ReplaceType;
friend class JSON::JSONParser; //for ReplaceType
friend class ModuleNamespace; // for slot setting.
friend class JavascriptOperators;
friend class JavascriptLibrary;
friend class ModuleNamespace; // for slot setting.

#if ENABLE_OBJECT_SOURCE_TRACKING
public:
Expand Down Expand Up @@ -111,8 +105,6 @@ namespace Js

void InitSlots(DynamicObject * instance, ScriptContext * scriptContext);
void SetTypeHandler(DynamicTypeHandler * typeHandler, bool hasChanged);
void ReplaceType(DynamicType * type);
void ReplaceTypeWithPredecessorType(DynamicType * previousType);

protected:
DEFINE_VTABLE_CTOR(DynamicObject, RecyclableObject);
Expand All @@ -138,6 +130,8 @@ namespace Js

void EnsureSlots(int oldCount, int newCount, ScriptContext * scriptContext, DynamicTypeHandler * newTypeHandler = nullptr);
void EnsureSlots(int newCount, ScriptContext *scriptContext);
void ReplaceType(DynamicType * type);
void ReplaceTypeWithPredecessorType(DynamicType * previousType);

DynamicTypeHandler * GetTypeHandler() const;

Expand Down