| ... | ... | @@ -38,8 +38,11 @@ pub const DataSection = struct { |
| 38 | 38 | /// Every data object will be appended to this list, |
| 39 | 39 | /// containing its `Decl`, the data in bytes, and its length. |
| 40 | 40 | segments: std.ArrayListUnmanaged(struct { |
| 41 | /// The decl that lives inside the 'data' section such as an array |
| 41 | 42 | decl: *Module.Decl, |
| 43 | /// The contents of the data in bytes |
| 42 | 44 | data: [*]const u8, |
| 45 | /// The length of the contents inside the 'data' section |
| 43 | 46 | len: u32, |
| 44 | 47 | }) = .{}, |
| 45 | 48 | |
| ... | ... | @@ -72,7 +75,7 @@ pub const DataSection = struct { |
| 72 | 75 | } |
| 73 | 76 | |
| 74 | 77 | /// Returns the index of a declaration and `null` when not found |
| 75 | | pub fn idx(self: DataSection, decl: *Module.Decl) ?usize { |
| 78 | pub fn getIdx(self: DataSection, decl: *Module.Decl) ?usize { |
| 76 | 79 | return for (self.segments.items) |entry, i| { |
| 77 | 80 | if (entry.decl == decl) break i; |
| 78 | 81 | } else null; |
| ... | ... | @@ -145,9 +148,8 @@ pub fn deinit(self: *Wasm) void { |
| 145 | 148 | decl.fn_link.wasm.idx_refs.deinit(self.base.allocator); |
| 146 | 149 | } |
| 147 | 150 | for (self.data.segments.items) |entry| { |
| 148 | | entry.decl.fn_link.wasm.functype.deinit(self.base.allocator); |
| 151 | // decl's that live in data section do not generate idx_refs or func types |
| 149 | 152 | entry.decl.fn_link.wasm.code.deinit(self.base.allocator); |
| 150 | | entry.decl.fn_link.wasm.idx_refs.deinit(self.base.allocator); |
| 151 | 153 | } |
| 152 | 154 | self.funcs.deinit(self.base.allocator); |
| 153 | 155 | self.ext_funcs.deinit(self.base.allocator); |
| ... | ... | @@ -155,15 +157,14 @@ pub fn deinit(self: *Wasm) void { |
| 155 | 157 | } |
| 156 | 158 | |
| 157 | 159 | pub fn allocateDeclIndexes(self: *Wasm, decl: *Module.Decl) !void { |
| 158 | | const tv = decl.typed_value.most_recent.typed_value; |
| 159 | | decl.fn_link.wasm = .{}; |
| 160 | const typed_value = decl.typed_value.most_recent.typed_value; |
| 160 | 161 | |
| 161 | | switch (tv.ty.zigTypeTag()) { |
| 162 | switch (typed_value.ty.zigTypeTag()) { |
| 162 | 163 | .Array => { |
| 163 | 164 | // if the codegen of the given decl contributes to the data segment |
| 164 | 165 | // we must calculate its data length now so that the data offsets are available |
| 165 | 166 | // to other decls when called |
| 166 | | const data_len = calcDataLen(self, tv) catch return error.AnalysisFail; |
| 167 | const data_len = self.calcDataLen(typed_value); |
| 167 | 168 | try self.data.segments.append(self.base.allocator, .{ |
| 168 | 169 | .decl = decl, |
| 169 | 170 | .data = undefined, |
| ... | ... | @@ -175,13 +176,18 @@ pub fn allocateDeclIndexes(self: *Wasm, decl: *Module.Decl) !void { |
| 175 | 176 | const idx: ?usize = for (self.data.segments.items) |entry, i| { |
| 176 | 177 | if (entry.decl.deletion_flag) break i; |
| 177 | 178 | } else null; |
| 179 | |
| 178 | 180 | if (idx) |id| { |
| 179 | | const old_decl = self.data.segments.swapRemove(id); // current decl is now in to-be-deleted decl's spot |
| 180 | | // re-append to end of list so it can be cleaned up by `freeDecl` |
| 181 | | try self.data.segments.append(self.base.allocator, old_decl); |
| 181 | // swap to-be-removed decl with newly added to create a contigious valid data segment |
| 182 | const items = self.data.segments.items; |
| 183 | std.mem.swap( |
| 184 | std.meta.Child(@TypeOf(items)), |
| 185 | &items[id], |
| 186 | &items[items.len - 1], |
| 187 | ); |
| 182 | 188 | } |
| 183 | 189 | }, |
| 184 | | .Fn => if (self.getFuncidx(decl) == null) switch (tv.val.tag()) { |
| 190 | .Fn => if (self.getFuncidx(decl) == null) switch (typed_value.val.tag()) { |
| 185 | 191 | // dependent on function type, appends it to the correct list |
| 186 | 192 | .function => try self.funcs.append(self.base.allocator, decl), |
| 187 | 193 | .extern_fn => try self.ext_funcs.append(self.base.allocator, decl), |
| ... | ... | @@ -191,32 +197,26 @@ pub fn allocateDeclIndexes(self: *Wasm, decl: *Module.Decl) !void { |
| 191 | 197 | } |
| 192 | 198 | } |
| 193 | 199 | |
| 194 | | // TODO, remove this and use the existing error mechanism |
| 195 | | const DataLenError = error{ |
| 196 | | TODO_WASM_CalcDataLenArray, |
| 197 | | TODO_WASM_CalcDataLen, |
| 198 | | }; |
| 199 | 200 | /// Calculates the length of the data segment that will be occupied by the given `TypedValue` |
| 200 | | fn calcDataLen(bin_file: *Wasm, typed_value: TypedValue) DataLenError!u32 { |
| 201 | fn calcDataLen(self: *Wasm, typed_value: TypedValue) u32 { |
| 201 | 202 | switch (typed_value.ty.zigTypeTag()) { |
| 202 | 203 | .Array => { |
| 203 | 204 | if (typed_value.val.castTag(.bytes)) |payload| { |
| 204 | 205 | if (typed_value.ty.sentinel()) |sentinel| { |
| 205 | | return @intCast(u32, payload.data.len) + try calcDataLen(bin_file, .{ |
| 206 | return @intCast(u32, payload.data.len) + self.calcDataLen(.{ |
| 206 | 207 | .ty = typed_value.ty.elemType(), |
| 207 | 208 | .val = sentinel, |
| 208 | 209 | }); |
| 209 | 210 | } |
| 210 | | return @intCast(u32, payload.data.len); |
| 211 | 211 | } |
| 212 | | return error.TODO_WASM_CalcDataLenArray; |
| 212 | return @intCast(u32, typed_value.ty.arrayLen()); |
| 213 | 213 | }, |
| 214 | 214 | .Int => { |
| 215 | | const info = typed_value.ty.intInfo(bin_file.base.options.target); |
| 216 | | return info.bits / 8; |
| 215 | const info = typed_value.ty.intInfo(self.base.options.target); |
| 216 | return std.math.divCeil(u32, info.bits, 8) catch unreachable; |
| 217 | 217 | }, |
| 218 | 218 | .Pointer => return 4, |
| 219 | | else => return error.TODO_WASM_CalcDataLen, |
| 219 | else => unreachable, |
| 220 | 220 | } |
| 221 | 221 | } |
| 222 | 222 | |
| ... | ... | @@ -256,7 +256,7 @@ pub fn updateDecl(self: *Wasm, module: *Module, decl: *Module.Decl) !void { |
| 256 | 256 | .Fn => { |
| 257 | 257 | // as locals are patched afterwards, the offsets of funcidx's are off, |
| 258 | 258 | // here we update them to correct them |
| 259 | | for (decl.fn_link.wasm.idx_refs.items) |*func| { |
| 259 | for (fn_data.idx_refs.items) |*func| { |
| 260 | 260 | // For each local, add 6 bytes (count + type) |
| 261 | 261 | func.offset += @intCast(u32, context.locals.items.len * 6); |
| 262 | 262 | } |
| ... | ... | @@ -291,7 +291,7 @@ pub fn freeDecl(self: *Wasm, decl: *Module.Decl) void { |
| 291 | 291 | else => unreachable, |
| 292 | 292 | } |
| 293 | 293 | } |
| 294 | | if (self.data.idx(decl)) |idx| { |
| 294 | if (self.data.getIdx(decl)) |idx| { |
| 295 | 295 | _ = self.data.segments.swapRemove(idx); |
| 296 | 296 | } |
| 297 | 297 | decl.fn_link.wasm.functype.deinit(self.base.allocator); |
| ... | ... | @@ -314,6 +314,7 @@ pub fn flushModule(self: *Wasm, comp: *Compilation) !void { |
| 314 | 314 | |
| 315 | 315 | const file = self.base.file.?; |
| 316 | 316 | const header_size = 5 + 1; |
| 317 | const data_size = self.data.size(); |
| 317 | 318 | |
| 318 | 319 | // No need to rewrite the magic/version header |
| 319 | 320 | try file.setEndPos(@sizeOf(@TypeOf(wasm.magic ++ wasm.version))); |
| ... | ... | @@ -384,7 +385,7 @@ pub fn flushModule(self: *Wasm, comp: *Compilation) !void { |
| 384 | 385 | } |
| 385 | 386 | |
| 386 | 387 | // Memory section |
| 387 | | if (self.data.size() != 0) { |
| 388 | if (data_size != 0) { |
| 388 | 389 | const header_offset = try reserveVecSectionHeader(file); |
| 389 | 390 | const writer = file.writer(); |
| 390 | 391 | |
| ... | ... | @@ -434,7 +435,7 @@ pub fn flushModule(self: *Wasm, comp: *Compilation) !void { |
| 434 | 435 | } |
| 435 | 436 | |
| 436 | 437 | // export memory if size is not 0 |
| 437 | | if (self.data.size() != 0) { |
| 438 | if (data_size != 0) { |
| 438 | 439 | try leb.writeULEB128(writer, @intCast(u32, "memory".len)); |
| 439 | 440 | try writer.writeAll("memory"); |
| 440 | 441 | try writer.writeByte(wasm.externalKind(.memory)); |
| ... | ... | @@ -483,7 +484,7 @@ pub fn flushModule(self: *Wasm, comp: *Compilation) !void { |
| 483 | 484 | } |
| 484 | 485 | |
| 485 | 486 | // Data section |
| 486 | | if (self.data.size() != 0) { |
| 487 | if (data_size != 0) { |
| 487 | 488 | const header_offset = try reserveVecSectionHeader(file); |
| 488 | 489 | const writer = file.writer(); |
| 489 | 490 | var len: u32 = 0; |
| ... | ... | @@ -496,7 +497,7 @@ pub fn flushModule(self: *Wasm, comp: *Compilation) !void { |
| 496 | 497 | try writer.writeByte(wasm.opcode(.end)); |
| 497 | 498 | |
| 498 | 499 | // payload size |
| 499 | | try leb.writeULEB128(writer, self.data.size()); |
| 500 | try leb.writeULEB128(writer, data_size); |
| 500 | 501 | |
| 501 | 502 | // write payload |
| 502 | 503 | for (self.data.segments.items) |entry| try writer.writeAll(entry.data[0..entry.len]); |