authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2020-10-07 21:19:45+02:00
committergravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2020-10-07 23:54:51+02:00
logea44d12d1be8eb17a1555f6ab794621da0212171
tree833ee5bbbe1f7a1d6cebe5ba2bed09ed6f9142db
parentb5b25d38a8fa4e66e54ff1279c1becee877793f6
signature Commit is signed but in an unrecognized format.

Add writeULEB128Mem test and couple fixes

Signed-off-by: Jakub Konka <kubkon@jakubkonka.com>

1 files changed, 128 insertions(+), 51 deletions(-)

src/link/MachO/Trie.zig+128-51
......@@ -34,6 +34,7 @@ const std = @import("std");
3434const mem = std.mem;
3535const leb = std.debug.leb;
3636const log = std.log.scoped(.link);
37const testing = std.testing;
3738const Allocator = mem.Allocator;
3839
3940pub const Symbol = struct {
......@@ -67,48 +68,33 @@ const Node = struct {
6768 self.edges.deinit(alloc);
6869 }
6970
70 fn put(self: *Node, alloc: *Allocator, fromEdge: ?*Edge, prefix: usize, label: []const u8) !*Node {
71 // Traverse all edges.
71 fn put(self: *Node, alloc: *Allocator, label: []const u8) !*Node {
72 // Check for match with edges from this node.
7273 for (self.edges.items) |*edge| {
73 const match = mem.indexOfDiff(u8, edge.label, label) orelse return self; // Got a full match, don't do anything.
74 if (match - prefix > 0) {
75 // If we match, we advance further down the trie.
76 return edge.to.put(alloc, edge, match, label);
77 }
78 }
79
80 if (fromEdge) |from| {
81 if (mem.eql(u8, from.label, label[0..prefix])) {
82 if (prefix == label.len) return self;
74 const match = mem.indexOfDiff(u8, edge.label, label) orelse return edge.to;
75 if (match == 0) continue;
76 if (match == edge.label.len) return edge.to.put(alloc, label[match..]);
77
78 // Found a match, need to splice up nodes.
79 // From: A -> B
80 // To: A -> C -> B
81 const mid = try alloc.create(Node);
82 mid.* = .{};
83 const to_label = edge.label;
84 const to_node = edge.to;
85 edge.to = mid;
86 edge.label = label[0..match];
87
88 try mid.edges.append(alloc, .{
89 .from = mid,
90 .to = to_node,
91 .label = to_label[match..],
92 });
93
94 if (match == label.len) {
95 return to_node;
8396 } else {
84 // Fixup nodes. We need to insert an intermediate node between
85 // from.to and self.
86 // Is: A -> B
87 // Should be: A -> C -> B
88 const mid = try alloc.create(Node);
89 mid.* = .{};
90 const to_label = from.label;
91 from.to = mid;
92 from.label = label[0..prefix];
93
94 try mid.edges.append(alloc, .{
95 .from = mid,
96 .to = self,
97 .label = to_label,
98 });
99
100 if (prefix == label.len) return self; // We're done.
101
102 const new_node = try alloc.create(Node);
103 new_node.* = .{};
104
105 try mid.edges.append(alloc, .{
106 .from = mid,
107 .to = new_node,
108 .label = label,
109 });
110
111 return new_node;
97 return mid.put(alloc, label[match..]);
11298 }
11399 }
114100
......@@ -148,7 +134,7 @@ const Node = struct {
148134 // Write number of edges (max legal number of edges is 256).
149135 try buffer.append(alloc, @intCast(u8, self.edges.items.len));
150136
151 var node_offset_info: [@sizeOf(u8)]u64 = undefined;
137 var node_offset_info: [std.math.maxInt(u8)]u64 = undefined;
152138 for (self.edges.items) |edge, i| {
153139 // Write edges labels leaving out space in-between to later populate
154140 // with offsets to each node.
......@@ -185,7 +171,7 @@ root: Node,
185171/// This operation may change the layout of the trie by splicing edges in
186172/// certain circumstances.
187173pub fn put(self: *Trie, alloc: *Allocator, symbol: Symbol) !void {
188 const node = try self.root.put(alloc, null, 0, symbol.name);
174 const node = try self.root.put(alloc, symbol.name);
189175 node.offset = symbol.offset;
190176 node.export_flags = symbol.export_flags;
191177}
......@@ -202,9 +188,7 @@ pub fn deinit(self: *Trie, alloc: *Allocator) void {
202188}
203189
204190test "Trie basic" {
205 const testing = @import("std").testing;
206191 var gpa = testing.allocator;
207
208192 var trie: Trie = .{
209193 .root = .{},
210194 };
......@@ -223,7 +207,7 @@ test "Trie basic" {
223207 testing.expect(mem.eql(u8, trie.root.edges.items[0].label, "_st"));
224208
225209 {
226 // root --- _st ---> node --- _start ---> node
210 // root --- _st ---> node --- art ---> node
227211 try trie.put(gpa, .{
228212 .name = "_start",
229213 .offset = 0,
......@@ -234,12 +218,12 @@ test "Trie basic" {
234218 const nextEdge = &trie.root.edges.items[0];
235219 testing.expect(mem.eql(u8, nextEdge.label, "_st"));
236220 testing.expect(nextEdge.to.edges.items.len == 1);
237 testing.expect(mem.eql(u8, nextEdge.to.edges.items[0].label, "_start"));
221 testing.expect(mem.eql(u8, nextEdge.to.edges.items[0].label, "art"));
238222 }
239223 {
240 // root --- _ ---> node --- _st ---> node --- _start ---> node
224 // root --- _ ---> node --- st ---> node --- art ---> node
241225 // |
242 // | --- _main ---> node
226 // | --- main ---> node
243227 try trie.put(gpa, .{
244228 .name = "_main",
245229 .offset = 0,
......@@ -250,10 +234,103 @@ test "Trie basic" {
250234 const nextEdge = &trie.root.edges.items[0];
251235 testing.expect(mem.eql(u8, nextEdge.label, "_"));
252236 testing.expect(nextEdge.to.edges.items.len == 2);
253 testing.expect(mem.eql(u8, nextEdge.to.edges.items[0].label, "_st"));
254 testing.expect(mem.eql(u8, nextEdge.to.edges.items[1].label, "_main"));
237 testing.expect(mem.eql(u8, nextEdge.to.edges.items[0].label, "st"));
238 testing.expect(mem.eql(u8, nextEdge.to.edges.items[1].label, "main"));
255239
256240 const nextNextEdge = &nextEdge.to.edges.items[0];
257 testing.expect(mem.eql(u8, nextNextEdge.to.edges.items[0].label, "_start"));
241 testing.expect(mem.eql(u8, nextNextEdge.to.edges.items[0].label, "art"));
258242 }
259243}
244
245test "Trie.writeULEB128Mem" {
246 var gpa = testing.allocator;
247 var trie: Trie = .{
248 .root = .{},
249 };
250 defer trie.deinit(gpa);
251
252 try trie.put(gpa, .{
253 .name = "__mh_execute_header",
254 .offset = 0,
255 .export_flags = 0,
256 });
257 try trie.put(gpa, .{
258 .name = "_main",
259 .offset = 0x1000,
260 .export_flags = 0,
261 });
262
263 var buffer: std.ArrayListUnmanaged(u8) = .{};
264 defer buffer.deinit(gpa);
265
266 try trie.writeULEB128Mem(gpa, &buffer);
267
268 const exp_buffer = [_]u8{
269 0x0,
270 0x1,
271 0x5f,
272 0x0,
273 0xc,
274 0x0,
275 0x0,
276 0x0,
277 0x0,
278 0x0,
279 0x0,
280 0x0,
281 0x0,
282 0x2,
283 0x5f,
284 0x6d,
285 0x68,
286 0x5f,
287 0x65,
288 0x78,
289 0x65,
290 0x63,
291 0x75,
292 0x74,
293 0x65,
294 0x5f,
295 0x68,
296 0x65,
297 0x61,
298 0x64,
299 0x65,
300 0x72,
301 0x0,
302 0x36,
303 0x0,
304 0x0,
305 0x0,
306 0x0,
307 0x0,
308 0x0,
309 0x0,
310 0x6d,
311 0x61,
312 0x69,
313 0x6e,
314 0x0,
315 0x3a,
316 0x0,
317 0x0,
318 0x0,
319 0x0,
320 0x0,
321 0x0,
322 0x0,
323 0x2,
324 0x0,
325 0x0,
326 0x0,
327 0x3,
328 0x0,
329 0x80,
330 0x20,
331 0x0,
332 };
333
334 testing.expect(buffer.items.len == exp_buffer.len);
335 testing.expect(mem.eql(u8, buffer.items, exp_buffer[0..]));
336}