| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593 |
- //-------------------------------------------------------------------------------------------------------
- // Copyright (C) Microsoft. All rights reserved.
- // Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
- //-------------------------------------------------------------------------------------------------------
- #include "SCACorePch.h"
- namespace Js
- {
- template <class Reader>
- bool DeserializationCloner<Reader>::TryClonePrimitive(SrcTypeId typeId, Src src, Dst* dst)
- {
- if (!IsSCAPrimitive(typeId))
- {
- return false;
- }
- ScriptContext* scriptContext = this->GetScriptContext();
- JavascriptLibrary* lib = scriptContext->GetLibrary();
- switch (typeId)
- {
- case SCA_None:
- *dst = NULL;
- break;
- case SCA_Reference: // Handle reference explictly as a primitive
- {
- scaposition_t pos;
- m_reader->Read(&pos);
- if (!this->GetEngine()->TryGetClonedObject(pos, dst))
- {
- this->ThrowSCADataCorrupt();
- }
- }
- break;
- case SCA_NullValue:
- *dst = lib->GetNull();
- break;
- case SCA_UndefinedValue:
- *dst = lib->GetUndefined();
- break;
- case SCA_TrueValue:
- *dst = lib->GetTrue();
- break;
- case SCA_FalseValue:
- *dst = lib->GetFalse();
- break;
- case SCA_Int32Value:
- {
- int32 n;
- m_reader->Read(&n);
- *dst = JavascriptNumber::ToVar(n, scriptContext);
- }
- break;
- case SCA_DoubleValue:
- {
- double dbl;
- m_reader->Read(&dbl);
- *dst = JavascriptNumber::ToVarWithCheck(dbl, scriptContext);
- }
- break;
- case SCA_Int64Value:
- {
- __int64 n;
- m_reader->Read(&n);
- *dst = JavascriptInt64Number::ToVar(n, scriptContext);
- }
- break;
- case SCA_Uint64Value:
- {
- unsigned __int64 n;
- m_reader->Read(&n);
- *dst = JavascriptUInt64Number::ToVar(n, scriptContext);
- }
- break;
- default:
- return false; // Not a recognized primitive type
- }
- return true;
- }
- template <class Reader>
- bool DeserializationCloner<Reader>::TryCloneObject(SrcTypeId typeId, Src src, Dst* dst, SCADeepCloneType* deepClone)
- {
- ScriptContext* scriptContext = this->GetScriptContext();
- JavascriptLibrary* lib = scriptContext->GetLibrary();
- *deepClone = SCADeepCloneType::None;
- bool isObject = true;
- if (typeId == SCA_Transferable)
- {
- scaposition_t pos;
- m_reader->Read(&pos);
- *dst = this->GetEngine()->ClaimTransferable(pos, lib);
- if (*dst == nullptr)
- {
- this->ThrowSCADataCorrupt();
- }
- return true;
- }
- if (IsSCAHostObject(typeId))
- {
- *dst = m_reader->ReadHostObject();
- *deepClone = SCADeepCloneType::HostObject;
- return true;
- }
- switch (typeId)
- {
- case SCA_StringValue: // Clone string value as object type to resolve multiple references
- {
- charcount_t len;
- const char16* buf = ReadString(&len);
- *dst = Js::JavascriptString::NewWithBuffer(buf, len, scriptContext);
- isObject = false;
- }
- break;
- case SCA_BooleanTrueObject:
- *dst = lib->CreateBooleanObject(TRUE);
- break;
- case SCA_BooleanFalseObject:
- *dst = lib->CreateBooleanObject(FALSE);
- break;
- case SCA_DateObject:
- {
- double dbl;
- m_reader->Read(&dbl);
- *dst = lib->CreateDate(dbl);
- }
- break;
- case SCA_NumberObject:
- {
- double dbl;
- m_reader->Read(&dbl);
- *dst = lib->CreateNumberObjectWithCheck(dbl);
- }
- break;
- case SCA_StringObject:
- {
- charcount_t len;
- const char16* buf = ReadString(&len);
- *dst = lib->CreateStringObject(buf, len);
- }
- break;
- case SCA_RegExpObject:
- {
- charcount_t len;
- const char16* buf = ReadString(&len);
- DWORD flags;
- m_reader->Read(&flags);
- *dst = JavascriptRegExp::CreateRegEx(buf, len,
- static_cast<UnifiedRegex::RegexFlags>(flags), scriptContext);
- }
- break;
- case SCA_Object:
- {
- *dst = lib->CreateObject();
- *deepClone = SCADeepCloneType::Object;
- }
- break;
- case SCA_Map:
- {
- *dst = JavascriptMap::New(scriptContext);
- *deepClone = SCADeepCloneType::Map;
- }
- break;
- case SCA_Set:
- {
- *dst = JavascriptSet::New(scriptContext);
- *deepClone = SCADeepCloneType::Set;
- }
- break;
- case SCA_DenseArray:
- case SCA_SparseArray:
- {
- uint32 length;
- Read(&length);
- *dst = lib->CreateArray(length);
- *deepClone = SCADeepCloneType::Object;
- }
- break;
- case SCA_ArrayBuffer:
- {
- uint32 len;
- m_reader->Read(&len);
- ArrayBuffer* arrayBuffer = lib->CreateArrayBuffer(len);
- Read(arrayBuffer->GetBuffer(), arrayBuffer->GetByteLength());
- *dst = arrayBuffer;
- }
- break;
- case SCA_SharedArrayBuffer:
- {
- SharedContents * sharedContents;
- m_reader->Read((intptr_t*)&sharedContents);
- SharedArrayBuffer* arrayBuffer = lib->CreateSharedArrayBuffer(sharedContents);
- Assert(arrayBuffer->IsWebAssemblyArrayBuffer() == sharedContents->IsWebAssembly());
- *dst = arrayBuffer;
- }
- break;
- //#ifdef ENABLE_WASM
- // case SCA_WebAssemblyModule:
- // {
- // uint32 len;
- // m_reader->Read(&len);
- // byte* buffer = RecyclerNewArrayLeaf(scriptContext->GetRecycler(), byte, len);
- // Read(buffer, len);
- // WebAssemblySource wasmSrc(buffer, len, true, scriptContext);
- // *dst = WebAssemblyModule::CreateModule(scriptContext, &wasmSrc);
- // break;
- // }
- // case SCA_WebAssemblyMemory:
- // {
- // uint32 initialLength = 0;
- // uint32 maximumLength = 0;
- // uint32 isShared = 0;
- // m_reader->Read(&initialLength);
- // m_reader->Read(&maximumLength);
- //
- //#ifdef ENABLE_WASM_THREADS
- // m_reader->Read(&isShared);
- // if (isShared)
- // {
- // SharedContents * sharedContents;
- // m_reader->Read((intptr_t*)&sharedContents);
- // *dst = WebAssemblyMemory::CreateFromSharedContents(initialLength, maximumLength, sharedContents, scriptContext);
- // }
- // else
- //#endif
- // {
- // uint32 len;
- // m_reader->Read(&len);
- // WebAssemblyMemory* mem = WebAssemblyMemory::CreateForExistingBuffer(initialLength, maximumLength, len, scriptContext);
- // Read(mem->GetBuffer()->GetBuffer(), len);
- // *dst = mem;
- // }
- // break;
- // }
- //#endif
- case SCA_Uint8ClampedArray:
- // If Khronos Interop is not enabled, we don't have Uint8ClampedArray available.
- // This is a scenario where the source buffer was created in a newer document mode
- // but needs to be deserialized in an older document mode.
- // What we want to do is return the buffer as a CanvasPixelArray instead of
- // Uint8ClampedArray since the older document mode knows what CanvasPixelArray is but
- // not what Uint8ClampedArray is.
- // We don't support pixelarray in edge anymore.
- // Intentionally fall through to default (TypedArray) label
- default:
- if (IsSCATypedArray(typeId) || typeId == SCA_DataView)
- {
- ReadTypedArray(typeId, dst);
- break;
- }
- return false; // Not a supported object type
- }
- #ifdef ENABLE_JS_ETW
- if (EventEnabledJSCRIPT_RECYCLER_ALLOCATE_OBJECT() && isObject)
- {
- EventWriteJSCRIPT_RECYCLER_ALLOCATE_OBJECT(*dst);
- }
- #endif
- #if ENABLE_DEBUG_CONFIG_OPTIONS
- if (Js::Configuration::Global.flags.IsEnabled(Js::autoProxyFlag))
- {
- *dst = JavascriptProxy::AutoProxyWrapper(*dst);
- }
- #endif
- return true;
- }
- template <class Reader>
- void DeserializationCloner<Reader>::CloneHostObjectProperties(SrcTypeId typeId, Src src, Dst dst)
- {
- // We have already created host obect.
- }
- template <class Reader>
- void DeserializationCloner<Reader>::CloneProperties(SrcTypeId typeId, Src src, Dst dst)
- {
- // ScriptContext* scriptContext = GetScriptContext();
- RecyclableObject* obj = VarTo<RecyclableObject>(dst);
- if (obj->IsExternal()) // Read host object properties
- {
- Assert(false);
- }
- else // Read native object properties
- {
- // Read array index named properties
- if (typeId == SCA_DenseArray)
- {
- JavascriptArray* arr = JavascriptArray::FromAnyArray(obj); // (might be ES5Array if -ForceES5Array)
- uint32 length = arr->GetLength();
- for (uint32 i = 0; i < length; i++)
- {
- Dst value = NULL;
- this->GetEngine()->Clone(m_reader->GetPosition(), &value);
- if (value)
- {
- arr->DirectSetItemAt(i, value); //Note: no prototype check
- }
- }
- }
- else if (typeId == SCA_SparseArray)
- {
- JavascriptArray* arr = JavascriptArray::FromAnyArray(obj); // (might be ES5Array if -ForceES5Array)
- while (true)
- {
- uint32 i;
- Read(&i);
- if (i == SCA_PROPERTY_TERMINATOR)
- {
- break;
- }
- Dst value = NULL;
- this->GetEngine()->Clone(m_reader->GetPosition(), &value);
- if (value == NULL)
- {
- this->ThrowSCADataCorrupt();
- }
- arr->DirectSetItemAt(i, value); //Note: no prototype check
- }
- }
- // Read non-index named properties
- ReadObjectPropertiesIntoObject(obj);
- }
- }
- template <class Reader>
- void DeserializationCloner<Reader>::CloneMap(Src src, Dst dst)
- {
- JavascriptMap* map = VarTo<JavascriptMap>(dst);
- int32 size;
- m_reader->Read(&size);
- for (int i = 0; i < size; i++)
- {
- Var key;
- Var value;
- this->GetEngine()->Clone(m_reader->GetPosition(), &key);
- if (!key)
- {
- this->ThrowSCADataCorrupt();
- }
- this->GetEngine()->Clone(m_reader->GetPosition(), &value);
- if (!value)
- {
- this->ThrowSCADataCorrupt();
- }
- map->Set(key, value);
- }
- }
- template <class Reader>
- void DeserializationCloner<Reader>::CloneSet(Src src, Dst dst)
- {
- JavascriptSet* set = VarTo<JavascriptSet>(dst);
- int32 size;
- m_reader->Read(&size);
- for (int i = 0; i < size; i++)
- {
- Var value;
- this->GetEngine()->Clone(m_reader->GetPosition(), &value);
- if (!value)
- {
- this->ThrowSCADataCorrupt();
- }
- set->Add(value);
- }
- }
- template <class Reader>
- void DeserializationCloner<Reader>::CloneObjectReference(Src src, Dst dst)
- {
- Assert(FALSE); // Should never call this. Object reference handled explictly.
- }
-
- //
- // Try to read a SCAString layout in the form of: [byteLen] [string content] [padding].
- // SCAString is also used for property name in object layout. In case of property terminator,
- // SCA_PROPERTY_TERMINATOR will appear at the place of [byteLen]. Return false in this case.
- //
- // If buffer is not null and the size is appropriate, will try reusing it
- //
- template <class Reader>
- const char16* DeserializationCloner<Reader>::TryReadString(charcount_t* len, bool reuseBuffer) const
- {
- // m_buffer is allocated on GC heap and stored in a regular field.
- // that is ok since 'this' is always a stack instance.
- Assert(ThreadContext::IsOnStack(this));
- uint32 byteLen;
- m_reader->Read(&byteLen);
- if (byteLen == SCA_PROPERTY_TERMINATOR)
- {
- return nullptr;
- }
- else if (byteLen == 0)
- {
- *len = 0;
- return _u("");
- }
- else
- {
- charcount_t newLen = byteLen / sizeof(char16);
- char16* buf;
- if (reuseBuffer)
- {
- if (this->m_bufferLength < newLen)
- {
- Recycler* recycler = this->GetScriptContext()->GetRecycler();
- this->m_buffer = RecyclerNewArrayLeaf(recycler, char16, newLen + 1);
- this->m_bufferLength = newLen;
- }
- buf = this->m_buffer;
- }
- else
- {
- Recycler* recycler = this->GetScriptContext()->GetRecycler();
- buf = RecyclerNewArrayLeaf(recycler, char16, newLen + 1);
- }
- m_reader->Read(buf, byteLen);
- buf[newLen] = NULL;
- *len = newLen;
- uint32 unalignedLen = byteLen % sizeof(uint32);
- if (unalignedLen)
- {
- uint32 padding;
- m_reader->Read(&padding, sizeof(uint32) - unalignedLen);
- }
- return buf;
- }
- }
- //
- // Read a SCAString value from layout: [byteLen] [string content] [padding].
- // Throw if seeing SCA_PROPERTY_TERMINATOR.
- //
- template <class Reader>
- const char16* DeserializationCloner<Reader>::ReadString(charcount_t* len) const
- {
- const char16* str = TryReadString(len, false);
- if (str == nullptr)
- {
- this->ThrowSCADataCorrupt();
- }
- return str;
- }
- //
- // Read bytes data: [bytes] [padding]
- //
- template <class Reader>
- void DeserializationCloner<Reader>::Read(BYTE* buf, uint32 len) const
- {
- m_reader->Read(buf, len);
- uint32 unalignedLen = len % sizeof(uint32);
- if (unalignedLen)
- {
- uint32 padding;
- m_reader->Read(&padding, sizeof(uint32) - unalignedLen);
- }
- }
- //
- // Read a TypedArray or DataView.
- //
- template <class Reader>
- void DeserializationCloner<Reader>::ReadTypedArray(SrcTypeId typeId, Dst* dst) const
- {
- switch (typeId)
- {
- case SCA_Int8Array:
- ReadTypedArray<int8, false>(dst);
- break;
- case SCA_Uint8Array:
- ReadTypedArray<uint8, false>(dst);
- break;
- case SCA_Uint8ClampedArray:
- ReadTypedArray<uint8, true>(dst);
- break;
- case SCA_Int16Array:
- ReadTypedArray<int16, false>(dst);
- break;
- case SCA_Uint16Array:
- ReadTypedArray<uint16, false>(dst);
- break;
- case SCA_Int32Array:
- ReadTypedArray<int32, false>(dst);
- break;
- case SCA_Uint32Array:
- ReadTypedArray<uint32, false>(dst);
- break;
- case SCA_Float32Array:
- ReadTypedArray<float, false>(dst);
- break;
- case SCA_Float64Array:
- ReadTypedArray<double, false>(dst);
- break;
- case SCA_DataView:
- ReadTypedArray<DataView, false>(dst);
- break;
- default:
- Assert(false);
- break;
- }
- }
- template class DeserializationCloner<StreamReader>;
- Var SCADeserializationEngine::Deserialize(StreamReader* reader, Var* transferableVars, size_t cTransferableVars)
- {
- ScriptContext* scriptContext = reader->GetScriptContext();
- StreamDeserializationCloner cloner(scriptContext, reader);
- // Read version
- uint32 version;
- reader->Read(&version);
- if (GetSCAMajor(version) > SCA_FORMAT_MAJOR)
- {
- cloner.ThrowSCANewVersion();
- }
- Var value = SCAEngine<scaposition_t, Var, StreamDeserializationCloner>::Clone(reader->GetPosition(), &cloner, transferableVars, cTransferableVars);
- if (!value)
- {
- cloner.ThrowSCADataCorrupt();
- }
- return value;
- }
- }
|