1
+ //! Memory mapping utility for large files.
2
+ //! Its intended use is to map input object files into memory using `mmap` on supported
3
+ //! hosts with a fallback to `malloc` in case the former fails or is unsupported (e.g.,
4
+ //! on Windows).
5
+
1
6
const MappedFile = @This ();
2
7
3
8
const std = @import ("std" );
4
9
const builtin = @import ("builtin" );
10
+ const assert = std .debug .assert ;
5
11
const log = std .log .scoped (.mapped_file );
6
12
const fs = std .fs ;
7
13
const math = std .math ;
@@ -13,13 +19,19 @@ const File = fs.File;
13
19
14
20
tag : Tag ,
15
21
raw : union {
22
+ /// Backing memory when mapped directly with `mmap`
16
23
mmap : []align (mem .page_size ) const u8 ,
24
+ /// Backing memory when allocated with `malloc`
17
25
malloc : []const u8 ,
18
26
},
19
- offset : u64 = 0 ,
27
+ /// Offset into `mmap`ed memory to account for the requirement for
28
+ /// the mapped memory to be page size aligned
29
+ offset : usize = 0 ,
20
30
21
31
const Tag = enum {
32
+ /// Uses `mmap`
22
33
mmap ,
34
+ /// Uses `malloc`
23
35
malloc ,
24
36
};
25
37
@@ -29,12 +41,17 @@ const Error = error{
29
41
OutOfMemory ,
30
42
} || os .MMapError || os .SeekError || os .ReadError ;
31
43
44
+ /// Maps the entire file using either `mmap` (preferred), or `malloc` (if the former
45
+ /// fails and/or is unavailable).
46
+ /// Needs to be free'd using `unmap`.
32
47
pub fn map (gpa : Allocator , file : File ) Error ! MappedFile {
33
48
const file_len = math .cast (usize , try file .getEndPos ()) orelse return error .Overflow ;
34
49
return mapWithOptions (gpa , file , file_len , 0 );
35
50
}
36
51
37
- pub fn mapWithOptions (gpa : Allocator , file : File , length : usize , offset : u64 ) Error ! MappedFile {
52
+ /// Same as `map` however allows to specify the requested mapped length as well as start offset.
53
+ /// Note that offset is will be backwards aligned to the first available page boundary.
54
+ pub fn mapWithOptions (gpa : Allocator , file : File , length : usize , offset : usize ) Error ! MappedFile {
38
55
if (length == 0 ) {
39
56
return error .InputOutput ;
40
57
}
@@ -48,7 +65,7 @@ pub fn mapWithOptions(gpa: Allocator, file: File, length: usize, offset: u64) Er
48
65
};
49
66
}
50
67
51
- fn malloc (gpa : Allocator , file : File , length : usize , offset : u64 ) Error ! MappedFile {
68
+ fn malloc (gpa : Allocator , file : File , length : usize , offset : usize ) Error ! MappedFile {
52
69
const reader = file .reader ();
53
70
if (offset > 0 ) {
54
71
try file .seekTo (offset );
@@ -65,8 +82,9 @@ fn malloc(gpa: Allocator, file: File, length: usize, offset: u64) Error!MappedFi
65
82
};
66
83
}
67
84
68
- fn mmap (file : File , length : usize , offset : u64 ) Error ! MappedFile {
69
- const aligned_offset = mem .alignBackwardGeneric (u64 , offset , mem .page_size );
85
+ fn mmap (file : File , length : usize , offset : usize ) Error ! MappedFile {
86
+ const aligned_offset = math .cast (usize , mem .alignBackwardGeneric (u64 , offset , mem .page_size )) orelse
87
+ return error .Overflow ;
70
88
const adjusted_length = length + (offset - aligned_offset );
71
89
// Mold is using os.PROT.READ | os.PROT.WRITE together with os.MAP.PRIVATE most likely
72
90
// because it is overwriting the mapped memory with some adjusted metadata when parsing
@@ -86,13 +104,20 @@ fn mmap(file: File, length: usize, offset: u64) Error!MappedFile {
86
104
};
87
105
}
88
106
107
+ /// Call to unmap/deallocate mapped memory.
89
108
pub fn unmap (mf : MappedFile , gpa : Allocator ) void {
90
- switch (mf .tag ) {
109
+ if (builtin .os .tag == .windows ) {
110
+ assert (mf .tag == .malloc );
111
+ gpa .free (mf .raw .malloc );
112
+ } else switch (mf .tag ) {
91
113
.mmap = > os .munmap (mf .raw .mmap ),
92
114
.malloc = > gpa .free (mf .raw .malloc ),
93
115
}
94
116
}
95
117
118
+ /// Returns the mapped memory.
119
+ /// In case of `mmap`, it takes into account backwards aligned `offset` and thus it is not required
120
+ /// to adjust the slice as it is done automatically for the caller.
96
121
pub fn slice (mf : MappedFile ) []const u8 {
97
122
return switch (mf .tag ) {
98
123
.mmap = > mf .raw .mmap [mf .offset .. ],
0 commit comments