authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2023-05-29 18:14:16-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2023-06-10 20:47:56-07:00
log55cda9a592dd5aa030d1134351394e1014fefed1
tree9d6f6d7d580260467de89ff9562e5ffda8f6d46e
parentf7177fb8215714f9f22e3f9da0d3c7d3ad58d390

InternPool: avoid indexToKey recursion for ptr_slice

Recursion makes this hot function more difficult to profile and optimize. The ptr_slice encoding now additionally includes the slice type. This makes typeOf() implementable without indexToKey() as well as no longer using recursion in the ptr_slice prong of indexToKey itself. Unfortunately some logic had to be duplicated. However, I think that a future enhancement could eliminate the duplication as well as remove some other unwanted code, improving performance, by representing a slice value in `Key.Ptr` without `addr` populated directly, but with an `Index` pointing to the underlying manyptr value.

1 files changed, 82 insertions(+), 18 deletions(-)

src/InternPool.zig+82-18
...@@ -1803,8 +1803,6 @@ pub const Tag = enum(u8) {...@@ -1803,8 +1803,6 @@ pub const Tag = enum(u8) {
1803 ptr_field,1803 ptr_field,
1804 /// A slice.1804 /// A slice.
1805 /// data is extra index of PtrSlice, which contains the ptr and len values1805 /// data is extra index of PtrSlice, which contains the ptr and len values
1806 /// In order to use this encoding, one must ensure that the `InternPool`
1807 /// already contains the slice type corresponding to this payload.
1808 ptr_slice,1806 ptr_slice,
1809 /// An optional value that is non-null.1807 /// An optional value that is non-null.
1810 /// data is extra index of `TypeValue`.1808 /// data is extra index of `TypeValue`.
...@@ -2236,7 +2234,11 @@ pub const PtrBaseIndex = struct {...@@ -2236,7 +2234,11 @@ pub const PtrBaseIndex = struct {
2236};2234};
22372235
2238pub const PtrSlice = struct {2236pub const PtrSlice = struct {
2237 /// The slice type.
2238 ty: Index,
2239 /// A many pointer value.
2239 ptr: Index,2240 ptr: Index,
2241 /// A usize value.
2240 len: Index,2242 len: Index,
2241};2243};
22422244
...@@ -2606,16 +2608,25 @@ pub fn indexToKey(ip: *const InternPool, index: Index) Key {...@@ -2606,16 +2608,25 @@ pub fn indexToKey(ip: *const InternPool, index: Index) Key {
2606 .addr = .{ .comptime_field = info.field_val },2608 .addr = .{ .comptime_field = info.field_val },
2607 } };2609 } };
2608 },2610 },
2609 .ptr_int, .ptr_eu_payload, .ptr_opt_payload => {2611 .ptr_int => {
2610 const info = ip.extraData(PtrBase, data);2612 const info = ip.extraData(PtrBase, data);
2611 return .{ .ptr = .{2613 return .{ .ptr = .{
2612 .ty = info.ty,2614 .ty = info.ty,
2613 .addr = switch (item.tag) {2615 .addr = .{ .int = info.base },
2614 .ptr_int => .{ .int = info.base },2616 } };
2615 .ptr_eu_payload => .{ .eu_payload = info.base },2617 },
2616 .ptr_opt_payload => .{ .opt_payload = info.base },2618 .ptr_eu_payload => {
2617 else => unreachable,2619 const info = ip.extraData(PtrBase, data);
2618 },2620 return .{ .ptr = .{
2621 .ty = info.ty,
2622 .addr = .{ .eu_payload = info.base },
2623 } };
2624 },
2625 .ptr_opt_payload => {
2626 const info = ip.extraData(PtrBase, data);
2627 return .{ .ptr = .{
2628 .ty = info.ty,
2629 .addr = .{ .opt_payload = info.base },
2619 } };2630 } };
2620 },2631 },
2621 .ptr_elem => {2632 .ptr_elem => {
...@@ -2652,15 +2663,64 @@ pub fn indexToKey(ip: *const InternPool, index: Index) Key {...@@ -2652,15 +2663,64 @@ pub fn indexToKey(ip: *const InternPool, index: Index) Key {
2652 },2663 },
2653 .ptr_slice => {2664 .ptr_slice => {
2654 const info = ip.extraData(PtrSlice, data);2665 const info = ip.extraData(PtrSlice, data);
2655 const ptr = ip.indexToKey(info.ptr).ptr;2666 const ptr_item = ip.items.get(@enumToInt(info.ptr));
2656 var ptr_type = ip.indexToKey(ptr.ty).ptr_type;2667 return .{
2657 assert(ptr_type.size == .Many);2668 .ptr = .{
2658 ptr_type.size = .Slice;2669 .ty = info.ty,
2659 return .{ .ptr = .{2670 .addr = switch (ptr_item.tag) {
2660 .ty = ip.getAssumeExists(.{ .ptr_type = ptr_type }),2671 .ptr_decl => .{
2661 .addr = ptr.addr,2672 .decl = ip.extraData(PtrDecl, ptr_item.data).decl,
2662 .len = info.len,2673 },
2663 } };2674 .ptr_mut_decl => b: {
2675 const sub_info = ip.extraData(PtrMutDecl, ptr_item.data);
2676 break :b .{ .mut_decl = .{
2677 .decl = sub_info.decl,
2678 .runtime_index = sub_info.runtime_index,
2679 } };
2680 },
2681 .ptr_comptime_field => .{
2682 .comptime_field = ip.extraData(PtrComptimeField, ptr_item.data).field_val,
2683 },
2684 .ptr_int => .{
2685 .int = ip.extraData(PtrBase, ptr_item.data).base,
2686 },
2687 .ptr_eu_payload => .{
2688 .eu_payload = ip.extraData(PtrBase, ptr_item.data).base,
2689 },
2690 .ptr_opt_payload => .{
2691 .opt_payload = ip.extraData(PtrBase, ptr_item.data).base,
2692 },
2693 .ptr_elem => b: {
2694 // Avoid `indexToKey` recursion by asserting the tag encoding.
2695 const sub_info = ip.extraData(PtrBaseIndex, ptr_item.data);
2696 const index_item = ip.items.get(@enumToInt(sub_info.index));
2697 break :b switch (index_item.tag) {
2698 .int_usize => .{ .elem = .{
2699 .base = sub_info.base,
2700 .index = index_item.data,
2701 } },
2702 .int_positive => @panic("TODO"), // implement along with behavior test coverage
2703 else => unreachable,
2704 };
2705 },
2706 .ptr_field => b: {
2707 // Avoid `indexToKey` recursion by asserting the tag encoding.
2708 const sub_info = ip.extraData(PtrBaseIndex, ptr_item.data);
2709 const index_item = ip.items.get(@enumToInt(sub_info.index));
2710 break :b switch (index_item.tag) {
2711 .int_usize => .{ .field = .{
2712 .base = sub_info.base,
2713 .index = index_item.data,
2714 } },
2715 .int_positive => @panic("TODO"), // implement along with behavior test coverage
2716 else => unreachable,
2717 };
2718 },
2719 else => unreachable,
2720 },
2721 .len = info.len,
2722 },
2723 };
2664 },2724 },
2665 .int_u8 => .{ .int = .{2725 .int_u8 => .{ .int = .{
2666 .ty = .u8_type,2726 .ty = .u8_type,
...@@ -3340,6 +3400,9 @@ pub fn get(ip: *InternPool, gpa: Allocator, key: Key) Allocator.Error!Index {...@@ -3340,6 +3400,9 @@ pub fn get(ip: *InternPool, gpa: Allocator, key: Key) Allocator.Error!Index {
3340 }3400 }
3341 },3401 },
3342 else => {3402 else => {
3403 // TODO: change Key.Ptr for slices to reference the manyptr value
3404 // rather than having an addr field directly. Then we can avoid
3405 // these problematic calls to pop(), get(), and getOrPutAdapted().
3343 assert(ptr_type.size == .Slice);3406 assert(ptr_type.size == .Slice);
3344 _ = ip.map.pop();3407 _ = ip.map.pop();
3345 var new_key = key;3408 var new_key = key;
...@@ -3352,6 +3415,7 @@ pub fn get(ip: *InternPool, gpa: Allocator, key: Key) Allocator.Error!Index {...@@ -3352,6 +3415,7 @@ pub fn get(ip: *InternPool, gpa: Allocator, key: Key) Allocator.Error!Index {
3352 ip.items.appendAssumeCapacity(.{3415 ip.items.appendAssumeCapacity(.{
3353 .tag = .ptr_slice,3416 .tag = .ptr_slice,
3354 .data = try ip.addExtra(gpa, PtrSlice{3417 .data = try ip.addExtra(gpa, PtrSlice{
3418 .ty = ptr.ty,
3355 .ptr = ptr_index,3419 .ptr = ptr_index,
3356 .len = ptr.len,3420 .len = ptr.len,
3357 }),3421 }),