diff --git a/LICENSE b/LICENSE index 4151dbe4..670b668a 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,6 @@ MIT License -Copyright (c) 2019 Microsoft Corporation, Daan Leijen +Copyright (c) 2018-2021 Microsoft Corporation, Daan Leijen Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/doc/mimalloc-doc.h b/doc/mimalloc-doc.h index 59113402..b448f14a 100644 --- a/doc/mimalloc-doc.h +++ b/doc/mimalloc-doc.h @@ -1,5 +1,5 @@ /* ---------------------------------------------------------------------------- -Copyright (c) 2018, Microsoft Research, Daan Leijen +Copyright (c) 2018-2021, Microsoft Research, Daan Leijen This is free software; you can redistribute it and/or modify it under the terms of the MIT license. A copy of the license can be found in the file "LICENSE" at the root of this distribution. diff --git a/include/mimalloc-atomic.h b/include/mimalloc-atomic.h index db885319..d82bcfce 100644 --- a/include/mimalloc-atomic.h +++ b/include/mimalloc-atomic.h @@ -1,5 +1,5 @@ /* ---------------------------------------------------------------------------- -Copyright (c) 2018,2020 Microsoft Research, Daan Leijen +Copyright (c) 2018-2021 Microsoft Research, Daan Leijen This is free software; you can redistribute it and/or modify it under the terms of the MIT license. A copy of the license can be found in the file "LICENSE" at the root of this distribution. diff --git a/include/mimalloc-internal.h b/include/mimalloc-internal.h index 540d389e..380eeb01 100644 --- a/include/mimalloc-internal.h +++ b/include/mimalloc-internal.h @@ -1,5 +1,5 @@ /* ---------------------------------------------------------------------------- -Copyright (c) 2018, Microsoft Research, Daan Leijen +Copyright (c) 2018-2021, Microsoft Research, Daan Leijen This is free software; you can redistribute it and/or modify it under the terms of the MIT license. A copy of the license can be found in the file "LICENSE" at the root of this distribution. @@ -216,8 +216,16 @@ static inline uintptr_t _mi_align_up(uintptr_t sz, size_t alignment) { } } +// Align downwards static inline uintptr_t _mi_align_down(uintptr_t sz, size_t alignment) { - return (sz / alignment) * alignment; + mi_assert_internal(alignment != 0); + uintptr_t mask = alignment - 1; + if ((alignment & mask) == 0) { // power of two? + return (sz & ~mask); + } + else { + return ((sz / alignment) * alignment); + } } // Divide upwards: `s <= _mi_divide_up(s,d)*d < s+d`. @@ -305,7 +313,7 @@ extern bool _mi_process_is_initialized; mi_heap_t* _mi_heap_main_get(void); // statically allocated main backing heap #if defined(MI_MALLOC_OVERRIDE) -#if defined(__MACH__) // OSX +#if defined(__APPLE__) // macOS #define MI_TLS_SLOT 89 // seems unused? // other possible unused ones are 9, 29, __PTK_FRAMEWORK_JAVASCRIPTCORE_KEY4 (94), __PTK_FRAMEWORK_GC_KEY9 (112) and __PTK_FRAMEWORK_OLDGC_KEY9 (89) // see @@ -823,7 +831,7 @@ static inline void* mi_tls_slot(size_t slot) mi_attr_noexcept { const size_t ofs = (slot*sizeof(void*)); #if defined(__i386__) __asm__("movl %%gs:%1, %0" : "=r" (res) : "m" (*((void**)ofs)) : ); // 32-bit always uses GS -#elif defined(__MACH__) && defined(__x86_64__) +#elif defined(__APPLE__) && defined(__x86_64__) __asm__("movq %%gs:%1, %0" : "=r" (res) : "m" (*((void**)ofs)) : ); // x86_64 macOSX uses GS #elif defined(__x86_64__) && (MI_INTPTR_SIZE==4) __asm__("movl %%fs:%1, %0" : "=r" (res) : "m" (*((void**)ofs)) : ); // x32 ABI @@ -850,7 +858,7 @@ static inline void mi_tls_slot_set(size_t slot, void* value) mi_attr_noexcept { const size_t ofs = (slot*sizeof(void*)); #if defined(__i386__) __asm__("movl %1,%%gs:%0" : "=m" (*((void**)ofs)) : "rn" (value) : ); // 32-bit always uses GS -#elif defined(__MACH__) && defined(__x86_64__) +#elif defined(__APPLE__) && defined(__x86_64__) __asm__("movq %1,%%gs:%0" : "=m" (*((void**)ofs)) : "rn" (value) : ); // x86_64 macOSX uses GS #elif defined(__x86_64__) && (MI_INTPTR_SIZE==4) __asm__("movl %1,%%fs:%1" : "=m" (*((void**)ofs)) : "rn" (value) : ); // x32 ABI @@ -875,6 +883,9 @@ static inline uintptr_t _mi_thread_id(void) mi_attr_noexcept { #if defined(__aarch64__) && defined(__APPLE__) // M1 // on macOS on the M1, slot 0 does not seem to work, so we fall back to portable C for now. See issue #354 return (uintptr_t)&_mi_heap_default; +#elif defined(__BIONIC__) && (defined(__arm__) || defined(__aarch64__)) + // on Android, slot 1 is the thread ID (pointer to pthread internal struct) + return (uintptr_t)mi_tls_slot(1); #else // in all our other targets, slot 0 is the pointer to the thread control block return (uintptr_t)mi_tls_slot(0); diff --git a/include/mimalloc-new-delete.h b/include/mimalloc-new-delete.h index fded0c04..ba208f05 100644 --- a/include/mimalloc-new-delete.h +++ b/include/mimalloc-new-delete.h @@ -1,5 +1,5 @@ /* ---------------------------------------------------------------------------- -Copyright (c) 2018,2019 Microsoft Research, Daan Leijen +Copyright (c) 2018-2020 Microsoft Research, Daan Leijen This is free software; you can redistribute it and/or modify it under the terms of the MIT license. A copy of the license can be found in the file "LICENSE" at the root of this distribution. diff --git a/include/mimalloc-override.h b/include/mimalloc-override.h index 2362bfbc..7d9f3e7d 100644 --- a/include/mimalloc-override.h +++ b/include/mimalloc-override.h @@ -1,5 +1,5 @@ /* ---------------------------------------------------------------------------- -Copyright (c) 2018,2019 Microsoft Research, Daan Leijen +Copyright (c) 2018-2020 Microsoft Research, Daan Leijen This is free software; you can redistribute it and/or modify it under the terms of the MIT license. A copy of the license can be found in the file "LICENSE" at the root of this distribution. diff --git a/include/mimalloc-types.h b/include/mimalloc-types.h index c35874f6..750a2b28 100644 --- a/include/mimalloc-types.h +++ b/include/mimalloc-types.h @@ -1,5 +1,5 @@ /* ---------------------------------------------------------------------------- -Copyright (c) 2018, Microsoft Research, Daan Leijen +Copyright (c) 2018-2021, Microsoft Research, Daan Leijen This is free software; you can redistribute it and/or modify it under the terms of the MIT license. A copy of the license can be found in the file "LICENSE" at the root of this distribution. diff --git a/include/mimalloc.h b/include/mimalloc.h index 2cdded9f..c58ef906 100644 --- a/include/mimalloc.h +++ b/include/mimalloc.h @@ -1,5 +1,5 @@ /* ---------------------------------------------------------------------------- -Copyright (c) 2018-2020, Microsoft Research, Daan Leijen +Copyright (c) 2018-2021, Microsoft Research, Daan Leijen This is free software; you can redistribute it and/or modify it under the terms of the MIT license. A copy of the license can be found in the file "LICENSE" at the root of this distribution. diff --git a/readme.md b/readme.md index 00c6fbd1..e3662368 100644 --- a/readme.md +++ b/readme.md @@ -12,8 +12,8 @@ is a general purpose allocator with excellent [performance](#performance) charac Initially developed by Daan Leijen for the run-time systems of the [Koka](https://koka-lang.github.io) and [Lean](https://github.com/leanprover/lean) languages. -Latest release tag: `v2.0.0` (beta, 2021-01-31). -Latest stable tag: `v1.7.0` (2021-01-31). +Latest release tag: `v2.0.1` (beta, 2021-04-06). +Latest stable tag: `v1.7.1` (2021-04-06). mimalloc is a drop-in replacement for `malloc` and can be used in other programs without code changes, for example, on dynamically linked ELF-based systems (Linux, BSD, etc.) you can use it as: @@ -71,8 +71,10 @@ Enjoy! * `dev`: development branch for mimalloc v1. * `dev-slice`: development branch for mimalloc v2 with a new algorithm for managing internal mimalloc pages. -### Release +### Releases +* 2021-04-06, `v1.7.1`, `v2.0.1` (beta): fix bug in arena allocation for huge pages, improved aslr on large allocations, improved M1 support (still experimental). + * 2021-01-31, `v2.0.0`: beta release 2.0: new algorithm for managing internal mimalloc pages that tends to use reduce memory usage and fragmentation compared to mimalloc v1 (especially for large workloads). Should otherwise have similar performance (see [below](#performance)); please report if you observe any significant performance regression. diff --git a/src/alloc-aligned.c b/src/alloc-aligned.c index 4be651d4..724c0a1b 100644 --- a/src/alloc-aligned.c +++ b/src/alloc-aligned.c @@ -1,5 +1,5 @@ /* ---------------------------------------------------------------------------- -Copyright (c) 2018, Microsoft Research, Daan Leijen +Copyright (c) 2018-2021, Microsoft Research, Daan Leijen This is free software; you can redistribute it and/or modify it under the terms of the MIT license. A copy of the license can be found in the file "LICENSE" at the root of this distribution. diff --git a/src/alloc-override-osx.c b/src/alloc-override-osx.c index 4b77f631..3a46ecd9 100644 --- a/src/alloc-override-osx.c +++ b/src/alloc-override-osx.c @@ -1,5 +1,5 @@ /* ---------------------------------------------------------------------------- -Copyright (c) 2018, Microsoft Research, Daan Leijen +Copyright (c) 2018-2020, Microsoft Research, Daan Leijen This is free software; you can redistribute it and/or modify it under the terms of the MIT license. A copy of the license can be found in the file "LICENSE" at the root of this distribution. @@ -278,4 +278,4 @@ static void __attribute__((constructor(0))) _mi_macos_override_malloc() { } -#endif // MI_MALLOC_OVERRIDE \ No newline at end of file +#endif // MI_MALLOC_OVERRIDE diff --git a/src/alloc-override.c b/src/alloc-override.c index 5906bd20..48fc33bb 100644 --- a/src/alloc-override.c +++ b/src/alloc-override.c @@ -1,5 +1,5 @@ /* ---------------------------------------------------------------------------- -Copyright (c) 2018, Microsoft Research, Daan Leijen +Copyright (c) 2018-2021, Microsoft Research, Daan Leijen This is free software; you can redistribute it and/or modify it under the terms of the MIT license. A copy of the license can be found in the file "LICENSE" at the root of this distribution. @@ -13,13 +13,13 @@ terms of the MIT license. A copy of the license can be found in the file #error "It is only possible to override "malloc" on Windows when building as a DLL (and linking the C runtime as a DLL)" #endif -#if defined(MI_MALLOC_OVERRIDE) && !(defined(_WIN32)) // || (defined(__MACH__) && !defined(MI_INTERPOSE))) +#if defined(MI_MALLOC_OVERRIDE) && !(defined(_WIN32)) // || (defined(__APPLE__) && !defined(MI_INTERPOSE))) // ------------------------------------------------------ // Override system malloc // ------------------------------------------------------ -#if (defined(__GNUC__) || defined(__clang__)) && !defined(__MACH__) +#if (defined(__GNUC__) || defined(__clang__)) && !defined(__APPLE__) // use aliasing to alias the exported function to one of our `mi_` functions #if (defined(__GNUC__) && __GNUC__ >= 9) #define MI_FORWARD(fun) __attribute__((alias(#fun), used, visibility("default"), copy(fun))) @@ -81,7 +81,7 @@ terms of the MIT license. A copy of the license can be found in the file void free(void* p) MI_FORWARD0(mi_free, p); #endif -#if (defined(__GNUC__) || defined(__clang__)) && !defined(__MACH__) +#if (defined(__GNUC__) || defined(__clang__)) && !defined(__APPLE__) #pragma GCC visibility push(default) #endif @@ -187,11 +187,12 @@ void* memalign(size_t alignment, size_t size) { return mi_memali int posix_memalign(void** p, size_t alignment, size_t size) { return mi_posix_memalign(p, alignment, size); } void* _aligned_malloc(size_t alignment, size_t size) { return mi_aligned_alloc(alignment, size); } -// on some glibc `aligned_alloc` is declared `static inline` so we cannot override it (e.g. Conda). This happens -// when _GLIBCXX_HAVE_ALIGNED_ALLOC is not defined. However, in those cases it will use `memalign`, `posix_memalign`, -// or `_aligned_malloc` and we can avoid overriding it ourselves. -// We should always override if using C compilation. (issue #276) -#if _GLIBCXX_HAVE_ALIGNED_ALLOC || !defined(__cplusplus) +// `aligned_alloc` is only available when __USE_ISOC11 is defined. +// Note: Conda has a custom glibc where `aligned_alloc` is declared `static inline` and we cannot +// override it, but both _ISOC11_SOURCE and __USE_ISOC11 are undefined in Conda GCC7 or GCC9. +// Fortunately, in the case where `aligned_alloc` is declared as `static inline` it +// uses internally `memalign`, `posix_memalign`, or `_aligned_malloc` so we can avoid overriding it ourselves. +#if __USE_ISOC11 void* aligned_alloc(size_t alignment, size_t size) { return mi_aligned_alloc(alignment, size); } #endif @@ -214,7 +215,7 @@ void* aligned_alloc(size_t alignment, size_t size) { return mi_aligned_alloc(a } #endif -#if (defined(__GNUC__) || defined(__clang__)) && !defined(__MACH__) +#if (defined(__GNUC__) || defined(__clang__)) && !defined(__APPLE__) #pragma GCC visibility pop #endif diff --git a/src/alloc-posix.c b/src/alloc-posix.c index eef70ab5..43931e56 100644 --- a/src/alloc-posix.c +++ b/src/alloc-posix.c @@ -1,5 +1,5 @@ /* ---------------------------------------------------------------------------- -Copyright (c) 2018,2019, Microsoft Research, Daan Leijen +Copyright (c) 2018-2021, Microsoft Research, Daan Leijen This is free software; you can redistribute it and/or modify it under the terms of the MIT license. A copy of the license can be found in the file "LICENSE" at the root of this distribution. diff --git a/src/alloc.c b/src/alloc.c index 2de26b78..e3052f48 100644 --- a/src/alloc.c +++ b/src/alloc.c @@ -1,5 +1,5 @@ /* ---------------------------------------------------------------------------- -Copyright (c) 2018, Microsoft Research, Daan Leijen +Copyright (c) 2018-2021, Microsoft Research, Daan Leijen This is free software; you can redistribute it and/or modify it under the terms of the MIT license. A copy of the license can be found in the file "LICENSE" at the root of this distribution. diff --git a/src/arena.c b/src/arena.c index fae4ecaa..3f93c590 100644 --- a/src/arena.c +++ b/src/arena.c @@ -1,5 +1,5 @@ /* ---------------------------------------------------------------------------- -Copyright (c) 2019, 2020, Microsoft Research, Daan Leijen +Copyright (c) 2019-2021, Microsoft Research, Daan Leijen This is free software; you can redistribute it and/or modify it under the terms of the MIT license. A copy of the license can be found in the file "LICENSE" at the root of this distribution. diff --git a/src/bitmap.c b/src/bitmap.c index fa1b16c3..50fd4742 100644 --- a/src/bitmap.c +++ b/src/bitmap.c @@ -1,5 +1,5 @@ /* ---------------------------------------------------------------------------- -Copyright (c) 2019,2020 Microsoft Research, Daan Leijen +Copyright (c) 2019-2021 Microsoft Research, Daan Leijen This is free software; you can redistribute it and/or modify it under the terms of the MIT license. A copy of the license can be found in the file "LICENSE" at the root of this distribution. diff --git a/src/bitmap.h b/src/bitmap.h index 51b6a380..aae99279 100644 --- a/src/bitmap.h +++ b/src/bitmap.h @@ -1,5 +1,5 @@ /* ---------------------------------------------------------------------------- -Copyright (c) 2019,2020 Microsoft Research, Daan Leijen +Copyright (c) 2019-2020 Microsoft Research, Daan Leijen This is free software; you can redistribute it and/or modify it under the terms of the MIT license. A copy of the license can be found in the file "LICENSE" at the root of this distribution. diff --git a/src/heap.c b/src/heap.c index 274e6b51..cba0fd06 100644 --- a/src/heap.c +++ b/src/heap.c @@ -1,5 +1,5 @@ /*---------------------------------------------------------------------------- -Copyright (c) 2018, Microsoft Research, Daan Leijen +Copyright (c) 2018-2021, Microsoft Research, Daan Leijen This is free software; you can redistribute it and/or modify it under the terms of the MIT license. A copy of the license can be found in the file "LICENSE" at the root of this distribution. diff --git a/src/init.c b/src/init.c index ecb73d6c..76c20842 100644 --- a/src/init.c +++ b/src/init.c @@ -1,5 +1,5 @@ /* ---------------------------------------------------------------------------- -Copyright (c) 2018, Microsoft Research, Daan Leijen +Copyright (c) 2018-2021, Microsoft Research, Daan Leijen This is free software; you can redistribute it and/or modify it under the terms of the MIT license. A copy of the license can be found in the file "LICENSE" at the root of this distribution. diff --git a/src/options.c b/src/options.c index baa387ad..055f8446 100644 --- a/src/options.c +++ b/src/options.c @@ -1,5 +1,5 @@ /* ---------------------------------------------------------------------------- -Copyright (c) 2018, Microsoft Research, Daan Leijen +Copyright (c) 2018-2021, Microsoft Research, Daan Leijen This is free software; you can redistribute it and/or modify it under the terms of the MIT license. A copy of the license can be found in the file "LICENSE" at the root of this distribution. @@ -262,7 +262,7 @@ static _Atomic(uintptr_t) warning_count; // = 0; // when >= max_warning_count s static mi_decl_thread bool recurse = false; static bool mi_recurse_enter(void) { - #if defined(__MACH__) || defined(MI_TLS_RECURSE_GUARD) + #if defined(__APPLE__) || defined(MI_TLS_RECURSE_GUARD) if (_mi_preloading()) return true; #endif if (recurse) return false; @@ -271,7 +271,7 @@ static bool mi_recurse_enter(void) { } static void mi_recurse_exit(void) { - #if defined(__MACH__) || defined(MI_TLS_RECURSE_GUARD) + #if defined(__APPLE__) || defined(MI_TLS_RECURSE_GUARD) if (_mi_preloading()) return; #endif recurse = false; diff --git a/src/os.c b/src/os.c index df114373..42ed342e 100644 --- a/src/os.c +++ b/src/os.c @@ -1,5 +1,5 @@ /* ---------------------------------------------------------------------------- -Copyright (c) 2018, Microsoft Research, Daan Leijen +Copyright (c) 2018-2021, Microsoft Research, Daan Leijen This is free software; you can redistribute it and/or modify it under the terms of the MIT license. A copy of the license can be found in the file "LICENSE" at the root of this distribution. diff --git a/src/page-queue.c b/src/page-queue.c index c96a3d44..a109df43 100644 --- a/src/page-queue.c +++ b/src/page-queue.c @@ -1,5 +1,5 @@ /*---------------------------------------------------------------------------- -Copyright (c) 2018, Microsoft Research, Daan Leijen +Copyright (c) 2018-2020, Microsoft Research, Daan Leijen This is free software; you can redistribute it and/or modify it under the terms of the MIT license. A copy of the license can be found in the file "LICENSE" at the root of this distribution. diff --git a/src/page.c b/src/page.c index 184d3826..b732c078 100644 --- a/src/page.c +++ b/src/page.c @@ -1,5 +1,5 @@ /*---------------------------------------------------------------------------- -Copyright (c) 2018, Microsoft Research, Daan Leijen +Copyright (c) 2018-2020, Microsoft Research, Daan Leijen This is free software; you can redistribute it and/or modify it under the terms of the MIT license. A copy of the license can be found in the file "LICENSE" at the root of this distribution. diff --git a/src/random.c b/src/random.c index 113ba0fd..255bede4 100644 --- a/src/random.c +++ b/src/random.c @@ -1,5 +1,5 @@ /* ---------------------------------------------------------------------------- -Copyright (c) 2019, Microsoft Research, Daan Leijen +Copyright (c) 2019-2021, Microsoft Research, Daan Leijen This is free software; you can redistribute it and/or modify it under the terms of the MIT license. A copy of the license can be found in the file "LICENSE" at the root of this distribution. diff --git a/src/region.c b/src/region.c index 663859c8..79540730 100644 --- a/src/region.c +++ b/src/region.c @@ -1,5 +1,5 @@ /* ---------------------------------------------------------------------------- -Copyright (c) 2019, Microsoft Research, Daan Leijen +Copyright (c) 2019-2020, Microsoft Research, Daan Leijen This is free software; you can redistribute it and/or modify it under the terms of the MIT license. A copy of the license can be found in the file "LICENSE" at the root of this distribution. diff --git a/src/segment.c b/src/segment.c index acb7c58d..76ce2e0b 100644 --- a/src/segment.c +++ b/src/segment.c @@ -1,5 +1,5 @@ /* ---------------------------------------------------------------------------- -Copyright (c) 2018, Microsoft Research, Daan Leijen +Copyright (c) 2018-2020, Microsoft Research, Daan Leijen This is free software; you can redistribute it and/or modify it under the terms of the MIT license. A copy of the license can be found in the file "LICENSE" at the root of this distribution. diff --git a/src/static.c b/src/static.c index 79c0a033..5b34ddbb 100644 --- a/src/static.c +++ b/src/static.c @@ -1,5 +1,5 @@ /* ---------------------------------------------------------------------------- -Copyright (c) 2018, Microsoft Research, Daan Leijen +Copyright (c) 2018-2020, Microsoft Research, Daan Leijen This is free software; you can redistribute it and/or modify it under the terms of the MIT license. A copy of the license can be found in the file "LICENSE" at the root of this distribution. diff --git a/src/stats.c b/src/stats.c index ab21ec79..ecf07e4d 100644 --- a/src/stats.c +++ b/src/stats.c @@ -1,5 +1,5 @@ /* ---------------------------------------------------------------------------- -Copyright (c) 2018, Microsoft Research, Daan Leijen +Copyright (c) 2018-2021, Microsoft Research, Daan Leijen This is free software; you can redistribute it and/or modify it under the terms of the MIT license. A copy of the license can be found in the file "LICENSE" at the root of this distribution. @@ -479,12 +479,12 @@ static void mi_stat_process_info(mi_msecs_t* elapsed, mi_msecs_t* utime, mi_msec *page_faults = (size_t)info.PageFaultCount; } -#elif defined(__unix__) || defined(__unix) || defined(unix) || (defined(__APPLE__) && defined(__MACH__)) || defined(__HAIKU__) +#elif defined(__unix__) || defined(__unix) || defined(unix) || defined(__APPLE__) || defined(__HAIKU__) #include #include #include -#if defined(__APPLE__) && defined(__MACH__) +#if defined(__APPLE__) #include #endif @@ -520,7 +520,7 @@ static void mi_stat_process_info(mi_msecs_t* elapsed, mi_msecs_t* utime, mi_msec while (get_next_area_info(tid.team, &c, &mem) == B_OK) { *peak_rss += mem.ram_size; } -#elif defined(__APPLE__) && defined(__MACH__) +#elif defined(__APPLE__) *peak_rss = rusage.ru_maxrss; // BSD reports in bytes struct mach_task_basic_info info; mach_msg_type_number_t infoCount = MACH_TASK_BASIC_INFO_COUNT; diff --git a/test/test-api.c b/test/test-api.c index e5827a93..d3344928 100644 --- a/test/test-api.c +++ b/test/test-api.c @@ -1,5 +1,5 @@ /* ---------------------------------------------------------------------------- -Copyright (c) 2018, Microsoft Research, Daan Leijen +Copyright (c) 2018-2020, Microsoft Research, Daan Leijen This is free software; you can redistribute it and/or modify it under the terms of the MIT license. A copy of the license can be found in the file "LICENSE" at the root of this distribution. diff --git a/test/test-stress.c b/test/test-stress.c index fde0c791..9026baad 100644 --- a/test/test-stress.c +++ b/test/test-stress.c @@ -1,5 +1,5 @@ - /* ---------------------------------------------------------------------------- -Copyright (c) 2018,2019 Microsoft Research, Daan Leijen +/* ---------------------------------------------------------------------------- +Copyright (c) 2018-2020 Microsoft Research, Daan Leijen This is free software; you can redistribute it and/or modify it under the terms of the MIT license. -----------------------------------------------------------------------------*/