SCAEngine.h 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232
  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. #pragma once
  6. namespace Js
  7. {
  8. enum class SCADeepCloneType
  9. {
  10. None,
  11. Object,
  12. Map,
  13. Set,
  14. HostObject
  15. };
  16. //
  17. // SCAEngine performs the SCA algorithm by "cloning" a JavaScript var from Src representation
  18. // to Dst represetation. The representation could be a Var, or a location in a stream.
  19. //
  20. template <class Src, class Dst, class Cloner>
  21. class SCAEngine
  22. {
  23. private:
  24. // The map type that stores a map of cloned objects {Src->Dst}. Use
  25. // non leaf allocator because the map contains Vars.
  26. typedef JsUtil::BaseDictionary<Src, Dst, RecyclerNonLeafAllocator> ClonedObjectDictionary;
  27. Cloner* m_cloner;
  28. ClonedObjectDictionary* m_clonedObjects;
  29. Var* m_transferableVars;
  30. size_t m_cTransferableVars;
  31. private:
  32. SCAEngine(Cloner* cloner, Var* m_transferableVars, size_t cTransferableVars)
  33. : m_cloner(cloner),
  34. m_transferableVars(m_transferableVars),
  35. m_cTransferableVars(cTransferableVars)
  36. {
  37. Recycler* recycler = cloner->GetScriptContext()->GetRecycler();
  38. m_clonedObjects = RecyclerNew(recycler, ClonedObjectDictionary, recycler);
  39. m_cloner->SetEngine(this);
  40. }
  41. public:
  42. void Clone(Src src, Dst* dst)
  43. {
  44. PROBE_STACK(m_cloner->GetScriptContext(), Constants::MinStackDefault);
  45. #if ENABLE_COPYONACCESS_ARRAY
  46. JavascriptLibrary::CheckAndConvertCopyOnAccessNativeIntArray<Src>(src);
  47. #endif
  48. typename Cloner::SrcTypeId typeId = m_cloner->GetTypeId(src);
  49. if (m_cloner->TryClonePrimitive(typeId, src, dst))
  50. {
  51. return;
  52. }
  53. if (Cloner::ShouldLookupReference() && TryGetClonedObject(src, dst))
  54. {
  55. m_cloner->CloneObjectReference(src, *dst);
  56. return;
  57. }
  58. SCADeepCloneType deepClone;
  59. if (m_cloner->TryCloneObject(typeId, src, dst, &deepClone))
  60. {
  61. m_clonedObjects->Add(src, *dst);
  62. if (deepClone == SCADeepCloneType::Map)
  63. {
  64. m_cloner->CloneMap(src, *dst);
  65. deepClone = SCADeepCloneType::Object;
  66. }
  67. else if (deepClone == SCADeepCloneType::Set)
  68. {
  69. m_cloner->CloneSet(src, *dst);
  70. deepClone = SCADeepCloneType::Object;
  71. }
  72. if (deepClone == SCADeepCloneType::HostObject)
  73. {
  74. m_cloner->CloneHostObjectProperties(typeId, src, *dst);
  75. }
  76. else if (deepClone == SCADeepCloneType::Object)
  77. {
  78. m_cloner->CloneProperties(typeId, src, *dst);
  79. }
  80. return;
  81. }
  82. // Unsupported src type, throw
  83. m_cloner->ThrowSCAUnsupported();
  84. }
  85. void Clone(Src src)
  86. {
  87. Dst unused;
  88. Clone(src, &unused);
  89. }
  90. bool TryGetClonedObject(Src src, Dst* dst) const
  91. {
  92. return m_clonedObjects->TryGetValue(src, dst);
  93. }
  94. bool TryGetTransferredOrShared(Var source, size_t* outDestination)
  95. {
  96. if (m_transferableVars == nullptr)
  97. {
  98. return false;
  99. }
  100. for (size_t i = 0; i < m_cTransferableVars; i++)
  101. {
  102. if (m_transferableVars[i] == source)
  103. {
  104. if (outDestination != nullptr)
  105. {
  106. *outDestination = i;
  107. }
  108. return true;
  109. }
  110. }
  111. return false;
  112. }
  113. Dst ClaimTransferable(size_t index, JavascriptLibrary* library)
  114. {
  115. AssertMsg(index < this->m_cTransferableVars, "Index out of range.");
  116. ArrayBuffer *ab = VarTo<ArrayBuffer>(m_transferableVars[index]);
  117. return ab;
  118. }
  119. static Dst Clone(Src root, Cloner* cloner, Var* transferableVars, size_t cTransferableVars)
  120. {
  121. SCAEngine<Src, Dst, Cloner> engine(cloner, transferableVars, cTransferableVars);
  122. Dst dst;
  123. engine.Clone(root, &dst);
  124. return dst;
  125. }
  126. };
  127. //
  128. // Helper class that simply contains a ScriptContext*.
  129. //
  130. class ScriptContextHolder
  131. {
  132. private:
  133. ScriptContext* m_scriptContext;
  134. public:
  135. ScriptContextHolder(ScriptContext* scriptContext)
  136. : m_scriptContext(scriptContext)
  137. {
  138. }
  139. ScriptContext* GetScriptContext() const
  140. {
  141. return m_scriptContext;
  142. }
  143. void ThrowIfFailed(HRESULT hr) const;
  144. void __declspec(noreturn) ThrowSCAUnsupported() const
  145. {
  146. // E_SCA_UNSUPPORTED
  147. ThrowIfFailed(E_FAIL);
  148. }
  149. void __declspec(noreturn) ThrowSCANewVersion() const
  150. {
  151. // E_SCA_NEWVERSION
  152. ThrowIfFailed(E_FAIL);
  153. }
  154. void __declspec(noreturn) ThrowSCADataCorrupt() const
  155. {
  156. // E_SCA_DATACORRUPT
  157. ThrowIfFailed(E_FAIL);
  158. }
  159. void __declspec(noreturn) ThrowSCAObjectDetached() const
  160. {
  161. // E_SCA_TRANSFERABLE_NEUTERED
  162. ThrowIfFailed(E_FAIL);
  163. }
  164. };
  165. //
  166. // Helper class to implement Cloner.
  167. //
  168. template <class TSrc, class TDst, class TSrcTypeId, class Cloner>
  169. class ClonerBase : public ScriptContextHolder
  170. {
  171. public:
  172. typedef TSrc Src;
  173. typedef TDst Dst;
  174. typedef TSrcTypeId SrcTypeId;
  175. typedef SCAEngine<Src, Dst, Cloner> Engine;
  176. private:
  177. Engine* m_engine;
  178. public:
  179. ClonerBase(ScriptContext* scriptContext)
  180. : ScriptContextHolder(scriptContext),
  181. m_engine(NULL)
  182. {
  183. }
  184. Engine* GetEngine() const
  185. {
  186. Assert(m_engine); // Must have been set
  187. return m_engine;
  188. }
  189. void SetEngine(Engine* engine)
  190. {
  191. Assert(!m_engine); // Can only be set once
  192. m_engine = engine;
  193. }
  194. };
  195. }