| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459 |
- //-------------------------------------------------------------------------------------------------------
- // Copyright (C) Microsoft. All rights reserved.
- // Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
- //-------------------------------------------------------------------------------------------------------
- #include "RuntimeLibraryPch.h"
- namespace Js
- {
- CompileAssert(sizeof(ES5Array) == sizeof(JavascriptArray));
- ES5ArrayType::ES5ArrayType(DynamicType* type)
- : DynamicType(type->GetScriptContext(), TypeIds_ES5Array, type->GetPrototype(), type->GetEntryPoint(), type->GetTypeHandler(), false, false)
- {
- }
- DynamicType* ES5Array::DuplicateType()
- {
- return RecyclerNew(GetScriptContext()->GetRecycler(), ES5ArrayType, this->GetDynamicType());
- }
- bool ES5Array::IsLengthWritable() const
- {
- return GetTypeHandler()->IsLengthWritable();
- }
- PropertyQueryFlags ES5Array::HasPropertyQuery(PropertyId propertyId, _Inout_opt_ PropertyValueInfo* info)
- {
- if (propertyId == PropertyIds::length)
- {
- return PropertyQueryFlags::Property_Found;
- }
- // Skip JavascriptArray override
- return DynamicObject::HasPropertyQuery(propertyId, info);
- }
- BOOL ES5Array::IsWritable(PropertyId propertyId)
- {
- if (propertyId == PropertyIds::length)
- {
- return IsLengthWritable();
- }
- return __super::IsWritable(propertyId);
- }
- BOOL ES5Array::SetEnumerable(PropertyId propertyId, BOOL value)
- {
- // Skip JavascriptArray override
- return DynamicObject::SetEnumerable(propertyId, value);
- }
- BOOL ES5Array::SetWritable(PropertyId propertyId, BOOL value)
- {
- // Skip JavascriptArray override
- return DynamicObject::SetWritable(propertyId, value);
- }
- BOOL ES5Array::SetConfigurable(PropertyId propertyId, BOOL value)
- {
- // Skip JavascriptArray override
- return DynamicObject::SetConfigurable(propertyId, value);
- }
- BOOL ES5Array::SetAttributes(PropertyId propertyId, PropertyAttributes attributes)
- {
- // Skip JavascriptArray override
- return DynamicObject::SetAttributes(propertyId, attributes);
- }
- PropertyQueryFlags ES5Array::GetPropertyQuery(Var originalInstance, PropertyId propertyId, Var* value, PropertyValueInfo* info, ScriptContext* requestContext)
- {
- BOOL result;
- if (GetPropertyBuiltIns(propertyId, value, &result))
- {
- return JavascriptConversion::BooleanToPropertyQueryFlags(result);
- }
- // Skip JavascriptArray override
- return DynamicObject::GetPropertyQuery(originalInstance, propertyId, value, info, requestContext);
- }
- PropertyQueryFlags ES5Array::GetPropertyQuery(Var originalInstance, JavascriptString* propertyNameString, Var* value, PropertyValueInfo* info, ScriptContext* requestContext)
- {
- BOOL result;
- PropertyRecord const* propertyRecord;
- this->GetScriptContext()->FindPropertyRecord(propertyNameString, &propertyRecord);
- if (propertyRecord != nullptr && GetPropertyBuiltIns(propertyRecord->GetPropertyId(), value, &result))
- {
- return JavascriptConversion::BooleanToPropertyQueryFlags(result);
- }
- // Skip JavascriptArray override
- return DynamicObject::GetPropertyQuery(originalInstance, propertyNameString, value, info, requestContext);
- }
- bool ES5Array::GetPropertyBuiltIns(PropertyId propertyId, Var* value, BOOL* result)
- {
- if (propertyId == PropertyIds::length)
- {
- *value = JavascriptNumber::ToVar(this->GetLength(), GetScriptContext());
- *result = true;
- return true;
- }
- return false;
- }
- PropertyQueryFlags ES5Array::GetPropertyReferenceQuery(Var originalInstance, PropertyId propertyId, Var* value, PropertyValueInfo* info, ScriptContext* requestContext)
- {
- return ES5Array::GetPropertyQuery(originalInstance, propertyId, value, info, requestContext);
- }
- // Convert a Var to array length, throw RangeError if value is not valid for array length.
- uint32 ES5Array::ToLengthValue(Var value, ScriptContext* scriptContext)
- {
- if (TaggedInt::Is(value))
- {
- int32 newLen = TaggedInt::ToInt32(value);
- if (newLen < 0)
- {
- JavascriptError::ThrowRangeError(scriptContext, JSERR_ArrayLengthAssignIncorrect);
- }
- return static_cast<uint32>(newLen);
- }
- else
- {
- uint32 newLen = JavascriptConversion::ToUInt32(value, scriptContext);
- if (newLen != JavascriptConversion::ToNumber(value, scriptContext))
- {
- JavascriptError::ThrowRangeError(scriptContext, JSERR_ArrayLengthAssignIncorrect);
- }
- // Conversion can change the type (e.g. from String), invalidating assumptions made by the JIT
- scriptContext->GetThreadContext()->AddImplicitCallFlags(ImplicitCall_Accessor);
- return newLen;
- }
- }
- DescriptorFlags ES5Array::GetSetter(PropertyId propertyId, Var *setterValue, PropertyValueInfo* info, ScriptContext* requestContext)
- {
- DescriptorFlags result;
- if (GetSetterBuiltIns(propertyId, info, &result))
- {
- return result;
- }
- return DynamicObject::GetSetter(propertyId, setterValue, info, requestContext);
- }
- DescriptorFlags ES5Array::GetSetter(JavascriptString* propertyNameString, Var *setterValue, PropertyValueInfo* info, ScriptContext* requestContext)
- {
- DescriptorFlags result;
- PropertyRecord const* propertyRecord;
- this->GetScriptContext()->FindPropertyRecord(propertyNameString, &propertyRecord);
- if (propertyRecord != nullptr && GetSetterBuiltIns(propertyRecord->GetPropertyId(), info, &result))
- {
- return result;
- }
- return DynamicObject::GetSetter(propertyNameString, setterValue, info, requestContext);
- }
- bool ES5Array::GetSetterBuiltIns(PropertyId propertyId, PropertyValueInfo* info, DescriptorFlags* result)
- {
- if (propertyId == PropertyIds::length)
- {
- PropertyValueInfo::SetNoCache(info, this);
- *result = IsLengthWritable() ? WritableData : Data;
- return true;
- }
- return false;
- }
- BOOL ES5Array::SetProperty(PropertyId propertyId, Var value, PropertyOperationFlags propertyOperationFlags, PropertyValueInfo* info)
- {
- BOOL result;
- if (SetPropertyBuiltIns(propertyId, value, propertyOperationFlags, &result))
- {
- return result;
- }
- return __super::SetProperty(propertyId, value, propertyOperationFlags, info);
- }
- BOOL ES5Array::SetProperty(JavascriptString* propertyNameString, Var value, PropertyOperationFlags propertyOperationFlags, PropertyValueInfo* info)
- {
- BOOL result;
- PropertyRecord const* propertyRecord;
- this->GetScriptContext()->FindPropertyRecord(propertyNameString, &propertyRecord);
- if (propertyRecord != nullptr && SetPropertyBuiltIns(propertyRecord->GetPropertyId(), value, propertyOperationFlags, &result))
- {
- return result;
- }
- return __super::SetProperty(propertyNameString, value, propertyOperationFlags, info);
- }
- bool ES5Array::SetPropertyBuiltIns(PropertyId propertyId, Var value, PropertyOperationFlags propertyOperationFlags, BOOL* result)
- {
- ScriptContext* scriptContext = GetScriptContext();
- if (propertyId == PropertyIds::length)
- {
- if (!GetTypeHandler()->IsLengthWritable())
- {
- *result = false; // reject
- return true;
- }
- uint32 newLen = ToLengthValue(value, scriptContext);
- uint32 assignedLen = GetTypeHandler()->SetLength(this, newLen, propertyOperationFlags);
- if (newLen != assignedLen)
- {
- scriptContext->GetThreadContext()->AddImplicitCallFlags(ImplicitCall_NoOpSet);
- }
- *result = true;
- return true;
- }
- return false;
- }
- BOOL ES5Array::SetPropertyWithAttributes(PropertyId propertyId, Var value, PropertyAttributes attributes, PropertyValueInfo* info, PropertyOperationFlags flags, SideEffects possibleSideEffects)
- {
- if (propertyId == PropertyIds::length)
- {
- Assert(attributes == PropertyWritable);
- Assert(IsWritable(propertyId) && !IsConfigurable(propertyId) && !IsEnumerable(propertyId));
- uint32 newLen = ToLengthValue(value, GetScriptContext());
- GetTypeHandler()->SetLength(this, newLen, PropertyOperation_None);
- return true;
- }
- return __super::SetPropertyWithAttributes(propertyId, value, attributes, info, flags, possibleSideEffects);
- }
- BOOL ES5Array::DeleteItem(uint32 index, PropertyOperationFlags flags)
- {
- // Skip JavascriptArray override
- return DynamicObject::DeleteItem(index, flags);
- }
- PropertyQueryFlags ES5Array::HasItemQuery(uint32 index)
- {
- // Skip JavascriptArray override
- return DynamicObject::HasItemQuery(index);
- }
- PropertyQueryFlags ES5Array::GetItemQuery(Var originalInstance, uint32 index, Var* value, ScriptContext * requestContext)
- {
- // Skip JavascriptArray override
- return DynamicObject::GetItemQuery(originalInstance, index, value, requestContext);
- }
- PropertyQueryFlags ES5Array::GetItemReferenceQuery(Var originalInstance, uint32 index, Var* value, ScriptContext * requestContext)
- {
- // Skip JavascriptArray override
- return DynamicObject::GetItemReferenceQuery(originalInstance, index, value, requestContext);
- }
- DescriptorFlags ES5Array::GetItemSetter(uint32 index, Var* setterValue, ScriptContext* requestContext)
- {
- // Skip JavascriptArray override
- return DynamicObject::GetItemSetter(index, setterValue, requestContext);
- }
- BOOL ES5Array::SetItem(uint32 index, Var value, PropertyOperationFlags flags)
- {
- // Skip JavascriptArray override
- return DynamicObject::SetItem(index, value, flags);
- }
- BOOL ES5Array::SetAccessors(PropertyId propertyId, Var getter, Var setter, PropertyOperationFlags flags)
- {
- // Skip JavascriptArray override
- return DynamicObject::SetAccessors(propertyId, getter, setter, flags);
- }
- BOOL ES5Array::PreventExtensions()
- {
- // Skip JavascriptArray override
- return DynamicObject::PreventExtensions();
- }
- BOOL ES5Array::Seal()
- {
- // Skip JavascriptArray override
- return DynamicObject::Seal();
- }
- BOOL ES5Array::Freeze()
- {
- // Skip JavascriptArray override
- return DynamicObject::Freeze();
- }
- BOOL ES5Array::GetEnumerator(JavascriptStaticEnumerator * enumerator, EnumeratorFlags flags, ScriptContext* requestContext, EnumeratorCache * enumeratorCache)
- {
- return enumerator->Initialize(nullptr, this, this, flags, requestContext, enumeratorCache);
- }
- JavascriptEnumerator * ES5Array::GetIndexEnumerator(EnumeratorFlags flags, ScriptContext* requestContext)
- {
- // ES5Array does not support compat mode, ignore preferSnapshotSemantics
- return RecyclerNew(GetScriptContext()->GetRecycler(), ES5ArrayIndexEnumerator, this, flags, requestContext);
- }
- BOOL ES5Array::IsItemEnumerable(uint32 index)
- {
- return GetTypeHandler()->IsItemEnumerable(this, index);
- }
- BOOL ES5Array::SetItemWithAttributes(uint32 index, Var value, PropertyAttributes attributes)
- {
- return GetTypeHandler()->SetItemWithAttributes(this, index, value, attributes);
- }
- BOOL ES5Array::SetItemAttributes(uint32 index, PropertyAttributes attributes)
- {
- return GetTypeHandler()->SetItemAttributes(this, index, attributes);
- }
- BOOL ES5Array::SetItemAccessors(uint32 index, Var getter, Var setter)
- {
- return GetTypeHandler()->SetItemAccessors(this, index, getter, setter);
- }
- BOOL ES5Array::IsObjectArrayFrozen()
- {
- return GetTypeHandler()->IsObjectArrayFrozen(this);
- }
- BOOL ES5Array::IsValidDescriptorToken(void * descriptorValidationToken) const
- {
- return GetTypeHandler()->IsValidDescriptorToken(descriptorValidationToken);
- }
- uint32 ES5Array::GetNextDescriptor(uint32 key, IndexPropertyDescriptor** descriptor, void ** descriptorValidationToken)
- {
- return GetTypeHandler()->GetNextDescriptor(key, descriptor, descriptorValidationToken);
- }
- BOOL ES5Array::GetDescriptor(uint32 index, Js::IndexPropertyDescriptor **ppDescriptor)
- {
- return GetTypeHandler()->GetDescriptor(index, ppDescriptor);
- }
- #if ENABLE_TTD
- void ES5Array::MarkVisitKindSpecificPtrs(TTD::SnapshotExtractor* extractor)
- {
- this->JavascriptArray::MarkVisitKindSpecificPtrs(extractor);
- uint32 length = this->GetLength();
- uint32 descriptorIndex = Js::JavascriptArray::InvalidIndex;
- IndexPropertyDescriptor* descriptor = nullptr;
- void* descriptorValidationToken = nullptr;
- do
- {
- descriptorIndex = this->GetNextDescriptor(descriptorIndex, &descriptor, &descriptorValidationToken);
- if(descriptorIndex == Js::JavascriptArray::InvalidIndex || descriptorIndex >= length)
- {
- break;
- }
- if((descriptor->Attributes & PropertyDeleted) != PropertyDeleted)
- {
- if(descriptor->Getter != nullptr)
- {
- extractor->MarkVisitVar(descriptor->Getter);
- }
- if(descriptor->Setter != nullptr)
- {
- extractor->MarkVisitVar(descriptor->Setter);
- }
- }
- } while(true);
- }
- TTD::NSSnapObjects::SnapObjectType ES5Array::GetSnapTag_TTD() const
- {
- return TTD::NSSnapObjects::SnapObjectType::SnapES5ArrayObject;
- }
- void ES5Array::ExtractSnapObjectDataInto(TTD::NSSnapObjects::SnapObject* objData, TTD::SlabAllocator& alloc)
- {
- TTD::NSSnapObjects::SnapArrayInfo<TTD::TTDVar>* sai = TTD::NSSnapObjects::ExtractArrayValues<TTD::TTDVar>(this, alloc);
- TTD::NSSnapObjects::SnapES5ArrayInfo* es5ArrayInfo = alloc.SlabAllocateStruct<TTD::NSSnapObjects::SnapES5ArrayInfo>();
- //
- //TODO: reserving memory for entire length might be a problem if we have very large sparse arrays.
- //
- uint32 length = this->GetLength();
- es5ArrayInfo->IsLengthWritable = this->IsLengthWritable();
- es5ArrayInfo->GetterSetterCount = 0;
- es5ArrayInfo->GetterSetterEntries = alloc.SlabReserveArraySpace<TTD::NSSnapObjects::SnapES5ArrayGetterSetterEntry>(length + 1); //ensure we don't do a 0 reserve
- uint32 descriptorIndex = Js::JavascriptArray::InvalidIndex;
- IndexPropertyDescriptor* descriptor = nullptr;
- void* descriptorValidationToken = nullptr;
- do
- {
- descriptorIndex = this->GetNextDescriptor(descriptorIndex, &descriptor, &descriptorValidationToken);
- if(descriptorIndex == Js::JavascriptArray::InvalidIndex || descriptorIndex >= length)
- {
- break;
- }
- if((descriptor->Attributes & PropertyDeleted) != PropertyDeleted)
- {
- TTD::NSSnapObjects::SnapES5ArrayGetterSetterEntry* entry = es5ArrayInfo->GetterSetterEntries + es5ArrayInfo->GetterSetterCount;
- es5ArrayInfo->GetterSetterCount++;
- entry->Index = (uint32)descriptorIndex;
- entry->Attributes = descriptor->Attributes;
- entry->Getter = nullptr;
- if(descriptor->Getter != nullptr)
- {
- entry->Getter = descriptor->Getter;
- }
- entry->Setter = nullptr;
- if(descriptor->Setter != nullptr)
- {
- entry->Setter = descriptor->Setter;
- }
- }
- } while(true);
- if(es5ArrayInfo->GetterSetterCount != 0)
- {
- alloc.SlabCommitArraySpace<TTD::NSSnapObjects::SnapES5ArrayGetterSetterEntry>(es5ArrayInfo->GetterSetterCount, length + 1);
- }
- else
- {
- alloc.SlabAbortArraySpace<TTD::NSSnapObjects::SnapES5ArrayGetterSetterEntry>(length + 1);
- es5ArrayInfo->GetterSetterEntries = nullptr;
- }
- es5ArrayInfo->BasicArrayData = sai;
- TTD::NSSnapObjects::StdExtractSetKindSpecificInfo<TTD::NSSnapObjects::SnapES5ArrayInfo*, TTD::NSSnapObjects::SnapObjectType::SnapES5ArrayObject>(objData, es5ArrayInfo);
- }
- #endif
- }
|