Skip to content

Commit f89025b

Browse files
committed
Wasm element offset to support global initexprs
Updating WASM elements implementation. Adding support for offset to use globals as initexprs
1 parent 61e4635 commit f89025b

16 files changed

+312
-52
lines changed

lib/Runtime/Library/WasmLibrary.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -455,6 +455,9 @@ namespace Js
455455

456456
void WasmLibrary::WasmLoadIndirectFunctionTables(Wasm::WasmModule * wasmModule, ScriptContext* ctx, Var** indirectFunctionTables, Var* localModuleFunctions, Var* importFunctions)
457457
{
458+
// Globals can be imported, thus the offset must be resolved at at the last possible moment before instantiating the table.
459+
wasmModule->ResolveTableElementOffsets();
460+
458461
for (uint i = 0; i < wasmModule->GetTableSize(); ++i)
459462
{
460463
uint funcIndex = wasmModule->GetTableValue(i);

lib/WasmReader/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
add_library (Chakra.WasmReader OBJECT
22
WasmReaderPch.cpp
33
WasmDataSegment.cpp
4+
WasmElementSegment.cpp
45
WasmFunctionInfo.cpp
56
WasmModule.cpp
67
WasmSection.cpp

lib/WasmReader/Chakra.WasmReader.vcxproj

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@
3939
<ClCompile Include="$(MSBuildThisFileDirectory)WasmModule.cpp" />
4040
<ClCompile Include="$(MSBuildThisFileDirectory)WasmBytecodeGenerator.cpp" />
4141
<ClCompile Include="$(MSBuildThisFileDirectory)WasmDataSegment.cpp" />
42+
<ClCompile Include="$(MSBuildThisFileDirectory)WasmElementSegment.cpp" />
4243
<ClCompile Include="$(MSBuildThisFileDirectory)WasmFunctionInfo.cpp" />
4344
<ClCompile Include="$(MSBuildThisFileDirectory)WasmReaderPch.cpp">
4445
<PrecompiledHeader>Create</PrecompiledHeader>
@@ -53,6 +54,7 @@
5354
<ClInclude Include="WasmModule.h" />
5455
<ClInclude Include="WasmBytecodeGenerator.h" />
5556
<ClInclude Include="WasmDataSegment.h" />
57+
<ClInclude Include="WasmElementSegment.h" />
5658
<ClInclude Include="WasmFunctionInfo.h" />
5759
<ClInclude Include="WasmReader.h" />
5860
<ClInclude Include="WasmReaderPch.h" />

lib/WasmReader/Chakra.WasmReader.vcxproj.filters

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,12 +13,14 @@
1313
<ClInclude Include="WasmSections.h" />
1414
<ClInclude Include="WasmSection.h" />
1515
<ClInclude Include="WasmDataSegment.h" />
16+
<ClInclude Include="WasmElementSegment.h" />
1617
<ClInclude Include="WasmGlobal.h" />
1718
</ItemGroup>
1819
<ItemGroup>
1920
<ClCompile Include="$(MSBuildThisFileDirectory)WasmModule.cpp" />
2021
<ClCompile Include="$(MSBuildThisFileDirectory)WasmBytecodeGenerator.cpp" />
2122
<ClCompile Include="$(MSBuildThisFileDirectory)WasmDataSegment.cpp" />
23+
<ClCompile Include="$(MSBuildThisFileDirectory)WasmElementSegment.cpp" />
2224
<ClCompile Include="$(MSBuildThisFileDirectory)WasmFunctionInfo.cpp" />
2325
<ClCompile Include="$(MSBuildThisFileDirectory)WasmBinaryReader.cpp" />
2426
<ClCompile Include="$(MSBuildThisFileDirectory)WasmSection.cpp" />

lib/WasmReader/WasmBinaryReader.cpp

Lines changed: 15 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -751,7 +751,7 @@ void WasmBinaryReader::ReadTableSection()
751751
// Allocate maximum length for now until resizing supported
752752
initialLength = maximumLength;
753753
}
754-
m_module->AllocateTable(initialLength);
754+
m_module->SetTableSize(initialLength);
755755
m_module->CalculateEquivalentSignatures();
756756
TRACE_WASM_DECODER(_u("Indirect table: %u entries"), initialLength);
757757
}
@@ -762,30 +762,26 @@ WasmBinaryReader::ReadElementSection()
762762
{
763763
uint32 length = 0;
764764
uint32 count = LEB128(length);
765+
if (count != 0)
766+
{
767+
m_module->AllocateElementSegs(count);
768+
}
769+
TRACE_WASM_DECODER(_u("Indirect table element: %u entries"), count);
765770

766771
for (uint32 i = 0; i < count; ++i)
767772
{
768-
uint32 index = LEB128(length);
773+
uint32 index = LEB128(length); // Table id
769774
if (index != 0)
770775
{
771-
ThrowDecodingError(_u("Invalid table index %d"), index);
772-
}
773-
774-
WasmNode initExpr = ReadInitExpr();
775-
if (initExpr.op != wbI32Const)
776-
{
777-
ThrowDecodingError(_u("Only int32.const supported for element offset"));
776+
ThrowDecodingError(_u("Invalid table index %d"), index); //MVP limitation
778777
}
779778

780-
uint32 offset = initExpr.cnst.i32;
779+
WasmNode initExpr = ReadInitExpr(); //Offset Init
781780
uint32 numElem = LEB128(length);
782-
uint32 end = UInt32Math::Add(offset, numElem);
783-
if (end > m_module->GetTableSize())
784-
{
785-
ThrowDecodingError(_u("Out of bounds element in Table[%d][%d], max index: %d"), index, end - 1 , m_module->GetTableSize() - 1);
786-
}
787781

788-
for (uint32 iElem = offset; iElem < end; ++iElem)
782+
WasmElementSegment *eSeg = Anew(m_alloc, WasmElementSegment, m_alloc, index, initExpr, numElem);
783+
784+
for (uint32 iElem = 0; iElem < numElem; ++iElem)
789785
{
790786
uint32 elem = LEB128(length);
791787
FunctionIndexTypes::Type funcType = m_module->GetFunctionIndexType(elem);
@@ -797,8 +793,9 @@ WasmBinaryReader::ReadElementSection()
797793
{
798794
ThrowDecodingError(_u("Import functions in the table NYI"));
799795
}
800-
m_module->SetTableValue(elem, iElem);
796+
eSeg->AddElement(elem, *m_module);
801797
}
798+
m_module->SetTableValues(eSeg, i);
802799
}
803800
}
804801

@@ -821,10 +818,7 @@ WasmBinaryReader::ReadDataSegments()
821818
}
822819
TRACE_WASM_DECODER(_u("Data Segment #%u"), i);
823820
WasmNode initExpr = ReadInitExpr();
824-
if (initExpr.op != wbI32Const && initExpr.op != wbGetGlobal)
825-
{
826-
ThrowDecodingError(_u("Only i32.const supported for data segment offset"));
827-
}
821+
828822
//UINT32 offset = initExpr.cnst.i32;
829823
UINT32 dataByteLen = LEB128(len);
830824
WasmDataSegment *dseg = Anew(m_alloc, WasmDataSegment, m_alloc, initExpr, dataByteLen, m_pc);

lib/WasmReader/WasmDataSegment.cpp

Lines changed: 2 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
//-------------------------------------------------------------------------------------------------------
2-
// Copyright (C) Microsoft. All rights reserved.
2+
// Copyright (C) Microsoft Corporation and contributors. All rights reserved.
33
// Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
44
//-------------------------------------------------------------------------------------------------------
55

@@ -21,22 +21,7 @@ WasmDataSegment::WasmDataSegment(ArenaAllocator * alloc, WasmNode ie, uint32 _so
2121
uint32
2222
WasmDataSegment::getDestAddr(WasmModule* module) const
2323
{
24-
if (initExpr.op == wbI32Const)
25-
{
26-
return initExpr.cnst.i32;
27-
}
28-
if (initExpr.var.num >= (uint) module->globals.Count())
29-
{
30-
throw WasmCompilationException(_u("global %d doesn't exist"), initExpr.var.num);
31-
}
32-
WasmGlobal* global = module->globals.Item(initExpr.var.num);
33-
Assert(global->GetReferenceType() == WasmGlobal::Const);
34-
35-
if (global->GetType() != WasmTypes::I32)
36-
{
37-
throw WasmCompilationException(_u("global %d must be i32"), initExpr.var.num);
38-
}
39-
return global->cnst.i32;
24+
return module->GetOffsetFromInit(initExpr);
4025
}
4126

4227
uint32
Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
//-------------------------------------------------------------------------------------------------------
2+
// Copyright (C) Microsoft Corporation and contributors. All rights reserved.
3+
// Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
4+
//-------------------------------------------------------------------------------------------------------
5+
6+
#include "WasmReaderPch.h"
7+
8+
#ifdef ENABLE_WASM
9+
10+
namespace Wasm
11+
{
12+
WasmElementSegment::WasmElementSegment(ArenaAllocator * alloc, const UINT32 index, const WasmNode initExpr, const UINT32 numElem) :
13+
m_alloc(alloc),
14+
m_index(index),
15+
m_offsetExpr(initExpr),
16+
m_numElem(numElem),
17+
m_offset(0),
18+
m_limit(0),
19+
m_elemIdx(0),
20+
m_isOffsetResolved(false),
21+
m_elems(nullptr)
22+
{}
23+
24+
void
25+
WasmElementSegment::Init(const WasmModule& module)
26+
{
27+
Assert(m_numElem > 0);
28+
m_elems = AnewArray(m_alloc, UINT32, m_numElem);
29+
memset(m_elems, Js::Constants::UninitializedValue, m_numElem * sizeof(UINT32));
30+
}
31+
32+
void WasmElementSegment::ResolveOffsets(const WasmModule& module)
33+
{
34+
if (m_elems == nullptr)
35+
{
36+
return;
37+
}
38+
m_offset = module.GetOffsetFromInit(m_offsetExpr); // i32 or global (i32)
39+
m_limit = UInt32Math::Add(m_offset, m_numElem);
40+
41+
if (m_limit > module.GetTableSize())
42+
{
43+
throw WasmCompilationException(_u("Out of bounds element in Table[%d][%d], max index: %d"), m_index, m_limit - 1, module.GetTableSize() - 1);
44+
}
45+
m_isOffsetResolved = true;
46+
}
47+
48+
void
49+
WasmElementSegment::AddElement(const UINT32 funcIndex, const WasmModule& module)
50+
{
51+
if (m_elems == nullptr)
52+
{
53+
Init(module);
54+
}
55+
Assert(m_elemIdx < m_numElem);
56+
m_elems[m_elemIdx++] = funcIndex;
57+
}
58+
59+
inline bool
60+
WasmElementSegment::IsOffsetResolved() const
61+
{
62+
return m_isOffsetResolved;
63+
}
64+
65+
UINT32
66+
WasmElementSegment::GetElement(const UINT32 tableIndex) const
67+
{
68+
if (!IsOffsetResolved())
69+
{
70+
throw WasmCompilationException(_u("Offset not resolved: Cannot access table elements."));
71+
}
72+
if (m_offset > tableIndex || tableIndex >= m_limit)
73+
{
74+
return Js::Constants::UninitializedValue;
75+
}
76+
return m_elems[tableIndex - m_offset];
77+
}
78+
79+
} // namespace Wasm
80+
81+
#endif // ENABLE_WASM
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
//-------------------------------------------------------------------------------------------------------
2+
// Copyright (C) Microsoft Corporation and contributors. All rights reserved.
3+
// Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
4+
//-------------------------------------------------------------------------------------------------------
5+
6+
#pragma once
7+
8+
namespace Wasm
9+
{
10+
11+
class WasmElementSegment
12+
{
13+
public:
14+
WasmElementSegment(ArenaAllocator * alloc, const UINT32 index, const WasmNode initExpr, const UINT32 numElem);
15+
void AddElement(const UINT32 funcIndex, const WasmModule& module);
16+
UINT32 GetElement(const UINT32 tableIndex) const;
17+
UINT32 GetNumElements() const { return m_numElem; }
18+
void ResolveOffsets(const WasmModule& module);
19+
20+
private:
21+
ArenaAllocator* m_alloc;
22+
UINT32 m_index;
23+
const WasmNode m_offsetExpr;
24+
UINT32 m_numElem;
25+
UINT32 m_offset;
26+
UINT32 m_limit;
27+
UINT32 m_elemIdx;
28+
bool m_isOffsetResolved;
29+
UINT32* m_elems;
30+
31+
void Init(const WasmModule& module);
32+
bool IsOffsetResolved() const;
33+
};
34+
} // Namespace Wasm

0 commit comments

Comments
 (0)