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;