@@ -170,20 +170,13 @@ struct AddressSpace::Impl {
170
170
}
171
171
172
172
void Unmap (VAddr virtual_addr, size_t size, bool has_backing) {
173
- bool ret;
174
- if (has_backing) {
175
- ret = UnmapViewOfFile2 (process, reinterpret_cast <PVOID>(virtual_addr),
176
- MEM_PRESERVE_PLACEHOLDER);
177
- } else {
178
- ret = VirtualFreeEx (process, reinterpret_cast <PVOID>(virtual_addr), size,
179
- MEM_RELEASE | MEM_PRESERVE_PLACEHOLDER);
173
+ // A requested unmap region might contain multiple distinct placeholder mappings
174
+ const VAddr virtual_end = virtual_addr + size;
175
+ VAddr base = virtual_addr;
176
+ while (base < virtual_end) {
177
+ base = UnmapOneRegion (base, size, has_backing);
180
178
}
181
- ASSERT_MSG (ret, " Unmap operation on virtual_addr={:#X} failed: {}" , virtual_addr,
182
- Common::GetLastErrorMsg ());
183
-
184
- // The unmap call will create a new placeholder region. We need to see if we can coalesce it
185
- // with neighbors.
186
- JoinRegionsAfterUnmap (virtual_addr, size);
179
+ ASSERT_MSG (base == virtual_end && size == 0 , " Invalid state after unmap" );
187
180
}
188
181
189
182
// The following code is inspired from Dolphin's MemArena
@@ -261,18 +254,32 @@ struct AddressSpace::Impl {
261
254
}
262
255
}
263
256
264
- void JoinRegionsAfterUnmap (VAddr address, size_t size) {
265
- // There should be a mapping that matches the request exactly , find it
257
+ VAddr UnmapOneRegion (VAddr address, size_t & size, bool has_backing ) {
258
+ // There should be a mapping that is contained by the request, find it
266
259
auto it = regions.find (address);
267
- ASSERT_MSG (it != regions.end () && it->second .size = = size,
260
+ ASSERT_MSG (it != regions.end () && it->second .size < = size,
268
261
" Invalid address/size given to unmap." );
269
262
auto & [base, region] = *it;
263
+
264
+ const VAddr region_end = region.base + region.size ;
270
265
region.is_mapped = false ;
266
+ size -= region.size ;
267
+
268
+ bool ret;
269
+ if (has_backing) {
270
+ ret = UnmapViewOfFile2 (process, reinterpret_cast <PVOID>(address),
271
+ MEM_PRESERVE_PLACEHOLDER);
272
+ } else {
273
+ ret = VirtualFreeEx (process, reinterpret_cast <PVOID>(address), region.size ,
274
+ MEM_RELEASE | MEM_PRESERVE_PLACEHOLDER);
275
+ }
276
+ ASSERT_MSG (ret, " Unmap operation on virtual_addr={:#X} failed: {}" , address,
277
+ Common::GetLastErrorMsg ());
271
278
272
279
// Check if a placeholder exists right before us.
273
280
auto it_prev = it != regions.begin () ? std::prev (it) : regions.end ();
274
281
if (it_prev != regions.end () && !it_prev->second .is_mapped ) {
275
- const size_t total_size = it_prev->second .size + size;
282
+ const size_t total_size = it_prev->second .size + region. size ;
276
283
if (!VirtualFreeEx (process, LPVOID (it_prev->first ), total_size,
277
284
MEM_RELEASE | MEM_COALESCE_PLACEHOLDERS)) {
278
285
UNREACHABLE_MSG (" Region coalescing failed: {}" , Common::GetLastErrorMsg ());
@@ -295,6 +302,8 @@ struct AddressSpace::Impl {
295
302
it->second .size = total_size;
296
303
regions.erase (it_next);
297
304
}
305
+
306
+ return region_end;
298
307
}
299
308
300
309
void Protect (VAddr virtual_addr, size_t size, bool read, bool write, bool execute) {
0 commit comments