master
   1/*
   2 * Copyright 2018 The Emscripten Authors.  All rights reserved.
   3 * Emscripten is available under two separate licenses, the MIT license and the
   4 * University of Illinois/NCSA Open Source License.  Both these licenses can be
   5 * found in the LICENSE file.
   6 *
   7 * Simple minimalistic but efficient sbrk()-based malloc/free that works in
   8 * singlethreaded and multithreaded builds.
   9 *
  10 * Assumptions:
  11 *
  12 *  - sbrk() is used to claim new memory (sbrk handles geometric/linear
  13 *  - overallocation growth)
  14 *  - sbrk() can be used by other code outside emmalloc.
  15 *  - sbrk() is very fast in most cases (internal wasm call).
  16 *  - sbrk() returns pointers with an alignment of alignof(max_align_t)
  17 *
  18 * Invariants:
  19 *
  20 *  - Per-allocation header overhead is 8 bytes, smallest allocated payload
  21 *    amount is 8 bytes, and a multiple of 4 bytes.
  22 *  - Acquired memory blocks are subdivided into disjoint regions that lie
  23 *    next to each other.
  24 *  - A region is either in used or free.
  25 *    Used regions may be adjacent, and a used and unused region
  26 *    may be adjacent, but not two unused ones - they would be
  27 *    merged.
  28 *  - Memory allocation takes constant time, unless the alloc needs to sbrk()
  29 *    or memory is very close to being exhausted.
  30 *
  31 * Debugging:
  32 *
  33 *  - If not NDEBUG, runtime assert()s are in use.
  34 *  - If EMMALLOC_MEMVALIDATE is defined, a large amount of extra checks are done.
  35 *  - If EMMALLOC_VERBOSE is defined, a lot of operations are logged
  36 *    out, in addition to EMMALLOC_MEMVALIDATE.
  37 *  - Debugging and logging directly uses console.log via uses EM_ASM, not
  38 *    printf etc., to minimize any risk of debugging or logging depending on
  39 *    malloc.
  40 */
  41
  42#include <stdalign.h>
  43#include <stdbool.h>
  44#include <stddef.h>
  45#include <stdint.h>
  46#include <unistd.h>
  47#include <memory.h>
  48#include <assert.h>
  49#include <malloc.h>
  50#include <limits.h>
  51#include <stdlib.h>
  52
  53#ifdef __EMSCRIPTEN_TRACING__
  54#include <emscripten/trace.h>
  55#endif
  56
  57// Defind by the linker to have the address of the start of the heap.
  58extern unsigned char __heap_base;
  59extern unsigned char __heap_end;
  60
  61// Behavior of right shifting a signed integer is compiler implementation defined.
  62static_assert((((int32_t)0x80000000U) >> 31) == -1, "This malloc implementation requires that right-shifting a signed integer produces a sign-extending (arithmetic) shift!");
  63
  64// Configuration: specifies the minimum alignment that malloc()ed memory outputs. Allocation requests with smaller alignment
  65// than this will yield an allocation with this much alignment.
  66#define MALLOC_ALIGNMENT alignof(max_align_t)
  67static_assert(alignof(max_align_t) == 16, "max_align_t must be correct");
  68
  69#define EMMALLOC_EXPORT __attribute__((weak))
  70
  71#define MIN(x, y) ((x) < (y) ? (x) : (y))
  72#define MAX(x, y) ((x) > (y) ? (x) : (y))
  73
  74#define NUM_FREE_BUCKETS 64
  75#define BUCKET_BITMASK_T uint64_t
  76
  77// Dynamic memory is subdivided into regions, in the format
  78
  79// <size:uint32_t> ..... <size:uint32_t> | <size:uint32_t> ..... <size:uint32_t> | <size:uint32_t> ..... <size:uint32_t> | .....
  80
  81// That is, at the bottom and top end of each memory region, the size of that region is stored. That allows traversing the
  82// memory regions backwards and forwards. Because each allocation must be at least a multiple of 4 bytes, the lowest two bits of
  83// each size field is unused. Free regions are distinguished by used regions by having the FREE_REGION_FLAG bit present
  84// in the size field. I.e. for free regions, the size field is odd, and for used regions, the size field reads even.
  85#define FREE_REGION_FLAG 0x1u
  86
  87// Attempts to malloc() more than this many bytes would cause an overflow when calculating the size of a region,
  88// therefore allocations larger than this are short-circuited immediately on entry.
  89#define MAX_ALLOC_SIZE 0xFFFFFFC7u
  90
  91// A free region has the following structure:
  92// <size:size_t> <prevptr> <nextptr> ... <size:size_t>
  93
  94typedef struct Region
  95{
  96  size_t size;
  97  // Use a circular doubly linked list to represent free region data.
  98  struct Region *prev, *next;
  99  // ... N bytes of free data
 100  size_t _at_the_end_of_this_struct_size; // do not dereference, this is present for convenient struct sizeof() computation only
 101} Region;
 102
 103// Each memory block starts with a RootRegion at the beginning.
 104// The RootRegion specifies the size of the region block, and forms a linked
 105// list of all RootRegions in the program, starting with `listOfAllRegions`
 106// below.
 107typedef struct RootRegion
 108{
 109  uint32_t size;
 110  struct RootRegion *next;
 111  uint8_t* endPtr;
 112} RootRegion;
 113
 114#if defined(__EMSCRIPTEN_PTHREADS__)
 115// In multithreaded builds, use a simple global spinlock strategy to acquire/release access to the memory allocator.
 116static volatile uint8_t multithreadingLock = 0;
 117#define MALLOC_ACQUIRE() while(__sync_lock_test_and_set(&multithreadingLock, 1)) { while(multithreadingLock) { /*nop*/ } }
 118#define MALLOC_RELEASE() __sync_lock_release(&multithreadingLock)
 119// Test code to ensure we have tight malloc acquire/release guards in place.
 120#define ASSERT_MALLOC_IS_ACQUIRED() assert(multithreadingLock == 1)
 121#else
 122// In singlethreaded builds, no need for locking.
 123#define MALLOC_ACQUIRE() ((void)0)
 124#define MALLOC_RELEASE() ((void)0)
 125#define ASSERT_MALLOC_IS_ACQUIRED() ((void)0)
 126#endif
 127
 128#define IS_POWER_OF_2(val) (((val) & ((val)-1)) == 0)
 129#define ALIGN_UP(ptr, alignment) ((uint8_t*)((((uintptr_t)(ptr)) + ((alignment)-1)) & ~((alignment)-1)))
 130#define HAS_ALIGNMENT(ptr, alignment) ((((uintptr_t)(ptr)) & ((alignment)-1)) == 0)
 131
 132static_assert(IS_POWER_OF_2(MALLOC_ALIGNMENT), "MALLOC_ALIGNMENT must be a power of two value!");
 133static_assert(MALLOC_ALIGNMENT >= 4, "Smallest possible MALLOC_ALIGNMENT if 4!");
 134
 135// A region that contains as payload a single forward linked list of pointers to
 136// root regions of each disjoint region blocks.
 137static RootRegion *listOfAllRegions = NULL;
 138
 139// For each of the buckets, maintain a linked list head node. The head node for each
 140// free region is a sentinel node that does not actually represent any free space, but
 141// the sentinel is used to avoid awkward testing against (if node == freeRegionHeadNode)
 142// when adding and removing elements from the linked list, i.e. we are guaranteed that
 143// the sentinel node is always fixed and there, and the actual free region list elements
 144// start at freeRegionBuckets[i].next each.
 145static Region freeRegionBuckets[NUM_FREE_BUCKETS] = {
 146	{ .prev = &freeRegionBuckets[0], .next = &freeRegionBuckets[0] },
 147	{ .prev = &freeRegionBuckets[1], .next = &freeRegionBuckets[1] },
 148	{ .prev = &freeRegionBuckets[2], .next = &freeRegionBuckets[2] },
 149	{ .prev = &freeRegionBuckets[3], .next = &freeRegionBuckets[3] },
 150	{ .prev = &freeRegionBuckets[4], .next = &freeRegionBuckets[4] },
 151	{ .prev = &freeRegionBuckets[5], .next = &freeRegionBuckets[5] },
 152	{ .prev = &freeRegionBuckets[6], .next = &freeRegionBuckets[6] },
 153	{ .prev = &freeRegionBuckets[7], .next = &freeRegionBuckets[7] },
 154	{ .prev = &freeRegionBuckets[8], .next = &freeRegionBuckets[8] },
 155	{ .prev = &freeRegionBuckets[9], .next = &freeRegionBuckets[9] },
 156	{ .prev = &freeRegionBuckets[10], .next = &freeRegionBuckets[10] },
 157	{ .prev = &freeRegionBuckets[11], .next = &freeRegionBuckets[11] },
 158	{ .prev = &freeRegionBuckets[12], .next = &freeRegionBuckets[12] },
 159	{ .prev = &freeRegionBuckets[13], .next = &freeRegionBuckets[13] },
 160	{ .prev = &freeRegionBuckets[14], .next = &freeRegionBuckets[14] },
 161	{ .prev = &freeRegionBuckets[15], .next = &freeRegionBuckets[15] },
 162	{ .prev = &freeRegionBuckets[16], .next = &freeRegionBuckets[16] },
 163	{ .prev = &freeRegionBuckets[17], .next = &freeRegionBuckets[17] },
 164	{ .prev = &freeRegionBuckets[18], .next = &freeRegionBuckets[18] },
 165	{ .prev = &freeRegionBuckets[19], .next = &freeRegionBuckets[19] },
 166	{ .prev = &freeRegionBuckets[20], .next = &freeRegionBuckets[20] },
 167	{ .prev = &freeRegionBuckets[21], .next = &freeRegionBuckets[21] },
 168	{ .prev = &freeRegionBuckets[22], .next = &freeRegionBuckets[22] },
 169	{ .prev = &freeRegionBuckets[23], .next = &freeRegionBuckets[23] },
 170	{ .prev = &freeRegionBuckets[24], .next = &freeRegionBuckets[24] },
 171	{ .prev = &freeRegionBuckets[25], .next = &freeRegionBuckets[25] },
 172	{ .prev = &freeRegionBuckets[26], .next = &freeRegionBuckets[26] },
 173	{ .prev = &freeRegionBuckets[27], .next = &freeRegionBuckets[27] },
 174	{ .prev = &freeRegionBuckets[28], .next = &freeRegionBuckets[28] },
 175	{ .prev = &freeRegionBuckets[29], .next = &freeRegionBuckets[29] },
 176	{ .prev = &freeRegionBuckets[30], .next = &freeRegionBuckets[30] },
 177	{ .prev = &freeRegionBuckets[31], .next = &freeRegionBuckets[31] },
 178	{ .prev = &freeRegionBuckets[32], .next = &freeRegionBuckets[32] },
 179	{ .prev = &freeRegionBuckets[33], .next = &freeRegionBuckets[33] },
 180	{ .prev = &freeRegionBuckets[34], .next = &freeRegionBuckets[34] },
 181	{ .prev = &freeRegionBuckets[35], .next = &freeRegionBuckets[35] },
 182	{ .prev = &freeRegionBuckets[36], .next = &freeRegionBuckets[36] },
 183	{ .prev = &freeRegionBuckets[37], .next = &freeRegionBuckets[37] },
 184	{ .prev = &freeRegionBuckets[38], .next = &freeRegionBuckets[38] },
 185	{ .prev = &freeRegionBuckets[39], .next = &freeRegionBuckets[39] },
 186	{ .prev = &freeRegionBuckets[40], .next = &freeRegionBuckets[40] },
 187	{ .prev = &freeRegionBuckets[41], .next = &freeRegionBuckets[41] },
 188	{ .prev = &freeRegionBuckets[42], .next = &freeRegionBuckets[42] },
 189	{ .prev = &freeRegionBuckets[43], .next = &freeRegionBuckets[43] },
 190	{ .prev = &freeRegionBuckets[44], .next = &freeRegionBuckets[44] },
 191	{ .prev = &freeRegionBuckets[45], .next = &freeRegionBuckets[45] },
 192	{ .prev = &freeRegionBuckets[46], .next = &freeRegionBuckets[46] },
 193	{ .prev = &freeRegionBuckets[47], .next = &freeRegionBuckets[47] },
 194	{ .prev = &freeRegionBuckets[48], .next = &freeRegionBuckets[48] },
 195	{ .prev = &freeRegionBuckets[49], .next = &freeRegionBuckets[49] },
 196	{ .prev = &freeRegionBuckets[50], .next = &freeRegionBuckets[50] },
 197	{ .prev = &freeRegionBuckets[51], .next = &freeRegionBuckets[51] },
 198	{ .prev = &freeRegionBuckets[52], .next = &freeRegionBuckets[52] },
 199	{ .prev = &freeRegionBuckets[53], .next = &freeRegionBuckets[53] },
 200	{ .prev = &freeRegionBuckets[54], .next = &freeRegionBuckets[54] },
 201	{ .prev = &freeRegionBuckets[55], .next = &freeRegionBuckets[55] },
 202	{ .prev = &freeRegionBuckets[56], .next = &freeRegionBuckets[56] },
 203	{ .prev = &freeRegionBuckets[57], .next = &freeRegionBuckets[57] },
 204	{ .prev = &freeRegionBuckets[58], .next = &freeRegionBuckets[58] },
 205	{ .prev = &freeRegionBuckets[59], .next = &freeRegionBuckets[59] },
 206	{ .prev = &freeRegionBuckets[60], .next = &freeRegionBuckets[60] },
 207	{ .prev = &freeRegionBuckets[61], .next = &freeRegionBuckets[61] },
 208	{ .prev = &freeRegionBuckets[62], .next = &freeRegionBuckets[62] },
 209	{ .prev = &freeRegionBuckets[63], .next = &freeRegionBuckets[63] },
 210};
 211
 212// A bitmask that tracks the population status for each of the 64 distinct memory regions:
 213// a zero at bit position i means that the free list bucket i is empty. This bitmask is
 214// used to avoid redundant scanning of the 64 different free region buckets: instead by
 215// looking at the bitmask we can find in constant time an index to a free region bucket
 216// that contains free memory of desired size.
 217static BUCKET_BITMASK_T freeRegionBucketsUsed = 0;
 218
 219// Amount of bytes taken up by allocation header data
 220#define REGION_HEADER_SIZE (2*sizeof(size_t))
 221
 222// Smallest allocation size that is possible is 2*pointer size, since payload of each region must at least contain space
 223// to store the free region linked list prev and next pointers. An allocation size smaller than this will be rounded up
 224// to this size.
 225#define SMALLEST_ALLOCATION_SIZE (2*sizeof(void*))
 226
 227/* Subdivide regions of free space into distinct circular doubly linked lists, where each linked list
 228represents a range of free space blocks. The following function compute_free_list_bucket() converts
 229an allocation size to the bucket index that should be looked at. The buckets are grouped as follows:
 230
 231  Bucket 0: [8, 15], range size=8
 232  Bucket 1: [16, 23], range size=8
 233  Bucket 2: [24, 31], range size=8
 234  Bucket 3: [32, 39], range size=8
 235  Bucket 4: [40, 47], range size=8
 236  Bucket 5: [48, 55], range size=8
 237  Bucket 6: [56, 63], range size=8
 238  Bucket 7: [64, 71], range size=8
 239  Bucket 8: [72, 79], range size=8
 240  Bucket 9: [80, 87], range size=8
 241  Bucket 10: [88, 95], range size=8
 242  Bucket 11: [96, 103], range size=8
 243  Bucket 12: [104, 111], range size=8
 244  Bucket 13: [112, 119], range size=8
 245  Bucket 14: [120, 159], range size=40
 246  Bucket 15: [160, 191], range size=32
 247  Bucket 16: [192, 223], range size=32
 248  Bucket 17: [224, 255], range size=32
 249  Bucket 18: [256, 319], range size=64
 250  Bucket 19: [320, 383], range size=64
 251  Bucket 20: [384, 447], range size=64
 252  Bucket 21: [448, 511], range size=64
 253  Bucket 22: [512, 639], range size=128
 254  Bucket 23: [640, 767], range size=128
 255  Bucket 24: [768, 895], range size=128
 256  Bucket 25: [896, 1023], range size=128
 257  Bucket 26: [1024, 1279], range size=256
 258  Bucket 27: [1280, 1535], range size=256
 259  Bucket 28: [1536, 1791], range size=256
 260  Bucket 29: [1792, 2047], range size=256
 261  Bucket 30: [2048, 2559], range size=512
 262  Bucket 31: [2560, 3071], range size=512
 263  Bucket 32: [3072, 3583], range size=512
 264  Bucket 33: [3584, 6143], range size=2560
 265  Bucket 34: [6144, 8191], range size=2048
 266  Bucket 35: [8192, 12287], range size=4096
 267  Bucket 36: [12288, 16383], range size=4096
 268  Bucket 37: [16384, 24575], range size=8192
 269  Bucket 38: [24576, 32767], range size=8192
 270  Bucket 39: [32768, 49151], range size=16384
 271  Bucket 40: [49152, 65535], range size=16384
 272  Bucket 41: [65536, 98303], range size=32768
 273  Bucket 42: [98304, 131071], range size=32768
 274  Bucket 43: [131072, 196607], range size=65536
 275  Bucket 44: [196608, 262143], range size=65536
 276  Bucket 45: [262144, 393215], range size=131072
 277  Bucket 46: [393216, 524287], range size=131072
 278  Bucket 47: [524288, 786431], range size=262144
 279  Bucket 48: [786432, 1048575], range size=262144
 280  Bucket 49: [1048576, 1572863], range size=524288
 281  Bucket 50: [1572864, 2097151], range size=524288
 282  Bucket 51: [2097152, 3145727], range size=1048576
 283  Bucket 52: [3145728, 4194303], range size=1048576
 284  Bucket 53: [4194304, 6291455], range size=2097152
 285  Bucket 54: [6291456, 8388607], range size=2097152
 286  Bucket 55: [8388608, 12582911], range size=4194304
 287  Bucket 56: [12582912, 16777215], range size=4194304
 288  Bucket 57: [16777216, 25165823], range size=8388608
 289  Bucket 58: [25165824, 33554431], range size=8388608
 290  Bucket 59: [33554432, 50331647], range size=16777216
 291  Bucket 60: [50331648, 67108863], range size=16777216
 292  Bucket 61: [67108864, 100663295], range size=33554432
 293  Bucket 62: [100663296, 134217727], range size=33554432
 294  Bucket 63: 134217728 bytes and larger. */
 295static_assert(NUM_FREE_BUCKETS == 64, "Following function is tailored specifically for NUM_FREE_BUCKETS == 64 case");
 296static int compute_free_list_bucket(size_t allocSize)
 297{
 298  if (allocSize < 128) return (allocSize >> 3) - 1;
 299  int clz = __builtin_clz(allocSize);
 300  int bucketIndex = (clz > 19) ? 110 - (clz<<2) + ((allocSize >> (29-clz)) ^ 4) : MIN(71 - (clz<<1) + ((allocSize >> (30-clz)) ^ 2), NUM_FREE_BUCKETS-1);
 301  assert(bucketIndex >= 0);
 302  assert(bucketIndex < NUM_FREE_BUCKETS);
 303  return bucketIndex;
 304}
 305
 306#define DECODE_CEILING_SIZE(size) ((size_t)((size) & ~FREE_REGION_FLAG))
 307
 308static Region *prev_region(Region *region)
 309{
 310  size_t prevRegionSize = ((size_t*)region)[-1];
 311  prevRegionSize = DECODE_CEILING_SIZE(prevRegionSize);
 312  return (Region*)((uint8_t*)region - prevRegionSize);
 313}
 314
 315static Region *next_region(Region *region)
 316{
 317  return (Region*)((uint8_t*)region + region->size);
 318}
 319
 320static size_t region_ceiling_size(Region *region)
 321{
 322  return ((size_t*)((uint8_t*)region + region->size))[-1];
 323}
 324
 325static bool region_is_free(Region *r)
 326{
 327  return region_ceiling_size(r) & FREE_REGION_FLAG;
 328}
 329
 330static bool region_is_in_use(Region *r)
 331{
 332  return r->size == region_ceiling_size(r);
 333}
 334
 335static size_t size_of_region_from_ceiling(Region *r)
 336{
 337  size_t size = region_ceiling_size(r);
 338  return DECODE_CEILING_SIZE(size);
 339}
 340
 341static bool debug_region_is_consistent(Region *r)
 342{
 343  assert(r);
 344  size_t sizeAtBottom = r->size;
 345  size_t sizeAtCeiling = size_of_region_from_ceiling(r);
 346  return sizeAtBottom == sizeAtCeiling;
 347}
 348
 349static uint8_t *region_payload_start_ptr(Region *region)
 350{
 351  return (uint8_t*)region + sizeof(size_t);
 352}
 353
 354static uint8_t *region_payload_end_ptr(Region *region)
 355{
 356  return (uint8_t*)region + region->size - sizeof(size_t);
 357}
 358
 359static void create_used_region(void *ptr, size_t size)
 360{
 361  assert(ptr);
 362  assert(HAS_ALIGNMENT(ptr, sizeof(size_t)));
 363  assert(HAS_ALIGNMENT(size, sizeof(size_t)));
 364  assert(size >= sizeof(Region));
 365  *(size_t*)ptr = size;
 366  ((size_t*)ptr)[(size/sizeof(size_t))-1] = size;
 367}
 368
 369static void create_free_region(void *ptr, size_t size)
 370{
 371  assert(ptr);
 372  assert(HAS_ALIGNMENT(ptr, sizeof(size_t)));
 373  assert(HAS_ALIGNMENT(size, sizeof(size_t)));
 374  assert(size >= sizeof(Region));
 375  Region *freeRegion = (Region*)ptr;
 376  freeRegion->size = size;
 377  ((size_t*)ptr)[(size/sizeof(size_t))-1] = size | FREE_REGION_FLAG;
 378}
 379
 380static void prepend_to_free_list(Region *region, Region *prependTo)
 381{
 382  assert(region);
 383  assert(prependTo);
 384  // N.b. the region we are prepending to is always the sentinel node,
 385  // which represents a dummy node that is technically not a free node, so
 386  // region_is_free(prependTo) does not hold.
 387  assert(region_is_free((Region*)region));
 388  region->next = prependTo;
 389  region->prev = prependTo->prev;
 390  assert(region->prev);
 391  prependTo->prev = region;
 392  region->prev->next = region;
 393}
 394
 395static void unlink_from_free_list(Region *region)
 396{
 397  assert(region);
 398  assert(region_is_free((Region*)region));
 399  assert(region->prev);
 400  assert(region->next);
 401  region->prev->next = region->next;
 402  region->next->prev = region->prev;
 403}
 404
 405static void link_to_free_list(Region *freeRegion)
 406{
 407  assert(freeRegion);
 408  assert(freeRegion->size >= sizeof(Region));
 409  int bucketIndex = compute_free_list_bucket(freeRegion->size-REGION_HEADER_SIZE);
 410  Region *freeListHead = freeRegionBuckets + bucketIndex;
 411  freeRegion->prev = freeListHead;
 412  freeRegion->next = freeListHead->next;
 413  assert(freeRegion->next);
 414  freeListHead->next = freeRegion;
 415  freeRegion->next->prev = freeRegion;
 416  freeRegionBucketsUsed |= ((BUCKET_BITMASK_T)1) << bucketIndex;
 417}
 418
 419#if 0
 420static void dump_memory_regions()
 421{
 422  ASSERT_MALLOC_IS_ACQUIRED();
 423  RootRegion *root = listOfAllRegions;
 424  MAIN_THREAD_ASYNC_EM_ASM(console.log('All memory regions:'));
 425  while(root)
 426  {
 427    Region *r = (Region*)root;
 428    assert(debug_region_is_consistent(r));
 429    uint8_t *lastRegionEnd = root->endPtr;
 430    MAIN_THREAD_ASYNC_EM_ASM(console.log('Region block 0x'+($0>>>0).toString(16)+' - 0x'+($1>>>0).toString(16)+ ' ('+($2>>>0)+' bytes):'),
 431      r, lastRegionEnd, lastRegionEnd-(uint8_t*)r);
 432    while((uint8_t*)r < lastRegionEnd)
 433    {
 434      MAIN_THREAD_ASYNC_EM_ASM(console.log('Region 0x'+($0>>>0).toString(16)+', size: '+($1>>>0)+' ('+($2?"used":"--FREE--")+')'),
 435        r, r->size, region_ceiling_size(r) == r->size);
 436
 437      assert(debug_region_is_consistent(r));
 438      size_t sizeFromCeiling = size_of_region_from_ceiling(r);
 439      if (sizeFromCeiling != r->size)
 440        MAIN_THREAD_ASYNC_EM_ASM(console.log('Corrupt region! Size marker at the end of the region does not match: '+($0>>>0)), sizeFromCeiling);
 441      if (r->size == 0)
 442        break;
 443      r = next_region(r);
 444    }
 445    root = root->next;
 446    MAIN_THREAD_ASYNC_EM_ASM(console.log(""));
 447  }
 448  MAIN_THREAD_ASYNC_EM_ASM(console.log('Free regions:'));
 449  for(int i = 0; i < NUM_FREE_BUCKETS; ++i)
 450  {
 451    Region *prev = &freeRegionBuckets[i];
 452    Region *fr = freeRegionBuckets[i].next;
 453    while(fr != &freeRegionBuckets[i])
 454    {
 455      MAIN_THREAD_ASYNC_EM_ASM(console.log('In bucket '+$0+', free region 0x'+($1>>>0).toString(16)+', size: ' + ($2>>>0) + ' (size at ceiling: '+($3>>>0)+'), prev: 0x' + ($4>>>0).toString(16) + ', next: 0x' + ($5>>>0).toString(16)),
 456        i, fr, fr->size, size_of_region_from_ceiling(fr), fr->prev, fr->next);
 457      assert(debug_region_is_consistent(fr));
 458      assert(region_is_free(fr));
 459      assert(fr->prev == prev);
 460      prev = fr;
 461      assert(fr->next != fr);
 462      assert(fr->prev != fr);
 463      fr = fr->next;
 464    }
 465  }
 466  MAIN_THREAD_ASYNC_EM_ASM(console.log('Free bucket index map: ' + ($0>>>0).toString(2) + ' ' + ($1>>>0).toString(2)), (uint32_t)(freeRegionBucketsUsed >> 32), (uint32_t)freeRegionBucketsUsed);
 467  MAIN_THREAD_ASYNC_EM_ASM(console.log(""));
 468}
 469
 470void emmalloc_dump_memory_regions()
 471{
 472  MALLOC_ACQUIRE();
 473  dump_memory_regions();
 474  MALLOC_RELEASE();
 475}
 476
 477static int validate_memory_regions()
 478{
 479  ASSERT_MALLOC_IS_ACQUIRED();
 480  RootRegion *root = listOfAllRegions;
 481  while(root)
 482  {
 483    Region *r = (Region*)root;
 484    if (!debug_region_is_consistent(r))
 485    {
 486      MAIN_THREAD_ASYNC_EM_ASM(console.error('Used region 0x'+($0>>>0).toString(16)+', size: '+($1>>>0)+' ('+($2?"used":"--FREE--")+') is corrupt (size markers in the beginning and at the end of the region do not match!)'),
 487        r, r->size, region_ceiling_size(r) == r->size);
 488      return 1;
 489    }
 490    uint8_t *lastRegionEnd = root->endPtr;
 491    while((uint8_t*)r < lastRegionEnd)
 492    {
 493      if (!debug_region_is_consistent(r))
 494      {
 495        MAIN_THREAD_ASYNC_EM_ASM(console.error('Used region 0x'+($0>>>0).toString(16)+', size: '+($1>>>0)+' ('+($2?"used":"--FREE--")+') is corrupt (size markers in the beginning and at the end of the region do not match!)'),
 496          r, r->size, region_ceiling_size(r) == r->size);
 497        return 1;
 498      }
 499      if (r->size == 0)
 500        break;
 501      r = next_region(r);
 502    }
 503    root = root->next;
 504  }
 505  for(int i = 0; i < NUM_FREE_BUCKETS; ++i)
 506  {
 507    Region *prev = &freeRegionBuckets[i];
 508    Region *fr = freeRegionBuckets[i].next;
 509    while(fr != &freeRegionBuckets[i])
 510    {
 511      if (!debug_region_is_consistent(fr) || !region_is_free(fr) || fr->prev != prev || fr->next == fr || fr->prev == fr)
 512      {
 513        MAIN_THREAD_ASYNC_EM_ASM(console.log('In bucket '+$0+', free region 0x'+($1>>>0).toString(16)+', size: ' + ($2>>>0) + ' (size at ceiling: '+($3>>>0)+'), prev: 0x' + ($4>>>0).toString(16) + ', next: 0x' + ($5>>>0).toString(16) + ' is corrupt!'),
 514          i, fr, fr->size, size_of_region_from_ceiling(fr), fr->prev, fr->next);
 515        return 1;
 516      }
 517      prev = fr;
 518      fr = fr->next;
 519    }
 520  }
 521  return 0;
 522}
 523
 524int emmalloc_validate_memory_regions()
 525{
 526  MALLOC_ACQUIRE();
 527  int memoryError = validate_memory_regions();
 528  MALLOC_RELEASE();
 529  return memoryError;
 530}
 531#endif
 532
 533static bool claim_more_memory(size_t numBytes)
 534{
 535#ifdef EMMALLOC_VERBOSE
 536  MAIN_THREAD_ASYNC_EM_ASM(console.log('claim_more_memory(numBytes='+($0>>>0)+ ')'), numBytes);
 537#endif
 538
 539#ifdef EMMALLOC_MEMVALIDATE
 540  validate_memory_regions();
 541#endif
 542
 543  uint8_t *startPtr;
 544  uint8_t *endPtr;
 545  do {
 546    // If this is the first time we're called, see if we can use
 547    // the initial heap memory set up by wasm-ld.
 548    if (!listOfAllRegions) {
 549      unsigned char *heap_base = &__heap_base;
 550      unsigned char *heap_end = &__heap_end;
 551      if (heap_end < heap_base) {
 552	__builtin_trap();
 553      }
 554      if (numBytes <= (size_t)(heap_end - heap_base)) {
 555        startPtr = heap_base;
 556        endPtr = heap_end;
 557	break;
 558      }
 559    }
 560
 561    // Round numBytes up to the nearest page size.
 562    numBytes = (numBytes + (PAGE_SIZE-1)) & -PAGE_SIZE;
 563
 564    // Claim memory via sbrk
 565    startPtr = (uint8_t*)sbrk(numBytes);
 566    if ((intptr_t)startPtr == -1)
 567    {
 568#ifdef EMMALLOC_VERBOSE
 569      MAIN_THREAD_ASYNC_EM_ASM(console.error('claim_more_memory: sbrk failed!'));
 570#endif
 571      return false;
 572    }
 573#ifdef EMMALLOC_VERBOSE
 574    MAIN_THREAD_ASYNC_EM_ASM(console.log('claim_more_memory: claimed 0x' + ($0>>>0).toString(16) + ' - 0x' + ($1>>>0).toString(16) + ' (' + ($2>>>0) + ' bytes) via sbrk()'), startPtr, startPtr + numBytes, numBytes);
 575#endif
 576    assert(HAS_ALIGNMENT(startPtr, alignof(size_t)));
 577    endPtr = startPtr + numBytes;
 578  } while (0);
 579
 580  // Create a sentinel region at the end of the new heap block
 581  Region *endSentinelRegion = (Region*)(endPtr - sizeof(Region));
 582  create_used_region(endSentinelRegion, sizeof(Region));
 583
 584  // If we are the sole user of sbrk(), it will feed us continuous/consecutive memory addresses - take advantage
 585  // of that if so: instead of creating two disjoint memory regions blocks, expand the previous one to a larger size.
 586  uint8_t *previousSbrkEndAddress = listOfAllRegions ? listOfAllRegions->endPtr : 0;
 587  if (startPtr == previousSbrkEndAddress)
 588  {
 589    Region *prevEndSentinel = prev_region((Region*)startPtr);
 590    assert(debug_region_is_consistent(prevEndSentinel));
 591    assert(region_is_in_use(prevEndSentinel));
 592    Region *prevRegion = prev_region(prevEndSentinel);
 593    assert(debug_region_is_consistent(prevRegion));
 594
 595    listOfAllRegions->endPtr = endPtr;
 596
 597    // Two scenarios, either the last region of the previous block was in use, in which case we need to create
 598    // a new free region in the newly allocated space; or it was free, in which case we can extend that region
 599    // to cover a larger size.
 600    if (region_is_free(prevRegion))
 601    {
 602      size_t newFreeRegionSize = (uint8_t*)endSentinelRegion - (uint8_t*)prevRegion;
 603      unlink_from_free_list(prevRegion);
 604      create_free_region(prevRegion, newFreeRegionSize);
 605      link_to_free_list(prevRegion);
 606      return true;
 607    }
 608    // else: last region of the previous block was in use. Since we are joining two consecutive sbrk() blocks,
 609    // we can swallow the end sentinel of the previous block away.
 610    startPtr -= sizeof(Region);
 611  }
 612  else
 613  {
 614    // Create a root region at the start of the heap block
 615    create_used_region(startPtr, sizeof(Region));
 616
 617    // Dynamic heap start region:
 618    RootRegion *newRegionBlock = (RootRegion*)startPtr;
 619    newRegionBlock->next = listOfAllRegions; // Pointer to next region block head
 620    newRegionBlock->endPtr = endPtr; // Pointer to the end address of this region block
 621    listOfAllRegions = newRegionBlock;
 622    startPtr += sizeof(Region);
 623  }
 624
 625  // Create a new memory region for the new claimed free space.
 626  create_free_region(startPtr, (uint8_t*)endSentinelRegion - startPtr);
 627  link_to_free_list((Region*)startPtr);
 628  return true;
 629}
 630
 631#if 0
 632// Initialize emmalloc during static initialization.
 633// See system/lib/README.md for static constructor ordering.
 634__attribute__((constructor(47)))
 635static void initialize_emmalloc_heap()
 636{
 637  // Initialize circular doubly linked lists representing free space
 638  // Never useful to unroll this for loop, just takes up code size.
 639#pragma clang loop unroll(disable)
 640  for(int i = 0; i < NUM_FREE_BUCKETS; ++i)
 641    freeRegionBuckets[i].prev = freeRegionBuckets[i].next = &freeRegionBuckets[i];
 642
 643#ifdef EMMALLOC_VERBOSE
 644  MAIN_THREAD_ASYNC_EM_ASM(console.log('initialize_emmalloc_heap()'));
 645#endif
 646
 647  // Start with a tiny dynamic region.
 648  claim_more_memory(3*sizeof(Region));
 649}
 650
 651void emmalloc_blank_slate_from_orbit()
 652{
 653  MALLOC_ACQUIRE();
 654  listOfAllRegions = NULL;
 655  freeRegionBucketsUsed = 0;
 656  initialize_emmalloc_heap();
 657  MALLOC_RELEASE();
 658}
 659#endif
 660
 661static void *attempt_allocate(Region *freeRegion, size_t alignment, size_t size)
 662{
 663  ASSERT_MALLOC_IS_ACQUIRED();
 664  assert(freeRegion);
 665  // Look at the next potential free region to allocate into.
 666  // First, we should check if the free region has enough of payload bytes contained
 667  // in it to accommodate the new allocation. This check needs to take account the
 668  // requested allocation alignment, so the payload memory area needs to be rounded
 669  // upwards to the desired alignment.
 670  uint8_t *payloadStartPtr = region_payload_start_ptr(freeRegion);
 671  uint8_t *payloadStartPtrAligned = ALIGN_UP(payloadStartPtr, alignment);
 672  uint8_t *payloadEndPtr = region_payload_end_ptr(freeRegion);
 673
 674  // Do we have enough free space, taking into account alignment?
 675  if (payloadStartPtrAligned + size > payloadEndPtr)
 676    return NULL;
 677
 678  // We have enough free space, so the memory allocation will be made into this region. Remove this free region
 679  // from the list of free regions: whatever slop remains will be later added back to the free region pool.
 680  unlink_from_free_list(freeRegion);
 681
 682  // Before we proceed further, fix up the boundary of this region and the region that precedes this one,
 683  // so that the boundary between the two regions happens at a right spot for the payload to be aligned.
 684  if (payloadStartPtr != payloadStartPtrAligned)
 685  {
 686    Region *prevRegion = prev_region((Region*)freeRegion);
 687    // We never have two free regions adjacent to each other, so the region before this free
 688    // region should be in use.
 689    assert(region_is_in_use(prevRegion));
 690    size_t regionBoundaryBumpAmount = payloadStartPtrAligned - payloadStartPtr;
 691    size_t newThisRegionSize = freeRegion->size - regionBoundaryBumpAmount;
 692    create_used_region(prevRegion, prevRegion->size + regionBoundaryBumpAmount);
 693    freeRegion = (Region *)((uint8_t*)freeRegion + regionBoundaryBumpAmount);
 694    freeRegion->size = newThisRegionSize;
 695  }
 696  // Next, we need to decide whether this region is so large that it should be split into two regions,
 697  // one representing the newly used memory area, and at the high end a remaining leftover free area.
 698  // This splitting to two is done always if there is enough space for the high end to fit a region.
 699  // Carve 'size' bytes of payload off this region. So,
 700  // [sz prev next sz]
 701  // becomes
 702  // [sz payload sz] [sz prev next sz]
 703  if (sizeof(Region) + REGION_HEADER_SIZE + size <= freeRegion->size)
 704  {
 705    // There is enough space to keep a free region at the end of the carved out block
 706    // -> construct the new block
 707    Region *newFreeRegion = (Region *)((uint8_t*)freeRegion + REGION_HEADER_SIZE + size);
 708    create_free_region(newFreeRegion, freeRegion->size - size - REGION_HEADER_SIZE);
 709    link_to_free_list(newFreeRegion);
 710
 711    // Recreate the resized Region under its new size.
 712    create_used_region(freeRegion, size + REGION_HEADER_SIZE);
 713  }
 714  else
 715  {
 716    // There is not enough space to split the free memory region into used+free parts, so consume the whole
 717    // region as used memory, not leaving a free memory region behind.
 718    // Initialize the free region as used by resetting the ceiling size to the same value as the size at bottom.
 719    ((size_t*)((uint8_t*)freeRegion + freeRegion->size))[-1] = freeRegion->size;
 720  }
 721
 722#ifdef __EMSCRIPTEN_TRACING__
 723  emscripten_trace_record_allocation(freeRegion, freeRegion->size);
 724#endif
 725
 726#ifdef EMMALLOC_VERBOSE
 727  MAIN_THREAD_ASYNC_EM_ASM(console.log('attempt_allocate - succeeded allocating memory, region ptr=0x' + ($0>>>0).toString(16) + ', align=' + $1 + ', payload size=' + ($2>>>0) + ' bytes)'), freeRegion, alignment, size);
 728#endif
 729
 730  return (uint8_t*)freeRegion + sizeof(size_t);
 731}
 732
 733static size_t validate_alloc_alignment(size_t alignment)
 734{
 735  // Cannot perform allocations that are less than 4 byte aligned, because the Region
 736  // control structures need to be aligned. Also round up to minimum outputted alignment.
 737  alignment = MAX(alignment, MALLOC_ALIGNMENT);
 738  // Arbitrary upper limit on alignment - very likely a programming bug if alignment is higher than this.
 739  assert(alignment <= 1024*1024);
 740  return alignment;
 741}
 742
 743static size_t validate_alloc_size(size_t size)
 744{
 745  assert(size + REGION_HEADER_SIZE > size);
 746
 747  // Allocation sizes must be a multiple of pointer sizes, and at least 2*sizeof(pointer).
 748  size_t validatedSize = size > SMALLEST_ALLOCATION_SIZE ? (size_t)ALIGN_UP(size, sizeof(Region*)) : SMALLEST_ALLOCATION_SIZE;
 749  assert(validatedSize >= size); // 32-bit wraparound should not occur, too large sizes should be stopped before
 750
 751  return validatedSize;
 752}
 753
 754static void *allocate_memory(size_t alignment, size_t size)
 755{
 756  ASSERT_MALLOC_IS_ACQUIRED();
 757
 758#ifdef EMMALLOC_VERBOSE
 759  MAIN_THREAD_ASYNC_EM_ASM(console.log('allocate_memory(align=' + $0 + ', size=' + ($1>>>0) + ' bytes)'), alignment, size);
 760#endif
 761
 762#ifdef EMMALLOC_MEMVALIDATE
 763  validate_memory_regions();
 764#endif
 765
 766  if (!IS_POWER_OF_2(alignment))
 767  {
 768#ifdef EMMALLOC_VERBOSE
 769    MAIN_THREAD_ASYNC_EM_ASM(console.log('Allocation failed: alignment not power of 2!'));
 770#endif
 771    return 0;
 772  }
 773
 774  if (size > MAX_ALLOC_SIZE)
 775  {
 776#ifdef EMMALLOC_VERBOSE
 777    MAIN_THREAD_ASYNC_EM_ASM(console.log('Allocation failed: attempted allocation size is too large: ' + ($0 >>> 0) + 'bytes! (negative integer wraparound?)'), size);
 778#endif
 779    return 0;
 780  }
 781
 782  alignment = validate_alloc_alignment(alignment);
 783  size = validate_alloc_size(size);
 784
 785  // Attempt to allocate memory starting from smallest bucket that can contain the required amount of memory.
 786  // Under normal alignment conditions this should always be the first or second bucket we look at, but if
 787  // performing an allocation with complex alignment, we may need to look at multiple buckets.
 788  int bucketIndex = compute_free_list_bucket(size);
 789  BUCKET_BITMASK_T bucketMask = freeRegionBucketsUsed >> bucketIndex;
 790
 791  // Loop through each bucket that has free regions in it, based on bits set in freeRegionBucketsUsed bitmap.
 792  while(bucketMask)
 793  {
 794    BUCKET_BITMASK_T indexAdd = __builtin_ctzll(bucketMask);
 795    bucketIndex += indexAdd;
 796    bucketMask >>= indexAdd;
 797    assert(bucketIndex >= 0);
 798    assert(bucketIndex <= NUM_FREE_BUCKETS-1);
 799    assert(freeRegionBucketsUsed & (((BUCKET_BITMASK_T)1) << bucketIndex));
 800
 801    Region *freeRegion = freeRegionBuckets[bucketIndex].next;
 802    assert(freeRegion);
 803    if (freeRegion != &freeRegionBuckets[bucketIndex])
 804    {
 805      void *ptr = attempt_allocate(freeRegion, alignment, size);
 806      if (ptr)
 807        return ptr;
 808
 809      // We were not able to allocate from the first region found in this bucket, so penalize
 810      // the region by cycling it to the end of the doubly circular linked list. (constant time)
 811      // This provides a randomized guarantee that when performing allocations of size k to a
 812      // bucket of [k-something, k+something] range, we will not always attempt to satisfy the
 813      // allocation from the same available region at the front of the list, but we try each
 814      // region in turn.
 815      unlink_from_free_list(freeRegion);
 816      prepend_to_free_list(freeRegion, &freeRegionBuckets[bucketIndex]);
 817      // But do not stick around to attempt to look at other regions in this bucket - move
 818      // to search the next populated bucket index if this did not fit. This gives a practical
 819      // "allocation in constant time" guarantee, since the next higher bucket will only have
 820      // regions that are all of strictly larger size than the requested allocation. Only if
 821      // there is a difficult alignment requirement we may fail to perform the allocation from
 822      // a region in the next bucket, and if so, we keep trying higher buckets until one of them
 823      // works.
 824      ++bucketIndex;
 825      bucketMask >>= 1;
 826    }
 827    else
 828    {
 829      // This bucket was not populated after all with any regions,
 830      // but we just had a stale bit set to mark a populated bucket.
 831      // Reset the bit to update latest status so that we do not
 832      // redundantly look at this bucket again.
 833      freeRegionBucketsUsed &= ~(((BUCKET_BITMASK_T)1) << bucketIndex);
 834      bucketMask ^= 1;
 835    }
 836    // Instead of recomputing bucketMask from scratch at the end of each loop, it is updated as we go,
 837    // to avoid undefined behavior with (x >> 32)/(x >> 64) when bucketIndex reaches 32/64, (the shift would comes out as a no-op instead of 0).
 838
 839    assert((bucketIndex == NUM_FREE_BUCKETS && bucketMask == 0) || (bucketMask == freeRegionBucketsUsed >> bucketIndex));
 840  }
 841
 842  // None of the buckets were able to accommodate an allocation. If this happens we are almost out of memory.
 843  // The largest bucket might contain some suitable regions, but we only looked at one region in that bucket, so
 844  // as a last resort, loop through more free regions in the bucket that represents the largest allocations available.
 845  // But only if the bucket representing largest allocations available is not any of the first thirty buckets,
 846  // these represent allocatable areas less than <1024 bytes - which could be a lot of scrap.
 847  // In such case, prefer to sbrk() in more memory right away.
 848  int largestBucketIndex = NUM_FREE_BUCKETS - 1 - __builtin_clzll(freeRegionBucketsUsed);
 849  // freeRegion will be null if there is absolutely no memory left. (all buckets are 100% used)
 850  Region *freeRegion = freeRegionBucketsUsed ? freeRegionBuckets[largestBucketIndex].next : 0;
 851  if (freeRegionBucketsUsed >> 30)
 852  {
 853    // Look only at a constant number of regions in this bucket max, to avoid bad worst case behavior.
 854    // If this many regions cannot find free space, we give up and prefer to sbrk() more instead.
 855    const int maxRegionsToTryBeforeGivingUp = 99;
 856    int numTriesLeft = maxRegionsToTryBeforeGivingUp;
 857    while(freeRegion != &freeRegionBuckets[largestBucketIndex] && numTriesLeft-- > 0)
 858    {
 859      void *ptr = attempt_allocate(freeRegion, alignment, size);
 860      if (ptr)
 861        return ptr;
 862      freeRegion = freeRegion->next;
 863    }
 864  }
 865
 866  // We were unable to find a free memory region. Must sbrk() in more memory!
 867  size_t numBytesToClaim = size+sizeof(Region)*3;
 868  assert(numBytesToClaim > size); // 32-bit wraparound should not happen here, allocation size has been validated above!
 869  bool success = claim_more_memory(numBytesToClaim);
 870  if (success)
 871    return allocate_memory(alignment, size); // Recurse back to itself to try again
 872
 873  // also sbrk() failed, we are really really constrained :( As a last resort, go back to looking at the
 874  // bucket we already looked at above, continuing where the above search left off - perhaps there are
 875  // regions we overlooked the first time that might be able to satisfy the allocation.
 876  if (freeRegion)
 877  {
 878    while(freeRegion != &freeRegionBuckets[largestBucketIndex])
 879    {
 880      void *ptr = attempt_allocate(freeRegion, alignment, size);
 881      if (ptr)
 882        return ptr;
 883      freeRegion = freeRegion->next;
 884    }
 885  }
 886
 887#ifdef EMMALLOC_VERBOSE
 888  MAIN_THREAD_ASYNC_EM_ASM(console.log('Could not find a free memory block!'));
 889#endif
 890
 891  return 0;
 892}
 893
 894static
 895void *emmalloc_memalign(size_t alignment, size_t size)
 896{
 897  MALLOC_ACQUIRE();
 898  void *ptr = allocate_memory(alignment, size);
 899  MALLOC_RELEASE();
 900  return ptr;
 901}
 902
 903#if 0
 904void * EMMALLOC_EXPORT memalign(size_t alignment, size_t size)
 905{
 906  return emmalloc_memalign(alignment, size);
 907}
 908#endif
 909
 910void * EMMALLOC_EXPORT aligned_alloc(size_t alignment, size_t size)
 911{
 912  if ((alignment % sizeof(void *) != 0) || (size % alignment) != 0)
 913    return 0;
 914  return emmalloc_memalign(alignment, size);
 915}
 916
 917static
 918void *emmalloc_malloc(size_t size)
 919{
 920  return emmalloc_memalign(MALLOC_ALIGNMENT, size);
 921}
 922
 923void * EMMALLOC_EXPORT malloc(size_t size)
 924{
 925  return emmalloc_malloc(size);
 926}
 927
 928static
 929size_t emmalloc_usable_size(void *ptr)
 930{
 931  if (!ptr)
 932    return 0;
 933
 934  uint8_t *regionStartPtr = (uint8_t*)ptr - sizeof(size_t);
 935  Region *region = (Region*)(regionStartPtr);
 936  assert(HAS_ALIGNMENT(region, sizeof(size_t)));
 937
 938  MALLOC_ACQUIRE();
 939
 940  size_t size = region->size;
 941  assert(size >= sizeof(Region));
 942  assert(region_is_in_use(region));
 943
 944  MALLOC_RELEASE();
 945
 946  return size - REGION_HEADER_SIZE;
 947}
 948
 949size_t EMMALLOC_EXPORT malloc_usable_size(void *ptr)
 950{
 951  return emmalloc_usable_size(ptr);
 952}
 953
 954static
 955void emmalloc_free(void *ptr)
 956{
 957#ifdef EMMALLOC_MEMVALIDATE
 958  emmalloc_validate_memory_regions();
 959#endif
 960
 961  if (!ptr)
 962    return;
 963
 964#ifdef EMMALLOC_VERBOSE
 965  MAIN_THREAD_ASYNC_EM_ASM(console.log('free(ptr=0x'+($0>>>0).toString(16)+')'), ptr);
 966#endif
 967
 968  uint8_t *regionStartPtr = (uint8_t*)ptr - sizeof(size_t);
 969  Region *region = (Region*)(regionStartPtr);
 970  assert(HAS_ALIGNMENT(region, sizeof(size_t)));
 971
 972  MALLOC_ACQUIRE();
 973
 974  size_t size = region->size;
 975#ifdef EMMALLOC_VERBOSE
 976  if (size < sizeof(Region) || !region_is_in_use(region))
 977  {
 978    if (debug_region_is_consistent(region))
 979      // LLVM wasm backend bug: cannot use MAIN_THREAD_ASYNC_EM_ASM() here, that generates internal compiler error
 980      // Reproducible by running e.g. other.test_alloc_3GB
 981      EM_ASM(console.error('Double free at region ptr 0x' + ($0>>>0).toString(16) + ', region->size: 0x' + ($1>>>0).toString(16) + ', region->sizeAtCeiling: 0x' + ($2>>>0).toString(16) + ')'), region, size, region_ceiling_size(region));
 982    else
 983      MAIN_THREAD_ASYNC_EM_ASM(console.error('Corrupt region at region ptr 0x' + ($0>>>0).toString(16) + ' region->size: 0x' + ($1>>>0).toString(16) + ', region->sizeAtCeiling: 0x' + ($2>>>0).toString(16) + ')'), region, size, region_ceiling_size(region));
 984  }
 985#endif
 986  assert(size >= sizeof(Region));
 987  assert(region_is_in_use(region));
 988
 989#ifdef __EMSCRIPTEN_TRACING__
 990  emscripten_trace_record_free(region);
 991#endif
 992
 993  // Check merging with left side
 994  size_t prevRegionSizeField = ((size_t*)region)[-1];
 995  size_t prevRegionSize = prevRegionSizeField & ~FREE_REGION_FLAG;
 996  if (prevRegionSizeField != prevRegionSize) // Previous region is free?
 997  {
 998    Region *prevRegion = (Region*)((uint8_t*)region - prevRegionSize);
 999    assert(debug_region_is_consistent(prevRegion));
1000    unlink_from_free_list(prevRegion);
1001    regionStartPtr = (uint8_t*)prevRegion;
1002    size += prevRegionSize;
1003  }
1004
1005  // Check merging with right side
1006  Region *nextRegion = next_region(region);
1007  assert(debug_region_is_consistent(nextRegion));
1008  size_t sizeAtEnd = *(size_t*)region_payload_end_ptr(nextRegion);
1009  if (nextRegion->size != sizeAtEnd)
1010  {
1011    unlink_from_free_list(nextRegion);
1012    size += nextRegion->size;
1013  }
1014
1015  create_free_region(regionStartPtr, size);
1016  link_to_free_list((Region*)regionStartPtr);
1017
1018  MALLOC_RELEASE();
1019
1020#ifdef EMMALLOC_MEMVALIDATE
1021  emmalloc_validate_memory_regions();
1022#endif
1023}
1024
1025void EMMALLOC_EXPORT free(void *ptr)
1026{
1027  emmalloc_free(ptr);
1028}
1029
1030// Can be called to attempt to increase or decrease the size of the given region
1031// to a new size (in-place). Returns 1 if resize succeeds, and 0 on failure.
1032static int attempt_region_resize(Region *region, size_t size)
1033{
1034  ASSERT_MALLOC_IS_ACQUIRED();
1035  assert(size > 0);
1036  assert(HAS_ALIGNMENT(size, sizeof(size_t)));
1037
1038#ifdef EMMALLOC_VERBOSE
1039  MAIN_THREAD_ASYNC_EM_ASM(console.log('attempt_region_resize(region=0x' + ($0>>>0).toString(16) + ', size=' + ($1>>>0) + ' bytes)'), region, size);
1040#endif
1041
1042  // First attempt to resize this region, if the next region that follows this one
1043  // is a free region.
1044  Region *nextRegion = next_region(region);
1045  uint8_t *nextRegionEndPtr = (uint8_t*)nextRegion + nextRegion->size;
1046  size_t sizeAtCeiling = ((size_t*)nextRegionEndPtr)[-1];
1047  if (nextRegion->size != sizeAtCeiling) // Next region is free?
1048  {
1049    assert(region_is_free(nextRegion));
1050    uint8_t *newNextRegionStartPtr = (uint8_t*)region + size;
1051    assert(HAS_ALIGNMENT(newNextRegionStartPtr, sizeof(size_t)));
1052    // Next region does not shrink to too small size?
1053    if (newNextRegionStartPtr + sizeof(Region) <= nextRegionEndPtr)
1054    {
1055      unlink_from_free_list(nextRegion);
1056      create_free_region(newNextRegionStartPtr, nextRegionEndPtr - newNextRegionStartPtr);
1057      link_to_free_list((Region*)newNextRegionStartPtr);
1058      create_used_region(region, newNextRegionStartPtr - (uint8_t*)region);
1059      return 1;
1060    }
1061    // If we remove the next region altogether, allocation is satisfied?
1062    if (newNextRegionStartPtr <= nextRegionEndPtr)
1063    {
1064      unlink_from_free_list(nextRegion);
1065      create_used_region(region, region->size + nextRegion->size);
1066      return 1;
1067    }
1068  }
1069  else
1070  {
1071    // Next region is an used region - we cannot change its starting address. However if we are shrinking the
1072    // size of this region, we can create a new free region between this and the next used region.
1073    if (size + sizeof(Region) <= region->size)
1074    {
1075      size_t freeRegionSize = region->size - size;
1076      create_used_region(region, size);
1077      Region *freeRegion = (Region *)((uint8_t*)region + size);
1078      create_free_region(freeRegion, freeRegionSize);
1079      link_to_free_list(freeRegion);
1080      return 1;
1081    }
1082    else if (size <= region->size)
1083    {
1084      // Caller was asking to shrink the size, but due to not being able to fit a full Region in the shrunk
1085      // area, we cannot actually do anything. This occurs if the shrink amount is really small. In such case,
1086      // just call it success without doing any work.
1087      return 1;
1088    }
1089  }
1090#ifdef EMMALLOC_VERBOSE
1091  MAIN_THREAD_ASYNC_EM_ASM(console.log('attempt_region_resize failed.'));
1092#endif
1093  return 0;
1094}
1095
1096static int acquire_and_attempt_region_resize(Region *region, size_t size)
1097{
1098  MALLOC_ACQUIRE();
1099  int success = attempt_region_resize(region, size);
1100  MALLOC_RELEASE();
1101  return success;
1102}
1103
1104static
1105void *emmalloc_aligned_realloc(void *ptr, size_t alignment, size_t size)
1106{
1107#ifdef EMMALLOC_VERBOSE
1108  MAIN_THREAD_ASYNC_EM_ASM(console.log('aligned_realloc(ptr=0x' + ($0>>>0).toString(16) + ', alignment=' + $1 + ', size=' + ($2>>>0)), ptr, alignment, size);
1109#endif
1110
1111  if (!ptr)
1112    return emmalloc_memalign(alignment, size);
1113
1114  if (size == 0)
1115  {
1116    free(ptr);
1117    return 0;
1118  }
1119
1120  if (size > MAX_ALLOC_SIZE)
1121  {
1122#ifdef EMMALLOC_VERBOSE
1123    MAIN_THREAD_ASYNC_EM_ASM(console.log('Allocation failed: attempted allocation size is too large: ' + ($0 >>> 0) + 'bytes! (negative integer wraparound?)'), size);
1124#endif
1125    return 0;
1126  }
1127
1128  assert(IS_POWER_OF_2(alignment));
1129  // aligned_realloc() cannot be used to ask to change the alignment of a pointer.
1130  assert(HAS_ALIGNMENT(ptr, alignment));
1131  size = validate_alloc_size(size);
1132
1133  // Calculate the region start address of the original allocation
1134  Region *region = (Region*)((uint8_t*)ptr - sizeof(size_t));
1135
1136  // First attempt to resize the given region to avoid having to copy memory around
1137  if (acquire_and_attempt_region_resize(region, size + REGION_HEADER_SIZE))
1138  {
1139#ifdef __EMSCRIPTEN_TRACING__
1140    emscripten_trace_record_reallocation(ptr, ptr, size);
1141#endif
1142    return ptr;
1143  }
1144
1145  // If resize failed, we must allocate a new region, copy the data over, and then
1146  // free the old region.
1147  void *newptr = emmalloc_memalign(alignment, size);
1148  if (newptr)
1149  {
1150    memcpy(newptr, ptr, MIN(size, region->size - REGION_HEADER_SIZE));
1151    free(ptr);
1152  }
1153  // N.B. If there is not enough memory, the old memory block should not be freed and
1154  // null pointer is returned.
1155  return newptr;
1156}
1157
1158#if 0
1159void * EMMALLOC_EXPORT aligned_realloc(void *ptr, size_t alignment, size_t size)
1160{
1161  return emmalloc_aligned_realloc(ptr, alignment, size);
1162}
1163#endif
1164
1165#if 0
1166// realloc_try() is like realloc(), but only attempts to try to resize the existing memory
1167// area. If resizing the existing memory area fails, then realloc_try() will return 0
1168// (the original memory block is not freed or modified). If resizing succeeds, previous
1169// memory contents will be valid up to min(old length, new length) bytes.
1170void *emmalloc_realloc_try(void *ptr, size_t size)
1171{
1172  if (!ptr)
1173    return 0;
1174
1175  if (size == 0)
1176  {
1177    free(ptr);
1178    return 0;
1179  }
1180
1181  if (size > MAX_ALLOC_SIZE)
1182  {
1183#ifdef EMMALLOC_VERBOSE
1184    MAIN_THREAD_ASYNC_EM_ASM(console.log('Allocation failed: attempted allocation size is too large: ' + ($0 >>> 0) + 'bytes! (negative integer wraparound?)'), size);
1185#endif
1186    return 0;
1187  }
1188
1189  size = validate_alloc_size(size);
1190
1191  // Calculate the region start address of the original allocation
1192  Region *region = (Region*)((uint8_t*)ptr - sizeof(size_t));
1193
1194  // Attempt to resize the given region to avoid having to copy memory around
1195  int success = acquire_and_attempt_region_resize(region, size + REGION_HEADER_SIZE);
1196#ifdef __EMSCRIPTEN_TRACING__
1197  if (success)
1198    emscripten_trace_record_reallocation(ptr, ptr, size);
1199#endif
1200  return success ? ptr : 0;
1201}
1202
1203// emmalloc_aligned_realloc_uninitialized() is like aligned_realloc(), but old memory contents
1204// will be undefined after reallocation. (old memory is not preserved in any case)
1205void *emmalloc_aligned_realloc_uninitialized(void *ptr, size_t alignment, size_t size)
1206{
1207  if (!ptr)
1208    return emmalloc_memalign(alignment, size);
1209
1210  if (size == 0)
1211  {
1212    free(ptr);
1213    return 0;
1214  }
1215
1216  if (size > MAX_ALLOC_SIZE)
1217  {
1218#ifdef EMMALLOC_VERBOSE
1219    MAIN_THREAD_ASYNC_EM_ASM(console.log('Allocation failed: attempted allocation size is too large: ' + ($0 >>> 0) + 'bytes! (negative integer wraparound?)'), size);
1220#endif
1221    return 0;
1222  }
1223
1224  size = validate_alloc_size(size);
1225
1226  // Calculate the region start address of the original allocation
1227  Region *region = (Region*)((uint8_t*)ptr - sizeof(size_t));
1228
1229  // First attempt to resize the given region to avoid having to copy memory around
1230  if (acquire_and_attempt_region_resize(region, size + REGION_HEADER_SIZE))
1231  {
1232#ifdef __EMSCRIPTEN_TRACING__
1233    emscripten_trace_record_reallocation(ptr, ptr, size);
1234#endif
1235    return ptr;
1236  }
1237
1238  // If resize failed, drop the old region and allocate a new region. Memory is not
1239  // copied over
1240  free(ptr);
1241  return emmalloc_memalign(alignment, size);
1242}
1243#endif
1244
1245static
1246void *emmalloc_realloc(void *ptr, size_t size)
1247{
1248  return emmalloc_aligned_realloc(ptr, MALLOC_ALIGNMENT, size);
1249}
1250
1251void * EMMALLOC_EXPORT realloc(void *ptr, size_t size)
1252{
1253  return emmalloc_realloc(ptr, size);
1254}
1255
1256#if 0
1257// realloc_uninitialized() is like realloc(), but old memory contents
1258// will be undefined after reallocation. (old memory is not preserved in any case)
1259void *emmalloc_realloc_uninitialized(void *ptr, size_t size)
1260{
1261  return emmalloc_aligned_realloc_uninitialized(ptr, MALLOC_ALIGNMENT, size);
1262}
1263#endif
1264
1265static
1266int emmalloc_posix_memalign(void **memptr, size_t alignment, size_t size)
1267{
1268  assert(memptr);
1269  if (alignment % sizeof(void *) != 0)
1270    return 22/* EINVAL*/;
1271  *memptr = emmalloc_memalign(alignment, size);
1272  return *memptr ?  0 : 12/*ENOMEM*/;
1273}
1274
1275int EMMALLOC_EXPORT posix_memalign(void **memptr, size_t alignment, size_t size)
1276{
1277  return emmalloc_posix_memalign(memptr, alignment, size);
1278}
1279
1280static
1281void *emmalloc_calloc(size_t num, size_t size)
1282{
1283  size_t bytes = num*size;
1284  void *ptr = emmalloc_memalign(MALLOC_ALIGNMENT, bytes);
1285  if (ptr)
1286    memset(ptr, 0, bytes);
1287  return ptr;
1288}
1289
1290void * EMMALLOC_EXPORT calloc(size_t num, size_t size)
1291{
1292  return emmalloc_calloc(num, size);
1293}
1294
1295#if 0
1296static int count_linked_list_size(Region *list)
1297{
1298  int size = 1;
1299  for(Region *i = list->next; i != list; list = list->next)
1300    ++size;
1301  return size;
1302}
1303
1304static size_t count_linked_list_space(Region *list)
1305{
1306  size_t space = 0;
1307  for(Region *i = list->next; i != list; list = list->next)
1308    space += region_payload_end_ptr(i) - region_payload_start_ptr(i);
1309  return space;
1310}
1311
1312struct mallinfo emmalloc_mallinfo()
1313{
1314  MALLOC_ACQUIRE();
1315
1316  struct mallinfo info;
1317  // Non-mmapped space allocated (bytes): For emmalloc,
1318  // let's define this as the difference between heap size and dynamic top end.
1319  info.arena = emscripten_get_heap_size() - (size_t)sbrk(0);
1320  // Number of "ordinary" blocks. Let's define this as the number of highest
1321  // size blocks. (subtract one from each, since there is a sentinel node in each list)
1322  info.ordblks = count_linked_list_size(&freeRegionBuckets[NUM_FREE_BUCKETS-1])-1;
1323  // Number of free "fastbin" blocks. For emmalloc, define this as the number
1324  // of blocks that are not in the largest pristine block.
1325  info.smblks = 0;
1326  // The total number of bytes in free "fastbin" blocks.
1327  info.fsmblks = 0;
1328  for(int i = 0; i < NUM_FREE_BUCKETS-1; ++i)
1329  {
1330    info.smblks += count_linked_list_size(&freeRegionBuckets[i])-1;
1331    info.fsmblks += count_linked_list_space(&freeRegionBuckets[i]);
1332  }
1333
1334  info.hblks = 0; // Number of mmapped regions: always 0. (no mmap support)
1335  info.hblkhd = 0; // Amount of bytes in mmapped regions: always 0. (no mmap support)
1336
1337  // Walk through all the heap blocks to report the following data:
1338  // The "highwater mark" for allocated space—that is, the maximum amount of
1339  // space that was ever allocated. Emmalloc does not want to pay code to
1340  // track this, so this is only reported from current allocation data, and
1341  // may not be accurate.
1342  info.usmblks = 0;
1343  info.uordblks = 0; // The total number of bytes used by in-use allocations.
1344  info.fordblks = 0; // The total number of bytes in free blocks.
1345  // The total amount of releasable free space at the top of the heap.
1346  // This is the maximum number of bytes that could ideally be released by malloc_trim(3).
1347  Region *lastActualRegion = prev_region((Region*)(listOfAllRegions->endPtr - sizeof(Region)));
1348  info.keepcost = region_is_free(lastActualRegion) ? lastActualRegion->size : 0;
1349
1350  RootRegion *root = listOfAllRegions;
1351  while(root)
1352  {
1353    Region *r = (Region*)root;
1354    assert(debug_region_is_consistent(r));
1355    uint8_t *lastRegionEnd = root->endPtr;
1356    while((uint8_t*)r < lastRegionEnd)
1357    {
1358      assert(debug_region_is_consistent(r));
1359
1360      if (region_is_free(r))
1361      {
1362        // Count only the payload of the free block towards free memory.
1363        info.fordblks += region_payload_end_ptr(r) - region_payload_start_ptr(r);
1364        // But the header data of the free block goes towards used memory.
1365        info.uordblks += REGION_HEADER_SIZE;
1366      }
1367      else
1368      {
1369        info.uordblks += r->size;
1370      }
1371      // Update approximate watermark data
1372      info.usmblks = MAX(info.usmblks, (intptr_t)r + r->size);
1373
1374      if (r->size == 0)
1375        break;
1376      r = next_region(r);
1377    }
1378    root = root->next;
1379  }
1380
1381  MALLOC_RELEASE();
1382  return info;
1383}
1384
1385struct mallinfo EMMALLOC_EXPORT mallinfo()
1386{
1387  return emmalloc_mallinfo();
1388}
1389
1390// Note! This function is not fully multithreadin safe: while this function is running, other threads should not be
1391// allowed to call sbrk()!
1392static int trim_dynamic_heap_reservation(size_t pad)
1393{
1394  ASSERT_MALLOC_IS_ACQUIRED();
1395
1396  if (!listOfAllRegions)
1397    return 0; // emmalloc is not controlling any dynamic memory at all - cannot release memory.
1398  uint8_t *previousSbrkEndAddress = listOfAllRegions->endPtr;
1399  assert(sbrk(0) == previousSbrkEndAddress);
1400  size_t lastMemoryRegionSize = ((size_t*)previousSbrkEndAddress)[-1];
1401  assert(lastMemoryRegionSize == 16); // // The last memory region should be a sentinel node of exactly 16 bytes in size.
1402  Region *endSentinelRegion = (Region*)(previousSbrkEndAddress - sizeof(Region));
1403  Region *lastActualRegion = prev_region(endSentinelRegion);
1404
1405  // Round padding up to multiple of 4 bytes to keep sbrk() and memory region alignment intact.
1406  // Also have at least 8 bytes of payload so that we can form a full free region.
1407  size_t newRegionSize = (size_t)ALIGN_UP(pad, 4);
1408  if (pad > 0)
1409    newRegionSize += sizeof(Region) - (newRegionSize - pad);
1410
1411  if (!region_is_free(lastActualRegion) || lastActualRegion->size <= newRegionSize)
1412    return 0; // Last actual region is in use, or caller desired to leave more free memory intact than there is.
1413
1414  // This many bytes will be shrunk away.
1415  size_t shrinkAmount = lastActualRegion->size - newRegionSize;
1416  assert(HAS_ALIGNMENT(shrinkAmount, 4));
1417
1418  unlink_from_free_list(lastActualRegion);
1419  // If pad == 0, we should delete the last free region altogether. If pad > 0,
1420  // shrink the last free region to the desired size.
1421  if (newRegionSize > 0)
1422  {
1423    create_free_region(lastActualRegion, newRegionSize);
1424    link_to_free_list(lastActualRegion);
1425  }
1426
1427  // Recreate the sentinel region at the end of the last free region
1428  endSentinelRegion = (Region*)((uint8_t*)lastActualRegion + newRegionSize);
1429  create_used_region(endSentinelRegion, sizeof(Region));
1430
1431  // And update the size field of the whole region block.
1432  listOfAllRegions->endPtr = (uint8_t*)endSentinelRegion + sizeof(Region);
1433
1434  // Finally call sbrk() to shrink the memory area.
1435  void *oldSbrk = sbrk(-(intptr_t)shrinkAmount);
1436  assert((intptr_t)oldSbrk != -1); // Shrinking with sbrk() should never fail.
1437  assert(oldSbrk == previousSbrkEndAddress); // Another thread should not have raced to increase sbrk() on us!
1438
1439  // All successful, and we actually trimmed memory!
1440  return 1;
1441}
1442
1443int emmalloc_trim(size_t pad)
1444{
1445  MALLOC_ACQUIRE();
1446  int success = trim_dynamic_heap_reservation(pad);
1447  MALLOC_RELEASE();
1448  return success;
1449}
1450
1451int EMMALLOC_EXPORT malloc_trim(size_t pad)
1452{
1453  return emmalloc_trim(pad);
1454}
1455
1456size_t emmalloc_dynamic_heap_size()
1457{
1458  size_t dynamicHeapSize = 0;
1459
1460  MALLOC_ACQUIRE();
1461  RootRegion *root = listOfAllRegions;
1462  while(root)
1463  {
1464    dynamicHeapSize += root->endPtr - (uint8_t*)root;
1465    root = root->next;
1466  }
1467  MALLOC_RELEASE();
1468  return dynamicHeapSize;
1469}
1470
1471size_t emmalloc_free_dynamic_memory()
1472{
1473  size_t freeDynamicMemory = 0;
1474
1475  int bucketIndex = 0;
1476
1477  MALLOC_ACQUIRE();
1478  BUCKET_BITMASK_T bucketMask = freeRegionBucketsUsed;
1479
1480  // Loop through each bucket that has free regions in it, based on bits set in freeRegionBucketsUsed bitmap.
1481  while(bucketMask)
1482  {
1483    BUCKET_BITMASK_T indexAdd = __builtin_ctzll(bucketMask);
1484    bucketIndex += indexAdd;
1485    bucketMask >>= indexAdd;
1486    for(Region *freeRegion = freeRegionBuckets[bucketIndex].next;
1487      freeRegion != &freeRegionBuckets[bucketIndex];
1488      freeRegion = freeRegion->next)
1489    {
1490      freeDynamicMemory += freeRegion->size - REGION_HEADER_SIZE;
1491    }
1492    ++bucketIndex;
1493    bucketMask >>= 1;
1494  }
1495  MALLOC_RELEASE();
1496  return freeDynamicMemory;
1497}
1498
1499size_t emmalloc_compute_free_dynamic_memory_fragmentation_map(size_t freeMemorySizeMap[32])
1500{
1501  memset((void*)freeMemorySizeMap, 0, sizeof(freeMemorySizeMap[0])*32);
1502
1503  size_t numFreeMemoryRegions = 0;
1504  int bucketIndex = 0;
1505  MALLOC_ACQUIRE();
1506  BUCKET_BITMASK_T bucketMask = freeRegionBucketsUsed;
1507
1508  // Loop through each bucket that has free regions in it, based on bits set in freeRegionBucketsUsed bitmap.
1509  while(bucketMask)
1510  {
1511    BUCKET_BITMASK_T indexAdd = __builtin_ctzll(bucketMask);
1512    bucketIndex += indexAdd;
1513    bucketMask >>= indexAdd;
1514    for(Region *freeRegion = freeRegionBuckets[bucketIndex].next;
1515      freeRegion != &freeRegionBuckets[bucketIndex];
1516      freeRegion = freeRegion->next)
1517    {
1518      ++numFreeMemoryRegions;
1519      size_t freeDynamicMemory = freeRegion->size - REGION_HEADER_SIZE;
1520      if (freeDynamicMemory > 0)
1521        ++freeMemorySizeMap[31-__builtin_clz(freeDynamicMemory)];
1522      else
1523        ++freeMemorySizeMap[0];
1524    }
1525    ++bucketIndex;
1526    bucketMask >>= 1;
1527  }
1528  MALLOC_RELEASE();
1529  return numFreeMemoryRegions;
1530}
1531
1532size_t emmalloc_unclaimed_heap_memory(void) {
1533  return emscripten_get_heap_max() - (size_t)sbrk(0);
1534}
1535#endif
1536
1537// Define these to satisfy musl references.
1538void *__libc_malloc(size_t) __attribute__((alias("malloc")));
1539void __libc_free(void *) __attribute__((alias("free")));
1540void *__libc_calloc(size_t nmemb, size_t size) __attribute__((alias("calloc")));