authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2020-04-18 19:41:45-04:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2020-04-19 19:31:50-04:00
log018daa028e2705a6a5d7621cccd277a490f17646
tree07ce402383481308045308d69e1cb7ba1e43ab23
parentf92ccf365be1e4dad74f6ac08503832ed2d7f805

rework types and values data layout


3 files changed, 201 insertions(+), 1088 deletions(-)

src-self-hosted/ir.zig+41-6
...@@ -2,6 +2,7 @@ const std = @import("std");...@@ -2,6 +2,7 @@ const std = @import("std");
2const mem = std.mem;2const mem = std.mem;
3const Allocator = std.mem.Allocator;3const Allocator = std.mem.Allocator;
4const Value = @import("value.zig").Value;4const Value = @import("value.zig").Value;
5const Type = @import("type.zig").Type;
5const assert = std.debug.assert;6const assert = std.debug.assert;
67
7pub const Inst = struct {8pub const Inst = struct {
...@@ -17,6 +18,7 @@ pub const Inst = struct {...@@ -17,6 +18,7 @@ pub const Inst = struct {
17 Fn,18 Fn,
18 };19 };
1920
21 /// These names are used for the IR text format.
20 pub const Tag = enum {22 pub const Tag = enum {
21 constant,23 constant,
22 ptrtoint,24 ptrtoint,
...@@ -32,9 +34,11 @@ pub const Inst = struct {...@@ -32,9 +34,11 @@ pub const Inst = struct {
32 /// a memory location for the value to survive after a const instruction.34 /// a memory location for the value to survive after a const instruction.
33 pub const Constant = struct {35 pub const Constant = struct {
34 base: Inst = Inst{ .tag = .constant },36 base: Inst = Inst{ .tag = .constant },
35 value: *Value,37 ty: Type,
3638
37 positionals: struct {},39 positionals: struct {
40 value: Value,
41 },
38 kw_args: struct {},42 kw_args: struct {},
39 };43 };
4044
...@@ -241,6 +245,31 @@ fn parseInstructionGeneric(ctx: *ParseContext, comptime fn_name: []const u8, com...@@ -241,6 +245,31 @@ fn parseInstructionGeneric(ctx: *ParseContext, comptime fn_name: []const u8, com
241}245}
242246
243fn parseParameterGeneric(ctx: *ParseContext, comptime T: type) !T {247fn parseParameterGeneric(ctx: *ParseContext, comptime T: type) !T {
248 if (@typeInfo(T) == .Enum) {
249 const start = ctx.i;
250 while (ctx.i < ctx.source.len) : (ctx.i += 1) switch (ctx.source[ctx.i]) {
251 ' ', '\n', ',', ')' => {
252 const enum_name = ctx.source[start..ctx.i];
253 ctx.i += 1;
254 return std.meta.stringToEnum(T, enum_name) orelse {
255 return parseError(ctx, "tag '{}' not a member of enum '{}'", .{ enum_name, @typeName(T) });
256 };
257 },
258 else => continue,
259 };
260 return parseError(ctx, "unexpected EOF in enum parameter", .{});
261 }
262 switch (T) {
263 Inst.Fn.Body => {
264 var instructions = std.ArrayList(*Inst).init(ctx.allocator);
265 try requireEatBytes(ctx, "{");
266 return T{
267 .instructions = instructions.toOwnedSlice(),
268 };
269 },
270 Value => return parseError(ctx, "TODO implement parseParameterGeneric for type Value", .{}),
271 else => @compileError("Unimplemented: ir parseParameterGeneric for type " ++ @typeName(T)),
272 }
244 return parseError(ctx, "TODO parse parameter {}", .{@typeName(T)});273 return parseError(ctx, "TODO parse parameter {}", .{@typeName(T)});
245}274}
246275
...@@ -261,12 +290,18 @@ fn parseStringLiteralConst(ctx: *ParseContext) !*Inst {...@@ -261,12 +290,18 @@ fn parseStringLiteralConst(ctx: *ParseContext) !*Inst {
261 },290 },
262 else => |e| return e,291 else => |e| return e,
263 };292 };
264 const bytes_val = try ctx.allocator.create(Value.Bytes);293 const bytes_payload = try ctx.allocator.create(Value.Payload.Bytes);
265 bytes_val.* = .{ .data = parsed };294 errdefer ctx.allocator.destroy(bytes_payload);
295 bytes_payload.* = .{ .data = parsed };
296
297 const ty_payload = try ctx.allocator.create(Type.Payload.Array_u8_Sentinel0);
298 errdefer ctx.allocator.destroy(ty_payload);
299 ty_payload.* = .{ .len = parsed.len };
300
266 const const_inst = try ctx.allocator.create(Inst.Constant);301 const const_inst = try ctx.allocator.create(Inst.Constant);
267 const_inst.* = .{302 const_inst.* = .{
268 .value = &bytes_val.base,303 .ty = Type.initPayload(&ty_payload.base),
269 .positionals = .{},304 .positionals = .{ .value = Value.initPayload(&bytes_payload.base) },
270 .kw_args = .{},305 .kw_args = .{},
271 };306 };
272 return &const_inst.base;307 return &const_inst.base;
src-self-hosted/type.zig+85-1048
...@@ -1,1075 +1,112 @@...@@ -1,1075 +1,112 @@
1const std = @import("std");1const std = @import("std");
2const builtin = std.builtin;
3const Scope = @import("scope.zig").Scope;
4const Compilation = @import("compilation.zig").Compilation;
5const Value = @import("value.zig").Value;2const Value = @import("value.zig").Value;
6const llvm = @import("llvm.zig");
7const event = std.event;
8const Allocator = std.mem.Allocator;
9const assert = std.debug.assert;3const assert = std.debug.assert;
104
11pub const Type = struct {5/// This is the raw data, with no bookkeeping, no memory awareness, no de-duplication.
12 base: Value,6/// It's important for this struct to be small.
13 id: Id,7/// It is not copyable since it may contain references to its inner data.
14 name: []const u8,8/// Types are not de-duplicated, which helps with multi-threading since it obviates the requirement
15 abi_alignment: AbiAlignment,9/// of obtaining a lock on a global type table, as well as making the
1610/// garbage collection bookkeeping simpler.
17 pub const AbiAlignment = event.Future(error{OutOfMemory}!u32);11/// This union takes advantage of the fact that the first page of memory
1812/// is unmapped, giving us 4096 possible enum tags that have no payload.
19 pub const Id = builtin.TypeId;13pub const Type = extern union {
2014 /// If the tag value is less than Tag.no_payload_count, then no pointer
21 pub fn destroy(base: *Type, comp: *Compilation) void {15 /// dereference is needed.
22 switch (base.id) {16 tag_if_small_enough: usize,
23 .Struct => @fieldParentPtr(Struct, "base", base).destroy(comp),17 ptr_otherwise: *Payload,
24 .Fn => @fieldParentPtr(Fn, "base", base).destroy(comp),18
25 .Type => @fieldParentPtr(MetaType, "base", base).destroy(comp),19 pub fn zigTypeTag(self: Type) std.builtin.TypeId {
26 .Void => @fieldParentPtr(Void, "base", base).destroy(comp),20 switch (self.tag()) {
27 .Bool => @fieldParentPtr(Bool, "base", base).destroy(comp),21 .int_u8, .int_usize => return .Int,
28 .NoReturn => @fieldParentPtr(NoReturn, "base", base).destroy(comp),22 .array_u8, .array_u8_sentinel_0 => return .Array,
29 .Int => @fieldParentPtr(Int, "base", base).destroy(comp),23 .single_const_pointer => return .Pointer,
30 .Float => @fieldParentPtr(Float, "base", base).destroy(comp),
31 .Pointer => @fieldParentPtr(Pointer, "base", base).destroy(comp),
32 .Array => @fieldParentPtr(Array, "base", base).destroy(comp),
33 .ComptimeFloat => @fieldParentPtr(ComptimeFloat, "base", base).destroy(comp),
34 .ComptimeInt => @fieldParentPtr(ComptimeInt, "base", base).destroy(comp),
35 .EnumLiteral => @fieldParentPtr(EnumLiteral, "base", base).destroy(comp),
36 .Undefined => @fieldParentPtr(Undefined, "base", base).destroy(comp),
37 .Null => @fieldParentPtr(Null, "base", base).destroy(comp),
38 .Optional => @fieldParentPtr(Optional, "base", base).destroy(comp),
39 .ErrorUnion => @fieldParentPtr(ErrorUnion, "base", base).destroy(comp),
40 .ErrorSet => @fieldParentPtr(ErrorSet, "base", base).destroy(comp),
41 .Enum => @fieldParentPtr(Enum, "base", base).destroy(comp),
42 .Union => @fieldParentPtr(Union, "base", base).destroy(comp),
43 .BoundFn => @fieldParentPtr(BoundFn, "base", base).destroy(comp),
44 .Opaque => @fieldParentPtr(Opaque, "base", base).destroy(comp),
45 .Frame => @fieldParentPtr(Frame, "base", base).destroy(comp),
46 .AnyFrame => @fieldParentPtr(AnyFrame, "base", base).destroy(comp),
47 .Vector => @fieldParentPtr(Vector, "base", base).destroy(comp),
48 }24 }
49 }25 }
5026
51 pub fn getLlvmType(27 pub fn initTag(comptime tag: Tag) Type {
52 base: *Type,28 comptime assert(@enumToInt(tag) < Tag.no_payload_count);
53 allocator: *Allocator,29 return .{ .tag_if_small_enough = @enumToInt(tag) };
54 llvm_context: *llvm.Context,
55 ) error{OutOfMemory}!*llvm.Type {
56 switch (base.id) {
57 .Struct => return @fieldParentPtr(Struct, "base", base).getLlvmType(allocator, llvm_context),
58 .Fn => return @fieldParentPtr(Fn, "base", base).getLlvmType(allocator, llvm_context),
59 .Type => unreachable,
60 .Void => unreachable,
61 .Bool => return @fieldParentPtr(Bool, "base", base).getLlvmType(allocator, llvm_context),
62 .NoReturn => unreachable,
63 .Int => return @fieldParentPtr(Int, "base", base).getLlvmType(allocator, llvm_context),
64 .Float => return @fieldParentPtr(Float, "base", base).getLlvmType(allocator, llvm_context),
65 .Pointer => return @fieldParentPtr(Pointer, "base", base).getLlvmType(allocator, llvm_context),
66 .Array => return @fieldParentPtr(Array, "base", base).getLlvmType(allocator, llvm_context),
67 .ComptimeFloat => unreachable,
68 .ComptimeInt => unreachable,
69 .EnumLiteral => unreachable,
70 .Undefined => unreachable,
71 .Null => unreachable,
72 .Optional => return @fieldParentPtr(Optional, "base", base).getLlvmType(allocator, llvm_context),
73 .ErrorUnion => return @fieldParentPtr(ErrorUnion, "base", base).getLlvmType(allocator, llvm_context),
74 .ErrorSet => return @fieldParentPtr(ErrorSet, "base", base).getLlvmType(allocator, llvm_context),
75 .Enum => return @fieldParentPtr(Enum, "base", base).getLlvmType(allocator, llvm_context),
76 .Union => return @fieldParentPtr(Union, "base", base).getLlvmType(allocator, llvm_context),
77 .BoundFn => return @fieldParentPtr(BoundFn, "base", base).getLlvmType(allocator, llvm_context),
78 .Opaque => return @fieldParentPtr(Opaque, "base", base).getLlvmType(allocator, llvm_context),
79 .Frame => return @fieldParentPtr(Frame, "base", base).getLlvmType(allocator, llvm_context),
80 .AnyFrame => return @fieldParentPtr(AnyFrame, "base", base).getLlvmType(allocator, llvm_context),
81 .Vector => return @fieldParentPtr(Vector, "base", base).getLlvmType(allocator, llvm_context),
82 }
83 }30 }
8431
85 pub fn handleIsPtr(base: *Type) bool {32 pub fn initPayload(payload: *Payload) Type {
86 switch (base.id) {33 assert(@enumToInt(payload.tag) >= Tag.no_payload_count);
87 .Type,34 return .{ .ptr_otherwise = payload };
88 .ComptimeFloat,
89 .ComptimeInt,
90 .EnumLiteral,
91 .Undefined,
92 .Null,
93 .BoundFn,
94 .Opaque,
95 => unreachable,
96
97 .NoReturn,
98 .Void,
99 .Bool,
100 .Int,
101 .Float,
102 .Pointer,
103 .ErrorSet,
104 .Enum,
105 .Fn,
106 .Frame,
107 .AnyFrame,
108 .Vector,
109 => return false,
110
111 .Struct => @panic("TODO"),
112 .Array => @panic("TODO"),
113 .Optional => @panic("TODO"),
114 .ErrorUnion => @panic("TODO"),
115 .Union => @panic("TODO"),
116 }
117 }35 }
11836
119 pub fn hasBits(base: *Type) bool {37 pub fn tag(self: Type) Tag {
120 switch (base.id) {38 if (self.tag_if_small_enough < Tag.no_payload_count) {
121 .Type,39 return @intToEnum(self.tag_if_small_enough);
122 .ComptimeFloat,40 } else {
123 .ComptimeInt,41 return self.ptr_otherwise.tag;
124 .EnumLiteral,
125 .Undefined,
126 .Null,
127 .BoundFn,
128 .Opaque,
129 => unreachable,
130
131 .Void,
132 .NoReturn,
133 => return false,
134
135 .Bool,
136 .Int,
137 .Float,
138 .Fn,
139 .Frame,
140 .AnyFrame,
141 .Vector,
142 => return true,
143
144 .Pointer => {
145 const ptr_type = @fieldParentPtr(Pointer, "base", base);
146 return ptr_type.key.child_type.hasBits();
147 },
148
149 .ErrorSet => @panic("TODO"),
150 .Enum => @panic("TODO"),
151 .Struct => @panic("TODO"),
152 .Array => @panic("TODO"),
153 .Optional => @panic("TODO"),
154 .ErrorUnion => @panic("TODO"),
155 .Union => @panic("TODO"),
156 }42 }
157 }43 }
15844
159 pub fn cast(base: *Type, comptime T: type) ?*T {45 pub fn format(
160 if (base.id != @field(Id, @typeName(T))) return null;46 self: Type,
161 return @fieldParentPtr(T, "base", base);47 comptime fmt: []const u8,
162 }48 options: std.fmt.FormatOptions,
16349 out_stream: var,
164 pub fn dump(base: *const Type) void {50 ) !void {
165 std.debug.warn("{}", .{@tagName(base.id)});51 comptime assert(fmt.len == 0);
166 }52 switch (self.tag()) {
16753 .int_u8 => return out_stream.writeAll("u8"),
168 fn init(base: *Type, comp: *Compilation, id: Id, name: []const u8) void {54 .int_usize => return out_stream.writeAll("usize"),
169 base.* = Type{55 .array_u8_sentinel_0 => {
170 .base = Value{56 const payload = @fieldParentPtr(Payload.Array_u8_Sentinel0, "base", self.ptr_otherwise);
171 .id = .Type,57 return out_stream.print("[{}:0]u8", .{payload.len});
172 .typ = &MetaType.get(comp).base,58 },
173 .ref_count = std.atomic.Int(usize).init(1),59 .array => {
60 const payload = @fieldParentPtr(Payload.Array, "base", self.ptr_otherwise);
61 return out_stream.print("[{}]{}", .{ payload.len, payload.elem_type });
62 },
63 .single_const_pointer => {
64 const payload = @fieldParentPtr(Payload.SingleConstPointer, "base", self.ptr_otherwise);
65 return out_stream.print("*const {}", .{payload.pointee_type});
174 },66 },
175 .id = id,
176 .name = name,
177 .abi_alignment = AbiAlignment.init(),
178 };
179 }
180
181 /// If you happen to have an llvm context handy, use getAbiAlignmentInContext instead.
182 /// Otherwise, this one will grab one from the pool and then release it.
183 pub fn getAbiAlignment(base: *Type, comp: *Compilation) !u32 {
184 if (base.abi_alignment.start()) |ptr| return ptr.*;
185
186 {
187 const held = try comp.zig_compiler.getAnyLlvmContext();
188 defer held.release(comp.zig_compiler);
189
190 const llvm_context = held.node.data;
191
192 base.abi_alignment.data = base.resolveAbiAlignment(comp, llvm_context);
193 }67 }
194 base.abi_alignment.resolve();
195 return base.abi_alignment.data;
196 }68 }
19769
198 /// If you have an llvm conext handy, you can use it here.70 /// This enum does not directly correspond to `std.builtin.TypeId` because
199 pub fn getAbiAlignmentInContext(base: *Type, comp: *Compilation, llvm_context: *llvm.Context) !u32 {71 /// it has extra enum tags in it, as a way of using less memory. For example,
200 if (base.abi_alignment.start()) |ptr| return ptr.*;72 /// even though Zig recognizes `*align(10) i32` and `*i32` both as Pointer types
20173 /// but with different alignment values, in this data structure they are represented
202 base.abi_alignment.data = base.resolveAbiAlignment(comp, llvm_context);74 /// with different enum tags, because the the former requires more payload data than the latter.
203 base.abi_alignment.resolve();75 /// See `zigTypeTag` for the function that corresponds to `std.builtin.TypeId`.
204 return base.abi_alignment.data;76 pub const Tag = enum {
205 }77 // The first section of this enum are tags that require no payload.
20678 int_u8,
207 /// Lower level function that does the work. See getAbiAlignment.79 int_usize,
208 fn resolveAbiAlignment(base: *Type, comp: *Compilation, llvm_context: *llvm.Context) !u32 {80 // Bump this when adding items above.
209 const llvm_type = try base.getLlvmType(comp.gpa(), llvm_context);81 pub const last_no_payload_tag = Tag.int_usize;
210 return @intCast(u32, llvm.ABIAlignmentOfType(comp.target_data_ref, llvm_type));82 pub const no_payload_count = @enumToInt(last_no_payload_tag) + 1;
211 }83 // After this, the tag requires a payload.
21284
213 pub const Struct = struct {85 array_u8_sentinel_0,
214 base: Type,86 array,
215 decls: *Scope.Decls,87 single_const_pointer,
21688 };
217 pub fn destroy(self: *Struct, comp: *Compilation) void {89
218 comp.gpa().destroy(self);90 pub const Payload = struct {
219 }91 tag: Tag,
22092
221 pub fn getLlvmType(self: *Struct, allocator: *Allocator, llvm_context: *llvm.Context) *llvm.Type {93 pub const Array_u8_Sentinel0 = struct {
222 @panic("TODO");94 base: Payload = Payload{ .tag = .array_u8_sentinel_0 },
223 }95
224 };96 len: u64,
225
226 pub const Fn = struct {
227 base: Type,
228 key: Key,
229 non_key: NonKey,
230 garbage_node: std.atomic.Stack(*Fn).Node,
231
232 pub const Kind = enum {
233 Normal,
234 Generic,
235 };
236
237 pub const NonKey = union {
238 Normal: Normal,
239 Generic: void,
240
241 pub const Normal = struct {
242 variable_list: std.ArrayList(*Scope.Var),
243 };
244 };
245
246 pub const Key = struct {
247 data: Data,
248 alignment: ?u32,
249
250 pub const Data = union(Kind) {
251 Generic: Generic,
252 Normal: Normal,
253 };
254
255 pub const Normal = struct {
256 params: []Param,
257 return_type: *Type,
258 is_var_args: bool,
259 cc: CallingConvention,
260 };
261
262 pub const Generic = struct {
263 param_count: usize,
264 cc: CallingConvention,
265 };
266
267 pub fn hash(self: *const Key) u32 {
268 var result: u32 = 0;
269 result +%= hashAny(self.alignment, 0);
270 switch (self.data) {
271 .Generic => |generic| {
272 result +%= hashAny(generic.param_count, 1);
273 result +%= hashAny(generic.cc, 3);
274 },
275 .Normal => |normal| {
276 result +%= hashAny(normal.return_type, 4);
277 result +%= hashAny(normal.is_var_args, 5);
278 result +%= hashAny(normal.cc, 6);
279 for (normal.params) |param| {
280 result +%= hashAny(param.is_noalias, 7);
281 result +%= hashAny(param.typ, 8);
282 }
283 },
284 }
285 return result;
286 }
287
288 pub fn eql(self: *const Key, other: *const Key) bool {
289 if ((self.alignment == null) != (other.alignment == null)) return false;
290 if (self.alignment) |self_align| {
291 if (self_align != other.alignment.?) return false;
292 }
293 if (@as(@TagType(Data), self.data) != @as(@TagType(Data), other.data)) return false;
294 switch (self.data) {
295 .Generic => |*self_generic| {
296 const other_generic = &other.data.Generic;
297 if (self_generic.param_count != other_generic.param_count) return false;
298 if (self_generic.cc != other_generic.cc) return false;
299 },
300 .Normal => |*self_normal| {
301 const other_normal = &other.data.Normal;
302 if (self_normal.cc != other_normal.cc) return false;
303 if (self_normal.is_var_args != other_normal.is_var_args) return false;
304 if (self_normal.return_type != other_normal.return_type) return false;
305 for (self_normal.params) |*self_param, i| {
306 const other_param = &other_normal.params[i];
307 if (self_param.is_noalias != other_param.is_noalias) return false;
308 if (self_param.typ != other_param.typ) return false;
309 }
310 },
311 }
312 return true;
313 }
314
315 pub fn deref(key: Key, comp: *Compilation) void {
316 switch (key.data) {
317 .Generic => {},
318 .Normal => |normal| {
319 normal.return_type.base.deref(comp);
320 for (normal.params) |param| {
321 param.typ.base.deref(comp);
322 }
323 },
324 }
325 }
326
327 pub fn ref(key: Key) void {
328 switch (key.data) {
329 .Generic => {},
330 .Normal => |normal| {
331 normal.return_type.base.ref();
332 for (normal.params) |param| {
333 param.typ.base.ref();
334 }
335 },
336 }
337 }
338 };
339
340 const CallingConvention = builtin.CallingConvention;
341
342 pub const Param = struct {
343 is_noalias: bool,
344 typ: *Type,
345 };
346
347 fn ccFnTypeStr(cc: CallingConvention) []const u8 {
348 return switch (cc) {
349 .Unspecified => "",
350 .C => "extern ",
351 .Cold => "coldcc ",
352 .Naked => "nakedcc ",
353 .Stdcall => "stdcallcc ",
354 .Async => "async ",
355 else => unreachable,
356 };
357 }
358
359 pub fn paramCount(self: *Fn) usize {
360 return switch (self.key.data) {
361 .Generic => |generic| generic.param_count,
362 .Normal => |normal| normal.params.len,
363 };
364 }
365
366 /// takes ownership of key.Normal.params on success
367 pub fn get(comp: *Compilation, key: Key) !*Fn {
368 {
369 const held = comp.fn_type_table.acquire();
370 defer held.release();
371
372 if (held.value.get(&key)) |entry| {
373 entry.value.base.base.ref();
374 return entry.value;
375 }
376 }
377
378 key.ref();
379 errdefer key.deref(comp);
380
381 const self = try comp.gpa().create(Fn);
382 self.* = Fn{
383 .base = undefined,
384 .key = key,
385 .non_key = undefined,
386 .garbage_node = undefined,
387 };
388 errdefer comp.gpa().destroy(self);
389
390 var name_buf = std.ArrayList(u8).init(comp.gpa());
391 defer name_buf.deinit();
392
393 const name_stream = name_buf.outStream();
394
395 switch (key.data) {
396 .Generic => |generic| {
397 self.non_key = NonKey{ .Generic = {} };
398 const cc_str = ccFnTypeStr(generic.cc);
399 try name_stream.print("{}fn(", .{cc_str});
400 var param_i: usize = 0;
401 while (param_i < generic.param_count) : (param_i += 1) {
402 const arg = if (param_i == 0) "var" else ", var";
403 try name_stream.write(arg);
404 }
405 try name_stream.write(")");
406 if (key.alignment) |alignment| {
407 try name_stream.print(" align({})", .{alignment});
408 }
409 try name_stream.write(" var");
410 },
411 .Normal => |normal| {
412 self.non_key = NonKey{
413 .Normal = NonKey.Normal{ .variable_list = std.ArrayList(*Scope.Var).init(comp.gpa()) },
414 };
415 const cc_str = ccFnTypeStr(normal.cc);
416 try name_stream.print("{}fn(", .{cc_str});
417 for (normal.params) |param, i| {
418 if (i != 0) try name_stream.write(", ");
419 if (param.is_noalias) try name_stream.write("noalias ");
420 try name_stream.write(param.typ.name);
421 }
422 if (normal.is_var_args) {
423 if (normal.params.len != 0) try name_stream.write(", ");
424 try name_stream.write("...");
425 }
426 try name_stream.write(")");
427 if (key.alignment) |alignment| {
428 try name_stream.print(" align({})", .{alignment});
429 }
430 try name_stream.print(" {}", .{normal.return_type.name});
431 },
432 }
433
434 self.base.init(comp, .Fn, name_buf.toOwnedSlice());
435
436 {
437 const held = comp.fn_type_table.acquire();
438 defer held.release();
439
440 _ = try held.value.put(&self.key, self);
441 }
442 return self;
443 }
444
445 pub fn destroy(self: *Fn, comp: *Compilation) void {
446 self.key.deref(comp);
447 switch (self.key.data) {
448 .Generic => {},
449 .Normal => {
450 self.non_key.Normal.variable_list.deinit();
451 },
452 }
453 comp.gpa().destroy(self);
454 }
455
456 pub fn getLlvmType(self: *Fn, allocator: *Allocator, llvm_context: *llvm.Context) !*llvm.Type {
457 const normal = &self.key.data.Normal;
458 const llvm_return_type = switch (normal.return_type.id) {
459 .Void => llvm.VoidTypeInContext(llvm_context) orelse return error.OutOfMemory,
460 else => try normal.return_type.getLlvmType(allocator, llvm_context),
461 };
462 const llvm_param_types = try allocator.alloc(*llvm.Type, normal.params.len);
463 defer allocator.free(llvm_param_types);
464 for (llvm_param_types) |*llvm_param_type, i| {
465 llvm_param_type.* = try normal.params[i].typ.getLlvmType(allocator, llvm_context);
466 }
467
468 return llvm.FunctionType(
469 llvm_return_type,
470 llvm_param_types.ptr,
471 @intCast(c_uint, llvm_param_types.len),
472 @boolToInt(normal.is_var_args),
473 ) orelse error.OutOfMemory;
474 }
475 };
476
477 pub const MetaType = struct {
478 base: Type,
479 value: *Type,
480
481 /// Adds 1 reference to the resulting type
482 pub fn get(comp: *Compilation) *MetaType {
483 comp.meta_type.base.base.ref();
484 return comp.meta_type;
485 }
486
487 pub fn destroy(self: *MetaType, comp: *Compilation) void {
488 comp.gpa().destroy(self);
489 }
490 };
491
492 pub const Void = struct {
493 base: Type,
494
495 /// Adds 1 reference to the resulting type
496 pub fn get(comp: *Compilation) *Void {
497 comp.void_type.base.base.ref();
498 return comp.void_type;
499 }
500
501 pub fn destroy(self: *Void, comp: *Compilation) void {
502 comp.gpa().destroy(self);
503 }
504 };
505
506 pub const Bool = struct {
507 base: Type,
508
509 /// Adds 1 reference to the resulting type
510 pub fn get(comp: *Compilation) *Bool {
511 comp.bool_type.base.base.ref();
512 return comp.bool_type;
513 }
514
515 pub fn destroy(self: *Bool, comp: *Compilation) void {
516 comp.gpa().destroy(self);
517 }
518
519 pub fn getLlvmType(self: *Bool, allocator: *Allocator, llvm_context: *llvm.Context) *llvm.Type {
520 @panic("TODO");
521 }
522 };
523
524 pub const NoReturn = struct {
525 base: Type,
526
527 /// Adds 1 reference to the resulting type
528 pub fn get(comp: *Compilation) *NoReturn {
529 comp.noreturn_type.base.base.ref();
530 return comp.noreturn_type;
531 }
532
533 pub fn destroy(self: *NoReturn, comp: *Compilation) void {
534 comp.gpa().destroy(self);
535 }
536 };
537
538 pub const Int = struct {
539 base: Type,
540 key: Key,
541 garbage_node: std.atomic.Stack(*Int).Node,
542
543 pub const Key = struct {
544 bit_count: u32,
545 is_signed: bool,
546
547 pub fn hash(self: *const Key) u32 {
548 var result: u32 = 0;
549 result +%= hashAny(self.is_signed, 0);
550 result +%= hashAny(self.bit_count, 1);
551 return result;
552 }
553
554 pub fn eql(self: *const Key, other: *const Key) bool {
555 return self.bit_count == other.bit_count and self.is_signed == other.is_signed;
556 }
557 };
558
559 pub fn get_u8(comp: *Compilation) *Int {
560 comp.u8_type.base.base.ref();
561 return comp.u8_type;
562 }
563
564 pub fn get(comp: *Compilation, key: Key) !*Int {
565 {
566 const held = comp.int_type_table.acquire();
567 defer held.release();
568
569 if (held.value.get(&key)) |entry| {
570 entry.value.base.base.ref();
571 return entry.value;
572 }
573 }
574
575 const self = try comp.gpa().create(Int);
576 self.* = Int{
577 .base = undefined,
578 .key = key,
579 .garbage_node = undefined,
580 };
581 errdefer comp.gpa().destroy(self);
582
583 const u_or_i = "ui"[@boolToInt(key.is_signed)];
584 const name = try std.fmt.allocPrint(comp.gpa(), "{c}{}", .{ u_or_i, key.bit_count });
585 errdefer comp.gpa().free(name);
586
587 self.base.init(comp, .Int, name);
588
589 {
590 const held = comp.int_type_table.acquire();
591 defer held.release();
592
593 _ = try held.value.put(&self.key, self);
594 }
595 return self;
596 }
597
598 pub fn destroy(self: *Int, comp: *Compilation) void {
599 self.garbage_node = std.atomic.Stack(*Int).Node{
600 .data = self,
601 .next = undefined,
602 };
603 comp.registerGarbage(Int, &self.garbage_node);
604 }
605
606 pub fn gcDestroy(self: *Int, comp: *Compilation) void {
607 {
608 const held = comp.int_type_table.acquire();
609 defer held.release();
610
611 _ = held.value.remove(&self.key).?;
612 }
613 // we allocated the name
614 comp.gpa().free(self.base.name);
615 comp.gpa().destroy(self);
616 }
617
618 pub fn getLlvmType(self: *Int, allocator: *Allocator, llvm_context: *llvm.Context) !*llvm.Type {
619 return llvm.IntTypeInContext(llvm_context, self.key.bit_count) orelse return error.OutOfMemory;
620 }
621 };
622
623 pub const Float = struct {
624 base: Type,
625
626 pub fn destroy(self: *Float, comp: *Compilation) void {
627 comp.gpa().destroy(self);
628 }
629
630 pub fn getLlvmType(self: *Float, allocator: *Allocator, llvm_context: *llvm.Context) *llvm.Type {
631 @panic("TODO");
632 }
633 };
634 pub const Pointer = struct {
635 base: Type,
636 key: Key,
637 garbage_node: std.atomic.Stack(*Pointer).Node,
638
639 pub const Key = struct {
640 child_type: *Type,
641 mut: Mut,
642 vol: Vol,
643 size: Size,
644 alignment: Align,
645
646 pub fn hash(self: *const Key) u32 {
647 var result: u32 = 0;
648 result +%= switch (self.alignment) {
649 .Abi => 0xf201c090,
650 .Override => |x| hashAny(x, 0),
651 };
652 result +%= hashAny(self.child_type, 1);
653 result +%= hashAny(self.mut, 2);
654 result +%= hashAny(self.vol, 3);
655 result +%= hashAny(self.size, 4);
656 return result;
657 }
658
659 pub fn eql(self: *const Key, other: *const Key) bool {
660 if (self.child_type != other.child_type or
661 self.mut != other.mut or
662 self.vol != other.vol or
663 self.size != other.size or
664 @as(@TagType(Align), self.alignment) != @as(@TagType(Align), other.alignment))
665 {
666 return false;
667 }
668 switch (self.alignment) {
669 .Abi => return true,
670 .Override => |x| return x == other.alignment.Override,
671 }
672 }
673 };97 };
67498
675 pub const Mut = enum {99 pub const Array = struct {
676 Mut,100 base: Payload = Payload{ .tag = .array },
677 Const,
678 };
679
680 pub const Vol = enum {
681 Non,
682 Volatile,
683 };
684101
685 pub const Align = union(enum) {102 elem_type: Type,
686 Abi,103 len: u64,
687 Override: u32,
688 };104 };
689105
690 pub const Size = builtin.TypeInfo.Pointer.Size;106 pub const SingleConstPointer = struct {
691107 base: Payload = Payload{ .tag = .single_const_pointer },
692 pub fn destroy(self: *Pointer, comp: *Compilation) void {
693 self.garbage_node = std.atomic.Stack(*Pointer).Node{
694 .data = self,
695 .next = undefined,
696 };
697 comp.registerGarbage(Pointer, &self.garbage_node);
698 }
699
700 pub fn gcDestroy(self: *Pointer, comp: *Compilation) void {
701 {
702 const held = comp.ptr_type_table.acquire();
703 defer held.release();
704
705 _ = held.value.remove(&self.key).?;
706 }
707 self.key.child_type.base.deref(comp);
708 comp.gpa().destroy(self);
709 }
710
711 pub fn getAlignAsInt(self: *Pointer, comp: *Compilation) u32 {
712 switch (self.key.alignment) {
713 .Abi => return self.key.child_type.getAbiAlignment(comp),
714 .Override => |alignment| return alignment,
715 }
716 }
717
718 pub fn get(
719 comp: *Compilation,
720 key: Key,
721 ) !*Pointer {
722 var normal_key = key;
723 switch (key.alignment) {
724 .Abi => {},
725 .Override => |alignment| {
726 // TODO https://github.com/ziglang/zig/issues/3190
727 var align_spill = alignment;
728 const abi_align = try key.child_type.getAbiAlignment(comp);
729 if (abi_align == align_spill) {
730 normal_key.alignment = .Abi;
731 }
732 },
733 }
734 {
735 const held = comp.ptr_type_table.acquire();
736 defer held.release();
737
738 if (held.value.get(&normal_key)) |entry| {
739 entry.value.base.base.ref();
740 return entry.value;
741 }
742 }
743108
744 const self = try comp.gpa().create(Pointer);109 pointee_type: Type,
745 self.* = Pointer{
746 .base = undefined,
747 .key = normal_key,
748 .garbage_node = undefined,
749 };
750 errdefer comp.gpa().destroy(self);
751
752 const size_str = switch (self.key.size) {
753 .One => "*",
754 .Many => "[*]",
755 .Slice => "[]",
756 .C => "[*c]",
757 };
758 const mut_str = switch (self.key.mut) {
759 .Const => "const ",
760 .Mut => "",
761 };
762 const vol_str = switch (self.key.vol) {
763 .Volatile => "volatile ",
764 .Non => "",
765 };
766 const name = switch (self.key.alignment) {
767 .Abi => try std.fmt.allocPrint(comp.gpa(), "{}{}{}{}", .{
768 size_str,
769 mut_str,
770 vol_str,
771 self.key.child_type.name,
772 }),
773 .Override => |alignment| try std.fmt.allocPrint(comp.gpa(), "{}align<{}> {}{}{}", .{
774 size_str,
775 alignment,
776 mut_str,
777 vol_str,
778 self.key.child_type.name,
779 }),
780 };
781 errdefer comp.gpa().free(name);
782
783 self.base.init(comp, .Pointer, name);
784
785 {
786 const held = comp.ptr_type_table.acquire();
787 defer held.release();
788
789 _ = try held.value.put(&self.key, self);
790 }
791 return self;
792 }
793
794 pub fn getLlvmType(self: *Pointer, allocator: *Allocator, llvm_context: *llvm.Context) !*llvm.Type {
795 const elem_llvm_type = try self.key.child_type.getLlvmType(allocator, llvm_context);
796 return llvm.PointerType(elem_llvm_type, 0) orelse return error.OutOfMemory;
797 }
798 };
799
800 pub const Array = struct {
801 base: Type,
802 key: Key,
803 garbage_node: std.atomic.Stack(*Array).Node,
804
805 pub const Key = struct {
806 elem_type: *Type,
807 len: usize,
808
809 pub fn hash(self: *const Key) u32 {
810 var result: u32 = 0;
811 result +%= hashAny(self.elem_type, 0);
812 result +%= hashAny(self.len, 1);
813 return result;
814 }
815
816 pub fn eql(self: *const Key, other: *const Key) bool {
817 return self.elem_type == other.elem_type and self.len == other.len;
818 }
819 };110 };
820
821 pub fn destroy(self: *Array, comp: *Compilation) void {
822 self.key.elem_type.base.deref(comp);
823 comp.gpa().destroy(self);
824 }
825
826 pub fn get(comp: *Compilation, key: Key) !*Array {
827 key.elem_type.base.ref();
828 errdefer key.elem_type.base.deref(comp);
829
830 {
831 const held = comp.array_type_table.acquire();
832 defer held.release();
833
834 if (held.value.get(&key)) |entry| {
835 entry.value.base.base.ref();
836 return entry.value;
837 }
838 }
839
840 const self = try comp.gpa().create(Array);
841 self.* = Array{
842 .base = undefined,
843 .key = key,
844 .garbage_node = undefined,
845 };
846 errdefer comp.gpa().destroy(self);
847
848 const name = try std.fmt.allocPrint(comp.gpa(), "[{}]{}", .{ key.len, key.elem_type.name });
849 errdefer comp.gpa().free(name);
850
851 self.base.init(comp, .Array, name);
852
853 {
854 const held = comp.array_type_table.acquire();
855 defer held.release();
856
857 _ = try held.value.put(&self.key, self);
858 }
859 return self;
860 }
861
862 pub fn getLlvmType(self: *Array, allocator: *Allocator, llvm_context: *llvm.Context) !*llvm.Type {
863 const elem_llvm_type = try self.key.elem_type.getLlvmType(allocator, llvm_context);
864 return llvm.ArrayType(elem_llvm_type, @intCast(c_uint, self.key.len)) orelse return error.OutOfMemory;
865 }
866 };
867
868 pub const Vector = struct {
869 base: Type,
870
871 pub fn destroy(self: *Vector, comp: *Compilation) void {
872 comp.gpa().destroy(self);
873 }
874
875 pub fn getLlvmType(self: *Vector, allocator: *Allocator, llvm_context: *llvm.Context) *llvm.Type {
876 @panic("TODO");
877 }
878 };
879
880 pub const ComptimeFloat = struct {
881 base: Type,
882
883 pub fn destroy(self: *ComptimeFloat, comp: *Compilation) void {
884 comp.gpa().destroy(self);
885 }
886 };
887
888 pub const ComptimeInt = struct {
889 base: Type,
890
891 /// Adds 1 reference to the resulting type
892 pub fn get(comp: *Compilation) *ComptimeInt {
893 comp.comptime_int_type.base.base.ref();
894 return comp.comptime_int_type;
895 }
896
897 pub fn destroy(self: *ComptimeInt, comp: *Compilation) void {
898 comp.gpa().destroy(self);
899 }
900 };
901
902 pub const EnumLiteral = struct {
903 base: Type,
904
905 /// Adds 1 reference to the resulting type
906 pub fn get(comp: *Compilation) *EnumLiteral {
907 comp.comptime_int_type.base.base.ref();
908 return comp.comptime_int_type;
909 }
910
911 pub fn destroy(self: *EnumLiteral, comp: *Compilation) void {
912 comp.gpa().destroy(self);
913 }
914 };
915
916 pub const Undefined = struct {
917 base: Type,
918
919 pub fn destroy(self: *Undefined, comp: *Compilation) void {
920 comp.gpa().destroy(self);
921 }
922 };
923
924 pub const Null = struct {
925 base: Type,
926
927 pub fn destroy(self: *Null, comp: *Compilation) void {
928 comp.gpa().destroy(self);
929 }
930 };
931
932 pub const Optional = struct {
933 base: Type,
934
935 pub fn destroy(self: *Optional, comp: *Compilation) void {
936 comp.gpa().destroy(self);
937 }
938
939 pub fn getLlvmType(self: *Optional, allocator: *Allocator, llvm_context: *llvm.Context) *llvm.Type {
940 @panic("TODO");
941 }
942 };
943
944 pub const ErrorUnion = struct {
945 base: Type,
946
947 pub fn destroy(self: *ErrorUnion, comp: *Compilation) void {
948 comp.gpa().destroy(self);
949 }
950
951 pub fn getLlvmType(self: *ErrorUnion, allocator: *Allocator, llvm_context: *llvm.Context) *llvm.Type {
952 @panic("TODO");
953 }
954 };
955
956 pub const ErrorSet = struct {
957 base: Type,
958
959 pub fn destroy(self: *ErrorSet, comp: *Compilation) void {
960 comp.gpa().destroy(self);
961 }
962
963 pub fn getLlvmType(self: *ErrorSet, allocator: *Allocator, llvm_context: *llvm.Context) *llvm.Type {
964 @panic("TODO");
965 }
966 };
967
968 pub const Enum = struct {
969 base: Type,
970
971 pub fn destroy(self: *Enum, comp: *Compilation) void {
972 comp.gpa().destroy(self);
973 }
974
975 pub fn getLlvmType(self: *Enum, allocator: *Allocator, llvm_context: *llvm.Context) *llvm.Type {
976 @panic("TODO");
977 }
978 };
979
980 pub const Union = struct {
981 base: Type,
982
983 pub fn destroy(self: *Union, comp: *Compilation) void {
984 comp.gpa().destroy(self);
985 }
986
987 pub fn getLlvmType(self: *Union, allocator: *Allocator, llvm_context: *llvm.Context) *llvm.Type {
988 @panic("TODO");
989 }
990 };
991
992 pub const BoundFn = struct {
993 base: Type,
994
995 pub fn destroy(self: *BoundFn, comp: *Compilation) void {
996 comp.gpa().destroy(self);
997 }
998
999 pub fn getLlvmType(self: *BoundFn, allocator: *Allocator, llvm_context: *llvm.Context) *llvm.Type {
1000 @panic("TODO");
1001 }
1002 };
1003
1004 pub const Opaque = struct {
1005 base: Type,
1006
1007 pub fn destroy(self: *Opaque, comp: *Compilation) void {
1008 comp.gpa().destroy(self);
1009 }
1010
1011 pub fn getLlvmType(self: *Opaque, allocator: *Allocator, llvm_context: *llvm.Context) *llvm.Type {
1012 @panic("TODO");
1013 }
1014 };
1015
1016 pub const Frame = struct {
1017 base: Type,
1018
1019 pub fn destroy(self: *Frame, comp: *Compilation) void {
1020 comp.gpa().destroy(self);
1021 }
1022
1023 pub fn getLlvmType(self: *Frame, allocator: *Allocator, llvm_context: *llvm.Context) *llvm.Type {
1024 @panic("TODO");
1025 }
1026 };
1027
1028 pub const AnyFrame = struct {
1029 base: Type,
1030
1031 pub fn destroy(self: *AnyFrame, comp: *Compilation) void {
1032 comp.gpa().destroy(self);
1033 }
1034
1035 pub fn getLlvmType(self: *AnyFrame, allocator: *Allocator, llvm_context: *llvm.Context) *llvm.Type {
1036 @panic("TODO");
1037 }
1038 };111 };
1039};112};
1040
1041fn hashAny(x: var, comptime seed: u64) u32 {
1042 switch (@typeInfo(@TypeOf(x))) {
1043 .Int => |info| {
1044 comptime var rng = comptime std.rand.DefaultPrng.init(seed);
1045 const unsigned_x = @bitCast(std.meta.IntType(false, info.bits), x);
1046 if (info.bits <= 32) {
1047 return @as(u32, unsigned_x) *% comptime rng.random.scalar(u32);
1048 } else {
1049 return @truncate(u32, unsigned_x *% comptime rng.random.scalar(@TypeOf(unsigned_x)));
1050 }
1051 },
1052 .Pointer => |info| {
1053 switch (info.size) {
1054 .One => return hashAny(@ptrToInt(x), seed),
1055 .Many => @compileError("implement hash function"),
1056 .Slice => @compileError("implement hash function"),
1057 .C => unreachable,
1058 }
1059 },
1060 .Enum => return hashAny(@enumToInt(x), seed),
1061 .Bool => {
1062 comptime var rng = comptime std.rand.DefaultPrng.init(seed);
1063 const vals = comptime [2]u32{ rng.random.scalar(u32), rng.random.scalar(u32) };
1064 return vals[@boolToInt(x)];
1065 },
1066 .Optional => {
1067 if (x) |non_opt| {
1068 return hashAny(non_opt, seed);
1069 } else {
1070 return hashAny(@as(u32, 1), seed);
1071 }
1072 },
1073 else => @compileError("implement hash function for " ++ @typeName(@TypeOf(x))),
1074 }
1075}
src-self-hosted/value.zig+75-34
...@@ -1,26 +1,35 @@...@@ -1,26 +1,35 @@
1const std = @import("std");1const std = @import("std");
2const Type = @import("type.zig").Type;
3const log2 = std.math.log2;
4const assert = std.debug.assert;
25
3/// This is the raw data, with no bookkeeping, no memory awareness,6/// This is the raw data, with no bookkeeping, no memory awareness,
4/// no de-duplication, and no type system awareness.7/// no de-duplication, and no type system awareness.
5/// It's important for this struct to be small.8/// It's important for this struct to be small.
6/// It is not copyable since it may contain references to its inner data.9/// This union takes advantage of the fact that the first page of memory
7pub const Value = struct {10/// is unmapped, giving us 4096 possible enum tags that have no payload.
8 tag: Tag,11pub const Value = extern union {
12 /// If the tag value is less than Tag.no_payload_count, then no pointer
13 /// dereference is needed.
14 tag_if_small_enough: usize,
15 ptr_otherwise: *Payload,
916
10 pub const Tag = enum {17 pub const Tag = enum {
18 // The first section of this enum are tags that require no payload.
11 void_type,19 void_type,
12 noreturn_type,20 noreturn_type,
13 bool_type,21 bool_type,
14 usize_type,22 usize_type,
15
16 void_value,23 void_value,
17 noreturn_value,24 noreturn_value,
18 bool_true,25 bool_true,
19 bool_false,26 bool_false,
27 // Bump this when adding items above.
28 pub const last_no_payload_tag = Tag.bool_false;
29 pub const no_payload_count = @enumToInt(last_no_payload_tag) + 1;
30 // After this, the tag requires a payload.
2031
21 array_sentinel_0_u8_type,32 ty,
22 single_const_ptr_type,
23
24 int_u64,33 int_u64,
25 int_i64,34 int_i64,
26 function,35 function,
...@@ -28,44 +37,76 @@ pub const Value = struct {...@@ -28,44 +37,76 @@ pub const Value = struct {
28 bytes,37 bytes,
29 };38 };
3039
31 pub const Int_u64 = struct {40 pub fn initTag(comptime tag: Tag) Value {
32 base: Value = Value{ .tag = .int_u64 },41 comptime assert(@enumToInt(tag) < Tag.no_payload_count);
33 int: u64,42 return .{ .tag_if_small_enough = @enumToInt(tag) };
34 };43 }
3544
36 pub const Int_i64 = struct {45 pub fn initPayload(payload: *Payload) Value {
37 base: Value = Value{ .tag = .int_i64 },46 assert(@enumToInt(payload.tag) >= Tag.no_payload_count);
38 int: i64,47 return .{ .ptr_otherwise = payload };
39 };48 }
4049
41 pub const Function = struct {50 pub fn tag(self: Value) Tag {
42 base: Value = Value{ .tag = .function },51 if (self.tag_if_small_enough < Tag.no_payload_count) {
43 };52 return @intToEnum(self.tag_if_small_enough);
53 } else {
54 return self.ptr_otherwise.tag;
55 }
56 }
4457
45 pub const ArraySentinel0_u8_Type = struct {58 /// This type is not copyable since it may contain pointers to its inner data.
46 base: Value = Value{ .tag = .array_sentinel_0_u8_type },59 pub const Payload = struct {
47 len: u64,60 tag: Tag,
48 };
4961
50 pub const SingleConstPtrType = struct {62 pub const Int_u64 = struct {
51 base: Value = Value{ .tag = .single_const_ptr_type },63 base: Payload = Payload{ .tag = .int_u64 },
52 elem_type: *Value,64 int: u64,
53 };65 };
5466
55 pub const Ref = struct {67 pub const Int_i64 = struct {
56 base: Value = Value{ .tag = .ref },68 base: Payload = Payload{ .tag = .int_i64 },
57 pointee: *MemoryCell,69 int: i64,
58 };70 };
71
72 pub const Function = struct {
73 base: Payload = Payload{ .tag = .function },
74 };
75
76 pub const ArraySentinel0_u8_Type = struct {
77 base: Payload = Payload{ .tag = .array_sentinel_0_u8_type },
78 len: u64,
79 };
80
81 pub const SingleConstPtrType = struct {
82 base: Payload = Payload{ .tag = .single_const_ptr_type },
83 elem_type: *Type,
84 };
85
86 pub const Ref = struct {
87 base: Payload = Payload{ .tag = .ref },
88 pointee: *MemoryCell,
89 };
90
91 pub const Bytes = struct {
92 base: Payload = Payload{ .tag = .bytes },
93 data: []u8,
94 };
5995
60 pub const Bytes = struct {96 pub const Ty = struct {
61 base: Value = Value{ .tag = .bytes },97 base: Payload = Payload{ .tag = .fully_qualified_type },
62 data: []u8,98 ptr: *Type,
99 };
63 };100 };
64};101};
65102
103/// This is the heart of resource management of the Zig compiler. The Zig compiler uses
104/// stop-the-world mark-and-sweep garbage collection during compilation to manage the resources
105/// associated with evaluating compile-time code and semantic analysis. Each `MemoryCell` represents
106/// a root.
66pub const MemoryCell = struct {107pub const MemoryCell = struct {
67 parent: Parent,108 parent: Parent,
68 contents: *Value,109 contents: Value,
69110
70 pub const Parent = union(enum) {111 pub const Parent = union(enum) {
71 none,112 none,