blob: a3c8b577ae70d823960aa96ae2418186c6c4667a [file]
//-------------------------------------------------------------------------------------------------------
// Copyright (C) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
//-------------------------------------------------------------------------------------------------------
#include "RuntimeLibraryPch.h"
#ifdef ENABLE_WABT
#include "../WasmReader/WasmReaderPch.h"
#include "wabtapi.h"
#include "Codex/Utf8Helper.h"
namespace Js
{
struct Context
{
ArenaAllocator* allocator;
ScriptContext* scriptContext;
};
char16* NarrowStringToWide(Context* ctx, const char* src, const size_t* srcSize = nullptr, size_t* dstSize = nullptr)
{
auto allocator = [&ctx](size_t size) {return (char16*)AnewArray(ctx->allocator, char16, size); };
char16* dst = nullptr;
size_t size;
HRESULT hr = utf8::NarrowStringToWide(allocator, src, srcSize ? *srcSize : strlen(src), &dst, &size);
if (hr != S_OK)
{
JavascriptError::ThrowOutOfMemoryError(ctx->scriptContext);
}
if (dstSize)
{
*dstSize = size;
}
return dst;
}
static PropertyId propertyMap[ChakraWabt::PropertyIds::COUNT] = {
Js::PropertyIds::as,
Js::PropertyIds::action,
Js::PropertyIds::args,
Js::PropertyIds::buffer,
Js::PropertyIds::commands,
Js::PropertyIds::expected,
Js::PropertyIds::field,
Js::PropertyIds::line,
Js::PropertyIds::name,
Js::PropertyIds::module,
Js::PropertyIds::text,
Js::PropertyIds::type,
Js::PropertyIds::value,
};
bool SetProperty(Js::Var obj, PropertyId id, Js::Var value, void* user_data)
{
Context* ctx = (Context*)user_data;
Assert(id < ChakraWabt::PropertyIds::COUNT);
return !!JavascriptOperators::OP_SetProperty(obj, propertyMap[id], value, ctx->scriptContext);
}
Js::Var CreateObject(void* user_data)
{
Context* ctx = (Context*)user_data;
return JavascriptOperators::NewJavascriptObjectNoArg(ctx->scriptContext);
}
Js::Var CreateArray(void* user_data)
{
Context* ctx = (Context*)user_data;
return JavascriptOperators::NewJavascriptArrayNoArg(ctx->scriptContext);
}
void Push(Js::Var arr, Js::Var obj, void* user_data)
{
Context* ctx = (Context*)user_data;
JavascriptArray::Push(ctx->scriptContext, arr, obj);
}
Js::Var Int32ToVar(int32 value, void* user_data)
{
Context* ctx = (Context*)user_data;
return JavascriptNumber::ToVar(value, ctx->scriptContext);
}
Js::Var Int64ToVar(int64 value, void* user_data)
{
Context* ctx = (Context*)user_data;
return JavascriptNumber::ToVar(value, ctx->scriptContext);
}
Js::Var StringToVar(const char* src, uint length, void* user_data)
{
Context* ctx = (Context*)user_data;
size_t bufSize = 0;
size_t slength = (size_t)length;
char16* buf = NarrowStringToWide(ctx, src, &slength, &bufSize);
Assert(bufSize < UINT32_MAX);
return JavascriptString::NewCopyBuffer(buf, (charcount_t)bufSize, ctx->scriptContext);
}
Js::Var CreateBuffer(const char* buf, uint size, void* user_data)
{
Context* ctx = (Context*)user_data;
ArrayBuffer* arrayBuffer = ctx->scriptContext->GetLibrary()->CreateArrayBuffer(size);
js_memcpy_s(arrayBuffer->GetBuffer(), arrayBuffer->GetByteLength(), buf, size);
return arrayBuffer;
}
void* Allocate(uint size, void* user_data)
{
Context* ctx = (Context*)user_data;
return (void*)AnewArrayZ(ctx->allocator, byte, size);
};
Js::Var WabtInterface::EntryConvertWast2Wasm(RecyclableObject* function, CallInfo callInfo, ...)
{
ScriptContext* scriptContext = function->GetScriptContext();
PROBE_STACK(function->GetScriptContext(), Constants::MinStackDefault);
ARGUMENTS(args, callInfo);
AssertMsg(args.Info.Count > 0, "Should always have implicit 'this'");
Assert(!(callInfo.Flags & CallFlags_New));
if (args.Info.Count < 2 || !JavascriptString::Is(args[1]))
{
JavascriptError::ThrowTypeError(scriptContext, WASMERR_NeedBufferSource);
}
bool isSpecText = false;
if (args.Info.Count > 2)
{
// optional config object
if (!JavascriptOperators::IsObject(args[2]))
{
JavascriptError::ThrowTypeError(scriptContext, JSERR_NeedObject, _u("config"));
}
DynamicObject * configObject = JavascriptObject::FromVar(args[2]);
Js::Var isSpecVar = JavascriptOperators::OP_GetProperty(configObject, PropertyIds::spec, scriptContext);
isSpecText = JavascriptConversion::ToBool(isSpecVar, scriptContext);
}
JavascriptString* string = (JavascriptString*)args[1];
const char16* str = string->GetString();
ArenaAllocator arena(_u("Wast2Wasm"), scriptContext->GetThreadContext()->GetPageAllocator(), Throw::OutOfMemory);
Context context;
context.allocator = &arena;
context.scriptContext = scriptContext;
size_t origSize = string->GetLength();
size_t wastSize;
char* wastBuffer = nullptr;
auto allocator = [&arena](size_t size) {return (utf8char_t*)AnewArray(&arena, byte, size);};
utf8::WideStringToNarrow(allocator, str, origSize, &wastBuffer, &wastSize);
try
{
ChakraWabt::SpecContext spec;
ChakraWabt::Context wabtCtx;
wabtCtx.user_data = &context;
wabtCtx.allocator = Allocate;
wabtCtx.createBuffer = CreateBuffer;
if (isSpecText)
{
wabtCtx.spec = &spec;
spec.setProperty = SetProperty;
spec.int32ToVar = Int32ToVar;
spec.int64ToVar = Int64ToVar;
spec.stringToVar = StringToVar;
spec.createObject = CreateObject;
spec.createArray = CreateArray;
spec.push = Push;
}
void* result = ChakraWabt::ConvertWast2Wasm(wabtCtx, wastBuffer, (uint)wastSize, isSpecText);
if (result == nullptr)
{
return scriptContext->GetLibrary()->GetUndefined();
}
return result;
}
catch (ChakraWabt::Error& e)
{
JavascriptError::ThrowTypeErrorVar(scriptContext, WABTERR_WabtError, NarrowStringToWide(&context, e.message));
}
}
}
#endif // ENABLE_WABT