WebAssemblyTable.cpp 8.1 KB

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