WebAssemblyEnvironment.cpp 9.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255
  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 "../WasmReader/WasmReaderPch.h"
  8. namespace Js
  9. {
  10. WebAssemblyEnvironment::WebAssemblyEnvironment(WebAssemblyModule* module):
  11. m_alloc(_u("WebAssemblyEnvironment"), module->GetScriptContext()->GetThreadContext()->GetPageAllocator(), Js::Throw::OutOfMemory)
  12. {
  13. this->module = module;
  14. ScriptContext* scriptContext = module->GetScriptContext();
  15. uint32 size = module->GetModuleEnvironmentSize();
  16. this->start = RecyclerNewArrayZ(scriptContext->GetRecycler(), Field(Var), size);
  17. this->end = start + size;
  18. Assert(start < end);
  19. this->memory = this->start + module->GetMemoryOffset();
  20. this->imports = this->start + module->GetImportFuncOffset();
  21. this->functions = this->start + module->GetFuncOffset();
  22. this->table = this->start + module->GetTableEnvironmentOffset();
  23. this->globals = this->start + module->GetGlobalOffset();
  24. uint32 globalsSize = WAsmJs::ConvertOffset<byte, Js::Var>(module->GetGlobalsByteSize());
  25. // Assumes globals are last
  26. Assert(globals > table && globals > functions && globals > imports && globals > memory);
  27. if (globals < start ||
  28. (globals + globalsSize) > end)
  29. {
  30. // Something went wrong in the allocation and/or offset calculation failfast
  31. JavascriptError::ThrowOutOfMemoryError(scriptContext);
  32. }
  33. AssertMsg(globals + globalsSize + 0x10 > end, "We don't expect to allocate much more memory than what's needed");
  34. elementSegmentOffsets = AnewArrayZ(&m_alloc, uint, module->GetElementSegCount());
  35. dataSegmentOffsets = AnewArrayZ(&m_alloc, uint, module->GetDataSegCount());
  36. }
  37. template<typename T>
  38. void WebAssemblyEnvironment::CheckPtrIsValid(intptr_t ptr) const
  39. {
  40. if (ptr < (intptr_t)PointerValue(start) || (intptr_t)(ptr + sizeof(T)) > (intptr_t)PointerValue(end))
  41. {
  42. Js::Throw::InternalError();
  43. }
  44. }
  45. template<typename T>
  46. T* WebAssemblyEnvironment::GetVarElement(Field(Var)* ptr, uint32 index, uint32 maxCount) const
  47. {
  48. if (index >= maxCount)
  49. {
  50. Js::Throw::InternalError();
  51. }
  52. Field(Var)* functionPtr = ptr + index;
  53. CheckPtrIsValid<T*>((intptr_t)functionPtr);
  54. Var varFunc = *functionPtr;
  55. if (varFunc)
  56. {
  57. if (!VarIs<T>(varFunc))
  58. {
  59. Js::Throw::InternalError();
  60. }
  61. return VarTo<T>(varFunc);
  62. }
  63. return nullptr;
  64. }
  65. template<typename T>
  66. void WebAssemblyEnvironment::SetVarElement(Field(Var)* ptr, T* val, uint32 index, uint32 maxCount)
  67. {
  68. if (index >= maxCount ||
  69. !VarIsCorrectType(val))
  70. {
  71. Js::Throw::InternalError();
  72. }
  73. Field(Var)* dst = ptr + index;
  74. CheckPtrIsValid<Var>((intptr_t)dst);
  75. AssertMsg(*dst == nullptr, "We shouldn't overwrite anything on the environment once it is set");
  76. *dst = val;
  77. }
  78. WasmScriptFunction* WebAssemblyEnvironment::GetWasmFunction(uint32 index) const
  79. {
  80. if (!(module->GetFunctionIndexType(index) == Wasm::FunctionIndexTypes::Function ||
  81. module->GetFunctionIndexType(index) == Wasm::FunctionIndexTypes::ImportThunk))
  82. {
  83. Js::Throw::InternalError();
  84. }
  85. return GetVarElement<WasmScriptFunction>(functions, index, module->GetWasmFunctionCount());
  86. }
  87. void WebAssemblyEnvironment::SetWasmFunction(uint32 index, WasmScriptFunction* func)
  88. {
  89. if (!(module->GetFunctionIndexType(index) == Wasm::FunctionIndexTypes::Function ||
  90. module->GetFunctionIndexType(index) == Wasm::FunctionIndexTypes::ImportThunk))
  91. {
  92. Js::Throw::InternalError();
  93. }
  94. SetVarElement<WasmScriptFunction>(functions, func, index, module->GetWasmFunctionCount());
  95. }
  96. void WebAssemblyEnvironment::SetImportedFunction(uint32 index, Var importedFunc)
  97. {
  98. SetVarElement<JavascriptFunction>(imports, (JavascriptFunction*)importedFunc, index, module->GetWasmFunctionCount());
  99. }
  100. Js::WebAssemblyTable* WebAssemblyEnvironment::GetTable(uint32 index) const
  101. {
  102. return GetVarElement<WebAssemblyTable>(table, index, 1);
  103. }
  104. void WebAssemblyEnvironment::SetTable(uint32 index, WebAssemblyTable* table)
  105. {
  106. SetVarElement<WebAssemblyTable>(this->table, table, index, 1);
  107. }
  108. WebAssemblyMemory* WebAssemblyEnvironment::GetMemory(uint32 index) const
  109. {
  110. return GetVarElement<WebAssemblyMemory>(memory, index, 1);
  111. }
  112. void WebAssemblyEnvironment::SetMemory(uint32 index, WebAssemblyMemory* mem)
  113. {
  114. SetVarElement<WebAssemblyMemory>(this->memory, mem, index, 1);
  115. }
  116. template<typename T>
  117. T WebAssemblyEnvironment::GetGlobalInternal(uint32 offset) const
  118. {
  119. Field(T)* ptr = (Field(T)*)PointerValue(start) + offset;
  120. CheckPtrIsValid<T>((intptr_t)ptr);
  121. return *ptr;
  122. }
  123. template<typename T>
  124. void WebAssemblyEnvironment::SetGlobalInternal(uint32 offset, T val)
  125. {
  126. Field(T)* ptr = (Field(T)*)PointerValue(start) + offset;
  127. CheckPtrIsValid<T>((intptr_t)PointerValue(ptr));
  128. AssertMsg(*ptr == 0, "We shouldn't overwrite anything on the environment once it is set");
  129. *ptr = val;
  130. }
  131. Wasm::WasmConstLitNode WebAssemblyEnvironment::GetGlobalValue(Wasm::WasmGlobal* global) const
  132. {
  133. AssertOrFailFast(global);
  134. Wasm::WasmConstLitNode cnst;
  135. uint32 offset = module->GetOffsetForGlobal(global);
  136. switch (global->GetType())
  137. {
  138. case Wasm::WasmTypes::I32: cnst.i32 = GetGlobalInternal<int>(offset); break;
  139. case Wasm::WasmTypes::I64: cnst.i64 = GetGlobalInternal<int64>(offset); break;
  140. case Wasm::WasmTypes::F32: cnst.f32 = GetGlobalInternal<float>(offset); break;
  141. case Wasm::WasmTypes::F64: cnst.f64 = GetGlobalInternal<double>(offset); break;
  142. #ifdef ENABLE_WASM_SIMD
  143. case Wasm::WasmTypes::V128: AssertOrFailFastMsg(UNREACHED, "Wasm.Simd globals not supported");
  144. #endif
  145. default:
  146. Wasm::WasmTypes::CompileAssertCases<Wasm::WasmTypes::I32, Wasm::WasmTypes::I64, Wasm::WasmTypes::F32, Wasm::WasmTypes::F64, WASM_V128_CHECK_TYPE>();
  147. }
  148. return cnst;
  149. }
  150. void WebAssemblyEnvironment::SetGlobalValue(Wasm::WasmGlobal* global, Wasm::WasmConstLitNode cnst)
  151. {
  152. AssertOrFailFast(global);
  153. uint32 offset = module->GetOffsetForGlobal(global);
  154. switch (global->GetType())
  155. {
  156. case Wasm::WasmTypes::I32: SetGlobalInternal<int>(offset, cnst.i32); break;
  157. case Wasm::WasmTypes::I64: SetGlobalInternal<int64>(offset, cnst.i64); break;
  158. case Wasm::WasmTypes::F32: SetGlobalInternal<float>(offset, cnst.f32); break;
  159. case Wasm::WasmTypes::F64: SetGlobalInternal<double>(offset, cnst.f64); break;
  160. #ifdef ENABLE_WASM_SIMD
  161. case Wasm::WasmTypes::V128: AssertOrFailFastMsg(UNREACHED, "Wasm.Simd globals not supported");
  162. #endif
  163. default:
  164. Wasm::WasmTypes::CompileAssertCases<Wasm::WasmTypes::I32, Wasm::WasmTypes::I64, Wasm::WasmTypes::F32, Wasm::WasmTypes::F64, WASM_V128_CHECK_TYPE>();
  165. }
  166. }
  167. void WebAssemblyEnvironment::CalculateOffsets(WebAssemblyTable* table, WebAssemblyMemory* memory)
  168. {
  169. DebugOnly(offsetInitialized = true);
  170. ScriptContext* scriptContext = module->GetScriptContext();
  171. if (!table || !memory)
  172. {
  173. JavascriptError::ThrowTypeError(scriptContext, JSERR_NeedObject);
  174. }
  175. int32 hCode = WASMERR_ElementSegOutOfRange;
  176. auto outOfRangeError = [scriptContext, &hCode] { JavascriptError::ThrowWebAssemblyLinkError(scriptContext, hCode); };
  177. for (uint elementsIndex = 0; elementsIndex < module->GetElementSegCount(); ++elementsIndex)
  178. {
  179. Wasm::WasmElementSegment* eSeg = module->GetElementSeg(elementsIndex);
  180. uint offset = module->GetOffsetFromInit(eSeg->GetOffsetExpr(), this);
  181. if (UInt32Math::Add(offset, eSeg->GetNumElements(), outOfRangeError) > table->GetCurrentLength())
  182. {
  183. outOfRangeError();
  184. }
  185. this->elementSegmentOffsets[elementsIndex] = offset;
  186. }
  187. ArrayBufferBase* buffer = memory->GetBuffer();
  188. Assert(!buffer->IsDetached());
  189. hCode = WASMERR_DataSegOutOfRange;
  190. for (uint32 iSeg = 0; iSeg < module->GetDataSegCount(); ++iSeg)
  191. {
  192. Wasm::WasmDataSegment* segment = module->GetDataSeg(iSeg);
  193. Assert(segment != nullptr);
  194. const uint32 offset = module->GetOffsetFromInit(segment->GetOffsetExpr(), this);
  195. const uint32 size = segment->GetSourceSize();
  196. if (UInt32Math::Add(offset, size, outOfRangeError) > buffer->GetByteLength())
  197. {
  198. outOfRangeError();
  199. }
  200. this->dataSegmentOffsets[iSeg] = offset;
  201. }
  202. }
  203. uint32 WebAssemblyEnvironment::GetElementSegmentOffset(uint32 index) const
  204. {
  205. Assert(offsetInitialized);
  206. if (index >= module->GetElementSegCount())
  207. {
  208. AssertMsg(UNREACHED, "We should only be using valid indexes");
  209. JavascriptError::ThrowRangeError(module->GetScriptContext(), JSERR_ArgumentOutOfRange);
  210. }
  211. return elementSegmentOffsets[index];
  212. }
  213. uint32 WebAssemblyEnvironment::GetDataSegmentOffset(uint32 index) const
  214. {
  215. Assert(offsetInitialized);
  216. if (index >= module->GetDataSegCount())
  217. {
  218. AssertMsg(UNREACHED, "We should only be using valid indexes");
  219. JavascriptError::ThrowRangeError(module->GetScriptContext(), JSERR_ArgumentOutOfRange);
  220. }
  221. return dataSegmentOffsets[index];
  222. }
  223. } // namespace Js
  224. #endif // ENABLE_WASM