WebAssemblyTable.cpp 8.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273
  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 "RuntimeLibraryPch.h"
  6. #ifdef ENABLE_WASM
  7. #include "WasmLimits.h"
  8. namespace Js
  9. {
  10. WebAssemblyTable::WebAssemblyTable(
  11. Field(Var) * values, uint32 currentLength, uint32 initialLength, uint32 maxLength, DynamicType * type) :
  12. DynamicObject(type),
  13. m_values(values),
  14. m_currentLength(currentLength),
  15. m_initialLength(initialLength),
  16. m_maxLength(maxLength)
  17. {
  18. }
  19. /* static */
  20. bool
  21. WebAssemblyTable::Is(Var value)
  22. {
  23. return JavascriptOperators::GetTypeId(value) == TypeIds_WebAssemblyTable;
  24. }
  25. /* static */
  26. WebAssemblyTable *
  27. WebAssemblyTable::FromVar(Var value)
  28. {
  29. AssertOrFailFast(WebAssemblyTable::Is(value));
  30. return static_cast<WebAssemblyTable*>(value);
  31. }
  32. /* static */
  33. WebAssemblyTable *
  34. WebAssemblyTable::UnsafeFromVar(Var value)
  35. {
  36. Assert(WebAssemblyTable::Is(value));
  37. return static_cast<WebAssemblyTable*>(value);
  38. }
  39. Var
  40. WebAssemblyTable::NewInstance(RecyclableObject* function, CallInfo callInfo, ...)
  41. {
  42. PROBE_STACK(function->GetScriptContext(), Js::Constants::MinStackDefault);
  43. ARGUMENTS(args, callInfo);
  44. ScriptContext* scriptContext = function->GetScriptContext();
  45. AssertMsg(args.HasArg(), "Should always have implicit 'this'");
  46. Var newTarget = args.GetNewTarget();
  47. JavascriptOperators::GetAndAssertIsConstructorSuperCall(args);
  48. if (!(callInfo.Flags & CallFlags_New) || (newTarget && JavascriptOperators::IsUndefinedObject(newTarget)))
  49. {
  50. JavascriptError::ThrowTypeError(scriptContext, JSERR_ClassConstructorCannotBeCalledWithoutNew, _u("WebAssembly.Table"));
  51. }
  52. if (args.Info.Count < 2 || !JavascriptOperators::IsObject(args[1]))
  53. {
  54. JavascriptError::ThrowTypeError(scriptContext, JSERR_NeedObject, _u("tableDescriptor"));
  55. }
  56. DynamicObject * tableDescriptor = JavascriptObject::FromVar(args[1]);
  57. Var elementVar = JavascriptOperators::OP_GetProperty(tableDescriptor, PropertyIds::element, scriptContext);
  58. if (!JavascriptOperators::StrictEqualString(elementVar, scriptContext->GetLibrary()->CreateStringFromCppLiteral(_u("anyfunc"))))
  59. {
  60. JavascriptError::ThrowTypeError(scriptContext, WASMERR_ExpectedAnyFunc, _u("tableDescriptor.element"));
  61. }
  62. Var initVar = JavascriptOperators::OP_GetProperty(tableDescriptor, PropertyIds::initial, scriptContext);
  63. uint32 initial = WebAssembly::ToNonWrappingUint32(initVar, scriptContext);
  64. uint32 maximum = Wasm::Limits::GetMaxTableSize();
  65. if (JavascriptOperators::OP_HasProperty(tableDescriptor, PropertyIds::maximum, scriptContext))
  66. {
  67. Var maxVar = JavascriptOperators::OP_GetProperty(tableDescriptor, PropertyIds::maximum, scriptContext);
  68. maximum = WebAssembly::ToNonWrappingUint32(maxVar, scriptContext);
  69. }
  70. return Create(initial, maximum, scriptContext);
  71. }
  72. Var
  73. WebAssemblyTable::EntryGetterLength(RecyclableObject* function, CallInfo callInfo, ...)
  74. {
  75. PROBE_STACK(function->GetScriptContext(), Js::Constants::MinStackDefault);
  76. ARGUMENTS(args, callInfo);
  77. ScriptContext* scriptContext = function->GetScriptContext();
  78. Assert(!(callInfo.Flags & CallFlags_New));
  79. if (args.Info.Count == 0 || !WebAssemblyTable::Is(args[0]))
  80. {
  81. JavascriptError::ThrowTypeError(scriptContext, WASMERR_NeedTableObject);
  82. }
  83. WebAssemblyTable * table = WebAssemblyTable::FromVar(args[0]);
  84. return JavascriptNumber::ToVar(table->m_currentLength, scriptContext);
  85. }
  86. Var
  87. WebAssemblyTable::EntryGrow(RecyclableObject* function, CallInfo callInfo, ...)
  88. {
  89. PROBE_STACK(function->GetScriptContext(), Js::Constants::MinStackDefault);
  90. ARGUMENTS(args, callInfo);
  91. ScriptContext* scriptContext = function->GetScriptContext();
  92. Assert(!(callInfo.Flags & CallFlags_New));
  93. if (args.Info.Count == 0 || !WebAssemblyTable::Is(args[0]))
  94. {
  95. JavascriptError::ThrowTypeError(scriptContext, WASMERR_NeedTableObject);
  96. }
  97. WebAssemblyTable * table = WebAssemblyTable::FromVar(args[0]);
  98. uint32 oldLength = table->m_currentLength;
  99. Var deltaVar = args.Info.Count >= 2 ? args[1] : scriptContext->GetLibrary()->GetUndefined();
  100. uint32 delta = WebAssembly::ToNonWrappingUint32(deltaVar, scriptContext);
  101. if (delta > 0)
  102. {
  103. uint32 newLength = 0;
  104. if (UInt32Math::Add(table->m_currentLength, delta, &newLength) || newLength > table->m_maxLength)
  105. {
  106. JavascriptError::ThrowRangeError(scriptContext, JSERR_ArgumentOutOfRange);
  107. }
  108. Field(Var) * newValues = RecyclerNewArrayZ(scriptContext->GetRecycler(), Field(Var), newLength);
  109. CopyArray(newValues, newLength, table->m_values, table->m_currentLength);
  110. table->m_values = newValues;
  111. table->m_currentLength = newLength;
  112. }
  113. return JavascriptNumber::ToVar(oldLength, scriptContext);
  114. }
  115. Var
  116. WebAssemblyTable::EntryGet(RecyclableObject* function, CallInfo callInfo, ...)
  117. {
  118. PROBE_STACK(function->GetScriptContext(), Js::Constants::MinStackDefault);
  119. ARGUMENTS(args, callInfo);
  120. ScriptContext* scriptContext = function->GetScriptContext();
  121. Assert(!(callInfo.Flags & CallFlags_New));
  122. if (args.Info.Count == 0 || !WebAssemblyTable::Is(args[0]))
  123. {
  124. JavascriptError::ThrowTypeError(scriptContext, WASMERR_NeedTableObject);
  125. }
  126. WebAssemblyTable * table = WebAssemblyTable::FromVar(args[0]);
  127. Var indexVar = scriptContext->GetLibrary()->GetUndefined();
  128. if (args.Info.Count >= 2)
  129. {
  130. indexVar = args[1];
  131. }
  132. uint32 index = WebAssembly::ToNonWrappingUint32(indexVar, scriptContext);
  133. if (index >= table->m_currentLength)
  134. {
  135. JavascriptError::ThrowRangeError(scriptContext, JSERR_ArgumentOutOfRange);
  136. }
  137. if (!table->m_values[index])
  138. {
  139. return scriptContext->GetLibrary()->GetNull();
  140. }
  141. return table->m_values[index];
  142. }
  143. Var
  144. WebAssemblyTable::EntrySet(RecyclableObject* function, CallInfo callInfo, ...)
  145. {
  146. PROBE_STACK(function->GetScriptContext(), Js::Constants::MinStackDefault);
  147. ARGUMENTS(args, callInfo);
  148. ScriptContext* scriptContext = function->GetScriptContext();
  149. Assert(!(callInfo.Flags & CallFlags_New));
  150. if (args.Info.Count == 0 || !WebAssemblyTable::Is(args[0]))
  151. {
  152. JavascriptError::ThrowTypeError(scriptContext, WASMERR_NeedTableObject);
  153. }
  154. WebAssemblyTable * table = WebAssemblyTable::FromVar(args[0]);
  155. if (args.Info.Count < 3)
  156. {
  157. JavascriptError::ThrowTypeError(scriptContext, WASMERR_NeedWebAssemblyFunc);
  158. }
  159. Var indexVar = args[1];
  160. Var value = args[2];
  161. if (JavascriptOperators::IsNull(value))
  162. {
  163. value = nullptr;
  164. }
  165. else if (!WasmScriptFunction::Is(args[2]))
  166. {
  167. JavascriptError::ThrowTypeError(scriptContext, WASMERR_NeedWebAssemblyFunc);
  168. }
  169. uint32 index = WebAssembly::ToNonWrappingUint32(indexVar, scriptContext);
  170. if (index >= table->m_currentLength)
  171. {
  172. JavascriptError::ThrowRangeError(scriptContext, JSERR_ArgumentOutOfRange);
  173. }
  174. table->m_values[index] = value;
  175. return scriptContext->GetLibrary()->GetUndefined();
  176. }
  177. WebAssemblyTable *
  178. WebAssemblyTable::Create(uint32 initial, uint32 maximum, ScriptContext * scriptContext)
  179. {
  180. if (initial > maximum || initial > Wasm::Limits::GetMaxTableSize() || maximum > Wasm::Limits::GetMaxTableSize())
  181. {
  182. JavascriptError::ThrowRangeError(scriptContext, JSERR_ArgumentOutOfRange);
  183. }
  184. Field(Var) * values = nullptr;
  185. if (initial > 0)
  186. {
  187. values = RecyclerNewArrayZ(scriptContext->GetRecycler(), Field(Var), initial);
  188. }
  189. return RecyclerNew(scriptContext->GetRecycler(), WebAssemblyTable, values, initial, initial, maximum, scriptContext->GetLibrary()->GetWebAssemblyTableType());
  190. }
  191. void
  192. WebAssemblyTable::DirectSetValue(uint index, Var val)
  193. {
  194. Assert(index < m_currentLength);
  195. Assert(!val || WasmScriptFunction::Is(val));
  196. m_values[index] = val;
  197. }
  198. Var
  199. WebAssemblyTable::DirectGetValue(uint index) const
  200. {
  201. Assert(index < m_currentLength);
  202. Var val = m_values[index];
  203. Assert(!val || WasmScriptFunction::Is(val));
  204. return val;
  205. }
  206. uint32
  207. WebAssemblyTable::GetCurrentLength() const
  208. {
  209. return m_currentLength;
  210. }
  211. uint32
  212. WebAssemblyTable::GetInitialLength() const
  213. {
  214. return m_initialLength;
  215. }
  216. uint32
  217. WebAssemblyTable::GetMaximumLength() const
  218. {
  219. return m_maxLength;
  220. }
  221. } // namespace Js
  222. #endif // ENABLE_WASM