WasmLibrary.cpp 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149
  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. // Included for AsmJsDefaultEntryThunk
  9. #include "Language/InterpreterStackFrame.h"
  10. namespace Js
  11. {
  12. Var WasmLibrary::WasmLazyTrapCallback(RecyclableObject *callee, CallInfo, ...)
  13. {
  14. WasmScriptFunction* asmFunction = static_cast<WasmScriptFunction*>(callee);
  15. Assert(asmFunction);
  16. ScriptContext * scriptContext = asmFunction->GetScriptContext();
  17. Assert(scriptContext);
  18. auto error = asmFunction->GetFunctionBody()->GetAsmJsFunctionInfo()->GetLazyError();
  19. JavascriptExceptionOperators::Throw(error, scriptContext);
  20. }
  21. void WasmLibrary::SetWasmEntryPointToInterpreter(Js::ScriptFunction* func, bool deferParse)
  22. {
  23. Assert(WasmScriptFunction::Is(func));
  24. FunctionEntryPointInfo* entrypointInfo = (FunctionEntryPointInfo*)func->GetEntryPointInfo();
  25. entrypointInfo->SetIsAsmJSFunction(true);
  26. if (deferParse)
  27. {
  28. func->SetEntryPoint(WasmLibrary::WasmDeferredParseExternalThunk);
  29. entrypointInfo->jsMethod = WasmLibrary::WasmDeferredParseInternalThunk;
  30. }
  31. else
  32. {
  33. func->SetEntryPoint(Js::AsmJsExternalEntryPoint);
  34. entrypointInfo->jsMethod = AsmJsDefaultEntryThunk;
  35. }
  36. }
  37. #if _M_IX86
  38. __declspec(naked)
  39. Var WasmLibrary::WasmDeferredParseExternalThunk(RecyclableObject* function, CallInfo callInfo, ...)
  40. {
  41. __asm
  42. {
  43. push 0;
  44. push [esp + 8];
  45. call WasmLibrary::WasmDeferredParseEntryPoint
  46. #ifdef _CONTROL_FLOW_GUARD
  47. // verify that the call target is valid
  48. mov ecx, eax
  49. call[__guard_check_icall_fptr]
  50. mov eax, ecx
  51. #endif
  52. // Although we don't restore ESP here on WinCE, this is fine because script profiler is not shipped for WinCE.
  53. jmp eax
  54. }
  55. }
  56. __declspec(naked)
  57. Var WasmLibrary::WasmDeferredParseInternalThunk(RecyclableObject* function, CallInfo callInfo, ...)
  58. {
  59. __asm
  60. {
  61. push 1;
  62. push [esp + 8];
  63. call WasmLibrary::WasmDeferredParseEntryPoint
  64. #ifdef _CONTROL_FLOW_GUARD
  65. // verify that the call target is valid
  66. mov ecx, eax
  67. call[__guard_check_icall_fptr]
  68. mov eax, ecx
  69. #endif
  70. // Although we don't restore ESP here on WinCE, this is fine because script profiler is not shipped for WinCE.
  71. jmp eax
  72. }
  73. }
  74. #elif defined(_M_X64)
  75. // Do nothing: the implementation of WasmLibrary::WasmDeferredParseExternalThunk is declared (appropriately decorated) in
  76. // Language\amd64\amd64_Thunks.asm.
  77. #endif // _M_IX86
  78. }
  79. #endif // ENABLE_WASM
  80. Js::JavascriptMethod Js::WasmLibrary::WasmDeferredParseEntryPoint(Js::AsmJsScriptFunction* func, int internalCall)
  81. {
  82. #ifdef ENABLE_WASM
  83. FunctionBody* body = func->GetFunctionBody();
  84. AsmJsFunctionInfo* info = body->GetAsmJsFunctionInfo();
  85. ScriptContext* scriptContext = func->GetScriptContext();
  86. Js::FunctionEntryPointInfo * entrypointInfo = (Js::FunctionEntryPointInfo*)func->GetEntryPointInfo();
  87. Wasm::WasmReaderInfo* readerInfo = info->GetWasmReaderInfo();
  88. if (readerInfo)
  89. {
  90. try
  91. {
  92. Wasm::WasmBytecodeGenerator::GenerateFunctionBytecode(scriptContext, readerInfo);
  93. func->GetDynamicType()->SetEntryPoint(Js::AsmJsExternalEntryPoint);
  94. entrypointInfo->jsMethod = AsmJsDefaultEntryThunk;
  95. WAsmJs::JitFunctionIfReady(func);
  96. }
  97. catch (Wasm::WasmCompilationException& ex)
  98. {
  99. AutoFreeExceptionMessage autoCleanExceptionMessage;
  100. char16* exceptionMessage = WebAssemblyModule::FormatExceptionMessage(&ex, &autoCleanExceptionMessage, readerInfo->m_module, body);
  101. JavascriptLibrary *library = scriptContext->GetLibrary();
  102. JavascriptError *pError = library->CreateWebAssemblyCompileError();
  103. JavascriptError::SetErrorMessage(pError, WASMERR_WasmCompileError, exceptionMessage, scriptContext);
  104. func->GetDynamicType()->SetEntryPoint(WasmLazyTrapCallback);
  105. entrypointInfo->jsMethod = WasmLazyTrapCallback;
  106. info->SetLazyError(pError);
  107. }
  108. info->SetWasmReaderInfo(nullptr);
  109. }
  110. else
  111. {
  112. // This can happen if another function had its type changed and then was parsed
  113. // They still share the function body, so just change the entry point
  114. Assert(body->GetByteCodeCount() > 0);
  115. Js::JavascriptMethod externalEntryPoint = info->GetLazyError() ? WasmLazyTrapCallback : Js::AsmJsExternalEntryPoint;
  116. func->GetDynamicType()->SetEntryPoint(externalEntryPoint);
  117. if (body->GetIsAsmJsFullJitScheduled())
  118. {
  119. Js::FunctionEntryPointInfo* defaultEntryPoint = (Js::FunctionEntryPointInfo*)body->GetDefaultEntryPointInfo();
  120. func->ChangeEntryPoint(defaultEntryPoint, defaultEntryPoint->jsMethod);
  121. }
  122. else if (entrypointInfo->jsMethod == WasmLibrary::WasmDeferredParseInternalThunk)
  123. {
  124. // The entrypointInfo is still shared even if the type has been changed
  125. // However, no sibling functions changed this entry point yet, so fix it
  126. entrypointInfo->jsMethod = info->GetLazyError() ? WasmLazyTrapCallback : AsmJsDefaultEntryThunk;
  127. }
  128. }
  129. Assert(body->HasValidEntryPoint());
  130. Js::JavascriptMethod entryPoint = internalCall ? entrypointInfo->jsMethod : func->GetDynamicType()->GetEntryPoint();
  131. return entryPoint;
  132. #else
  133. Js::Throw::InternalError();
  134. #endif
  135. }