WabtInterface.cpp 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182
  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_WABT
  7. #include "../WasmReader/WasmReaderPch.h"
  8. #include "wabtapi.h"
  9. #include "Codex/Utf8Helper.h"
  10. namespace Js
  11. {
  12. struct Context
  13. {
  14. ArenaAllocator* allocator;
  15. ScriptContext* scriptContext;
  16. };
  17. char16* NarrowStringToWide(Context* ctx, const char* src, const size_t* srcSize = nullptr, charcount_t* dstSize = nullptr)
  18. {
  19. auto allocator = [&ctx](size_t size) {return (char16*)AnewArray(ctx->allocator, char16, size); };
  20. char16* dst = nullptr;
  21. charcount_t size;
  22. HRESULT hr = utf8::NarrowStringToWide(allocator, src, srcSize ? *srcSize : strlen(src), &dst, &size);
  23. if (hr != S_OK)
  24. {
  25. JavascriptError::ThrowOutOfMemoryError(ctx->scriptContext);
  26. }
  27. if (dstSize)
  28. {
  29. *dstSize = size;
  30. }
  31. return dst;
  32. }
  33. static PropertyId propertyMap[] = {
  34. Js::PropertyIds::as,
  35. Js::PropertyIds::action,
  36. Js::PropertyIds::args,
  37. Js::PropertyIds::buffer,
  38. Js::PropertyIds::commands,
  39. Js::PropertyIds::expected,
  40. Js::PropertyIds::field,
  41. Js::PropertyIds::line,
  42. Js::PropertyIds::name,
  43. Js::PropertyIds::module,
  44. Js::PropertyIds::text,
  45. Js::PropertyIds::type,
  46. Js::PropertyIds::value,
  47. };
  48. bool SetProperty(Js::Var obj, PropertyId id, Js::Var value, void* user_data)
  49. {
  50. CompileAssert((sizeof(propertyMap)/sizeof(PropertyId)) == ChakraWabt::PropertyIds::COUNT);
  51. Context* ctx = (Context*)user_data;
  52. Assert(id < ChakraWabt::PropertyIds::COUNT);
  53. return !!JavascriptOperators::OP_SetProperty(obj, propertyMap[id], value, ctx->scriptContext);
  54. }
  55. Js::Var CreateObject(void* user_data)
  56. {
  57. Context* ctx = (Context*)user_data;
  58. return JavascriptOperators::NewJavascriptObjectNoArg(ctx->scriptContext);
  59. }
  60. Js::Var CreateArray(void* user_data)
  61. {
  62. Context* ctx = (Context*)user_data;
  63. return JavascriptOperators::NewJavascriptArrayNoArg(ctx->scriptContext);
  64. }
  65. void Push(Js::Var arr, Js::Var obj, void* user_data)
  66. {
  67. Context* ctx = (Context*)user_data;
  68. JavascriptArray::Push(ctx->scriptContext, arr, obj);
  69. }
  70. Js::Var Int32ToVar(int32 value, void* user_data)
  71. {
  72. Context* ctx = (Context*)user_data;
  73. return JavascriptNumber::ToVar(value, ctx->scriptContext);
  74. }
  75. Js::Var Int64ToVar(int64 value, void* user_data)
  76. {
  77. Context* ctx = (Context*)user_data;
  78. return JavascriptNumber::ToVar(value, ctx->scriptContext);
  79. }
  80. Js::Var StringToVar(const char* src, uint length, void* user_data)
  81. {
  82. Context* ctx = (Context*)user_data;
  83. charcount_t bufSize = 0;
  84. size_t slength = (size_t)length;
  85. char16* buf = NarrowStringToWide(ctx, src, &slength, &bufSize);
  86. Assert(bufSize < UINT32_MAX);
  87. return JavascriptString::NewCopyBuffer(buf, bufSize, ctx->scriptContext);
  88. }
  89. Js::Var CreateBuffer(const uint8* buf, uint size, void* user_data)
  90. {
  91. Context* ctx = (Context*)user_data;
  92. ArrayBuffer* arrayBuffer = ctx->scriptContext->GetLibrary()->CreateArrayBuffer(size);
  93. js_memcpy_s(arrayBuffer->GetBuffer(), arrayBuffer->GetByteLength(), buf, size);
  94. return arrayBuffer;
  95. }
  96. Js::Var WabtInterface::EntryConvertWast2Wasm(RecyclableObject* function, CallInfo callInfo, ...)
  97. {
  98. ScriptContext* scriptContext = function->GetScriptContext();
  99. PROBE_STACK(function->GetScriptContext(), Constants::MinStackDefault);
  100. ARGUMENTS(args, callInfo);
  101. AssertMsg(args.Info.Count > 0, "Should always have implicit 'this'");
  102. Assert(!(callInfo.Flags & CallFlags_New));
  103. if (args.Info.Count < 2 || !VarIs<JavascriptString>(args[1]))
  104. {
  105. JavascriptError::ThrowTypeError(scriptContext, WASMERR_NeedBufferSource);
  106. }
  107. bool isSpecText = false;
  108. if (args.Info.Count > 2)
  109. {
  110. // optional config object
  111. if (!JavascriptOperators::IsObject(args[2]))
  112. {
  113. JavascriptError::ThrowTypeError(scriptContext, JSERR_NeedObject, _u("config"));
  114. }
  115. DynamicObject * configObject = VarTo<DynamicObject>(args[2]);
  116. Js::Var isSpecVar = JavascriptOperators::OP_GetProperty(configObject, PropertyIds::spec, scriptContext);
  117. isSpecText = JavascriptConversion::ToBool(isSpecVar, scriptContext);
  118. }
  119. ArenaAllocator arena(_u("Wast2Wasm"), scriptContext->GetThreadContext()->GetPageAllocator(), Throw::OutOfMemory);
  120. Context context;
  121. size_t wastSize;
  122. char* wastBuffer = nullptr;
  123. ENTER_PINNED_SCOPE(JavascriptString, string);
  124. string = (JavascriptString*)args[1];
  125. const char16* str = string->GetString();
  126. context.allocator = &arena;
  127. context.scriptContext = scriptContext;
  128. size_t origSize = string->GetLength();
  129. auto allocator = [&arena](size_t size) {return (utf8char_t*)AnewArray(&arena, byte, size);};
  130. utf8::WideStringToNarrow(allocator, str, origSize, &wastBuffer, &wastSize);
  131. LEAVE_PINNED_SCOPE(); // string
  132. try
  133. {
  134. ChakraWabt::SpecContext spec;
  135. ChakraWabt::ChakraContext wabtCtx;
  136. wabtCtx.user_data = &context;
  137. wabtCtx.createBuffer = CreateBuffer;
  138. wabtCtx.features.sign_extends = CONFIG_FLAG(WasmSignExtends);
  139. wabtCtx.features.threads = Wasm::Threads::IsEnabled();
  140. wabtCtx.features.simd = Wasm::Simd::IsEnabled();
  141. wabtCtx.features.sat_float_to_int = Wasm::WasmNontrapping::IsEnabled();
  142. if (isSpecText)
  143. {
  144. wabtCtx.spec = &spec;
  145. spec.setProperty = SetProperty;
  146. spec.int32ToVar = Int32ToVar;
  147. spec.int64ToVar = Int64ToVar;
  148. spec.stringToVar = StringToVar;
  149. spec.createObject = CreateObject;
  150. spec.createArray = CreateArray;
  151. spec.push = Push;
  152. }
  153. void* result = ChakraWabt::ConvertWast2Wasm(wabtCtx, wastBuffer, (uint)wastSize, isSpecText);
  154. if (result == nullptr)
  155. {
  156. return scriptContext->GetLibrary()->GetUndefined();
  157. }
  158. return result;
  159. }
  160. catch (ChakraWabt::WabtAPIError& e)
  161. {
  162. JavascriptError::ThrowTypeErrorVar(scriptContext, WABTERR_WabtError, NarrowStringToWide(&context, e.message));
  163. }
  164. }
  165. }
  166. #endif // ENABLE_WABT