SCADeserialization.cpp 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593
  1. //-------------------------------------------------------------------------------------------------------
  2. // Copyright (C) Microsoft. All rights reserved.
  3. // Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
  4. //-------------------------------------------------------------------------------------------------------
  5. #include "SCACorePch.h"
  6. namespace Js
  7. {
  8. template <class Reader>
  9. bool DeserializationCloner<Reader>::TryClonePrimitive(SrcTypeId typeId, Src src, Dst* dst)
  10. {
  11. if (!IsSCAPrimitive(typeId))
  12. {
  13. return false;
  14. }
  15. ScriptContext* scriptContext = this->GetScriptContext();
  16. JavascriptLibrary* lib = scriptContext->GetLibrary();
  17. switch (typeId)
  18. {
  19. case SCA_None:
  20. *dst = NULL;
  21. break;
  22. case SCA_Reference: // Handle reference explictly as a primitive
  23. {
  24. scaposition_t pos;
  25. m_reader->Read(&pos);
  26. if (!this->GetEngine()->TryGetClonedObject(pos, dst))
  27. {
  28. this->ThrowSCADataCorrupt();
  29. }
  30. }
  31. break;
  32. case SCA_NullValue:
  33. *dst = lib->GetNull();
  34. break;
  35. case SCA_UndefinedValue:
  36. *dst = lib->GetUndefined();
  37. break;
  38. case SCA_TrueValue:
  39. *dst = lib->GetTrue();
  40. break;
  41. case SCA_FalseValue:
  42. *dst = lib->GetFalse();
  43. break;
  44. case SCA_Int32Value:
  45. {
  46. int32 n;
  47. m_reader->Read(&n);
  48. *dst = JavascriptNumber::ToVar(n, scriptContext);
  49. }
  50. break;
  51. case SCA_DoubleValue:
  52. {
  53. double dbl;
  54. m_reader->Read(&dbl);
  55. *dst = JavascriptNumber::ToVarWithCheck(dbl, scriptContext);
  56. }
  57. break;
  58. case SCA_Int64Value:
  59. {
  60. __int64 n;
  61. m_reader->Read(&n);
  62. *dst = JavascriptInt64Number::ToVar(n, scriptContext);
  63. }
  64. break;
  65. case SCA_Uint64Value:
  66. {
  67. unsigned __int64 n;
  68. m_reader->Read(&n);
  69. *dst = JavascriptUInt64Number::ToVar(n, scriptContext);
  70. }
  71. break;
  72. default:
  73. return false; // Not a recognized primitive type
  74. }
  75. return true;
  76. }
  77. template <class Reader>
  78. bool DeserializationCloner<Reader>::TryCloneObject(SrcTypeId typeId, Src src, Dst* dst, SCADeepCloneType* deepClone)
  79. {
  80. ScriptContext* scriptContext = this->GetScriptContext();
  81. JavascriptLibrary* lib = scriptContext->GetLibrary();
  82. *deepClone = SCADeepCloneType::None;
  83. bool isObject = true;
  84. if (typeId == SCA_Transferable)
  85. {
  86. scaposition_t pos;
  87. m_reader->Read(&pos);
  88. *dst = this->GetEngine()->ClaimTransferable(pos, lib);
  89. if (*dst == nullptr)
  90. {
  91. this->ThrowSCADataCorrupt();
  92. }
  93. return true;
  94. }
  95. if (IsSCAHostObject(typeId))
  96. {
  97. *dst = m_reader->ReadHostObject();
  98. *deepClone = SCADeepCloneType::HostObject;
  99. return true;
  100. }
  101. switch (typeId)
  102. {
  103. case SCA_StringValue: // Clone string value as object type to resolve multiple references
  104. {
  105. charcount_t len;
  106. const char16* buf = ReadString(&len);
  107. *dst = Js::JavascriptString::NewWithBuffer(buf, len, scriptContext);
  108. isObject = false;
  109. }
  110. break;
  111. case SCA_BooleanTrueObject:
  112. *dst = lib->CreateBooleanObject(TRUE);
  113. break;
  114. case SCA_BooleanFalseObject:
  115. *dst = lib->CreateBooleanObject(FALSE);
  116. break;
  117. case SCA_DateObject:
  118. {
  119. double dbl;
  120. m_reader->Read(&dbl);
  121. *dst = lib->CreateDate(dbl);
  122. }
  123. break;
  124. case SCA_NumberObject:
  125. {
  126. double dbl;
  127. m_reader->Read(&dbl);
  128. *dst = lib->CreateNumberObjectWithCheck(dbl);
  129. }
  130. break;
  131. case SCA_StringObject:
  132. {
  133. charcount_t len;
  134. const char16* buf = ReadString(&len);
  135. *dst = lib->CreateStringObject(buf, len);
  136. }
  137. break;
  138. case SCA_RegExpObject:
  139. {
  140. charcount_t len;
  141. const char16* buf = ReadString(&len);
  142. DWORD flags;
  143. m_reader->Read(&flags);
  144. *dst = JavascriptRegExp::CreateRegEx(buf, len,
  145. static_cast<UnifiedRegex::RegexFlags>(flags), scriptContext);
  146. }
  147. break;
  148. case SCA_Object:
  149. {
  150. *dst = lib->CreateObject();
  151. *deepClone = SCADeepCloneType::Object;
  152. }
  153. break;
  154. case SCA_Map:
  155. {
  156. *dst = JavascriptMap::New(scriptContext);
  157. *deepClone = SCADeepCloneType::Map;
  158. }
  159. break;
  160. case SCA_Set:
  161. {
  162. *dst = JavascriptSet::New(scriptContext);
  163. *deepClone = SCADeepCloneType::Set;
  164. }
  165. break;
  166. case SCA_DenseArray:
  167. case SCA_SparseArray:
  168. {
  169. uint32 length;
  170. Read(&length);
  171. *dst = lib->CreateArray(length);
  172. *deepClone = SCADeepCloneType::Object;
  173. }
  174. break;
  175. case SCA_ArrayBuffer:
  176. {
  177. uint32 len;
  178. m_reader->Read(&len);
  179. ArrayBuffer* arrayBuffer = lib->CreateArrayBuffer(len);
  180. Read(arrayBuffer->GetBuffer(), arrayBuffer->GetByteLength());
  181. *dst = arrayBuffer;
  182. }
  183. break;
  184. case SCA_SharedArrayBuffer:
  185. {
  186. SharedContents * sharedContents;
  187. m_reader->Read((intptr_t*)&sharedContents);
  188. SharedArrayBuffer* arrayBuffer = lib->CreateSharedArrayBuffer(sharedContents);
  189. Assert(arrayBuffer->IsWebAssemblyArrayBuffer() == sharedContents->IsWebAssembly());
  190. *dst = arrayBuffer;
  191. }
  192. break;
  193. //#ifdef ENABLE_WASM
  194. // case SCA_WebAssemblyModule:
  195. // {
  196. // uint32 len;
  197. // m_reader->Read(&len);
  198. // byte* buffer = RecyclerNewArrayLeaf(scriptContext->GetRecycler(), byte, len);
  199. // Read(buffer, len);
  200. // WebAssemblySource wasmSrc(buffer, len, true, scriptContext);
  201. // *dst = WebAssemblyModule::CreateModule(scriptContext, &wasmSrc);
  202. // break;
  203. // }
  204. // case SCA_WebAssemblyMemory:
  205. // {
  206. // uint32 initialLength = 0;
  207. // uint32 maximumLength = 0;
  208. // uint32 isShared = 0;
  209. // m_reader->Read(&initialLength);
  210. // m_reader->Read(&maximumLength);
  211. //
  212. //#ifdef ENABLE_WASM_THREADS
  213. // m_reader->Read(&isShared);
  214. // if (isShared)
  215. // {
  216. // SharedContents * sharedContents;
  217. // m_reader->Read((intptr_t*)&sharedContents);
  218. // *dst = WebAssemblyMemory::CreateFromSharedContents(initialLength, maximumLength, sharedContents, scriptContext);
  219. // }
  220. // else
  221. //#endif
  222. // {
  223. // uint32 len;
  224. // m_reader->Read(&len);
  225. // WebAssemblyMemory* mem = WebAssemblyMemory::CreateForExistingBuffer(initialLength, maximumLength, len, scriptContext);
  226. // Read(mem->GetBuffer()->GetBuffer(), len);
  227. // *dst = mem;
  228. // }
  229. // break;
  230. // }
  231. //#endif
  232. case SCA_Uint8ClampedArray:
  233. // If Khronos Interop is not enabled, we don't have Uint8ClampedArray available.
  234. // This is a scenario where the source buffer was created in a newer document mode
  235. // but needs to be deserialized in an older document mode.
  236. // What we want to do is return the buffer as a CanvasPixelArray instead of
  237. // Uint8ClampedArray since the older document mode knows what CanvasPixelArray is but
  238. // not what Uint8ClampedArray is.
  239. // We don't support pixelarray in edge anymore.
  240. // Intentionally fall through to default (TypedArray) label
  241. default:
  242. if (IsSCATypedArray(typeId) || typeId == SCA_DataView)
  243. {
  244. ReadTypedArray(typeId, dst);
  245. break;
  246. }
  247. return false; // Not a supported object type
  248. }
  249. #ifdef ENABLE_JS_ETW
  250. if (EventEnabledJSCRIPT_RECYCLER_ALLOCATE_OBJECT() && isObject)
  251. {
  252. EventWriteJSCRIPT_RECYCLER_ALLOCATE_OBJECT(*dst);
  253. }
  254. #endif
  255. #if ENABLE_DEBUG_CONFIG_OPTIONS
  256. if (Js::Configuration::Global.flags.IsEnabled(Js::autoProxyFlag))
  257. {
  258. *dst = JavascriptProxy::AutoProxyWrapper(*dst);
  259. }
  260. #endif
  261. return true;
  262. }
  263. template <class Reader>
  264. void DeserializationCloner<Reader>::CloneHostObjectProperties(SrcTypeId typeId, Src src, Dst dst)
  265. {
  266. // We have already created host obect.
  267. }
  268. template <class Reader>
  269. void DeserializationCloner<Reader>::CloneProperties(SrcTypeId typeId, Src src, Dst dst)
  270. {
  271. // ScriptContext* scriptContext = GetScriptContext();
  272. RecyclableObject* obj = VarTo<RecyclableObject>(dst);
  273. if (obj->IsExternal()) // Read host object properties
  274. {
  275. Assert(false);
  276. }
  277. else // Read native object properties
  278. {
  279. // Read array index named properties
  280. if (typeId == SCA_DenseArray)
  281. {
  282. JavascriptArray* arr = JavascriptArray::FromAnyArray(obj); // (might be ES5Array if -ForceES5Array)
  283. uint32 length = arr->GetLength();
  284. for (uint32 i = 0; i < length; i++)
  285. {
  286. Dst value = NULL;
  287. this->GetEngine()->Clone(m_reader->GetPosition(), &value);
  288. if (value)
  289. {
  290. arr->DirectSetItemAt(i, value); //Note: no prototype check
  291. }
  292. }
  293. }
  294. else if (typeId == SCA_SparseArray)
  295. {
  296. JavascriptArray* arr = JavascriptArray::FromAnyArray(obj); // (might be ES5Array if -ForceES5Array)
  297. while (true)
  298. {
  299. uint32 i;
  300. Read(&i);
  301. if (i == SCA_PROPERTY_TERMINATOR)
  302. {
  303. break;
  304. }
  305. Dst value = NULL;
  306. this->GetEngine()->Clone(m_reader->GetPosition(), &value);
  307. if (value == NULL)
  308. {
  309. this->ThrowSCADataCorrupt();
  310. }
  311. arr->DirectSetItemAt(i, value); //Note: no prototype check
  312. }
  313. }
  314. // Read non-index named properties
  315. ReadObjectPropertiesIntoObject(obj);
  316. }
  317. }
  318. template <class Reader>
  319. void DeserializationCloner<Reader>::CloneMap(Src src, Dst dst)
  320. {
  321. JavascriptMap* map = VarTo<JavascriptMap>(dst);
  322. int32 size;
  323. m_reader->Read(&size);
  324. for (int i = 0; i < size; i++)
  325. {
  326. Var key;
  327. Var value;
  328. this->GetEngine()->Clone(m_reader->GetPosition(), &key);
  329. if (!key)
  330. {
  331. this->ThrowSCADataCorrupt();
  332. }
  333. this->GetEngine()->Clone(m_reader->GetPosition(), &value);
  334. if (!value)
  335. {
  336. this->ThrowSCADataCorrupt();
  337. }
  338. map->Set(key, value);
  339. }
  340. }
  341. template <class Reader>
  342. void DeserializationCloner<Reader>::CloneSet(Src src, Dst dst)
  343. {
  344. JavascriptSet* set = VarTo<JavascriptSet>(dst);
  345. int32 size;
  346. m_reader->Read(&size);
  347. for (int i = 0; i < size; i++)
  348. {
  349. Var value;
  350. this->GetEngine()->Clone(m_reader->GetPosition(), &value);
  351. if (!value)
  352. {
  353. this->ThrowSCADataCorrupt();
  354. }
  355. set->Add(value);
  356. }
  357. }
  358. template <class Reader>
  359. void DeserializationCloner<Reader>::CloneObjectReference(Src src, Dst dst)
  360. {
  361. Assert(FALSE); // Should never call this. Object reference handled explictly.
  362. }
  363. //
  364. // Try to read a SCAString layout in the form of: [byteLen] [string content] [padding].
  365. // SCAString is also used for property name in object layout. In case of property terminator,
  366. // SCA_PROPERTY_TERMINATOR will appear at the place of [byteLen]. Return false in this case.
  367. //
  368. // If buffer is not null and the size is appropriate, will try reusing it
  369. //
  370. template <class Reader>
  371. const char16* DeserializationCloner<Reader>::TryReadString(charcount_t* len, bool reuseBuffer) const
  372. {
  373. // m_buffer is allocated on GC heap and stored in a regular field.
  374. // that is ok since 'this' is always a stack instance.
  375. Assert(ThreadContext::IsOnStack(this));
  376. uint32 byteLen;
  377. m_reader->Read(&byteLen);
  378. if (byteLen == SCA_PROPERTY_TERMINATOR)
  379. {
  380. return nullptr;
  381. }
  382. else if (byteLen == 0)
  383. {
  384. *len = 0;
  385. return _u("");
  386. }
  387. else
  388. {
  389. charcount_t newLen = byteLen / sizeof(char16);
  390. char16* buf;
  391. if (reuseBuffer)
  392. {
  393. if (this->m_bufferLength < newLen)
  394. {
  395. Recycler* recycler = this->GetScriptContext()->GetRecycler();
  396. this->m_buffer = RecyclerNewArrayLeaf(recycler, char16, newLen + 1);
  397. this->m_bufferLength = newLen;
  398. }
  399. buf = this->m_buffer;
  400. }
  401. else
  402. {
  403. Recycler* recycler = this->GetScriptContext()->GetRecycler();
  404. buf = RecyclerNewArrayLeaf(recycler, char16, newLen + 1);
  405. }
  406. m_reader->Read(buf, byteLen);
  407. buf[newLen] = NULL;
  408. *len = newLen;
  409. uint32 unalignedLen = byteLen % sizeof(uint32);
  410. if (unalignedLen)
  411. {
  412. uint32 padding;
  413. m_reader->Read(&padding, sizeof(uint32) - unalignedLen);
  414. }
  415. return buf;
  416. }
  417. }
  418. //
  419. // Read a SCAString value from layout: [byteLen] [string content] [padding].
  420. // Throw if seeing SCA_PROPERTY_TERMINATOR.
  421. //
  422. template <class Reader>
  423. const char16* DeserializationCloner<Reader>::ReadString(charcount_t* len) const
  424. {
  425. const char16* str = TryReadString(len, false);
  426. if (str == nullptr)
  427. {
  428. this->ThrowSCADataCorrupt();
  429. }
  430. return str;
  431. }
  432. //
  433. // Read bytes data: [bytes] [padding]
  434. //
  435. template <class Reader>
  436. void DeserializationCloner<Reader>::Read(BYTE* buf, uint32 len) const
  437. {
  438. m_reader->Read(buf, len);
  439. uint32 unalignedLen = len % sizeof(uint32);
  440. if (unalignedLen)
  441. {
  442. uint32 padding;
  443. m_reader->Read(&padding, sizeof(uint32) - unalignedLen);
  444. }
  445. }
  446. //
  447. // Read a TypedArray or DataView.
  448. //
  449. template <class Reader>
  450. void DeserializationCloner<Reader>::ReadTypedArray(SrcTypeId typeId, Dst* dst) const
  451. {
  452. switch (typeId)
  453. {
  454. case SCA_Int8Array:
  455. ReadTypedArray<int8, false>(dst);
  456. break;
  457. case SCA_Uint8Array:
  458. ReadTypedArray<uint8, false>(dst);
  459. break;
  460. case SCA_Uint8ClampedArray:
  461. ReadTypedArray<uint8, true>(dst);
  462. break;
  463. case SCA_Int16Array:
  464. ReadTypedArray<int16, false>(dst);
  465. break;
  466. case SCA_Uint16Array:
  467. ReadTypedArray<uint16, false>(dst);
  468. break;
  469. case SCA_Int32Array:
  470. ReadTypedArray<int32, false>(dst);
  471. break;
  472. case SCA_Uint32Array:
  473. ReadTypedArray<uint32, false>(dst);
  474. break;
  475. case SCA_Float32Array:
  476. ReadTypedArray<float, false>(dst);
  477. break;
  478. case SCA_Float64Array:
  479. ReadTypedArray<double, false>(dst);
  480. break;
  481. case SCA_DataView:
  482. ReadTypedArray<DataView, false>(dst);
  483. break;
  484. default:
  485. Assert(false);
  486. break;
  487. }
  488. }
  489. template class DeserializationCloner<StreamReader>;
  490. Var SCADeserializationEngine::Deserialize(StreamReader* reader, Var* transferableVars, size_t cTransferableVars)
  491. {
  492. ScriptContext* scriptContext = reader->GetScriptContext();
  493. StreamDeserializationCloner cloner(scriptContext, reader);
  494. // Read version
  495. uint32 version;
  496. reader->Read(&version);
  497. if (GetSCAMajor(version) > SCA_FORMAT_MAJOR)
  498. {
  499. cloner.ThrowSCANewVersion();
  500. }
  501. Var value = SCAEngine<scaposition_t, Var, StreamDeserializationCloner>::Clone(reader->GetPosition(), &cloner, transferableVars, cTransferableVars);
  502. if (!value)
  503. {
  504. cloner.ThrowSCADataCorrupt();
  505. }
  506. return value;
  507. }
  508. }