1package wazevoapi
2
3import (
4 "github.com/tetratelabs/wazero/internal/wasm"
5)
6
7const (
8 // FunctionInstanceSize is the size of wazevo.functionInstance.
9 FunctionInstanceSize = 24
10 // FunctionInstanceExecutableOffset is an offset of `executable` field in wazevo.functionInstance
11 FunctionInstanceExecutableOffset = 0
12 // FunctionInstanceModuleContextOpaquePtrOffset is an offset of `moduleContextOpaquePtr` field in wazevo.functionInstance
13 FunctionInstanceModuleContextOpaquePtrOffset = 8
14 // FunctionInstanceTypeIDOffset is an offset of `typeID` field in wazevo.functionInstance
15 FunctionInstanceTypeIDOffset = 16
16)
17
18const (
19 // ExecutionContextOffsetExitCodeOffset is an offset of `exitCode` field in wazevo.executionContext
20 ExecutionContextOffsetExitCodeOffset Offset = 0
21 // ExecutionContextOffsetCallerModuleContextPtr is an offset of `callerModuleContextPtr` field in wazevo.executionContext
22 ExecutionContextOffsetCallerModuleContextPtr Offset = 8
23 // ExecutionContextOffsetOriginalFramePointer is an offset of `originalFramePointer` field in wazevo.executionContext
24 ExecutionContextOffsetOriginalFramePointer Offset = 16
25 // ExecutionContextOffsetOriginalStackPointer is an offset of `originalStackPointer` field in wazevo.executionContext
26 ExecutionContextOffsetOriginalStackPointer Offset = 24
27 // ExecutionContextOffsetGoReturnAddress is an offset of `goReturnAddress` field in wazevo.executionContext
28 ExecutionContextOffsetGoReturnAddress Offset = 32
29 // ExecutionContextOffsetStackBottomPtr is an offset of `stackBottomPtr` field in wazevo.executionContext
30 ExecutionContextOffsetStackBottomPtr Offset = 40
31 // ExecutionContextOffsetGoCallReturnAddress is an offset of `goCallReturnAddress` field in wazevo.executionContext
32 ExecutionContextOffsetGoCallReturnAddress Offset = 48
33 // ExecutionContextOffsetStackPointerBeforeGoCall is an offset of `StackPointerBeforeGoCall` field in wazevo.executionContext
34 ExecutionContextOffsetStackPointerBeforeGoCall Offset = 56
35 // ExecutionContextOffsetStackGrowRequiredSize is an offset of `stackGrowRequiredSize` field in wazevo.executionContext
36 ExecutionContextOffsetStackGrowRequiredSize Offset = 64
37 // ExecutionContextOffsetMemoryGrowTrampolineAddress is an offset of `memoryGrowTrampolineAddress` field in wazevo.executionContext
38 ExecutionContextOffsetMemoryGrowTrampolineAddress Offset = 72
39 // ExecutionContextOffsetStackGrowCallTrampolineAddress is an offset of `stackGrowCallTrampolineAddress` field in wazevo.executionContext.
40 ExecutionContextOffsetStackGrowCallTrampolineAddress Offset = 80
41 // ExecutionContextOffsetCheckModuleExitCodeTrampolineAddress is an offset of `checkModuleExitCodeTrampolineAddress` field in wazevo.executionContext.
42 ExecutionContextOffsetCheckModuleExitCodeTrampolineAddress Offset = 88
43 // ExecutionContextOffsetSavedRegistersBegin is an offset of the first element of `savedRegisters` field in wazevo.executionContext
44 ExecutionContextOffsetSavedRegistersBegin Offset = 96
45 // ExecutionContextOffsetGoFunctionCallCalleeModuleContextOpaque is an offset of `goFunctionCallCalleeModuleContextOpaque` field in wazevo.executionContext
46 ExecutionContextOffsetGoFunctionCallCalleeModuleContextOpaque Offset = 1120
47 // ExecutionContextOffsetTableGrowTrampolineAddress is an offset of `tableGrowTrampolineAddress` field in wazevo.executionContext
48 ExecutionContextOffsetTableGrowTrampolineAddress Offset = 1128
49 // ExecutionContextOffsetRefFuncTrampolineAddress is an offset of `refFuncTrampolineAddress` field in wazevo.executionContext
50 ExecutionContextOffsetRefFuncTrampolineAddress Offset = 1136
51 ExecutionContextOffsetMemmoveAddress Offset = 1144
52 ExecutionContextOffsetFramePointerBeforeGoCall Offset = 1152
53 ExecutionContextOffsetMemoryWait32TrampolineAddress Offset = 1160
54 ExecutionContextOffsetMemoryWait64TrampolineAddress Offset = 1168
55 ExecutionContextOffsetMemoryNotifyTrampolineAddress Offset = 1176
56)
57
58// ModuleContextOffsetData allows the compilers to get the information about offsets to the fields of wazevo.moduleContextOpaque,
59// This is unique per module.
60type ModuleContextOffsetData struct {
61 TotalSize int
62 ModuleInstanceOffset,
63 LocalMemoryBegin,
64 ImportedMemoryBegin,
65 ImportedFunctionsBegin,
66 GlobalsBegin,
67 TypeIDs1stElement,
68 TablesBegin,
69 BeforeListenerTrampolines1stElement,
70 AfterListenerTrampolines1stElement,
71 DataInstances1stElement,
72 ElementInstances1stElement Offset
73}
74
75// ImportedFunctionOffset returns an offset of the i-th imported function.
76// Each item is stored as wazevo.functionInstance whose size matches FunctionInstanceSize.
77func (m *ModuleContextOffsetData) ImportedFunctionOffset(i wasm.Index) (
78 executableOffset, moduleCtxOffset, typeIDOffset Offset,
79) {
80 base := m.ImportedFunctionsBegin + Offset(i)*FunctionInstanceSize
81 return base, base + 8, base + 16
82}
83
84// GlobalInstanceOffset returns an offset of the i-th global instance.
85func (m *ModuleContextOffsetData) GlobalInstanceOffset(i wasm.Index) Offset {
86 return m.GlobalsBegin + Offset(i)*16
87}
88
89// Offset represents an offset of a field of a struct.
90type Offset int32
91
92// U32 encodes an Offset as uint32 for convenience.
93func (o Offset) U32() uint32 {
94 return uint32(o)
95}
96
97// I64 encodes an Offset as int64 for convenience.
98func (o Offset) I64() int64 {
99 return int64(o)
100}
101
102// U64 encodes an Offset as int64 for convenience.
103func (o Offset) U64() uint64 {
104 return uint64(o)
105}
106
107// LocalMemoryBase returns an offset of the first byte of the local memory.
108func (m *ModuleContextOffsetData) LocalMemoryBase() Offset {
109 return m.LocalMemoryBegin
110}
111
112// LocalMemoryLen returns an offset of the length of the local memory buffer.
113func (m *ModuleContextOffsetData) LocalMemoryLen() Offset {
114 if l := m.LocalMemoryBegin; l >= 0 {
115 return l + 8
116 }
117 return -1
118}
119
120// TableOffset returns an offset of the i-th table instance.
121func (m *ModuleContextOffsetData) TableOffset(tableIndex int) Offset {
122 return m.TablesBegin + Offset(tableIndex)*8
123}
124
125// NewModuleContextOffsetData creates a ModuleContextOffsetData determining the structure of moduleContextOpaque for the given Module.
126// The structure is described in the comment of wazevo.moduleContextOpaque.
127func NewModuleContextOffsetData(m *wasm.Module, withListener bool) ModuleContextOffsetData {
128 ret := ModuleContextOffsetData{}
129 var offset Offset
130
131 ret.ModuleInstanceOffset = 0
132 offset += 8
133
134 if m.MemorySection != nil {
135 ret.LocalMemoryBegin = offset
136 // buffer base + memory size.
137 const localMemorySizeInOpaqueModuleContext = 16
138 offset += localMemorySizeInOpaqueModuleContext
139 } else {
140 // Indicates that there's no local memory
141 ret.LocalMemoryBegin = -1
142 }
143
144 if m.ImportMemoryCount > 0 {
145 offset = align8(offset)
146 // *wasm.MemoryInstance + imported memory's owner (moduleContextOpaque)
147 const importedMemorySizeInOpaqueModuleContext = 16
148 ret.ImportedMemoryBegin = offset
149 offset += importedMemorySizeInOpaqueModuleContext
150 } else {
151 // Indicates that there's no imported memory
152 ret.ImportedMemoryBegin = -1
153 }
154
155 if m.ImportFunctionCount > 0 {
156 offset = align8(offset)
157 ret.ImportedFunctionsBegin = offset
158 // Each function is stored wazevo.functionInstance.
159 size := int(m.ImportFunctionCount) * FunctionInstanceSize
160 offset += Offset(size)
161 } else {
162 ret.ImportedFunctionsBegin = -1
163 }
164
165 if globals := int(m.ImportGlobalCount) + len(m.GlobalSection); globals > 0 {
166 // Align to 16 bytes for globals, as f32/f64/v128 might be loaded via SIMD instructions.
167 offset = align16(offset)
168 ret.GlobalsBegin = offset
169 // Pointers to *wasm.GlobalInstance.
170 offset += Offset(globals) * 16
171 } else {
172 ret.GlobalsBegin = -1
173 }
174
175 if tables := len(m.TableSection) + int(m.ImportTableCount); tables > 0 {
176 offset = align8(offset)
177 ret.TypeIDs1stElement = offset
178 offset += 8 // First element of TypeIDs.
179
180 ret.TablesBegin = offset
181 // Pointers to *wasm.TableInstance.
182 offset += Offset(tables) * 8
183 } else {
184 ret.TypeIDs1stElement = -1
185 ret.TablesBegin = -1
186 }
187
188 if withListener {
189 offset = align8(offset)
190 ret.BeforeListenerTrampolines1stElement = offset
191 offset += 8 // First element of BeforeListenerTrampolines.
192
193 ret.AfterListenerTrampolines1stElement = offset
194 offset += 8 // First element of AfterListenerTrampolines.
195 } else {
196 ret.BeforeListenerTrampolines1stElement = -1
197 ret.AfterListenerTrampolines1stElement = -1
198 }
199
200 ret.DataInstances1stElement = offset
201 offset += 8 // First element of DataInstances.
202
203 ret.ElementInstances1stElement = offset
204 offset += 8 // First element of ElementInstances.
205
206 ret.TotalSize = int(align16(offset))
207 return ret
208}
209
210func align16(o Offset) Offset {
211 return (o + 15) &^ 15
212}
213
214func align8(o Offset) Offset {
215 return (o + 7) &^ 7
216}