From 978c1719c0072fcf049387e449399ed39b88b2bf Mon Sep 17 00:00:00 2001 From: Paul Leathers Date: Tue, 6 Mar 2018 15:09:16 -0800 Subject: [PATCH] Use PathTypeHandler's for function objects with non-default properties/attributes. Move from creating new non-shared SimpleTypeHandler's when a new property is added to a SimpleTypeHandler, or an attribute is changed, to creating PathTypeHandler's. Build a new root and evolve from the root to the current state of the SimpleTypeHandler, then replace the type's existing SimpleTypeHandler with the new PathTypeHandler. From there, we can evolve to the state required by the new property/attribute, and future instances of the same function that make the same type transition will get the same type. Also fix up some shared SimpleTypeHandler's in the library that didn't represent the desired state of their library objects and were forcing type transitions during initialization. --- lib/Runtime/Language/CacheOperators.cpp | 8 ++ lib/Runtime/Library/JavascriptLibrary.cpp | 32 ++++- lib/Runtime/Library/JavascriptLibrary.h | 6 +- lib/Runtime/Library/JavascriptProxy.cpp | 2 +- lib/Runtime/Library/ScriptFunction.cpp | 14 +++ lib/Runtime/Runtime.h | 2 +- lib/Runtime/Types/PathTypeHandler.cpp | 42 +++++-- lib/Runtime/Types/PathTypeHandler.h | 9 +- lib/Runtime/Types/SimpleTypeHandler.cpp | 136 +++++++++++++--------- lib/Runtime/Types/SimpleTypeHandler.h | 8 +- 10 files changed, 186 insertions(+), 73 deletions(-) diff --git a/lib/Runtime/Language/CacheOperators.cpp b/lib/Runtime/Language/CacheOperators.cpp index 612400758db..730b804886d 100644 --- a/lib/Runtime/Language/CacheOperators.cpp +++ b/lib/Runtime/Language/CacheOperators.cpp @@ -234,8 +234,16 @@ namespace Js DynamicTypeHandler* oldTypeHandler = oldType->GetTypeHandler(); DynamicTypeHandler* newTypeHandler = newType->GetTypeHandler(); +#if ENABLE_FIXED_FIELDS // the newType is a path-type so the old one should be too: Assert(oldTypeHandler->IsPathTypeHandler()); +#else + // This may be the transition from deferred type handler to path type handler. Don't try to cache now. + if (!oldTypeHandler->IsPathTypeHandler()) + { + return; + } +#endif int oldCapacity = oldTypeHandler->GetSlotCapacity(); int newCapacity = newTypeHandler->GetSlotCapacity(); diff --git a/lib/Runtime/Library/JavascriptLibrary.cpp b/lib/Runtime/Library/JavascriptLibrary.cpp index d64656c0419..34ee06c0880 100644 --- a/lib/Runtime/Library/JavascriptLibrary.cpp +++ b/lib/Runtime/Library/JavascriptLibrary.cpp @@ -32,6 +32,12 @@ namespace Js SimplePropertyDescriptor(NO_WRITE_BARRIER_TAG(BuiltInPropertyRecords::name), PropertyConfigurable) }; + SimplePropertyDescriptor const JavascriptLibrary::SharedIdMappedFunctionPropertyDescriptors[2] = + { + SimplePropertyDescriptor(NO_WRITE_BARRIER_TAG(BuiltInPropertyRecords::prototype), PropertyNone), + SimplePropertyDescriptor(NO_WRITE_BARRIER_TAG(BuiltInPropertyRecords::name), PropertyConfigurable) + }; + SimplePropertyDescriptor const JavascriptLibrary::FunctionWithLengthAndNameTypeDescriptors[2] = { SimplePropertyDescriptor(NO_WRITE_BARRIER_TAG(BuiltInPropertyRecords::length), PropertyConfigurable), @@ -40,14 +46,15 @@ namespace Js SimplePropertyDescriptor const JavascriptLibrary::ModuleNamespaceTypeDescriptors[1] = { - SimplePropertyDescriptor(NO_WRITE_BARRIER_TAG(BuiltInPropertyRecords::_symbolToStringTag), PropertyConfigurable) + SimplePropertyDescriptor(NO_WRITE_BARRIER_TAG(BuiltInPropertyRecords::_symbolToStringTag), PropertyNone) }; SimpleTypeHandler<1> JavascriptLibrary::SharedPrototypeTypeHandler(NO_WRITE_BARRIER_TAG(BuiltInPropertyRecords::constructor), PropertyWritable | PropertyConfigurable, PropertyTypesWritableDataOnly, 4, sizeof(DynamicObject)); SimpleTypeHandler<1> JavascriptLibrary::SharedFunctionWithoutPrototypeTypeHandler(NO_WRITE_BARRIER_TAG(BuiltInPropertyRecords::name), PropertyConfigurable); SimpleTypeHandler<1> JavascriptLibrary::SharedFunctionWithPrototypeTypeHandlerV11(NO_WRITE_BARRIER_TAG(BuiltInPropertyRecords::prototype), PropertyWritable); SimpleTypeHandler<2> JavascriptLibrary::SharedFunctionWithPrototypeTypeHandler(NO_WRITE_BARRIER_TAG(SharedFunctionPropertyDescriptors)); - SimpleTypeHandler<1> JavascriptLibrary::SharedIdMappedFunctionWithPrototypeTypeHandler(NO_WRITE_BARRIER_TAG(BuiltInPropertyRecords::prototype)); + SimpleTypeHandler<2> JavascriptLibrary::SharedIdMappedFunctionWithPrototypeTypeHandler(NO_WRITE_BARRIER_TAG(SharedIdMappedFunctionPropertyDescriptors)); + SimpleTypeHandler<1> JavascriptLibrary::SharedFunctionWithConfigurableLengthTypeHandler(NO_WRITE_BARRIER_TAG(BuiltInPropertyRecords::length), PropertyConfigurable); SimpleTypeHandler<1> JavascriptLibrary::SharedFunctionWithLengthTypeHandler(NO_WRITE_BARRIER_TAG(BuiltInPropertyRecords::length)); SimpleTypeHandler<2> JavascriptLibrary::SharedFunctionWithLengthAndNameTypeHandler(NO_WRITE_BARRIER_TAG(FunctionWithLengthAndNameTypeDescriptors)); SimpleTypeHandler<1> JavascriptLibrary::SharedNamespaceSymbolTypeHandler(NO_WRITE_BARRIER_TAG(ModuleNamespaceTypeDescriptors)); @@ -898,6 +905,11 @@ namespace Js GetDeferredFunctionTypeHandler(), false, false); } + DynamicType * JavascriptLibrary::CreateFunctionWithConfigurableLengthType(FunctionInfo * functionInfo) + { + return CreateFunctionWithConfigurableLengthType(this->GetFunctionPrototype(), functionInfo); + } + DynamicType * JavascriptLibrary::CreateFunctionWithLengthType(FunctionInfo * functionInfo) { return CreateFunctionWithLengthType(this->GetFunctionPrototype(), functionInfo); @@ -913,6 +925,14 @@ namespace Js return CreateFunctionWithLengthAndPrototypeType(this->GetFunctionPrototype(), functionInfo); } + DynamicType * JavascriptLibrary::CreateFunctionWithConfigurableLengthType(DynamicObject * prototype, FunctionInfo * functionInfo) + { + Assert(!functionInfo->HasBody()); + return DynamicType::New(scriptContext, TypeIds_Function, prototype, + this->inProfileMode? ProfileEntryThunk : functionInfo->GetOriginalEntryPoint(), + &SharedFunctionWithConfigurableLengthTypeHandler); + } + DynamicType * JavascriptLibrary::CreateFunctionWithLengthType(DynamicObject * prototype, FunctionInfo * functionInfo) { Assert(!functionInfo->HasBody()); @@ -5034,11 +5054,15 @@ namespace Js { function->ReplaceType(crossSiteExternalConstructFunctionWithPrototypeType); } - else + else if (typeHandler == &SharedIdMappedFunctionWithPrototypeTypeHandler) { - Assert(typeHandler == &SharedIdMappedFunctionWithPrototypeTypeHandler); function->ReplaceType(crossSiteIdMappedFunctionWithPrototypeType); } + else + { + function->ChangeType(); + function->SetEntryPoint(scriptContext->CurrentCrossSiteThunk); + } } } diff --git a/lib/Runtime/Library/JavascriptLibrary.h b/lib/Runtime/Library/JavascriptLibrary.h index 1ec608a1982..76340d863b7 100644 --- a/lib/Runtime/Library/JavascriptLibrary.h +++ b/lib/Runtime/Library/JavascriptLibrary.h @@ -519,13 +519,15 @@ namespace Js static SimpleTypeHandler<1> SharedFunctionWithoutPrototypeTypeHandler; static SimpleTypeHandler<1> SharedFunctionWithPrototypeTypeHandlerV11; static SimpleTypeHandler<2> SharedFunctionWithPrototypeTypeHandler; + static SimpleTypeHandler<1> SharedFunctionWithConfigurableLengthTypeHandler; static SimpleTypeHandler<1> SharedFunctionWithLengthTypeHandler; static SimpleTypeHandler<2> SharedFunctionWithLengthAndNameTypeHandler; - static SimpleTypeHandler<1> SharedIdMappedFunctionWithPrototypeTypeHandler; + static SimpleTypeHandler<2> SharedIdMappedFunctionWithPrototypeTypeHandler; static SimpleTypeHandler<1> SharedNamespaceSymbolTypeHandler; static MissingPropertyTypeHandler MissingPropertyHolderTypeHandler; static SimplePropertyDescriptor const SharedFunctionPropertyDescriptors[2]; + static SimplePropertyDescriptor const SharedIdMappedFunctionPropertyDescriptors[2]; static SimplePropertyDescriptor const HeapArgumentsPropertyDescriptors[3]; static SimplePropertyDescriptor const FunctionWithLengthAndPrototypeTypeDescriptors[2]; static SimplePropertyDescriptor const FunctionWithLengthAndNameTypeDescriptors[2]; @@ -984,9 +986,11 @@ namespace Js DynamicType * CreateDeferredPrototypeFunctionType(JavascriptMethod entrypoint); DynamicType * CreateDeferredPrototypeFunctionTypeNoProfileThunk(JavascriptMethod entrypoint, bool isShared = false, bool isLengthAvailable = false); DynamicType * CreateFunctionType(JavascriptMethod entrypoint, RecyclableObject* prototype = nullptr); + DynamicType * CreateFunctionWithConfigurableLengthType(FunctionInfo * functionInfo); DynamicType * CreateFunctionWithLengthType(FunctionInfo * functionInfo); DynamicType * CreateFunctionWithLengthAndNameType(FunctionInfo * functionInfo); DynamicType * CreateFunctionWithLengthAndPrototypeType(FunctionInfo * functionInfo); + DynamicType * CreateFunctionWithConfigurableLengthType(DynamicObject * prototype, FunctionInfo * functionInfo); DynamicType * CreateFunctionWithLengthType(DynamicObject * prototype, FunctionInfo * functionInfo); DynamicType * CreateFunctionWithLengthAndNameType(DynamicObject * prototype, FunctionInfo * functionInfo); DynamicType * CreateFunctionWithLengthAndPrototypeType(DynamicObject * prototype, FunctionInfo * functionInfo); diff --git a/lib/Runtime/Library/JavascriptProxy.cpp b/lib/Runtime/Library/JavascriptProxy.cpp index 1e0dba372f0..8b9dbba6c23 100644 --- a/lib/Runtime/Library/JavascriptProxy.cpp +++ b/lib/Runtime/Library/JavascriptProxy.cpp @@ -130,7 +130,7 @@ namespace Js JavascriptProxy* proxy = JavascriptProxy::Create(scriptContext, args); JavascriptLibrary* library = scriptContext->GetLibrary(); - DynamicType* type = library->CreateFunctionWithLengthType(&EntryInfo::Revoke); + DynamicType* type = library->CreateFunctionWithConfigurableLengthType(&EntryInfo::Revoke); RuntimeFunction* revoker = RecyclerNewEnumClass(scriptContext->GetRecycler(), JavascriptLibrary::EnumFunctionClass, RuntimeFunction, type, &EntryInfo::Revoke); diff --git a/lib/Runtime/Library/ScriptFunction.cpp b/lib/Runtime/Library/ScriptFunction.cpp index 2e92bf8c202..9827c9cf0ec 100644 --- a/lib/Runtime/Library/ScriptFunction.cpp +++ b/lib/Runtime/Library/ScriptFunction.cpp @@ -106,6 +106,13 @@ namespace Js pfuncScriptWithInlineCache->SetHasSuperReference(hasSuperReference); + ScriptFunctionType *scFuncType = functionProxy->GetUndeferredFunctionType(); + if (scFuncType) + { + Assert(pfuncScriptWithInlineCache->GetType() == functionProxy->GetDeferredPrototypeType()); + pfuncScriptWithInlineCache->GetTypeHandler()->EnsureObjectReady(pfuncScriptWithInlineCache); + } + if (PHASE_TRACE1(Js::ScriptFunctionWithInlineCachePhase)) { char16 debugStringBuffer[MAX_FUNCTION_BODY_DEBUG_STRING_SIZE]; @@ -123,6 +130,13 @@ namespace Js pfuncScript->SetHasSuperReference(hasSuperReference); + ScriptFunctionType *scFuncType = functionProxy->GetUndeferredFunctionType(); + if (scFuncType) + { + Assert(pfuncScript->GetType() == functionProxy->GetDeferredPrototypeType()); + pfuncScript->GetTypeHandler()->EnsureObjectReady(pfuncScript); + } + JS_ETW(EventWriteJSCRIPT_RECYCLER_ALLOCATE_FUNCTION(pfuncScript, EtwTrace::GetFunctionId(functionProxy))); return pfuncScript; diff --git a/lib/Runtime/Runtime.h b/lib/Runtime/Runtime.h index 8ef6716bd86..bb91abb4983 100644 --- a/lib/Runtime/Runtime.h +++ b/lib/Runtime/Runtime.h @@ -134,7 +134,7 @@ namespace Js class DeferredTypeHandlerBase; template class NullTypeHandler; template class SimpleTypeHandler; - class PathTypeHandler; + class PathTypeHandlerBase; class IndexPropertyDescriptor; class DynamicObject; class ArrayObject; diff --git a/lib/Runtime/Types/PathTypeHandler.cpp b/lib/Runtime/Types/PathTypeHandler.cpp index f1906de0cc7..b29a4d9ff3d 100644 --- a/lib/Runtime/Types/PathTypeHandler.cpp +++ b/lib/Runtime/Types/PathTypeHandler.cpp @@ -130,6 +130,12 @@ namespace Js #endif } + void PathTypeSingleSuccessorInfo::ReplaceSuccessor(DynamicType * type, const PathTypeSuccessorKey key, RecyclerWeakReference * typeWeakRef) + { + Assert(successorKey == key); + successorTypeWeakRef = typeWeakRef; + } + template void PathTypeSingleSuccessorInfo::MapSingleSuccessor(Fn fn) { @@ -168,6 +174,13 @@ namespace Js propertySuccessors->Item(key, typeWeakRef); } + void PathTypeMultiSuccessorInfo::ReplaceSuccessor(DynamicType * type, const PathTypeSuccessorKey key, RecyclerWeakReference * typeWeakRef) + { + Assert(this->propertySuccessors); + Assert(propertySuccessors->Item(key)); + propertySuccessors->Item(key, typeWeakRef); + } + template void PathTypeMultiSuccessorInfo::MapMultiSuccessors(Fn fn) { @@ -343,9 +356,21 @@ namespace Js return found; } - BOOL PathTypeHandlerBase::SetAttributesHelper(DynamicObject* instance, PropertyId propertyId, PropertyIndex propertyIndex, ObjectSlotAttributes * instanceAttributes, ObjectSlotAttributes propertyAttributes) + BOOL PathTypeHandlerBase::SetAttributesHelper(DynamicObject* instance, PropertyId propertyId, PropertyIndex propertyIndex, ObjectSlotAttributes * instanceAttributes, ObjectSlotAttributes propertyAttributes, bool isInit) { - if (instanceAttributes == nullptr ? propertyAttributes == ObjectSlotAttr_Default : propertyAttributes == instanceAttributes[propertyIndex]) + if (instanceAttributes) + { + if (!isInit) + { + // Preserve non-default bits like accessors + propertyAttributes = (ObjectSlotAttributes)(propertyAttributes | (instanceAttributes[propertyIndex] & ~ObjectSlotAttr_PropertyAttributesMask)); + } + if (propertyAttributes == instanceAttributes[propertyIndex]) + { + return true; + } + } + else if (propertyAttributes == ObjectSlotAttr_Default) { return true; } @@ -714,18 +739,16 @@ namespace Js // In CacheOperators::CachePropertyWrite we ensure that we never cache property adds for types that aren't shared. Assert(!instance->GetDynamicType()->GetIsShared() || GetIsShared()); - Assert(instance->GetDynamicType()->GetIsShared() == GetIsShared()); - if (setAttributes) { - this->SetAttributesHelper(instance, propertyId, index, GetAttributeArray(), attr); + this->SetAttributesHelper(instance, propertyId, index, GetAttributeArray(), attr, isInit); } else if (isInit) { ObjectSlotAttributes * attributes = this->GetAttributeArray(); if (attributes && (attributes[index] & ObjectSlotAttr_Accessor)) { - this->SetAttributesHelper(instance, propertyId, index, attributes, (ObjectSlotAttributes)(attributes[index] & ~ObjectSlotAttr_Accessor)); + this->SetAttributesHelper(instance, propertyId, index, attributes, (ObjectSlotAttributes)(attributes[index] & ~ObjectSlotAttr_Accessor), true); } } PathTypeHandlerBase *newTypeHandler = PathTypeHandlerBase::FromTypeHandler(instance->GetDynamicType()->GetTypeHandler()); @@ -1722,7 +1745,12 @@ namespace Js return true; } - return SetAttributesHelper(instance, propertyId, propertyIndex, GetAttributeArray(), PropertyAttributesToObjectSlotAttributes(attributes)); + return SetAttributesAtIndex(instance, propertyId, propertyIndex, attributes); + } + + BOOL PathTypeHandlerBase::SetAttributesAtIndex(DynamicObject* instance, PropertyId propertyId, PropertyIndex index, PropertyAttributes attributes) + { + return SetAttributesHelper(instance, propertyId, index, GetAttributeArray(), PropertyAttributesToObjectSlotAttributes(attributes)); } BOOL PathTypeHandlerBase::GetAttributesWithPropertyIndex(DynamicObject * instance, PropertyId propertyId, BigPropertyIndex index, PropertyAttributes * attributes) diff --git a/lib/Runtime/Types/PathTypeHandler.h b/lib/Runtime/Types/PathTypeHandler.h index 2c19956fc40..0e75a55799d 100644 --- a/lib/Runtime/Types/PathTypeHandler.h +++ b/lib/Runtime/Types/PathTypeHandler.h @@ -39,6 +39,7 @@ namespace Js bool IsMultiSuccessor() const { return !IsSingleSuccessor(); } virtual bool GetSuccessor(const PathTypeSuccessorKey successorKey, RecyclerWeakReference ** typeWeakRef) const = 0; virtual void SetSuccessor(DynamicType * type, const PathTypeSuccessorKey successorKey, RecyclerWeakReference * typeWeakRef, ScriptContext * scriptContext) = 0; + virtual void ReplaceSuccessor(DynamicType * type, PathTypeSuccessorKey successorKey, RecyclerWeakReference * typeWeakRef) = 0; template void MapSuccessors(Fn fn); template void MapSuccessorsUntil(Fn fn); @@ -61,6 +62,7 @@ namespace Js virtual bool GetSuccessor(const PathTypeSuccessorKey successorKey, RecyclerWeakReference ** typeWeakRef) const override; virtual void SetSuccessor(DynamicType * type, const PathTypeSuccessorKey successorKey, RecyclerWeakReference * typeWeakRef, ScriptContext * scriptContext) override; + virtual void ReplaceSuccessor(DynamicType * type, PathTypeSuccessorKey successorKey, RecyclerWeakReference * typeWeakRef) override; template void MapSingleSuccessor(Fn fn); @@ -78,6 +80,7 @@ namespace Js virtual bool GetSuccessor(const PathTypeSuccessorKey successorKey, RecyclerWeakReference ** typeWeakRef) const override; virtual void SetSuccessor(DynamicType * type, const PathTypeSuccessorKey successorKey, RecyclerWeakReference * typeWeakRef, ScriptContext * scriptContext) override; + virtual void ReplaceSuccessor(DynamicType * type, PathTypeSuccessorKey successorKey, RecyclerWeakReference * typeWeakRef) override; template void MapMultiSuccessors(Fn fn); template void MapMultiSuccessorsUntil(Fn fn); @@ -89,6 +92,8 @@ namespace Js class PathTypeHandlerBase : public DynamicTypeHandler { + template + friend class SimpleTypeHandler; friend class PathTypeHandlerNoAttr; friend class PathTypeHandlerWithAttr; friend class DynamicObject; @@ -115,6 +120,7 @@ namespace Js template void MapSuccessorsUntil(Fn fn); PathTypeSuccessorInfo * GetSuccessorInfo() const { return successorInfo; } void SetSuccessorInfo(PathTypeSuccessorInfo * info) { successorInfo = info; } + void ReplaceSuccessor(DynamicType * type, PathTypeSuccessorKey key, RecyclerWeakReference * typeWeakRef) { return successorInfo->ReplaceSuccessor(type, key, typeWeakRef); } static PropertyAttributes ObjectSlotAttributesToPropertyAttributes(const ObjectSlotAttributes attr) { return attr & ObjectSlotAttr_PropertyAttributesMask; } static ObjectSlotAttributes PropertyAttributesToObjectSlotAttributes(const PropertyAttributes attr) { return (ObjectSlotAttributes)(attr & ObjectSlotAttr_PropertyAttributesMask); } @@ -182,7 +188,8 @@ namespace Js BOOL FindNextPropertyHelper(ScriptContext* scriptContext, ObjectSlotAttributes * objectAttributes, PropertyIndex& index, JavascriptString** propertyString, PropertyId* propertyId, PropertyAttributes* attributes, Type* type, DynamicType *typeToEnumerate, EnumeratorFlags flags, DynamicObject* instance, PropertyValueInfo* info); - BOOL SetAttributesHelper(DynamicObject* instance, PropertyId propertyId, PropertyIndex propertyIndex, ObjectSlotAttributes * instanceAttributes, ObjectSlotAttributes propertyAttributes); + BOOL SetAttributesAtIndex(DynamicObject* instance, PropertyId propertyId, PropertyIndex index, PropertyAttributes attributes); + BOOL SetAttributesHelper(DynamicObject* instance, PropertyId propertyId, PropertyIndex propertyIndex, ObjectSlotAttributes * instanceAttributes, ObjectSlotAttributes propertyAttributes, bool isInit = false); BOOL SetAccessorsHelper(DynamicObject* instance, PropertyId propertyId, ObjectSlotAttributes * attributes, PathTypeSetterSlotIndex * setters, Var getter, Var setter, PropertyOperationFlags flags); #if ENABLE_NATIVE_CODEGEN diff --git a/lib/Runtime/Types/SimpleTypeHandler.cpp b/lib/Runtime/Types/SimpleTypeHandler.cpp index 58c825f20eb..199477b3e18 100644 --- a/lib/Runtime/Types/SimpleTypeHandler.cpp +++ b/lib/Runtime/Types/SimpleTypeHandler.cpp @@ -61,29 +61,6 @@ namespace Js SetIsInlineSlotCapacityLocked(); } - template - SimpleTypeHandler * SimpleTypeHandler::ConvertToNonSharedSimpleType(DynamicObject* instance) - { - ScriptContext* scriptContext = instance->GetScriptContext(); - Recycler* recycler = scriptContext->GetRecycler(); - - - CompileAssert(_countof(descriptors) == size); - - SimpleTypeHandler * newTypeHandler = RecyclerNew(recycler, SimpleTypeHandler, this); - - // Consider: Add support for fixed fields to SimpleTypeHandler when - // non-shared. Here we could set the instance as the singleton instance on the newly - // created handler. - - newTypeHandler->SetFlags(IsPrototypeFlag | HasKnownSlot0Flag, this->GetFlags()); - Assert(newTypeHandler->GetIsInlineSlotCapacityLocked()); - newTypeHandler->SetPropertyTypes(PropertyTypesWritableDataOnly | PropertyTypesWritableDataOnlyDetection, this->GetPropertyTypes()); - newTypeHandler->SetInstanceTypeHandler(instance); - - return newTypeHandler; - } - template template T* SimpleTypeHandler::ConvertToTypeHandler(DynamicObject* instance) @@ -135,6 +112,64 @@ namespace Js return newTypeHandler; } + template + PathTypeHandlerBase* SimpleTypeHandler::ConvertToPathType(DynamicObject* instance) + { + ScriptContext *scriptContext = instance->GetScriptContext(); + PathTypeHandlerBase* newTypeHandler = + PathTypeHandlerNoAttr::New( + scriptContext, + scriptContext->GetLibrary()->GetRootPath(), + 0, + static_cast(this->GetSlotCapacity()), + this->GetInlineSlotCapacity(), + this->GetOffsetOfInlineSlots(), + true, + false); + newTypeHandler->SetMayBecomeShared(); + + DynamicType *existingType = instance->GetDynamicType(); + DynamicType *currentType = DynamicType::New(scriptContext, existingType->GetTypeId(), existingType->GetPrototype(), nullptr, newTypeHandler, false, false); + PropertyId propertyId = Constants::NoProperty; + ObjectSlotAttributes attr = ObjectSlotAttr_None; + for (PropertyIndex i = 0; i < propertyCount; i++) + { + Var value = instance->GetSlot(i); + propertyId = descriptors[i].Id->GetPropertyId(); + attr = PathTypeHandlerBase::PropertyAttributesToObjectSlotAttributes(descriptors[i].Attributes); + Assert(value != nullptr || IsInternalPropertyId(propertyId)); + PropertyIndex index; + currentType = newTypeHandler->PromoteType(currentType, PathTypeSuccessorKey(propertyId, attr), false, scriptContext, instance, &index); + newTypeHandler = PathTypeHandlerBase::FromTypeHandler(currentType->GetTypeHandler()); +#if ENABLE_FIXED_FIELDS +#ifdef SUPPORT_FIXED_FIELDS_ON_PATH_TYPES + bool markAsFixed = !IsInternalPropertyId(propertyId) && + (JavascriptFunction::Is(value) ? ShouldFixMethodProperties() : false); + newTypeHandler->InitializePath(instance, i, newTypeHandler->GetPathLength(), scriptContext, [=]() { return markAsFixed; }); +#endif +#endif + } + + if (existingType->GetIsLocked()) + { + newTypeHandler->LockTypeHandler(); + } + if (existingType->GetIsShared()) + { + newTypeHandler->ShareTypeHandler(scriptContext); + } + newTypeHandler->SetFlags(IsPrototypeFlag | HasKnownSlot0Flag, this->GetFlags()); + newTypeHandler->SetPropertyTypes(PropertyTypesWritableDataOnly | PropertyTypesWritableDataOnlyDetection, this->GetPropertyTypes()); + newTypeHandler->SetInstanceTypeHandler(instance, false); + if (newTypeHandler->GetPredecessorType()) + { + PathTypeHandlerBase *predTypeHandler = PathTypeHandlerBase::FromTypeHandler(newTypeHandler->GetPredecessorType()->GetTypeHandler()); + predTypeHandler->ReplaceSuccessor(newTypeHandler->GetPredecessorType(), PathTypeSuccessorKey(propertyId, attr), scriptContext->GetRecycler()->CreateWeakReferenceHandle(existingType)); + } + + return newTypeHandler; + } + template DictionaryTypeHandler* SimpleTypeHandler::ConvertToDictionaryType(DynamicObject* instance) { @@ -250,7 +285,7 @@ namespace Js template PropertyIndex SimpleTypeHandler::GetPropertyIndex(PropertyRecord const* propertyRecord) { - int index; + PropertyIndex index; if (GetDescriptor(propertyRecord->GetPropertyId(), &index) && !(descriptors[index].Attributes & PropertyDeleted)) { return (PropertyIndex)index; @@ -262,7 +297,7 @@ namespace Js template bool SimpleTypeHandler::GetPropertyEquivalenceInfo(PropertyRecord const* propertyRecord, PropertyEquivalenceInfo& info) { - int index; + PropertyIndex index; if (GetDescriptor(propertyRecord->GetPropertyId(), &index) && !(descriptors[index].Attributes & PropertyDeleted)) { info.slotIndex = AdjustSlotIndexForInlineSlots((PropertyIndex)index); @@ -448,7 +483,7 @@ namespace Js BOOL SimpleTypeHandler::SetProperty(DynamicObject* instance, PropertyId propertyId, Var value, PropertyOperationFlags flags, PropertyValueInfo* info) { ScriptContext* scriptContext = instance->GetScriptContext(); - int index; + PropertyIndex index; JavascriptLibrary::CheckAndInvalidateIsConcatSpreadableCache(propertyId, scriptContext); @@ -499,7 +534,7 @@ namespace Js template DescriptorFlags SimpleTypeHandler::GetSetter(DynamicObject* instance, PropertyId propertyId, Var* setterValue, PropertyValueInfo* info, ScriptContext* requestContext) { - int index; + PropertyIndex index; PropertyValueInfo::SetNoCache(info, instance); if (GetDescriptor(propertyId, &index)) { @@ -545,7 +580,7 @@ namespace Js BOOL SimpleTypeHandler::DeleteProperty(DynamicObject* instance, PropertyId propertyId, PropertyOperationFlags propertyOperationFlags) { ScriptContext* scriptContext = instance->GetScriptContext(); - int index; + PropertyIndex index; if (GetDescriptor(propertyId, &index)) { if (descriptors[index].Attributes & PropertyDeleted) @@ -608,7 +643,7 @@ namespace Js template BOOL SimpleTypeHandler::IsEnumerable(DynamicObject* instance, PropertyId propertyId) { - int index; + PropertyIndex index; if (!GetDescriptor(propertyId, &index)) { return true; @@ -619,7 +654,7 @@ namespace Js template BOOL SimpleTypeHandler::IsWritable(DynamicObject* instance, PropertyId propertyId) { - int index; + PropertyIndex index; if (!GetDescriptor(propertyId, &index)) { return true; @@ -630,7 +665,7 @@ namespace Js template BOOL SimpleTypeHandler::IsConfigurable(DynamicObject* instance, PropertyId propertyId) { - int index; + PropertyIndex index; if (!GetDescriptor(propertyId, &index)) { return true; @@ -641,7 +676,7 @@ namespace Js template BOOL SimpleTypeHandler::SetEnumerable(DynamicObject* instance, PropertyId propertyId, BOOL value) { - int index; + PropertyIndex index; if (!GetDescriptor(propertyId, &index)) { // Upgrade type handler if set objectArray item attribute. @@ -673,7 +708,7 @@ namespace Js template BOOL SimpleTypeHandler::SetWritable(DynamicObject* instance, PropertyId propertyId, BOOL value) { - int index; + PropertyIndex index; if (!GetDescriptor(propertyId, &index)) { // Upgrade type handler if set objectArray item attribute. @@ -719,7 +754,7 @@ namespace Js template BOOL SimpleTypeHandler::SetConfigurable(DynamicObject* instance, PropertyId propertyId, BOOL value) { - int index; + PropertyIndex index; if (!GetDescriptor(propertyId, &index)) { // Upgrade type handler if set objectArray item attribute. @@ -746,9 +781,9 @@ namespace Js } template - BOOL SimpleTypeHandler::GetDescriptor(PropertyId propertyId, int * index) + BOOL SimpleTypeHandler::GetDescriptor(PropertyId propertyId, PropertyIndex * index) { - for (int i = 0; i < propertyCount; i++) + for (PropertyIndex i = 0; i < propertyCount; i++) { if (descriptors[i].Id->GetPropertyId() == propertyId) { @@ -763,7 +798,7 @@ namespace Js // Set an attribute bit. Return true if change is made. // template - BOOL SimpleTypeHandler::SetAttribute(DynamicObject* instance, int index, PropertyAttributes attribute) + BOOL SimpleTypeHandler::SetAttribute(DynamicObject* instance, PropertyIndex index, PropertyAttributes attribute) { if (descriptors[index].Attributes & PropertyDeleted) { @@ -787,7 +822,7 @@ namespace Js DynamicType* oldType = instance->GetDynamicType(); #endif // This changes TypeHandler, but non-necessarily Type. - this->ConvertToNonSharedSimpleType(instance)->descriptors[index].Attributes = attributes; + this->ConvertToPathType(instance)->SetAttributesAtIndex(instance, descriptors[index].Id->GetPropertyId(), index, attributes); #if DBG Assert(!oldType->GetIsLocked() || instance->GetDynamicType() != oldType); #endif @@ -803,7 +838,7 @@ namespace Js // Clear an attribute bit. Return true if change is made. // template - BOOL SimpleTypeHandler::ClearAttribute(DynamicObject* instance, int index, PropertyAttributes attribute) + BOOL SimpleTypeHandler::ClearAttribute(DynamicObject* instance, PropertyIndex index, PropertyAttributes attribute) { if (descriptors[index].Attributes & PropertyDeleted) { @@ -827,7 +862,7 @@ namespace Js DynamicType* oldType = instance->GetDynamicType(); #endif // This changes TypeHandler, but non-necessarily Type. - this->ConvertToNonSharedSimpleType(instance)->descriptors[index].Attributes = attributes; + this->ConvertToPathType(instance)->SetAttributesAtIndex(instance, descriptors[index].Id->GetPropertyId(), index, attributes); #if DBG Assert(!oldType->GetIsLocked() || instance->GetDynamicType() != oldType); #endif @@ -842,7 +877,7 @@ namespace Js template BOOL SimpleTypeHandler::SetAccessors(DynamicObject* instance, PropertyId propertyId, Var getter, Var setter, PropertyOperationFlags flags) { - return ConvertToDictionaryType(instance)->SetAccessors(instance, propertyId, getter, setter, flags); + return ConvertToPathType(instance)->SetAccessors(instance, propertyId, getter, setter, flags); } template @@ -866,7 +901,7 @@ namespace Js template BOOL SimpleTypeHandler::SetPropertyWithAttributes(DynamicObject* instance, PropertyId propertyId, Var value, PropertyAttributes attributes, PropertyValueInfo* info, PropertyOperationFlags flags, SideEffects possibleSideEffects) { - int index; + PropertyIndex index; if (GetDescriptor(propertyId, &index)) { if (descriptors[index].Attributes != attributes) @@ -874,13 +909,7 @@ namespace Js SimpleTypeHandler * typeHandler = this; if (GetIsLocked()) { -#if DBG - DynamicType* oldType = instance->GetDynamicType(); -#endif - typeHandler = this->ConvertToNonSharedSimpleType(instance); -#if DBG - Assert(!oldType->GetIsLocked() || instance->GetDynamicType() != oldType); -#endif + return this->ConvertToPathType(instance)->SetPropertyWithAttributes(instance, propertyId, value, attributes, info, flags, possibleSideEffects); } typeHandler->descriptors[index].Attributes = attributes; if (attributes & PropertyEnumerable) @@ -974,7 +1003,7 @@ namespace Js ScriptContext* scriptContext = instance->GetScriptContext(); #if DBG - int index; + PropertyIndex index; uint32 indexVal; Assert(!GetDescriptor(propertyId, &index)); Assert(!scriptContext->IsNumericPropertyId(propertyId, &indexVal)); @@ -983,8 +1012,7 @@ namespace Js if (propertyCount >= sizeof(descriptors)/sizeof(SimplePropertyDescriptor)) { Assert(propertyId != Constants::NoProperty); - PropertyRecord const* propertyRecord = scriptContext->GetPropertyName(propertyId); - return ConvertToSimpleDictionaryType(instance)->AddProperty(instance, propertyRecord, value, attributes, info, flags, possibleSideEffects); + return ConvertToPathType(instance)->SetPropertyWithAttributes(instance, propertyId, value, attributes, info, flags); } descriptors[propertyCount].Id = scriptContext->GetPropertyName(propertyId); @@ -1078,7 +1106,7 @@ namespace Js bool SimpleTypeHandler::CanStorePropertyValueDirectly(const DynamicObject* instance, PropertyId propertyId, bool allowLetConst) { Assert(!allowLetConst); - int index; + PropertyIndex index; if (GetDescriptor(propertyId, &index)) { return true; @@ -1125,7 +1153,7 @@ namespace Js template Js::BigPropertyIndex SimpleTypeHandler::GetPropertyIndex_EnumerateTTD(const Js::PropertyRecord* pRecord) { - int index; + PropertyIndex index; if(this->GetDescriptor(pRecord->GetPropertyId(), &index)) { TTDAssert(!(this->descriptors[index].Attributes & PropertyDeleted), "How is this deleted but we enumerated it anyway???"); diff --git a/lib/Runtime/Types/SimpleTypeHandler.h b/lib/Runtime/Types/SimpleTypeHandler.h index 7631bcfc004..c1e0278a633 100644 --- a/lib/Runtime/Types/SimpleTypeHandler.h +++ b/lib/Runtime/Types/SimpleTypeHandler.h @@ -85,14 +85,14 @@ namespace Js template T* ConvertToTypeHandler(DynamicObject* instance); + PathTypeHandlerBase* ConvertToPathType(DynamicObject* instance); DictionaryTypeHandler* ConvertToDictionaryType(DynamicObject* instance); SimpleDictionaryTypeHandler* ConvertToSimpleDictionaryType(DynamicObject* instance); ES5ArrayTypeHandler* ConvertToES5ArrayType(DynamicObject* instance); - SimpleTypeHandler* ConvertToNonSharedSimpleType(DynamicObject * instance); - BOOL GetDescriptor(PropertyId propertyId, int * index); - BOOL SetAttribute(DynamicObject* instance, int index, PropertyAttributes attribute); - BOOL ClearAttribute(DynamicObject* instance, int index, PropertyAttributes attribute); + BOOL GetDescriptor(PropertyId propertyId, PropertyIndex * index); + BOOL SetAttribute(DynamicObject* instance, PropertyIndex index, PropertyAttributes attribute); + BOOL ClearAttribute(DynamicObject* instance, PropertyIndex index, PropertyAttributes attribute); BOOL AddProperty(DynamicObject* instance, PropertyId propertyId, Var value, PropertyAttributes attributes, PropertyValueInfo* info, PropertyOperationFlags flags, SideEffects possibleSideEffects); virtual BOOL FreezeImpl(DynamicObject* instance, bool isConvertedType) override;