Skip to content

Commit 507e4cb

Browse files
committed
[MERGE chakra-core#2246 @Cellule] WASM - Custom sections
Merge pull request chakra-core#2246 from Cellule:customSections Support WebAssembly.Module.customSections Fixes chakra-core#2241
2 parents 77dd587 + 25f20ba commit 507e4cb

16 files changed

Lines changed: 2097 additions & 1770 deletions

lib/Runtime/Base/JnDirectFields.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -292,6 +292,7 @@ ENTRY(instance)
292292
ENTRY(kind)
293293
ENTRY(exports)
294294
ENTRY(imports)
295+
ENTRY(customSections)
295296
ENTRY(initial)
296297
ENTRY(maximum)
297298
ENTRY(element)

lib/Runtime/Library/InJavascript/Intl.js.bc.32b.h

Lines changed: 409 additions & 409 deletions
Large diffs are not rendered by default.

lib/Runtime/Library/InJavascript/Intl.js.bc.64b.h

Lines changed: 403 additions & 403 deletions
Large diffs are not rendered by default.

lib/Runtime/Library/InJavascript/Intl.js.nojit.bc.32b.h

Lines changed: 403 additions & 403 deletions
Large diffs are not rendered by default.

lib/Runtime/Library/InJavascript/Intl.js.nojit.bc.64b.h

Lines changed: 398 additions & 398 deletions
Large diffs are not rendered by default.

lib/Runtime/Library/JavascriptBuiltInFunctionList.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -310,6 +310,7 @@ BUILTIN(WebAssembly, Instantiate, EntryInstantiate, FunctionInfo::ErrorOnNew)
310310
BUILTIN(WebAssemblyModule, NewInstance, NewInstance, FunctionInfo::SkipDefaultNewObject)
311311
BUILTIN(WebAssemblyModule, Exports, EntryExports, FunctionInfo::ErrorOnNew)
312312
BUILTIN(WebAssemblyModule, Imports, EntryImports, FunctionInfo::ErrorOnNew)
313+
BUILTIN(WebAssemblyModule, CustomSections, EntryCustomSections, FunctionInfo::ErrorOnNew)
313314
BUILTIN(WebAssemblyInstance, NewInstance, NewInstance, FunctionInfo::SkipDefaultNewObject)
314315
BUILTIN(WebAssemblyMemory, NewInstance, NewInstance, FunctionInfo::SkipDefaultNewObject)
315316
BUILTIN(WebAssemblyMemory, Grow, EntryGrow, FunctionInfo::ErrorOnNew)

lib/Runtime/Library/JavascriptLibrary.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2830,6 +2830,7 @@ namespace Js
28302830

28312831
library->AddFunctionToLibraryObject(constructor, PropertyIds::exports, &WebAssemblyModule::EntryInfo::Exports, 2);
28322832
library->AddFunctionToLibraryObject(constructor, PropertyIds::imports, &WebAssemblyModule::EntryInfo::Imports, 2);
2833+
library->AddFunctionToLibraryObject(constructor, PropertyIds::customSections, &WebAssemblyModule::EntryInfo::CustomSections, 2);
28332834

28342835
if (scriptContext->GetConfig()->IsES6FunctionNameEnabled())
28352836
{

lib/Runtime/Library/WebAssemblyModule.cpp

Lines changed: 90 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,8 @@ WebAssemblyModule::WebAssemblyModule(Js::ScriptContext* scriptContext, const byt
3232
m_signatures(nullptr),
3333
m_signaturesCount(0),
3434
m_startFuncIndex(Js::Constants::UninitializedValue),
35-
m_binaryBuffer(binaryBuffer)
35+
m_binaryBuffer(binaryBuffer),
36+
m_customSections(nullptr)
3637
{
3738
//the first elm is the number of Vars in front of I32; makes for a nicer offset computation
3839
memset(m_globalCounts, 0, sizeof(uint) * Wasm::WasmTypes::Limit);
@@ -156,6 +157,51 @@ WebAssemblyModule::EntryImports(RecyclableObject* function, CallInfo callInfo, .
156157
return importArray;
157158
}
158159

160+
Var WebAssemblyModule::EntryCustomSections(RecyclableObject* function, CallInfo callInfo, ...)
161+
{
162+
PROBE_STACK(function->GetScriptContext(), Js::Constants::MinStackDefault);
163+
164+
ARGUMENTS(args, callInfo);
165+
AssertMsg(args.Info.Count > 0, "Should always have implicit 'this'");
166+
ScriptContext* scriptContext = function->GetScriptContext();
167+
168+
Assert(!(callInfo.Flags & CallFlags_New));
169+
170+
if (args.Info.Count < 2 || !WebAssemblyModule::Is(args[1]))
171+
{
172+
JavascriptError::ThrowTypeError(scriptContext, WASMERR_NeedModule);
173+
}
174+
if (args.Info.Count < 3)
175+
{
176+
JavascriptError::ThrowTypeErrorVar(scriptContext, JSERR_NeedString, _u("sectionName"));
177+
}
178+
179+
WebAssemblyModule * module = WebAssemblyModule::FromVar(args[1]);
180+
JavascriptString * sectionName = JavascriptConversion::ToString(args[2], scriptContext);
181+
const char16* sectionNameBuf = sectionName->GetString();
182+
charcount_t sectionNameLength = sectionName->GetLength();
183+
184+
Var customSections = JavascriptOperators::NewJavascriptArrayNoArg(scriptContext);
185+
for (uint32 i = 0; i < module->GetCustomSectionCount(); ++i)
186+
{
187+
Wasm::CustomSection customSection = module->GetCustomSection(i);
188+
if (sectionNameLength == customSection.nameLength &&
189+
// can't use string compare because null-terminator is a valid character for custom section names
190+
memcmp(sectionNameBuf, customSection.name, sectionNameLength * sizeof(char16)) == 0)
191+
{
192+
const uint32 byteLength = customSection.payloadSize;
193+
ArrayBuffer* arrayBuffer = scriptContext->GetLibrary()->CreateArrayBuffer(byteLength);
194+
if (byteLength > 0)
195+
{
196+
js_memcpy_s(arrayBuffer->GetBuffer(), byteLength, customSection.payload, byteLength);
197+
}
198+
JavascriptArray::Push(scriptContext, customSections, arrayBuffer);
199+
}
200+
}
201+
202+
return customSections;
203+
}
204+
159205
/* static */
160206
WebAssemblyModule *
161207
WebAssemblyModule::CreateModule(
@@ -682,14 +728,16 @@ WebAssemblyModule::GetStartFunction() const
682728
return m_startFuncIndex;
683729
}
684730

685-
void WebAssemblyModule::SetSignatureCount(uint32 count)
731+
void
732+
WebAssemblyModule::SetSignatureCount(uint32 count)
686733
{
687734
Assert(m_signaturesCount == 0 && m_signatures == nullptr);
688735
m_signaturesCount = count;
689736
m_signatures = RecyclerNewArrayZ(GetRecycler(), Wasm::WasmSignature, count);
690737
}
691738

692-
uint32 WebAssemblyModule::GetModuleEnvironmentSize() const
739+
uint32
740+
WebAssemblyModule::GetModuleEnvironmentSize() const
693741
{
694742
static const uint DOUBLE_SIZE_IN_INTS = sizeof(double) / sizeof(int);
695743
// 1 each for memory, table, and signatures
@@ -700,20 +748,25 @@ uint32 WebAssemblyModule::GetModuleEnvironmentSize() const
700748
return size;
701749
}
702750

703-
void WebAssemblyModule::Finalize(bool isShutdown)
751+
void
752+
WebAssemblyModule::Finalize(bool isShutdown)
704753
{
705754
m_alloc.Clear();
706755
}
707756

708-
void WebAssemblyModule::Dispose(bool isShutdown)
757+
void
758+
WebAssemblyModule::Dispose(bool isShutdown)
709759
{
710760
Assert(m_alloc.Size() == 0);
711761
}
712762

713-
void WebAssemblyModule::Mark(Recycler * recycler)
763+
void
764+
WebAssemblyModule::Mark(Recycler * recycler)
714765
{
715766
}
716-
uint WebAssemblyModule::GetOffsetForGlobal(Wasm::WasmGlobal* global) const
767+
768+
uint
769+
WebAssemblyModule::GetOffsetForGlobal(Wasm::WasmGlobal* global) const
717770
{
718771
Wasm::WasmTypes::WasmType type = global->GetType();
719772
if (type >= Wasm::WasmTypes::Limit)
@@ -734,7 +787,8 @@ uint WebAssemblyModule::GetOffsetForGlobal(Wasm::WasmGlobal* global) const
734787
return WAsmJs::ConvertOffset(offset, sizeof(byte), typeSize);
735788
}
736789

737-
uint WebAssemblyModule::AddGlobalByteSizeToOffset(Wasm::WasmTypes::WasmType type, uint32 offset) const
790+
uint
791+
WebAssemblyModule::AddGlobalByteSizeToOffset(Wasm::WasmTypes::WasmType type, uint32 offset) const
738792
{
739793
uint32 typeSize = Wasm::WasmTypes::GetTypeByteSize(type);
740794
offset = ::Math::AlignOverflowCheck(offset, typeSize);
@@ -762,7 +816,8 @@ WebAssemblyModule::GetExternalKindString(ScriptContext * scriptContext, Wasm::Ex
762816
return nullptr;
763817
}
764818

765-
uint WebAssemblyModule::GetGlobalsByteSize() const
819+
uint
820+
WebAssemblyModule::GetGlobalsByteSize() const
766821
{
767822
uint32 size = 0;
768823
for (Wasm::WasmTypes::WasmType type = (Wasm::WasmTypes::WasmType)(Wasm::WasmTypes::Void + 1); type < Wasm::WasmTypes::Limit; type = (Wasm::WasmTypes::WasmType)(type + 1))
@@ -772,6 +827,32 @@ uint WebAssemblyModule::GetGlobalsByteSize() const
772827
return size;
773828
}
774829

830+
void
831+
WebAssemblyModule::AddCustomSection(Wasm::CustomSection customSection)
832+
{
833+
if (!m_customSections)
834+
{
835+
m_customSections = Anew(&m_alloc, CustomSectionsList, &m_alloc);
836+
}
837+
m_customSections->Add(customSection);
838+
}
839+
840+
uint32
841+
WebAssemblyModule::GetCustomSectionCount() const
842+
{
843+
return m_customSections ? (uint32)m_customSections->Count() : 0;
844+
}
845+
846+
Wasm::CustomSection
847+
WebAssemblyModule::GetCustomSection(uint32 index) const
848+
{
849+
if (index >= GetCustomSectionCount())
850+
{
851+
throw Wasm::WasmCompilationException(_u("Custom section index out of bounds %u"), index);
852+
}
853+
return m_customSections->Item(index);
854+
}
855+
775856
} // namespace Js
776857

777858
#endif

lib/Runtime/Library/WebAssemblyModule.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ namespace Wasm
1717
class WasmGlobal;
1818
struct WasmImport;
1919
struct WasmExport;
20+
struct CustomSection;
2021
}
2122

2223
namespace Js
@@ -31,11 +32,13 @@ class WebAssemblyModule : public DynamicObject
3132
static FunctionInfo NewInstance;
3233
static FunctionInfo Exports;
3334
static FunctionInfo Imports;
35+
static FunctionInfo CustomSections;
3436
};
3537

3638
static Var NewInstance(RecyclableObject* function, CallInfo callInfo, ...);
3739
static Var EntryExports(RecyclableObject* function, CallInfo callInfo, ...);
3840
static Var EntryImports(RecyclableObject* function, CallInfo callInfo, ...);
41+
static Var EntryCustomSections(RecyclableObject* function, CallInfo callInfo, ...);
3942

4043
static bool Is(Var aValue);
4144
static WebAssemblyModule * FromVar(Var aValue);
@@ -129,6 +132,10 @@ class WebAssemblyModule : public DynamicObject
129132
uint AddGlobalByteSizeToOffset(Wasm::WasmTypes::WasmType type, uint32 offset) const;
130133
uint GetGlobalsByteSize() const;
131134

135+
void AddCustomSection(Wasm::CustomSection customSection);
136+
uint32 GetCustomSectionCount() const;
137+
Wasm::CustomSection GetCustomSection(uint32 index) const;
138+
132139
Wasm::WasmBinaryReader* GetReader() const { return m_reader; }
133140

134141
virtual void Finalize(bool isShutdown) override;
@@ -160,6 +167,8 @@ class WebAssemblyModule : public DynamicObject
160167
Wasm::WasmDataSegment** m_datasegs;
161168
Wasm::WasmBinaryReader* m_reader;
162169
uint32* m_equivalentSignatureMap;
170+
typedef JsUtil::List<Wasm::CustomSection, ArenaAllocator> CustomSectionsList;
171+
CustomSectionsList* m_customSections;
163172

164173
uint m_globalCounts[Wasm::WasmTypes::Limit];
165174
typedef JsUtil::List<Wasm::WasmGlobal*, ArenaAllocator> WasmGlobalsList;

lib/WasmReader/WasmBinaryReader.cpp

Lines changed: 71 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -110,32 +110,47 @@ WasmBinaryReader::ThrowDecodingError(const char16* msg, ...)
110110
bool
111111
WasmBinaryReader::ReadNextSection(SectionCode nextSection)
112112
{
113-
if (EndOfModule() || SectionInfo::All[nextSection].flag == fSectIgnore)
113+
while (true)
114114
{
115-
return false;
116-
}
115+
if (EndOfModule() || SectionInfo::All[nextSection].flag == fSectIgnore)
116+
{
117+
return false;
118+
}
117119

118-
SectionHeader secHeader = ReadSectionHeader();
119-
if (secHeader.code == bSectInvalid || SectionInfo::All[secHeader.code].flag == fSectIgnore)
120-
{
121-
TRACE_WASM_DECODER(_u("Ignore this section"));
122-
m_pc = secHeader.end;
123-
return ReadNextSection(nextSection);
124-
}
125-
if (secHeader.code < nextSection)
126-
{
127-
ThrowDecodingError(_u("Invalid Section %s"), secHeader.code);
128-
}
120+
m_currentSection = ReadSectionHeader();
121+
if (SectionInfo::All[m_currentSection.code].flag == fSectIgnore)
122+
{
123+
TRACE_WASM_DECODER(_u("Ignore this section"));
124+
m_pc = m_currentSection.end;
125+
// Read next section
126+
continue;
127+
}
129128

130-
if (secHeader.code != nextSection)
131-
{
132-
TRACE_WASM_DECODER(_u("The current section is not the one we are looking for"));
133-
// We know about this section, but it's not the one we're looking for
134-
m_pc = secHeader.start;
135-
return false;
129+
// Process the custom sections now
130+
if (m_currentSection.code == bSectCustom)
131+
{
132+
if (!ProcessCurrentSection())
133+
{
134+
ThrowDecodingError(_u("Error while reading custom section %s"), m_currentSection.name);
135+
}
136+
// Read next section
137+
continue;
138+
}
139+
140+
if (m_currentSection.code < nextSection)
141+
{
142+
ThrowDecodingError(_u("Invalid Section %s"), m_currentSection.code);
143+
}
144+
145+
if (m_currentSection.code != nextSection)
146+
{
147+
TRACE_WASM_DECODER(_u("The current section is not the one we are looking for"));
148+
// We know about this section, but it's not the one we're looking for
149+
m_pc = m_currentSection.start;
150+
return false;
151+
}
152+
return true;
136153
}
137-
m_currentSection = secHeader;
138-
return true;
139154
}
140155

141156
bool
@@ -183,6 +198,9 @@ WasmBinaryReader::ProcessCurrentSection()
183198
case bSectGlobal:
184199
ReadGlobalsSection();
185200
break;
201+
case bSectCustom:
202+
ReadCustomSection();
203+
break;
186204
default:
187205
Assert(UNREACHED);
188206
m_readerState = READER_STATE_UNKNOWN;
@@ -228,11 +246,14 @@ WasmBinaryReader::ReadSectionHeader()
228246
{
229247
nameLength = LEB128(len);
230248
CheckBytesLeft(nameLength);
231-
sectionName = (char*)(m_pc);
232-
m_pc += nameLength; //skip section name for now
233-
header.code = bSectUser;
249+
sectionName = (const char*)(m_pc);
250+
m_pc += nameLength;
251+
header.code = bSectCustom;
234252
}
235253

254+
header.nameLength = nameLength;
255+
header.name = sectionName;
256+
236257
#if ENABLE_DEBUG_CONFIG_OPTIONS
237258
if (DO_WASM_TRACE_SECTION)
238259
{
@@ -958,7 +979,25 @@ WasmBinaryReader::ReadGlobalsSection()
958979
}
959980
}
960981

961-
const char16* WasmBinaryReader::ReadInlineName(uint32& length, uint32& nameLength)
982+
void
983+
WasmBinaryReader::ReadCustomSection()
984+
{
985+
CustomSection customSection;
986+
customSection.name = CvtUtf8Str((LPCUTF8)m_currentSection.name, m_currentSection.nameLength, &customSection.nameLength);
987+
customSection.payload = m_pc;
988+
989+
size_t size = m_currentSection.end - m_pc;
990+
if (m_currentSection.end < m_pc || !Math::FitsInDWord(size))
991+
{
992+
ThrowDecodingError(_u("Invalid custom section size"));
993+
}
994+
customSection.payloadSize = (uint32)size;
995+
m_module->AddCustomSection(customSection);
996+
m_pc = m_currentSection.end;
997+
}
998+
999+
const char16*
1000+
WasmBinaryReader::ReadInlineName(uint32& length, uint32& nameLength)
9621001
{
9631002
nameLength = LEB128(length);
9641003
CheckBytesLeft(nameLength);
@@ -970,7 +1009,8 @@ const char16* WasmBinaryReader::ReadInlineName(uint32& length, uint32& nameLengt
9701009
return CvtUtf8Str(rawName, nameLength);
9711010
}
9721011

973-
const char16* WasmBinaryReader::CvtUtf8Str(LPCUTF8 name, uint32 nameLen)
1012+
const char16*
1013+
WasmBinaryReader::CvtUtf8Str(LPCUTF8 name, uint32 nameLen, charcount_t* dstLength)
9741014
{
9751015
utf8::DecodeOptions decodeOptions = utf8::doDefault;
9761016
charcount_t utf16Len = utf8::ByteIndexIntoCharacterIndex(name, nameLen, decodeOptions);
@@ -980,6 +1020,10 @@ const char16* WasmBinaryReader::CvtUtf8Str(LPCUTF8 name, uint32 nameLen)
9801020
Js::Throw::OutOfMemory();
9811021
}
9821022
utf8::DecodeIntoAndNullTerminate(contents, name, utf16Len, decodeOptions);
1023+
if (dstLength)
1024+
{
1025+
*dstLength = utf16Len;
1026+
}
9831027
return contents;
9841028
}
9851029

0 commit comments

Comments
 (0)