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