diff --git a/kotlin-native/runtime/src/alloc/custom/cpp/GCApi.cpp b/kotlin-native/runtime/src/alloc/custom/cpp/GCApi.cpp index 47474412b17..54d83bdef6a 100644 --- a/kotlin-native/runtime/src/alloc/custom/cpp/GCApi.cpp +++ b/kotlin-native/runtime/src/alloc/custom/cpp/GCApi.cpp @@ -7,6 +7,7 @@ #include #include +#include #include #include @@ -77,7 +78,7 @@ bool SweepExtraObject(mm::ExtraObjectData* extraObject, gc::GCHandle::GCSweepExt void* SafeAlloc(uint64_t size) noexcept { if (size > std::numeric_limits::max()) { konan::consoleErrorf("Out of memory trying to allocate %" PRIu64 "bytes. Aborting.\n", size); - konan::abort(); + std::abort(); } void* memory; bool error; @@ -97,7 +98,7 @@ void* SafeAlloc(uint64_t size) noexcept { } if (error) { konan::consoleErrorf("Out of memory trying to allocate %" PRIu64 "bytes: %s. Aborting.\n", size, strerror(errno)); - konan::abort(); + std::abort(); } auto previousSize = allocatedBytesCounter.fetch_add(static_cast(size), std::memory_order_relaxed); OnMemoryAllocation(previousSize + static_cast(size)); diff --git a/kotlin-native/runtime/src/alloc/legacy/cpp/ObjectFactory.hpp b/kotlin-native/runtime/src/alloc/legacy/cpp/ObjectFactory.hpp index 3c4633ca090..7ce81c94f46 100644 --- a/kotlin-native/runtime/src/alloc/legacy/cpp/ObjectFactory.hpp +++ b/kotlin-native/runtime/src/alloc/legacy/cpp/ObjectFactory.hpp @@ -7,6 +7,7 @@ #include #include +#include #include #include #include @@ -105,7 +106,7 @@ public: // TODO: This should throw OutOfMemoryError in the future if we add hard memory limits instead // of limiting at virtual address space boundary. konan::consoleErrorf("Out of memory trying to allocate %" PRIu64 " bytes. Aborting.\n", totalSize); - konan::abort(); + std::abort(); } RuntimeAssert(IsAligned(ptr, DataAlignment), "Allocator returned unaligned to %zu pointer %p", DataAlignment, ptr); return unique_ptr(new (ptr) Node()); diff --git a/kotlin-native/runtime/src/alloc/std/cpp/ObjectAlloc.cpp b/kotlin-native/runtime/src/alloc/std/cpp/ObjectAlloc.cpp index 3b42ea53127..9859209cd69 100644 --- a/kotlin-native/runtime/src/alloc/std/cpp/ObjectAlloc.cpp +++ b/kotlin-native/runtime/src/alloc/std/cpp/ObjectAlloc.cpp @@ -5,34 +5,17 @@ #include "ObjectAlloc.hpp" -#ifndef KONAN_NO_THREADS #include -#endif #include "Memory.h" -#if KONAN_INTERNAL_DLMALLOC -extern "C" void* dlcalloc(size_t, size_t); -extern "C" void dlfree(void*); - -#define callocImpl dlcalloc -#define freeImpl dlfree -#else #include -#define callocImpl ::calloc -#define freeImpl ::free -#endif - using namespace kotlin; namespace { -#ifndef KONAN_NO_THREADS std::atomic allocatedBytesCounter = 0; -#else -size_t allocatedBytesCounter = 0; -#endif } // namespace @@ -40,25 +23,16 @@ void alloc::initObjectPool() noexcept {} void* alloc::allocateInObjectPool(size_t size) noexcept { // TODO: Check that alignment to kObjectAlignment is satisfied. - void* result = callocImpl(1, size); -#ifndef KONAN_NO_THREADS + void* result = ::calloc(1, size); auto newSize = allocatedBytesCounter.fetch_add(size, std::memory_order_relaxed); newSize += size; -#else - allocatedBytesCounter += size; - auto newSize = allocatedBytesCounter; -#endif OnMemoryAllocation(newSize); return result; } void alloc::freeInObjectPool(void* ptr, size_t size) noexcept { -#ifndef KONAN_NO_THREADS allocatedBytesCounter.fetch_sub(size, std::memory_order_relaxed); -#else - allocatedBytesCounter -= size; -#endif - freeImpl(ptr); + ::free(ptr); } void alloc::compactObjectPoolInCurrentThread() noexcept {} @@ -66,9 +40,5 @@ void alloc::compactObjectPoolInCurrentThread() noexcept {} void alloc::compactObjectPoolInMainThread() noexcept {} size_t alloc::allocatedBytes() noexcept { -#ifndef KONAN_NO_THREADS return allocatedBytesCounter.load(); -#else - return allocatedBytesCounter; -#endif } diff --git a/kotlin-native/runtime/src/exceptions_support/cpp/ExceptionsSupport.cpp b/kotlin-native/runtime/src/exceptions_support/cpp/ExceptionsSupport.cpp index 234df5de640..affaaa7f3dd 100644 --- a/kotlin-native/runtime/src/exceptions_support/cpp/ExceptionsSupport.cpp +++ b/kotlin-native/runtime/src/exceptions_support/cpp/ExceptionsSupport.cpp @@ -2,8 +2,6 @@ #include "Porting.h" #include -#ifndef KONAN_NO_EXCEPTIONS - std::type_info const* ExceptionObjHolderRTTI; // Just some DCE-surviving code referencing RTTI of ExceptionObjHolder. @@ -11,5 +9,3 @@ std::type_info const* ExceptionObjHolderRTTI; void referenceExceptionObjHolderRTTI() { ExceptionObjHolderRTTI = &typeid(ExceptionObjHolder); } - -#endif \ No newline at end of file diff --git a/kotlin-native/runtime/src/gc/common/cpp/GCStatistics.cpp b/kotlin-native/runtime/src/gc/common/cpp/GCStatistics.cpp index 3699fc1511a..90914a029dc 100644 --- a/kotlin-native/runtime/src/gc/common/cpp/GCStatistics.cpp +++ b/kotlin-native/runtime/src/gc/common/cpp/GCStatistics.cpp @@ -4,15 +4,16 @@ */ #include "GCStatistics.hpp" -#include "Mutex.hpp" -#include "Porting.h" -#include "Types.h" -#include "Logging.hpp" -#include "ThreadData.hpp" -#include "std_support/Optional.hpp" #include #include +#include + +#include "Logging.hpp" +#include "Mutex.hpp" +#include "Porting.h" +#include "ThreadData.hpp" +#include "Types.h" using namespace kotlin; diff --git a/kotlin-native/runtime/src/gc/common/cpp/GCStatistics.hpp b/kotlin-native/runtime/src/gc/common/cpp/GCStatistics.hpp index 06259a0558f..01c0c6012f0 100644 --- a/kotlin-native/runtime/src/gc/common/cpp/GCStatistics.hpp +++ b/kotlin-native/runtime/src/gc/common/cpp/GCStatistics.hpp @@ -6,13 +6,12 @@ #pragma once #include -#include +#include #include "Common.h" #include "Logging.hpp" #include "Porting.h" #include "Utils.hpp" -#include "std_support/Optional.hpp" #define GCLogInfo(epoch, format, ...) RuntimeLogInfo({kTagGC}, "Epoch #%" PRIu64 ": " format, epoch, ##__VA_ARGS__) #define GCLogDebug(epoch, format, ...) RuntimeLogDebug({kTagGC}, "Epoch #%" PRIu64 ": " format, epoch, ##__VA_ARGS__) diff --git a/kotlin-native/runtime/src/launcher/cpp/launcher.cpp b/kotlin-native/runtime/src/launcher/cpp/launcher.cpp index 54082f6f9e2..62bf032bd91 100644 --- a/kotlin-native/runtime/src/launcher/cpp/launcher.cpp +++ b/kotlin-native/runtime/src/launcher/cpp/launcher.cpp @@ -48,11 +48,6 @@ extern "C" KInt Konan_run_start(int argc, const char** argv) { } extern "C" RUNTIME_USED int Init_and_run_start(int argc, const char** argv, int memoryDeInit) { -#ifdef KONAN_NO_CTORS_SECTION - extern void _Konan_constructors(void); - _Konan_constructors(); -#endif - Kotlin_initRuntimeIfNeeded(); Kotlin_mm_switchThreadStateRunnable(); @@ -72,20 +67,3 @@ extern "C" RUNTIME_USED int Konan_main_standalone(int argc, const char** argv) { #endif return Init_and_run_start(argc, argv, 1); } - -#ifdef KONAN_WASM -// Before we pass control to Konan_main, we need to obtain argv elements -// from the javascript world. -extern "C" int Konan_js_arg_size(int index); -extern "C" int Konan_js_fetch_arg(int index, char* ptr); - -extern "C" RUNTIME_USED int Konan_js_main(int argc, int memoryDeInit) { - char** argv = (char**)std_support::calloc(1, argc); - for (int i = 0; i< argc; ++i) { - argv[i] = (char*)std_support::calloc(1, Konan_js_arg_size(i)); - Konan_js_fetch_arg(i, argv[i]); - } - return Init_and_run_start(argc, (const char**)argv, memoryDeInit); -} - -#endif diff --git a/kotlin-native/runtime/src/main/cpp/Atomic.h b/kotlin-native/runtime/src/main/cpp/Atomic.h index 568cb81b448..ce986c2fdb2 100644 --- a/kotlin-native/runtime/src/main/cpp/Atomic.h +++ b/kotlin-native/runtime/src/main/cpp/Atomic.h @@ -5,16 +5,12 @@ template ALWAYS_INLINE inline T atomicAdd(volatile T* where, T what) { -#ifndef KONAN_NO_THREADS return __sync_add_and_fetch(where, what); -#else - return *where += what; -#endif } #pragma clang diagnostic push -#if (KONAN_ANDROID || KONAN_IOS || KONAN_WATCHOS || KONAN_LINUX) && (KONAN_ARM32 || KONAN_X86 || KONAN_MIPS32 || KONAN_MIPSEL32) +#if (KONAN_ANDROID || KONAN_IOS || KONAN_WATCHOS || KONAN_LINUX) && (KONAN_ARM32 || KONAN_X86) // On 32-bit Android clang generates library calls for "large" atomic operations // and warns about "significant performance penalty". See more details here: // https://github.com/llvm/llvm-project/blob/ce56e1a1cc5714f4af5675dd963cfebed766d9e1/clang/lib/CodeGen/CGAtomic.cpp#L775 @@ -25,20 +21,10 @@ ALWAYS_INLINE inline T atomicAdd(volatile T* where, T what) { // as if (std::atomic where).compare_exchange_strong(expectedValue, newValue) template ALWAYS_INLINE inline bool compareExchange(volatile T& where, T &expectedValue, T newValue) { -#ifndef KONAN_NO_THREADS #ifdef KONAN_NO_64BIT_ATOMIC static_assert(sizeof(T) <= 4); #endif return __atomic_compare_exchange_n(&where, &expectedValue, newValue, false, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST); -#else - T oldValue = where; - if (oldValue == expectedValue) { - where = newValue; - return true; - } - expectedValue = oldValue; - return false; -#endif } template @@ -55,14 +41,10 @@ ALWAYS_INLINE inline bool compareAndSet(volatile T* where, T expectedValue, T ne template ALWAYS_INLINE inline void atomicSet(volatile T* where, T what) { -#ifndef KONAN_NO_THREADS #ifdef KONAN_NO_64BIT_ATOMIC static_assert(sizeof(T) <= 4); #endif __atomic_store(where, &what, model); -#else - *where = what; -#endif } template @@ -73,16 +55,12 @@ ALWAYS_INLINE inline void atomicSetRelease(volatile T* where, T what) { template ALWAYS_INLINE inline T atomicGet(volatile const T* where) { -#ifndef KONAN_NO_THREADS #ifdef KONAN_NO_64BIT_ATOMIC static_assert(sizeof(T) <= 4); #endif T what; __atomic_load(where, &what, model); return what; -#else - return *where; -#endif } template @@ -98,9 +76,7 @@ ALWAYS_INLINE inline T atomicGetRelaxed(volatile const T* where) { #pragma clang diagnostic pop static ALWAYS_INLINE inline void synchronize() { -#ifndef KONAN_NO_THREADS __sync_synchronize(); -#endif } -#endif // RUNTIME_ATOMIC_H \ No newline at end of file +#endif // RUNTIME_ATOMIC_H diff --git a/kotlin-native/runtime/src/main/cpp/Cleaner.cpp b/kotlin-native/runtime/src/main/cpp/Cleaner.cpp index e68936f1500..bb482436d31 100644 --- a/kotlin-native/runtime/src/main/cpp/Cleaner.cpp +++ b/kotlin-native/runtime/src/main/cpp/Cleaner.cpp @@ -51,9 +51,6 @@ void disposeCleaner(CleanerImpl* thiz) { } // namespace RUNTIME_NOTHROW void DisposeCleaner(KRef thiz) { -#if KONAN_NO_EXCEPTIONS - disposeCleaner(reinterpret_cast(thiz)); -#else try { disposeCleaner(reinterpret_cast(thiz)); } catch (...) { @@ -61,7 +58,6 @@ RUNTIME_NOTHROW void DisposeCleaner(KRef thiz) { // and write to iOS crash log. std::terminate(); } -#endif } void ShutdownCleaners(bool executeScheduledCleaners) { diff --git a/kotlin-native/runtime/src/main/cpp/Common.h b/kotlin-native/runtime/src/main/cpp/Common.h index 100ca01c95e..286075f2696 100644 --- a/kotlin-native/runtime/src/main/cpp/Common.h +++ b/kotlin-native/runtime/src/main/cpp/Common.h @@ -40,11 +40,7 @@ #define OPTNONE __attribute__((optnone)) -#if KONAN_NO_THREADS -#define THREAD_LOCAL_VARIABLE -#else #define THREAD_LOCAL_VARIABLE __thread -#endif #define ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0])) diff --git a/kotlin-native/runtime/src/main/cpp/CompilerConstants.hpp b/kotlin-native/runtime/src/main/cpp/CompilerConstants.hpp index d19006d5ea9..82390b552f5 100644 --- a/kotlin-native/runtime/src/main/cpp/CompilerConstants.hpp +++ b/kotlin-native/runtime/src/main/cpp/CompilerConstants.hpp @@ -7,18 +7,7 @@ #define RUNTIME_COMPILER_CONSTANTS_H #include -#if __has_include() #include -#elif __has_include() -// TODO: Remove when wasm32 is gone. -#include -#include -namespace std { -using string_view = std::experimental::string_view; -} -#else -#error "No " -#endif #include "Common.h" diff --git a/kotlin-native/runtime/src/main/cpp/Exceptions.cpp b/kotlin-native/runtime/src/main/cpp/Exceptions.cpp index 01fcd765f43..1fb28088349 100644 --- a/kotlin-native/runtime/src/main/cpp/Exceptions.cpp +++ b/kotlin-native/runtime/src/main/cpp/Exceptions.cpp @@ -13,8 +13,8 @@ * See the License for the specific language governing permissions and * limitations under the License. */ +#include #include -#include #include #include @@ -38,29 +38,19 @@ extern "C" void ReportUnhandledException(KRef exception); void ThrowException(KRef exception) { RuntimeAssert(exception != nullptr && IsInstanceInternal(exception, theThrowableTypeInfo), "Throwing something non-throwable"); -#if KONAN_NO_EXCEPTIONS - PrintThrowable(exception); - RuntimeCheck(false, "Exceptions unsupported"); -#else ExceptionObjHolder::Throw(exception); -#endif } void HandleCurrentExceptionWhenLeavingKotlinCode() { -#if KONAN_NO_EXCEPTIONS - RuntimeCheck(false, "Exceptions unsupported"); -#else try { std::rethrow_exception(std::current_exception()); } catch (ExceptionObjHolder& e) { std::terminate(); // Terminate when it's a kotlin exception. } -#endif } namespace { -#if !KONAN_NO_EXCEPTIONS class { /** * Timeout 5 sec for concurrent (second) terminate attempt to give a chance the first one to finish. @@ -73,7 +63,7 @@ class { if (compareAndSet(&terminatingFlag, 0, 1)) { block(); // block() is supposed to be NORETURN, otherwise go to normal abort() - konan::abort(); + std::abort(); } else { kotlin::NativeOrUnregisteredThreadGuard guard(/* reentrant = */ true); sleep(timeoutSec); @@ -82,48 +72,33 @@ class { _Exit(EXIT_FAILURE); // force exit } } concurrentTerminateWrapper; -#endif void RUNTIME_NORETURN terminateWithUnhandledException(KRef exception) { kotlin::AssertThreadState(kotlin::ThreadState::kRunnable); -#if KONAN_NO_EXCEPTIONS - RuntimeCheck(false, "Exceptions unsupported"); -#else concurrentTerminateWrapper([exception]() { ReportUnhandledException(exception); #if KONAN_REPORT_BACKTRACE_TO_IOS_CRASH_LOG ReportBacktraceToIosCrashLog(exception); #endif - konan::abort(); + std::abort(); }); -#endif } void processUnhandledException(KRef exception) noexcept { kotlin::AssertThreadState(kotlin::ThreadState::kRunnable); -#if KONAN_NO_EXCEPTIONS - terminateWithUnhandledException(exception); -#else try { Kotlin_runUnhandledExceptionHook(exception); } catch (ExceptionObjHolder& e) { terminateWithUnhandledException(e.GetExceptionObject()); } -#endif } } // namespace ALWAYS_INLINE RUNTIME_NOTHROW OBJ_GETTER(Kotlin_getExceptionObject, void* holder) { -#if !KONAN_NO_EXCEPTIONS RETURN_OBJ(static_cast(holder)->GetExceptionObject()); -#else - RETURN_OBJ(nullptr); -#endif } -#if !KONAN_NO_EXCEPTIONS - namespace { // Copy, move and assign would be safe, but not much useful, so let's delete all (rule of 5) class TerminateHandler : private kotlin::Pinned { @@ -191,14 +166,6 @@ void SetKonanTerminateHandler() { TerminateHandler::install(); } -#else // !KONAN_NO_EXCEPTIONS - -void SetKonanTerminateHandler() { - // Nothing to do. -} - -#endif // !KONAN_NO_EXCEPTIONS - extern "C" void RUNTIME_NORETURN Kotlin_terminateWithUnhandledException(KRef exception) { kotlin::AssertThreadState(kotlin::ThreadState::kRunnable); terminateWithUnhandledException(exception); diff --git a/kotlin-native/runtime/src/main/cpp/ExecFormat.cpp b/kotlin-native/runtime/src/main/cpp/ExecFormat.cpp index 7222c0cc706..6997b7587ef 100644 --- a/kotlin-native/runtime/src/main/cpp/ExecFormat.cpp +++ b/kotlin-native/runtime/src/main/cpp/ExecFormat.cpp @@ -14,8 +14,10 @@ * limitations under the License. */ - #include "ExecFormat.h" + +#include + #include "Porting.h" #include "std_support/CStdlib.hpp" #include "std_support/New.hpp" @@ -357,7 +359,7 @@ extern "C" bool AddressToSymbol(const void* address, char* resultBuffer, size_t } else if (info.dli_fname) { result = info.dli_fname; resultOffset = reinterpret_cast(address) - reinterpret_cast(info.dli_fbase); - } else if (0 < konan::snprintf(symbuf, sizeof(symbuf), "%p", info.dli_saddr)) { + } else if (0 < std::snprintf(symbuf, sizeof(symbuf), "%p", info.dli_saddr)) { result = symbuf; resultOffset = reinterpret_cast(address) - reinterpret_cast(info.dli_saddr); } else { diff --git a/kotlin-native/runtime/src/main/cpp/Format.cpp b/kotlin-native/runtime/src/main/cpp/Format.cpp index 587c1129d12..0a996a81de5 100644 --- a/kotlin-native/runtime/src/main/cpp/Format.cpp +++ b/kotlin-native/runtime/src/main/cpp/Format.cpp @@ -5,6 +5,8 @@ #include "Format.h" +#include + #include "Porting.h" using namespace kotlin; @@ -23,7 +25,7 @@ std_support::span kotlin::VFormatToSpan(std_support::span buffer, co buffer.front() = '\0'; return buffer; } - int written = konan::vsnprintf(buffer.data(), buffer.size(), format, args); + int written = std::vsnprintf(buffer.data(), buffer.size(), format, args); // Consider this a failure, nothing has been written. TODO: Should this be an exception/RuntimeAssert? if (written < 0) return buffer; // If `written` is larger than the buffer size, just pretend we filled the entire buffer (ignoring the trailing \0). diff --git a/kotlin-native/runtime/src/main/cpp/IntrusiveList.hpp b/kotlin-native/runtime/src/main/cpp/IntrusiveList.hpp index 9c049b14c8e..8a12a2c9d8b 100644 --- a/kotlin-native/runtime/src/main/cpp/IntrusiveList.hpp +++ b/kotlin-native/runtime/src/main/cpp/IntrusiveList.hpp @@ -8,10 +8,10 @@ #include #include #include +#include #include "KAssert.h" #include "Utils.hpp" -#include "std_support/Optional.hpp" namespace kotlin { diff --git a/kotlin-native/runtime/src/main/cpp/JSInterop.cpp b/kotlin-native/runtime/src/main/cpp/JSInterop.cpp deleted file mode 100644 index 85a37ae4d8d..00000000000 --- a/kotlin-native/runtime/src/main/cpp/JSInterop.cpp +++ /dev/null @@ -1,81 +0,0 @@ -/* - * Copyright 2010-2018 JetBrains s.r.o. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "Porting.h" -#include "Types.h" - -typedef KInt Arena; -typedef KInt Object; -typedef KInt Pointer; - -#ifndef KONAN_WASM - -extern "C" { - -// These functions are implemented in JS file for WASM and are not available on other platforms. -RUNTIME_NORETURN Arena Konan_js_allocateArena() { - RuntimeAssert(false, "JavaScript interop is disabled"); - konan::abort(); -} - -RUNTIME_NORETURN void Konan_js_freeArena(Arena arena) { - RuntimeAssert(false, "JavaScript interop is disabled"); - konan::abort(); -} - -RUNTIME_NORETURN void Konan_js_pushIntToArena(Arena arena, KInt value) { - RuntimeAssert(false, "JavaScript interop is disabled"); - konan::abort(); -} - -RUNTIME_NORETURN KInt Konan_js_getInt(Arena arena, - Object obj, - Pointer propertyPtr, - KInt propertyLen) { - RuntimeAssert(false, "JavaScript interop is disabled"); - konan::abort(); -} - -RUNTIME_NORETURN KInt Konan_js_getProperty(Arena arena, - Object obj, - Pointer propertyPtr, - KInt propertyLen) { - RuntimeAssert(false, "JavaScript interop is disabled"); - konan::abort(); -} - -RUNTIME_NORETURN void Konan_js_setFunction(Arena arena, - Object obj, - Pointer propertyName, - KInt propertyLength, - KInt function) { - RuntimeAssert(false, "JavaScript interop is disabled"); - konan::abort(); -} - -RUNTIME_NORETURN void Konan_js_setString(Arena arena, - Object obj, - Pointer propertyName, - KInt propertyLength, - Pointer stringPtr, - KInt stringLength) { - RuntimeAssert(false, "JavaScript interop is disabled"); - konan::abort(); -} - -}; // extern "C" - -#endif // #ifndef KONAN_WASM diff --git a/kotlin-native/runtime/src/main/cpp/KAssert.cpp b/kotlin-native/runtime/src/main/cpp/KAssert.cpp index 59e026281e4..89d2d2186ef 100644 --- a/kotlin-native/runtime/src/main/cpp/KAssert.cpp +++ b/kotlin-native/runtime/src/main/cpp/KAssert.cpp @@ -7,6 +7,7 @@ #include #include +#include #include "std_support/Span.hpp" #include "CallsChecker.hpp" @@ -72,5 +73,5 @@ RUNTIME_NORETURN void internal::RuntimeAssertFailedPanic(bool allowStacktrace, c va_start(args, format); PrintAssert(allowStacktrace, location, format, args); va_end(args); - konan::abort(); + std::abort(); } diff --git a/kotlin-native/runtime/src/main/cpp/KString.cpp b/kotlin-native/runtime/src/main/cpp/KString.cpp index c0a55541b02..13c0caf894c 100644 --- a/kotlin-native/runtime/src/main/cpp/KString.cpp +++ b/kotlin-native/runtime/src/main/cpp/KString.cpp @@ -14,6 +14,7 @@ * limitations under the License. */ +#include #include #include @@ -40,10 +41,12 @@ typedef KChar* utf8to16(const char*, const char*, KChar*); typedef KStdStringInserter utf16to8(const KChar*,const KChar*, KStdStringInserter); KStdStringInserter utf16toUtf8OrThrow(const KChar* start, const KChar* end, KStdStringInserter result) { - TRY_CATCH(result = utf8::utf16to8(start, end, result), - result = utf8::unchecked::utf16to8(start, end, result), - ThrowCharacterCodingException()); - return result; + try { + result = utf8::utf16to8(start, end, result); + return result; + } catch (...) { + ThrowCharacterCodingException(); + } } template @@ -70,9 +73,11 @@ OBJ_GETTER(unsafeUtf16ToUtf8Impl, KString thiz, KInt start, KInt size) { OBJ_GETTER(utf8ToUtf16OrThrow, const char* rawString, size_t rawStringLength) { const char* end = rawString + rawStringLength; uint32_t charCount; - TRY_CATCH(charCount = utf8::utf16_length(rawString, end), - charCount = utf8::unchecked::utf16_length(rawString, end), - ThrowCharacterCodingException()); + try { + charCount = utf8::utf16_length(rawString, end); + } catch (...) { + ThrowCharacterCodingException(); + } RETURN_RESULT_OF(utf8ToUtf16Impl, rawString, end, charCount); } @@ -307,7 +312,7 @@ KInt Kotlin_StringBuilder_insertInt(KRef builder, KInt position, KInt value) { auto toArray = builder->array(); RuntimeAssert(toArray->count_ >= static_cast(11 + position), "must be true"); char cstring[12]; - auto length = konan::snprintf(cstring, sizeof(cstring), "%d", value); + auto length = std::snprintf(cstring, sizeof(cstring), "%d", value); RuntimeAssert(length >= 0, "This should never happen"); // may be overkill RuntimeAssert(static_cast(length) < sizeof(cstring), "Unexpectedly large value"); // Can't be, but this is what sNprintf for auto* from = &cstring[0]; diff --git a/kotlin-native/runtime/src/main/cpp/KotlinMath.cpp b/kotlin-native/runtime/src/main/cpp/KotlinMath.cpp index 54aa5b1bea1..8f79d9d7d8e 100644 --- a/kotlin-native/runtime/src/main/cpp/KotlinMath.cpp +++ b/kotlin-native/runtime/src/main/cpp/KotlinMath.cpp @@ -20,8 +20,6 @@ #include "DoubleConversions.h" #include "Exceptions.h" -#include "KotlinMath.h" -#include "ReturnSlot.h" #include "Types.h" #if (__MINGW32__ || __MINGW64__) @@ -96,10 +94,6 @@ namespace { extern "C" { -#ifndef KONAN_NO_MATH // We have a platform math library. Call its math functions. - -#ifndef KONAN_WASM // Use libm. - // region Double math. KDouble Kotlin_math_sin(KDouble x) { return sin(x); } @@ -261,332 +255,4 @@ KLong Kotlin_math_absl(KLong x) { return llabs(x); } // endregion -#else // KONAN_WASM defined. Use JS math implementation. - -#define RETURN_RESULT_OF_JS_CALL(call, doubleArg) { \ - call(doubleUpper(doubleArg), doubleLower(doubleArg)); \ - return ReturnSlot_getDouble(); \ -} - -#define RETURN_RESULT_OF_JS_CALL2(call, doubleArg1, doubleArg2) { \ - call(doubleUpper(doubleArg1), \ - doubleLower(doubleArg1), \ - doubleUpper(doubleArg2), \ - doubleLower(doubleArg2)); \ - return ReturnSlot_getDouble(); \ -} - -KDouble Kotlin_math_sin(KDouble x) { RETURN_RESULT_OF_JS_CALL(knjs__Math_sin, x); } -KDouble Kotlin_math_cos(KDouble x) { RETURN_RESULT_OF_JS_CALL(knjs__Math_cos, x); } -KDouble Kotlin_math_tan(KDouble x) { RETURN_RESULT_OF_JS_CALL(knjs__Math_tan, x); } -KDouble Kotlin_math_asin(KDouble x) { RETURN_RESULT_OF_JS_CALL(knjs__Math_asin, x); } -KDouble Kotlin_math_acos(KDouble x) { RETURN_RESULT_OF_JS_CALL(knjs__Math_acos, x); } -KDouble Kotlin_math_atan(KDouble x) { RETURN_RESULT_OF_JS_CALL(knjs__Math_atan, x); } - -KDouble Kotlin_math_sinh(KDouble x) { RETURN_RESULT_OF_JS_CALL(knjs__Math_sinh, x); } -KDouble Kotlin_math_cosh(KDouble x) { RETURN_RESULT_OF_JS_CALL(knjs__Math_cosh, x); } -KDouble Kotlin_math_tanh(KDouble x) { RETURN_RESULT_OF_JS_CALL(knjs__Math_tanh, x); } -KDouble Kotlin_math_asinh(KDouble x) { RETURN_RESULT_OF_JS_CALL(knjs__Math_asinh, x); } -KDouble Kotlin_math_acosh(KDouble x) { RETURN_RESULT_OF_JS_CALL(knjs__Math_acosh, x); } -KDouble Kotlin_math_atanh(KDouble x) { RETURN_RESULT_OF_JS_CALL(knjs__Math_atanh, x); } - -KDouble Kotlin_math_sqrt(KDouble x) { RETURN_RESULT_OF_JS_CALL(knjs__Math_sqrt, x); } -KDouble Kotlin_math_exp(KDouble x) { RETURN_RESULT_OF_JS_CALL(knjs__Math_exp, x); } -KDouble Kotlin_math_expm1(KDouble x) { RETURN_RESULT_OF_JS_CALL(knjs__Math_expm1, x); } - -KDouble Kotlin_math_ln(KDouble x) { RETURN_RESULT_OF_JS_CALL(knjs__Math_log, x); } -KDouble Kotlin_math_log10(KDouble x) { RETURN_RESULT_OF_JS_CALL(knjs__Math_log10, x); } -KDouble Kotlin_math_log2(KDouble x) { RETURN_RESULT_OF_JS_CALL(knjs__Math_log2, x); } -KDouble Kotlin_math_ln1p(KDouble x) { RETURN_RESULT_OF_JS_CALL(knjs__Math_log1p, x); } - -KDouble Kotlin_math_ceil(KDouble x) { RETURN_RESULT_OF_JS_CALL(knjs__Math_ceil, x); } -KDouble Kotlin_math_floor(KDouble x) { RETURN_RESULT_OF_JS_CALL(knjs__Math_floor, x); } - -KDouble Kotlin_math_round(KDouble x) { - if (fmod(x, 0.5) != 0.0) { - RETURN_RESULT_OF_JS_CALL(knjs__Math_round, x); - } - KDouble f = floor(x); - return (fmod(f, 2) == 0.0) ? f : ceil(x); -} - -KDouble Kotlin_math_abs(KDouble x) { RETURN_RESULT_OF_JS_CALL(knjs__Math_abs, x); } - -KDouble Kotlin_math_atan2(KDouble y, KDouble x) { RETURN_RESULT_OF_JS_CALL2(knjs__Math_atan2, y, x); } -KDouble Kotlin_math_hypot(KDouble x, KDouble y) { RETURN_RESULT_OF_JS_CALL2(knjs__Math_hypot, x, y); } - -KDouble Kotlin_math_cbrt(KDouble x) { RETURN_RESULT_OF_JS_CALL(knjs__Math_cbrt, x); } - -// extensions - -KDouble Kotlin_math_Double_pow(KDouble thiz, KDouble x) { RETURN_RESULT_OF_JS_CALL2(knjs__Math_pow, thiz, x); } - -KDouble Kotlin_math_Double_IEEErem(KDouble thiz, KDouble divisor) { - if (isnan(thiz) || isnan(divisor) || isinf(thiz) || divisor == 0.0) { - return NAN; - } - if (!isinf(thiz) && isinf(divisor)) { - return thiz; - } - KDouble rounded = Kotlin_math_round(thiz / divisor); - return thiz - rounded * divisor; -} - -KDouble Kotlin_math_Double_nextUp(KDouble thiz) { - if (isnan(thiz) || thiz == HUGE_VAL) { - return thiz; - } - if (thiz == 0.0) { - return DBL_TRUE_MIN; - } - return bitsToDouble(doubleToBits(thiz) + (thiz > 0 ? 1 : -1)); -} - -KDouble Kotlin_math_Double_nextDown(KDouble thiz) { - if (isnan(thiz) || thiz == -HUGE_VAL) { - return thiz; - } - if (thiz == 0.0) { - return -DBL_TRUE_MIN; - } - return bitsToDouble(doubleToBits(thiz) - (thiz > 0 ? 1 : -1)); -} - -KDouble Kotlin_math_Double_nextTowards(KDouble thiz, KDouble to) { - if (isnan(thiz) || isnan(to)) { - return NAN; - } - if (to > thiz) { - return Kotlin_math_Double_nextUp(thiz); - } - if (to < thiz) { - return Kotlin_math_Double_nextDown(thiz); - } - // thiz == to - return to; -} - -KBoolean Kotlin_math_Double_signBit(KDouble thiz) { - return (doubleToBits(thiz) & (KLong) 1 << 63) != 0; -} - -KDouble Kotlin_math_Double_withSign(KDouble thiz, KDouble sign) { - bool oldSign = Kotlin_math_Double_signBit(thiz); - bool newSign = Kotlin_math_Double_signBit(sign); - return (oldSign == newSign) ? thiz : -thiz; -} - -// endregion - -// region Float math. - -KFloat Kotlin_math_sinf(KFloat x) { return (KFloat)Kotlin_math_sin (x); } -KFloat Kotlin_math_cosf(KFloat x) { return (KFloat)Kotlin_math_cos (x); } -KFloat Kotlin_math_tanf(KFloat x) { return (KFloat)Kotlin_math_tan (x); } -KFloat Kotlin_math_asinf(KFloat x) { return (KFloat)Kotlin_math_asin (x); } -KFloat Kotlin_math_acosf(KFloat x) { return (KFloat)Kotlin_math_acos (x); } -KFloat Kotlin_math_atanf(KFloat x) { return (KFloat)Kotlin_math_atan (x); } - -KFloat Kotlin_math_sinhf(KFloat x) { return (KFloat)Kotlin_math_sinh (x); } -KFloat Kotlin_math_coshf(KFloat x) { return (KFloat)Kotlin_math_cosh (x); } -KFloat Kotlin_math_tanhf(KFloat x) { return (KFloat)Kotlin_math_tanh (x); } -KFloat Kotlin_math_asinhf(KFloat x) { return (KFloat)Kotlin_math_asinh (x); } -KFloat Kotlin_math_acoshf(KFloat x) { return (KFloat)Kotlin_math_acosh (x); } -KFloat Kotlin_math_atanhf(KFloat x) { return (KFloat)Kotlin_math_atanh (x); } - -KFloat Kotlin_math_sqrtf(KFloat x) { return (KFloat)Kotlin_math_sqrt (x); } -KFloat Kotlin_math_expf(KFloat x) { return (KFloat)Kotlin_math_exp (x); } -KFloat Kotlin_math_expm1f(KFloat x) { return (KFloat)Kotlin_math_expm1 (x); } - -KFloat Kotlin_math_lnf(KFloat x) { return (KFloat)Kotlin_math_ln (x); } -KFloat Kotlin_math_log10f(KFloat x) { return (KFloat)Kotlin_math_log10 (x); } -KFloat Kotlin_math_log2f(KFloat x) { return (KFloat)Kotlin_math_log2 (x); } -KFloat Kotlin_math_ln1pf(KFloat x) { return (KFloat)Kotlin_math_ln1p (x); } - -KFloat Kotlin_math_ceilf(KFloat x) { return (KFloat)Kotlin_math_ceil (x); } -KFloat Kotlin_math_floorf(KFloat x) { return (KFloat)Kotlin_math_floor (x); } -KFloat Kotlin_math_roundf(KFloat x) { return (KFloat)Kotlin_math_round (x); } - -KFloat Kotlin_math_absf(KFloat x) { return (KFloat)Kotlin_math_abs (x); } - -KFloat Kotlin_math_atan2f(KFloat y, KFloat x) { return (KFloat)Kotlin_math_atan2(y, x); } -KFloat Kotlin_math_hypotf(KFloat x, KFloat y) { return (KFloat)Kotlin_math_hypot(x, y); } - -KFloat Kotlin_math_cbrtf(KFloat x) { return (KFloat)Kotlin_math_cbrt(x); } - -// extensions - -KFloat Kotlin_math_Float_pow(KFloat thiz, KFloat x) { return (KFloat)Kotlin_math_Double_pow(thiz, x); } - -KFloat Kotlin_math_Float_IEEErem(KFloat thiz, KFloat divisor) { - return (KFloat)Kotlin_math_Double_IEEErem(thiz, divisor); -} - -KFloat Kotlin_math_Float_withSign(KFloat thiz, KFloat sign) { - return (KFloat)Kotlin_math_Double_withSign(thiz, sign); -} - -KFloat Kotlin_math_Float_nextUp(KFloat thiz) { - if (isnan(thiz) || thiz == HUGE_VALF) { - return thiz; - } - if (thiz == 0.0) { - return FLT_TRUE_MIN; - } - return bitsToFloat(floatToBits(thiz) + (thiz > 0 ? 1 : -1)); -} - -KFloat Kotlin_math_Float_nextDown(KFloat thiz) { - if (isnan(thiz) || thiz == -HUGE_VALF) { - return thiz; - } - if (thiz == 0.0) { - return -FLT_TRUE_MIN; - } - return bitsToFloat(floatToBits(thiz) - (thiz > 0 ? 1 : -1)); -} - -KFloat Kotlin_math_Float_nextTowards(KFloat thiz, KFloat to) { - if (isnan(thiz) || isnan(to)) { - return NAN; - } - if (to > thiz) { - return Kotlin_math_Float_nextUp(thiz); - } - if (to < thiz) { - return Kotlin_math_Float_nextDown(thiz); - } - // thiz == to - return to; -} - -KBoolean Kotlin_math_Float_signBit(KFloat thiz) { return Kotlin_math_Double_signBit(thiz); } - -// endregion - -// region Integer math - -KInt Kotlin_math_absi(KInt x) { return (x >= 0) ? x : -x; } -KLong Kotlin_math_absl(KLong x) { return (x >= 0) ? x : -x; } - -#endif // #ifndef KONAN_WASM - -#else // KONAN_NO_MATH defined - we have no patform math library. Throw NotImplementedError from math functions. - -namespace { - -RUNTIME_NORETURN void NotImplemented() { - ThrowNotImplementedError(); -} - -} // namespace - -KDouble Kotlin_math_sin(KDouble x) { NotImplemented(); } -KDouble Kotlin_math_cos(KDouble x) { NotImplemented(); } -KDouble Kotlin_math_tan(KDouble x) { NotImplemented(); } -KDouble Kotlin_math_asin(KDouble x) { NotImplemented(); } -KDouble Kotlin_math_acos(KDouble x) { NotImplemented(); } -KDouble Kotlin_math_atan(KDouble x) { NotImplemented(); } -KDouble Kotlin_math_atan2(KDouble y, KDouble x) { NotImplemented(); } - -KDouble Kotlin_math_sinh(KDouble x) { NotImplemented(); } -KDouble Kotlin_math_cosh(KDouble x) { NotImplemented(); } -KDouble Kotlin_math_tanh(KDouble x) { NotImplemented(); } -KDouble Kotlin_math_asinh(KDouble x) { NotImplemented(); } -KDouble Kotlin_math_acosh(KDouble x) { NotImplemented(); } -KDouble Kotlin_math_atanh(KDouble x) { NotImplemented(); } - -KDouble Kotlin_math_hypot(KDouble x, KDouble y) { NotImplemented(); } -KDouble Kotlin_math_sqrt(KDouble x) { NotImplemented(); } -KDouble Kotlin_math_exp(KDouble x) { NotImplemented(); } -KDouble Kotlin_math_expm1(KDouble x) { NotImplemented(); } - -KDouble Kotlin_math_ln(KDouble x) { NotImplemented(); } -KDouble Kotlin_math_log10(KDouble x) { NotImplemented(); } -KDouble Kotlin_math_log2(KDouble x) { NotImplemented(); } -KDouble Kotlin_math_ln1p(KDouble x) { NotImplemented(); } - -KDouble Kotlin_math_ceil(KDouble x) { NotImplemented(); } -KDouble Kotlin_math_floor(KDouble x) { NotImplemented(); } -KDouble Kotlin_math_round(KDouble x) { NotImplemented(); } - -KDouble Kotlin_math_abs(KDouble x) { NotImplemented(); } - -KDouble Kotlin_math_cbrt(KDouble x) { NotImplemented(); } - -// extensions - -KDouble Kotlin_math_Double_pow(KDouble thiz, KDouble x) { NotImplemented(); } -KDouble Kotlin_math_Double_IEEErem(KDouble thiz, KDouble divisor) { NotImplemented(); } -KDouble Kotlin_math_Double_withSign(KDouble thiz, KDouble sign) { NotImplemented(); } - -KDouble Kotlin_math_Double_nextUp(KDouble thiz) { NotImplemented(); } -KDouble Kotlin_math_Double_nextDown(KDouble thiz) { NotImplemented(); } -KDouble Kotlin_math_Double_nextTowards(KDouble thiz, KDouble to) { NotImplemented(); } - -KBoolean Kotlin_math_Double_signBit(KDouble thiz) { NotImplemented(); } - -// endregion - -// region Float math. - -KFloat Kotlin_math_sinf(KFloat x) { NotImplemented(); } -KFloat Kotlin_math_cosf(KFloat x) { NotImplemented(); } -KFloat Kotlin_math_tanf(KFloat x) { NotImplemented(); } -KFloat Kotlin_math_asinf(KFloat x) { NotImplemented(); } -KFloat Kotlin_math_acosf(KFloat x) { NotImplemented(); } -KFloat Kotlin_math_atanf(KFloat x) { NotImplemented(); } -KFloat Kotlin_math_atan2f(KFloat y, KFloat x) { NotImplemented(); } - -KFloat Kotlin_math_sinhf(KFloat x) { NotImplemented(); } -KFloat Kotlin_math_coshf(KFloat x) { NotImplemented(); } -KFloat Kotlin_math_tanhf(KFloat x) { NotImplemented(); } -KFloat Kotlin_math_asinhf(KFloat x) { NotImplemented(); } -KFloat Kotlin_math_acoshf(KFloat x) { NotImplemented(); } -KFloat Kotlin_math_atanhf(KFloat x) { NotImplemented(); } - -KFloat Kotlin_math_hypotf(KFloat x, KFloat y) { NotImplemented(); } -KFloat Kotlin_math_sqrtf(KFloat x) { NotImplemented(); } -KFloat Kotlin_math_expf(KFloat x) { NotImplemented(); } -KFloat Kotlin_math_expm1f(KFloat x) { NotImplemented(); } - -KFloat Kotlin_math_lnf(KFloat x) { NotImplemented(); } -KFloat Kotlin_math_log10f(KFloat x) { NotImplemented(); } -KFloat Kotlin_math_log2f(KFloat x) { NotImplemented(); } -KFloat Kotlin_math_ln1pf(KFloat x) { NotImplemented(); } - -KFloat Kotlin_math_ceilf(KFloat x) { NotImplemented(); } -KFloat Kotlin_math_floorf(KFloat x) { NotImplemented(); } -KFloat Kotlin_math_roundf(KFloat x) { NotImplemented(); } - -KFloat Kotlin_math_absf(KFloat x) { NotImplemented(); } - -KFloat Kotlin_math_cbrtf(KFloat x) { NotImplemented(); } - -// extensions - -KFloat Kotlin_math_Float_pow(KFloat thiz, KFloat x) { NotImplemented(); } -KFloat Kotlin_math_Float_IEEErem(KFloat thiz, KFloat divisor) { NotImplemented(); } -KFloat Kotlin_math_Float_withSign(KFloat thiz, KFloat sign) { NotImplemented(); } - -KFloat Kotlin_math_Float_nextUp(KFloat thiz) { NotImplemented(); } -KFloat Kotlin_math_Float_nextDown(KFloat thiz) { NotImplemented(); } -KFloat Kotlin_math_Float_nextTowards(KFloat thiz, KFloat to) { NotImplemented(); } - -KBoolean Kotlin_math_Float_signBit(KFloat thiz) { NotImplemented(); } - -// endregion - -// region Integer math - -KInt Kotlin_math_absi(KInt x) { NotImplemented(); } -KInt Kotlin_math_mini(KInt a, KInt b) { NotImplemented(); } -KInt Kotlin_math_maxi(KInt a, KInt b) { NotImplemented(); } - -KLong Kotlin_math_absl(KLong x) { NotImplemented(); } -KLong Kotlin_math_minl(KLong a, KLong b) { NotImplemented(); } -KLong Kotlin_math_maxl(KLong a, KLong b) { NotImplemented(); } - -#endif // #ifndef KONAN_NO_MATH - } // extern "C" diff --git a/kotlin-native/runtime/src/main/cpp/KotlinMath.h b/kotlin-native/runtime/src/main/cpp/KotlinMath.h deleted file mode 100644 index 3662a38f5c3..00000000000 --- a/kotlin-native/runtime/src/main/cpp/KotlinMath.h +++ /dev/null @@ -1,69 +0,0 @@ -/* - * Copyright 2010-2018 JetBrains s.r.o. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef RUNTIME_KOTLINMATH_H -#define RUNTIME_KOTLINMATH_H - -#include "Types.h" - -#ifdef KONAN_WASM - -extern "C" { - -// TODO: consider auto-generating this header file. - -// Bridges for JS math. -void knjs__Math_abs(KInt xUpper, KInt xLower); -void knjs__Math_acos(KInt xUpper, KInt xLower); -void knjs__Math_acosh(KInt xUpper, KInt xLower); -void knjs__Math_asin(KInt xUpper, KInt xLower); -void knjs__Math_asinh(KInt xUpper, KInt xLower); -void knjs__Math_atan(KInt xUpper, KInt xLower); -void knjs__Math_atan2(KInt yUpper, KInt yLower, KInt xUpper, KInt xLower); -void knjs__Math_atanh(KInt xUpper, KInt xLower); -void knjs__Math_cbrt(KInt xUpper, KInt xLower); -void knjs__Math_ceil(KInt xUpper, KInt xLower); -void knjs__Math_clz32(KInt xUpper, KInt xLower); -void knjs__Math_cos(KInt xUpper, KInt xLower); -void knjs__Math_cosh(KInt xUpper, KInt xLower); -void knjs__Math_exp(KInt xUpper, KInt xLower); -void knjs__Math_expm1(KInt xUpper, KInt xLower); -void knjs__Math_floor(KInt xUpper, KInt xLower); -void knjs__Math_fround(KInt xUpper, KInt xLower); -void knjs__Math_log(KInt xUpper, KInt xLower); -void knjs__Math_log1p(KInt xUpper, KInt xLower); -void knjs__Math_log10(KInt xUpper, KInt xLower); -void knjs__Math_log2(KInt xUpper, KInt xLower); -void knjs__Math_round(KInt xUpper, KInt xLower); -void knjs__Math_sign(KInt xUpper, KInt xLower); -void knjs__Math_sin(KInt xUpper, KInt xLower); -void knjs__Math_sinh(KInt xUpper, KInt xLower); -void knjs__Math_sqrt(KInt xUpper, KInt xLower); -void knjs__Math_tan(KInt xUpper, KInt xLower); -void knjs__Math_tanh(KInt xUpper, KInt xLower); -void knjs__Math_trunc(KInt xUpper, KInt xLower); - -void knjs__Math_hypot(KInt xUpper, KInt xLower, KInt yUpper, KInt yLower); -void knjs__Math_max(KInt xUpper, KInt xLower, KInt yUpper, KInt yLower); -void knjs__Math_min(KInt xUpper, KInt xLower, KInt yUpper, KInt yLower); - -void knjs__Math_pow(KInt xUpper, KInt xLower, KInt yUpper, KInt yLower); - -} - -#endif // KONAN_WASM - -#endif // RUNTIME_KOTLINMATH_H diff --git a/kotlin-native/runtime/src/main/cpp/Logging.cpp b/kotlin-native/runtime/src/main/cpp/Logging.cpp index f8530863841..4caceb65e3b 100644 --- a/kotlin-native/runtime/src/main/cpp/Logging.cpp +++ b/kotlin-native/runtime/src/main/cpp/Logging.cpp @@ -7,6 +7,7 @@ #include #include +#include #include "CallsChecker.hpp" #include "Format.h" @@ -14,7 +15,6 @@ #include "Porting.h" #include "std_support/Map.hpp" #include "std_support/String.hpp" -#include "std_support/Optional.hpp" using namespace kotlin; diff --git a/kotlin-native/runtime/src/main/cpp/Logging.hpp b/kotlin-native/runtime/src/main/cpp/Logging.hpp index dfeef0d2983..e2bfb9788be 100644 --- a/kotlin-native/runtime/src/main/cpp/Logging.hpp +++ b/kotlin-native/runtime/src/main/cpp/Logging.hpp @@ -8,18 +8,7 @@ #include #include -#if __has_include() #include -#elif __has_include() -// TODO: Remove when wasm32 is gone. -#include -#include -namespace std { -using string_view = std::experimental::string_view; -} -#else -#error "No " -#endif #include "Clock.hpp" #include "CompilerConstants.hpp" diff --git a/kotlin-native/runtime/src/main/cpp/Memory.h b/kotlin-native/runtime/src/main/cpp/Memory.h index 328ad10eea3..ee2c1132277 100644 --- a/kotlin-native/runtime/src/main/cpp/Memory.h +++ b/kotlin-native/runtime/src/main/cpp/Memory.h @@ -77,11 +77,7 @@ struct ObjHeader { * Hardware guaranties on many supported platforms doesn't allow this to happen. */ const TypeInfo* type_info() const { -#ifdef KONAN_TARGET_HAS_ADDRESS_DEPENDENCY return atomicGetRelaxed(&clearPointerBits(typeInfoOrMetaRelaxed(), OBJECT_TAG_MASK)->typeInfo_); -#else - return atomicGetRelaxed(&clearPointerBits(typeInfoOrMetaAcquire(), OBJECT_TAG_MASK)->typeInfo_); -#endif } bool has_meta_object() const { @@ -145,7 +141,6 @@ struct ArrayHeader { }; static_assert(alignof(ArrayHeader) <= kotlin::kObjectAlignment); -#ifndef KONAN_WASM namespace kotlin { struct ObjectBody; @@ -197,7 +192,6 @@ struct type_layout::descriptor { }; } // namespace kotlin -#endif ALWAYS_INLINE bool isPermanentOrFrozen(const ObjHeader* obj); ALWAYS_INLINE bool isShareable(const ObjHeader* obj); @@ -461,11 +455,9 @@ class ObjHolder { class ExceptionObjHolder { public: -#if !KONAN_NO_EXCEPTIONS static void Throw(ObjHeader* exception) RUNTIME_NORETURN; ObjHeader* GetExceptionObject() noexcept; -#endif // Exceptions are not on a hot path, so having virtual dispatch is fine. virtual ~ExceptionObjHolder() = default; diff --git a/kotlin-native/runtime/src/main/cpp/Natives.cpp b/kotlin-native/runtime/src/main/cpp/Natives.cpp index dbea80ff3cc..9b6d7e68c62 100644 --- a/kotlin-native/runtime/src/main/cpp/Natives.cpp +++ b/kotlin-native/runtime/src/main/cpp/Natives.cpp @@ -104,7 +104,7 @@ void Kotlin_interop_free(void* ptr) { } void Kotlin_system_exitProcess(KInt status) { - konan::exit(status); + std::exit(status); } const void* Kotlin_Any_getTypeInfo(KConstRef obj) { diff --git a/kotlin-native/runtime/src/main/cpp/Porting.cpp b/kotlin-native/runtime/src/main/cpp/Porting.cpp index 0b908641908..a95f02d2d71 100644 --- a/kotlin-native/runtime/src/main/cpp/Porting.cpp +++ b/kotlin-native/runtime/src/main/cpp/Porting.cpp @@ -17,14 +17,12 @@ #ifdef KONAN_ANDROID #include #endif +#include #include #include #include -#include #include -#if !KONAN_NO_THREADS #include -#endif #include #if KONAN_WINDOWS #include @@ -40,15 +38,6 @@ using namespace kotlin; -#if KONAN_WASM || KONAN_ZEPHYR -extern "C" RUNTIME_NORETURN void Konan_abort(const char*); -extern "C" RUNTIME_NORETURN void Konan_exit(int32_t status); -#endif -#ifdef KONAN_ZEPHYR -// In Zephyr's Newlib strnlen(3) is not included from string.h by default. -extern "C" size_t strnlen(const char* buffer, size_t maxSize); -#endif - namespace konan { // Console operations. @@ -104,9 +93,7 @@ int getLastErrorMessage(char* message, uint32_t size) { #endif int32_t consoleReadUtf8(void* utf8, uint32_t maxSizeBytes) { -#ifdef KONAN_ZEPHYR - return 0; -#elif KONAN_WINDOWS +#if KONAN_WINDOWS auto length = 0; void *stdInHandle = ::GetStdHandle(STD_INPUT_HANDLE); if (::GetFileType(stdInHandle) == FILE_TYPE_CHAR) { @@ -153,18 +140,11 @@ int32_t consoleReadUtf8(void* utf8, uint32_t maxSizeBytes) { return length; } -#if KONAN_INTERNAL_SNPRINTF -extern "C" int rpl_vsnprintf(char *, size_t, const char *, va_list); -#define vsnprintf_impl rpl_vsnprintf -#else -#define vsnprintf_impl ::vsnprintf -#endif - NO_EXTERNAL_CALLS_CHECK void consolePrintf(const char* format, ...) { char buffer[1024]; va_list args; va_start(args, format); - int rv = vsnprintf_impl(buffer, sizeof(buffer), format, args); + int rv = std::vsnprintf(buffer, sizeof(buffer), format, args); if (rv < 0) return; // TODO: this may be too much exotic, but should i try to print itoa(error) and terminate? if (static_cast(rv) >= sizeof(buffer)) rv = sizeof(buffer) - 1; // TODO: Consider realloc or report truncating. va_end(args); @@ -176,7 +156,7 @@ NO_EXTERNAL_CALLS_CHECK void consoleErrorf(const char* format, ...) { char buffer[1024]; va_list args; va_start(args, format); - int rv = vsnprintf_impl(buffer, sizeof(buffer), format, args); + int rv = std::vsnprintf(buffer, sizeof(buffer), format, args); if (rv < 0) return; // TODO: this may be too much exotic, but should i try to print itoa(error) and terminate? if (static_cast(rv) >= sizeof(buffer)) rv = sizeof(buffer) - 1; // TODO: Consider realloc or report truncating. va_end(args); @@ -188,9 +168,6 @@ void consoleFlush() { ::fflush(stderr); } -// Thread execution. -#if !KONAN_NO_THREADS - pthread_key_t terminationKey; pthread_once_t terminationKeyOnceControl = PTHREAD_ONCE_INIT; @@ -233,16 +210,7 @@ static void onThreadExitInit() { pthread_key_create(&terminationKey, onThreadExitCallback); } -#endif // !KONAN_NO_THREADS - void onThreadExit(void (*destructor)(void*), void* destructorParameter) { -#if KONAN_NO_THREADS -#if KONAN_WASM || KONAN_ZEPHYR - // No way to do that. -#else -#error "How to do onThreadExit()?" -#endif -#else // !KONAN_NO_THREADS // We cannot use pthread_cleanup_push() as it is lexical scope bound. pthread_once(&terminationKeyOnceControl, onThreadExitInit); DestructorRecord* destructorRecord = (DestructorRecord*)std_support::calloc(1, sizeof(DestructorRecord)); @@ -251,7 +219,6 @@ void onThreadExit(void (*destructor)(void*), void* destructorParameter) { destructorRecord->next = reinterpret_cast(pthread_getspecific(terminationKey)); pthread_setspecific(terminationKey, destructorRecord); -#endif // !KONAN_NO_THREADS } #if KONAN_LINUX @@ -268,14 +235,6 @@ NO_EXTERNAL_CALLS_CHECK NO_INLINE int gettid() { #endif NO_EXTERNAL_CALLS_CHECK int currentThreadId() { -#if KONAN_NO_THREADS -#if KONAN_WASM || KONAN_ZEPHYR - // No way to do that. - return 0; -#else -#error "How to find currentThreadId()?" -#endif -#else // !KONAN_NO_THREADS #if defined(KONAN_OSX) or defined(KONAN_IOS) or defined(KONAN_TVOS) or defined(KONAN_WATCHOS) uint64_t tid; pthread_t self = pthread_self(); @@ -291,24 +250,8 @@ NO_EXTERNAL_CALLS_CHECK int currentThreadId() { #else #error "How to find currentThreadId()?" #endif -#endif // !KONAN_NO_THREADS } -// Process execution. -void abort(void) { - ::abort(); -} - -#if KONAN_WASM || KONAN_ZEPHYR -void exit(int32_t status) { - Konan_exit(status); -} -#else -void exit(int32_t status) { - ::exit(status); -} -#endif - // String/byte operations. // memcpy/memmove are not here intentionally, as frequently implemented/optimized // by C compiler. @@ -325,49 +268,6 @@ void* memmem(const void *big, size_t bigLen, const void *little, size_t littleLe } -// The sprintf family. -int snprintf(char* buffer, size_t size, const char* format, ...) { - va_list args; - va_start(args, format); - int rv = vsnprintf(buffer, size, format, args); - va_end(args); - return rv; -} - -int vsnprintf(char* buffer, size_t size, const char* format, va_list args) { - return vsnprintf_impl(buffer, size, format, args); -} - -size_t strnlen(const char* buffer, size_t maxSize) { - return ::strnlen(buffer, maxSize); -} - -#if KONAN_INTERNAL_NOW - -#ifdef KONAN_ZEPHYR -void Konan_date_now(uint64_t* arg) { - // TODO: so how will we support time for embedded? - *arg = 0LL; -} -#else -extern "C" void Konan_date_now(uint64_t*); -#endif - -uint64_t getTimeMillis() { - uint64_t now; - Konan_date_now(&now); - return now; -} - -uint64_t getTimeMicros() { - return getTimeMillis() * 1000ULL; -} - -uint64_t getTimeNanos() { - return getTimeMillis() * 1000000ULL; -} - -#else // Time operations. using namespace std::chrono; @@ -385,156 +285,5 @@ uint64_t getTimeNanos() { uint64_t getTimeMicros() { return duration_cast(steady_time_clock::now().time_since_epoch()).count(); } -#endif } // namespace konan - -extern "C" { -// TODO: get rid of these. -#if (KONAN_WASM || KONAN_ZEPHYR) - void _ZNKSt3__120__vector_base_commonILb1EE20__throw_length_errorEv(void) { - Konan_abort("TODO: throw_length_error not implemented."); - } - void _ZNKSt3__220__vector_base_commonILb1EE20__throw_length_errorEv(void) { - Konan_abort("TODO: throw_length_error not implemented."); - } - void _ZNKSt3__121__basic_string_commonILb1EE20__throw_length_errorEv(void) { - Konan_abort("TODO: throw_length_error not implemented."); - } - void _ZNKSt3__221__basic_string_commonILb1EE20__throw_length_errorEv(void) { - Konan_abort("TODO: throw_length_error not implemented."); - } - int _ZNSt3__212__next_primeEj(unsigned long n) { - static unsigned long primes[] = { - 11UL, - 101UL, - 1009UL, - 10007UL, - 100003UL, - 1000003UL, - 10000019UL, - 100000007UL, - 1000000007UL - }; - size_t table_length = sizeof(primes)/sizeof(unsigned long); - - if (n > primes[table_length - 1]) konan::abort(); - - unsigned long prime = primes[0]; - for (unsigned long i=0; i< table_length; i++) { - prime = primes[i]; - if (prime >= n) break; - } - return prime; - } - - int _ZNSt3__212__next_primeEm(int n) { - return _ZNSt3__212__next_primeEj(n); - } - - int _ZNSt3__112__next_primeEj(unsigned long n) { - return _ZNSt3__212__next_primeEj(n); - } - void __assert_fail(const char* assertion, const char* file, int line, const char* function) { - char buf[1024]; - konan::snprintf(buf, sizeof(buf), "%s:%d in %s: runtime assert: %s\n", file, line, function, assertion); - Konan_abort(buf); - } - int* __errno_location() { - static int theErrno = 0; - return &theErrno; - } - - // Some math.h functions. - - double pow(double x, double y) { - return __builtin_pow(x, y); - } -#endif - -#ifdef KONAN_WASM - // Some string.h functions. - void *memcpy(void *dst, const void *src, size_t n) { - for (size_t i = 0; i != n; ++i) - *((char*)dst + i) = *((char*)src + i); - return dst; - } - - void *memmove(void *dst, const void *src, size_t len) { - if (src < dst) { - for (long i = len; i != 0; --i) { - *((char*)dst + i - 1) = *((char*)src + i - 1); - } - } else { - memcpy(dst, src, len); - } - return dst; - } - - int memcmp(const void *s1, const void *s2, size_t n) { - for (size_t i = 0; i != n; ++i) { - if (*((char*)s1 + i) != *((char*)s2 + i)) { - return *((char*)s1 + i) - *((char*)s2 + i); - } - } - return 0; - } - - void *memset(void *b, int c, size_t len) { - for (size_t i = 0; i != len; ++i) { - *((char*)b + i) = c; - } - return b; - } - - size_t strlen(const char *s) { - for (long i = 0;; ++i) { - if (s[i] == 0) return i; - } - } - - size_t strnlen(const char *s, size_t maxlen) { - for (size_t i = 0; i<=maxlen; ++i) { - if (s[i] == 0) return i; - } - return maxlen; - } -#endif - -#ifdef KONAN_ZEPHYR - RUNTIME_USED void Konan_abort(const char*) { - while(1) {} - } -#endif // KONAN_ZEPHYR - -#if defined(KONAN_MIPS32) || defined(KONAN_MIPSEL32) - -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Watomic-alignment" - -// By some reasons clang generates __sync functions instead of __atomic ones, -// but they are not actually available on mips. So let's implement them ourselfs using existing __atomic ones. - - -int64_t replace_sync_fetch_and_add_8(int64_t *ptr, int64_t value) asm("__sync_fetch_and_add_8"); -RUNTIME_USED int64_t replace_sync_fetch_and_add_8(int64_t *ptr, int64_t value) { - return __atomic_fetch_add(ptr, value, __ATOMIC_SEQ_CST); -} -int64_t replace_sync_val_compare_and_swap(int64_t *ptr, int64_t oldval, int64_t newval) asm("__sync_val_compare_and_swap_8"); -RUNTIME_USED int64_t replace_sync_val_compare_and_swap (int64_t *ptr, int64_t oldval, int64_t newval) { - __atomic_compare_exchange_n(ptr, &oldval, newval, false, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST); - return oldval; -} - -int64_t replace_sync_lock_test_and_set(int64_t *ptr, int64_t value) asm("__sync_lock_test_and_set_8"); -RUNTIME_USED int64_t replace_sync_lock_test_and_set(int64_t *ptr, int64_t value) { - return __atomic_exchange_n(ptr, value, __ATOMIC_SEQ_CST); -} - - -#pragma clang diagnostic pop - -#endif - - -} // extern "C" diff --git a/kotlin-native/runtime/src/main/cpp/Porting.h b/kotlin-native/runtime/src/main/cpp/Porting.h index e20fda1222b..ba79907505c 100644 --- a/kotlin-native/runtime/src/main/cpp/Porting.h +++ b/kotlin-native/runtime/src/main/cpp/Porting.h @@ -35,10 +35,6 @@ void consoleErrorUtf8(const char* utf8, uint32_t sizeBytes); int32_t consoleReadUtf8(void* utf8, uint32_t maxSizeBytes); void consoleFlush(); -// Process control. -RUNTIME_NORETURN void abort(void); -RUNTIME_NORETURN void exit(int32_t status); - // Thread control. void onThreadExit(void (*destructor)(void*), void* destructorParameter); bool isOnThreadExitNotSetOrAlreadyStarted(); @@ -48,52 +44,12 @@ int currentThreadId(); // memcpy/memmove/memcmp are not here intentionally, as frequently implemented/optimized // by C compiler. void* memmem(const void *big, size_t bigLen, const void *little, size_t littleLen); -int snprintf(char* buffer, size_t size, const char* format, ...) __attribute__((format(printf, 3, 4))); -int vsnprintf(char* buffer, size_t size, const char* format, va_list args) __attribute__((format(printf, 3, 0))); -size_t strnlen(const char* buffer, size_t maxSize); - - -// These functions should be marked with RUNTIME_USED attribute for wasm target -// because clang replaces these operations with intrinsics that will be -// replaced back to library calls only on codegen step. And there is no stdlib -// for wasm target for now :( -// Otherwise `opt` will see no usages of these definitions and will remove them. -extern "C" { -#ifdef KONAN_WASM - -RUNTIME_USED -double pow(double x, double y); - -RUNTIME_USED -void *memcpy(void *dst, const void *src, size_t n); - -RUNTIME_USED -void *memmove(void *dst, const void *src, size_t len); - -RUNTIME_USED -int memcmp(const void *s1, const void *s2, size_t n); - -RUNTIME_USED -void *memset(void *b, int c, size_t len); - -#endif -} // Time operations. uint64_t getTimeMillis(); uint64_t getTimeMicros(); uint64_t getTimeNanos(); -#if KONAN_NO_EXCEPTIONS -#define TRY_CATCH(tryAction, actionWithoutExceptions, catchAction) actionWithoutExceptions; -#else -#define TRY_CATCH(tryAction, actionWithoutExceptions, catchAction) \ -do { \ - try { tryAction; } \ - catch(...) { catchAction; } \ -} while(0) -#endif - } // namespace konan #endif // RUNTIME_PORTING_H diff --git a/kotlin-native/runtime/src/main/cpp/RepeatedTimer.hpp b/kotlin-native/runtime/src/main/cpp/RepeatedTimer.hpp index 2fc8b3896d7..fe1b000de76 100644 --- a/kotlin-native/runtime/src/main/cpp/RepeatedTimer.hpp +++ b/kotlin-native/runtime/src/main/cpp/RepeatedTimer.hpp @@ -5,8 +5,6 @@ #pragma once -#ifndef KONAN_NO_THREADS - #include #include #include @@ -80,5 +78,3 @@ private: }; } // namespace kotlin - -#endif // !KONAN_NO_THREADS diff --git a/kotlin-native/runtime/src/main/cpp/ReturnSlot.cpp b/kotlin-native/runtime/src/main/cpp/ReturnSlot.cpp deleted file mode 100644 index 2c5ac47787e..00000000000 --- a/kotlin-native/runtime/src/main/cpp/ReturnSlot.cpp +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Copyright 2010-2017 JetBrains s.r.o. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "ReturnSlot.h" - -#ifdef KONAN_WASM -namespace { - -THREAD_LOCAL_VARIABLE long long storage; - -} // namespace - -extern "C" { - -RUNTIME_USED -KDouble ReturnSlot_getDouble() { - return *reinterpret_cast(&::storage); -} - -RUNTIME_USED -void ReturnSlot_setDouble(KInt upper, KInt lower) { - reinterpret_cast(&::storage)[0] = lower; - reinterpret_cast(&::storage)[1] = upper; -} - -} // extern "C" -#endif // KONAN_WASM diff --git a/kotlin-native/runtime/src/main/cpp/ReturnSlot.h b/kotlin-native/runtime/src/main/cpp/ReturnSlot.h deleted file mode 100644 index 547c84a0ef1..00000000000 --- a/kotlin-native/runtime/src/main/cpp/ReturnSlot.h +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Copyright 2010-2017 JetBrains s.r.o. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "Types.h" - -#ifdef KONAN_WASM - -#ifdef __cplusplus -extern "C" { -#endif - -KDouble ReturnSlot_getDouble(); -void ReturnSlot_setDouble(KInt upper, KInt lower); - -#ifdef __cplusplus -} // extern "C" -#endif - -#endif // KONAN_WASM diff --git a/kotlin-native/runtime/src/main/cpp/Runtime.cpp b/kotlin-native/runtime/src/main/cpp/Runtime.cpp index a181f737ccc..c42d0dd2473 100644 --- a/kotlin-native/runtime/src/main/cpp/Runtime.cpp +++ b/kotlin-native/runtime/src/main/cpp/Runtime.cpp @@ -18,10 +18,8 @@ #include "KString.h" #include "std_support/New.hpp" #include - -#ifndef KONAN_NO_THREADS +#include #include -#endif using namespace kotlin; @@ -107,7 +105,7 @@ RuntimeState* initRuntime() { firstRuntime = atomicAdd(&aliveRuntimesCount, 1) == 1; if (!kotlin::kSupportsMultipleMutators && !firstRuntime) { konan::consoleErrorf("This GC implementation does not support multiple mutator threads."); - konan::abort(); + std::abort(); } break; case kotlin::compiler::DestroyRuntimeMode::kOnShutdown: @@ -121,7 +119,7 @@ RuntimeState* initRuntime() { firstRuntime = lastStatus == kGlobalRuntimeUninitialized; if (!kotlin::kSupportsMultipleMutators && !firstRuntime) { konan::consoleErrorf("This GC implementation does not support multiple mutator threads."); - konan::abort(); + std::abort(); } result->memoryState = InitMemory(firstRuntime); // Switch thread state because worker and globals inits require the runnable state. @@ -277,7 +275,7 @@ void Kotlin_shutdownRuntime() { if (Kotlin_forceCheckedShutdown()) { if (otherRuntimesCount > 0) { konan::consoleErrorf("Cannot run checkers when there are %d alive runtimes at the shutdown", otherRuntimesCount); - konan::abort(); + std::abort(); } } else { // Cannot destroy runtime globally if there're some other threads with Kotlin runtime on them. @@ -315,8 +313,6 @@ KInt Konan_Platform_getOsFamily() { return 4; #elif KONAN_ANDROID return 5; -#elif KONAN_WASM - return 6; #elif KONAN_TVOS return 7; #elif KONAN_WATCHOS @@ -336,12 +332,6 @@ KInt Konan_Platform_getCpuArchitecture() { return 3; #elif KONAN_X64 return 4; -#elif KONAN_MIPS32 - return 5; -#elif KONAN_MIPSEL32 - return 6; -#elif KONAN_WASM - return 7; #else #warning "Unknown CPU" return 0; @@ -369,9 +359,6 @@ KBoolean Konan_Platform_getMemoryLeakChecker() { } KInt Konan_Platform_getAvailableProcessors() { -#ifdef KONAN_NO_THREADS - return 1; -#else auto res = std::thread::hardware_concurrency(); // C++ standard says that if this function can return 0 if value is not "well defined or not computable" // In current libstdc++ implementation, seems it can happen only on unsupported targets. @@ -384,7 +371,6 @@ KInt Konan_Platform_getAvailableProcessors() { res = std::numeric_limits::max(); } return static_cast(res); -#endif } OBJ_GETTER0(Konan_Platform_getAvailableProcessorsEnv) { @@ -484,9 +470,6 @@ NO_INLINE void CallInitGlobalPossiblyLock(int* state, void (*init)()) { } if (compareAndSwap(state, FILE_NOT_INITIALIZED, FILE_BEING_INITIALIZED | (threadId << 2)) == FILE_NOT_INITIALIZED) { // actual initialization -#if KONAN_NO_EXCEPTIONS - init(); -#else try { CurrentFrameGuard guard; init(); @@ -496,7 +479,6 @@ NO_INLINE void CallInitGlobalPossiblyLock(int* state, void (*init)()) { atomicSetRelease(state, FILE_FAILED_TO_INITIALIZE); ThrowFileFailedToInitializeException(exception); } -#endif atomicSetRelease(state, FILE_INITIALIZED); } else { CallInitGlobalAwaitInitialized(state); @@ -507,9 +489,6 @@ void CallInitThreadLocal(int volatile* globalState, int* localState, void (*init if (*localState == FILE_FAILED_TO_INITIALIZE || (globalState != nullptr && *globalState == FILE_FAILED_TO_INITIALIZE)) ThrowFileFailedToInitializeException(nullptr); *localState = FILE_INITIALIZED; -#if KONAN_NO_EXCEPTIONS - init(); -#else try { CurrentFrameGuard guard; init(); @@ -519,7 +498,6 @@ void CallInitThreadLocal(int volatile* globalState, int* localState, void (*init *localState = FILE_FAILED_TO_INITIALIZE; ThrowFileFailedToInitializeException(exception); } -#endif } } // extern "C" diff --git a/kotlin-native/runtime/src/main/cpp/ScopedThread.cpp b/kotlin-native/runtime/src/main/cpp/ScopedThread.cpp index f0fe0baa622..5903cf3dfa0 100644 --- a/kotlin-native/runtime/src/main/cpp/ScopedThread.cpp +++ b/kotlin-native/runtime/src/main/cpp/ScopedThread.cpp @@ -3,8 +3,6 @@ * that can be found in the LICENSE file. */ -#ifndef KONAN_NO_THREADS - #include "ScopedThread.hpp" #include @@ -28,5 +26,3 @@ void internal::setCurrentThreadName(std::string_view name) noexcept { } #endif } - -#endif // !KONAN_NO_THREADS diff --git a/kotlin-native/runtime/src/main/cpp/ScopedThread.hpp b/kotlin-native/runtime/src/main/cpp/ScopedThread.hpp index 8a8347c1233..90700269d27 100644 --- a/kotlin-native/runtime/src/main/cpp/ScopedThread.hpp +++ b/kotlin-native/runtime/src/main/cpp/ScopedThread.hpp @@ -5,8 +5,6 @@ #pragma once -#ifndef KONAN_NO_THREADS - #include #include #include @@ -97,5 +95,3 @@ private: }; } // namespace kotlin - -#endif // !KONAN_NO_THREADS diff --git a/kotlin-native/runtime/src/main/cpp/StackTrace.cpp b/kotlin-native/runtime/src/main/cpp/StackTrace.cpp index afc4a06f5c9..faf6d079a56 100644 --- a/kotlin-native/runtime/src/main/cpp/StackTrace.cpp +++ b/kotlin-native/runtime/src/main/cpp/StackTrace.cpp @@ -5,9 +5,7 @@ #include "StackTrace.hpp" -#if KONAN_NO_BACKTRACE -// Nothing to include -#elif USE_GCC_UNWIND +#if USE_GCC_UNWIND // GCC unwinder for backtrace. #include #if __MINGW64__ @@ -118,21 +116,15 @@ NO_INLINE size_t winAPIUnwind(size_t skipCount, std_support::span result) THREAD_LOCAL_VARIABLE bool disallowSourceInfo = false; -#if !KONAN_NO_BACKTRACE int getSourceInfo(void* symbol, SourceInfo *result, int result_len) { return disallowSourceInfo ? 0 : compiler::getSourceInfo(symbol, result, result_len); } -#endif } // namespace // TODO: this implementation is just a hack, e.g. the result is inexact; // however it is better to have an inexact stacktrace than not to have any. NO_INLINE std_support::vector kotlin::internal::GetCurrentStackTrace(size_t skipFrames) noexcept { -#if KONAN_NO_BACKTRACE - return {}; -#else - // Skip GetCurrentStackTrace + anything asked by the caller. const size_t kSkipFrames = 1 + skipFrames; @@ -167,16 +159,11 @@ NO_INLINE std_support::vector kotlin::internal::GetCurrentStackTrace(size result.erase(result.begin(), std::next(result.begin(), kSkipFrames)); return result; #endif // !USE_GCC_UNWIND -#endif // !KONAN_NO_BACKTRACE } // TODO: this implementation is just a hack, e.g. the result is inexact; // however it is better to have an inexact stacktrace than not to have any. NO_INLINE size_t kotlin::internal::GetCurrentStackTrace(size_t skipFrames, std_support::span buffer) noexcept { -#if KONAN_NO_BACKTRACE - return {}; -#else - // Skip GetCurrentStackTrace + anything asked by the caller. const size_t kSkipFrames = 1 + skipFrames; @@ -197,10 +184,8 @@ NO_INLINE size_t kotlin::internal::GetCurrentStackTrace(size_t skipFrames, std_s std::copy_n(std::begin(tmpBuffer) + kSkipFrames, elementsCount, std::begin(buffer)); return elementsCount; #endif // !USE_GCC_UNWIND -#endif // !KONAN_NO_BACKTRACE } -#if ! KONAN_NO_BACKTRACE #include #include #include "std_support/Span.hpp" @@ -245,7 +230,6 @@ static size_t snprintf_with_addr(char* buf, size_t size, size_t frame, const voi va_end(args); return size - buffer.size(); } -#endif // ! KONAN_NO_BACKTRACE /* @@ -274,11 +258,6 @@ KNativePtr adjustAddressForSourceInfo(KNativePtr address) { return address; } #endif std_support::vector kotlin::GetStackTraceStrings(std_support::span stackTrace) noexcept { -#if KONAN_NO_BACKTRACE - std_support::vector strings; - strings.push_back(""); - return strings; -#else size_t size = stackTrace.size(); std_support::vector strings; strings.reserve(size); @@ -329,7 +308,6 @@ std_support::vector kotlin::GetStackTraceStrings(std_suppor } } return strings; -#endif // !KONAN_NO_BACKTRACE } void kotlin::DisallowSourceInfo() { diff --git a/kotlin-native/runtime/src/main/cpp/StackTrace.hpp b/kotlin-native/runtime/src/main/cpp/StackTrace.hpp index 88c35966b6b..a0a58e0b695 100644 --- a/kotlin-native/runtime/src/main/cpp/StackTrace.hpp +++ b/kotlin-native/runtime/src/main/cpp/StackTrace.hpp @@ -24,9 +24,7 @@ enum class StackTraceCapacityKind { template constexpr size_t GetMaxStackTraceDepth() noexcept { -#if KONAN_NO_BACKTRACE - return 0; -#elif USE_GCC_UNWIND +#if USE_GCC_UNWIND return std::numeric_limits::max(); #else switch (kind) { diff --git a/kotlin-native/runtime/src/main/cpp/StackTraceTest.cpp b/kotlin-native/runtime/src/main/cpp/StackTraceTest.cpp index 86f205b222b..c59bb3a55dd 100644 --- a/kotlin-native/runtime/src/main/cpp/StackTraceTest.cpp +++ b/kotlin-native/runtime/src/main/cpp/StackTraceTest.cpp @@ -5,6 +5,7 @@ #include "StackTrace.hpp" +#include #include #include "gmock/gmock.h" @@ -50,7 +51,7 @@ OPTNONE StackTrace GetDeepStackTrace(size_t depth) { NO_INLINE void AbortWithStackTrace(int) { PrintStackTraceStderr(); - konan::abort(); + std::abort(); } } // namespace diff --git a/kotlin-native/runtime/src/main/cpp/ToString.cpp b/kotlin-native/runtime/src/main/cpp/ToString.cpp index 31dfa5e7fe8..7b93754cd4a 100644 --- a/kotlin-native/runtime/src/main/cpp/ToString.cpp +++ b/kotlin-native/runtime/src/main/cpp/ToString.cpp @@ -14,8 +14,8 @@ * limitations under the License. */ +#include #include -#include #include #include "KAssert.h" @@ -71,7 +71,7 @@ extern "C" { OBJ_GETTER(Kotlin_Byte_toString, KByte value) { char cstring[8]; - konan::snprintf(cstring, sizeof(cstring), "%d", value); + std::snprintf(cstring, sizeof(cstring), "%d", value); RETURN_RESULT_OF(CreateStringFromCString, cstring); } @@ -83,13 +83,13 @@ OBJ_GETTER(Kotlin_Char_toString, KChar value) { OBJ_GETTER(Kotlin_Short_toString, KShort value) { char cstring[8]; - konan::snprintf(cstring, sizeof(cstring), "%d", value); + std::snprintf(cstring, sizeof(cstring), "%d", value); RETURN_RESULT_OF(CreateStringFromCString, cstring); } OBJ_GETTER(Kotlin_Int_toString, KInt value) { char cstring[16]; - konan::snprintf(cstring, sizeof(cstring), "%d", value); + std::snprintf(cstring, sizeof(cstring), "%d", value); RETURN_RESULT_OF(CreateStringFromCString, cstring); } @@ -99,7 +99,7 @@ OBJ_GETTER(Kotlin_Int_toStringRadix, KInt value, KInt radix) { OBJ_GETTER(Kotlin_Long_toString, KLong value) { char cstring[32]; - konan::snprintf(cstring, sizeof(cstring), "%lld", static_cast(value)); + std::snprintf(cstring, sizeof(cstring), "%lld", static_cast(value)); RETURN_RESULT_OF(CreateStringFromCString, cstring); } @@ -109,7 +109,7 @@ OBJ_GETTER(Kotlin_Long_toStringRadix, KLong value, KInt radix) { OBJ_GETTER(Kotlin_DurationValue_formatToExactDecimals, KDouble value, KInt decimals) { char cstring[40]; // log(2^62*1_000_000) + 2 (sign, decimal point) + 12 (max decimals) - konan::snprintf(cstring, sizeof(cstring), "%.*f", decimals, value); + std::snprintf(cstring, sizeof(cstring), "%.*f", decimals, value); RETURN_RESULT_OF(CreateStringFromCString, cstring) } diff --git a/kotlin-native/runtime/src/main/cpp/TypeLayout.hpp b/kotlin-native/runtime/src/main/cpp/TypeLayout.hpp index 0a0fa823a00..80d13a25b4a 100644 --- a/kotlin-native/runtime/src/main/cpp/TypeLayout.hpp +++ b/kotlin-native/runtime/src/main/cpp/TypeLayout.hpp @@ -5,8 +5,6 @@ #pragma once -#ifndef KONAN_WASM - #include #include #include @@ -194,5 +192,3 @@ public: }; } // namespace kotlin::type_layout - -#endif diff --git a/kotlin-native/runtime/src/main/cpp/Worker.cpp b/kotlin-native/runtime/src/main/cpp/Worker.cpp index e6e2384d781..24075e1fc39 100644 --- a/kotlin-native/runtime/src/main/cpp/Worker.cpp +++ b/kotlin-native/runtime/src/main/cpp/Worker.cpp @@ -14,18 +14,12 @@ * limitations under the License. */ -#ifndef KONAN_NO_THREADS -#define WITH_WORKERS 1 -#endif - -#include +#include #include #include -#if WITH_WORKERS #include #include "PthreadUtils.h" -#endif #include "Exceptions.h" #include "KAssert.h" @@ -49,7 +43,6 @@ RUNTIME_NORETURN void ThrowWorkerAlreadyTerminated(); RUNTIME_NORETURN void ThrowWrongWorkerOrAlreadyTerminated(); RUNTIME_NORETURN void ThrowCannotTransferOwnership(); RUNTIME_NORETURN void ThrowFutureInvalidState(); -RUNTIME_NORETURN void ThrowWorkerUnsupported(); OBJ_GETTER(WorkerLaunchpad, KRef); } // extern "C" @@ -73,8 +66,6 @@ WorkerExceptionHandling workerExceptionHandling() noexcept { } // namespace -#if WITH_WORKERS - namespace { class Future; @@ -220,12 +211,8 @@ class Worker { MemoryState* memoryState_ = nullptr; }; -#endif // WITH_WORKERS - namespace { -#if WITH_WORKERS - THREAD_LOCAL_VARIABLE Worker* g_worker = nullptr; KNativePtr transfer(ObjHolder* holder, KInt mode) { @@ -639,7 +626,7 @@ class State { "Use `Platform.isMemoryLeakCheckerActive = false` to avoid this check.\n", remainingNativeWorkers); konan::consoleFlush(); - konan::abort(); + std::abort(); } } @@ -808,86 +795,13 @@ OBJ_GETTER0(activeWorkers) { RETURN_RESULT_OF0(theState()->getActiveWorkers); } -#else - -KInt startWorker(WorkerExceptionHandling exceptionHandling, KRef customName) { - ThrowWorkerUnsupported(); -} - -KInt stateOfFuture(KInt id) { - ThrowWorkerUnsupported(); -} - -KInt execute(KInt id, KInt transferMode, KRef producer, KNativePtr jobFunction) { - ThrowWorkerUnsupported(); -} - -void executeAfter(KInt id, KRef job, KLong afterMicroseconds) { - ThrowWorkerUnsupported(); -} - -KBoolean processQueue(KInt id) { - ThrowWorkerUnsupported(); -} - -KBoolean park(KInt id, KLong timeoutMicroseconds, KBoolean process) { - ThrowWorkerUnsupported(); -} - -KInt currentWorker() { - ThrowWorkerUnsupported(); -} - -OBJ_GETTER(consumeFuture, KInt id) { - ThrowWorkerUnsupported(); -} - -OBJ_GETTER(getWorkerName, KInt id) { - ThrowWorkerUnsupported(); -} - -KInt requestTermination(KInt id, KBoolean processScheduledJobs) { - ThrowWorkerUnsupported(); -} - -KBoolean waitForAnyFuture(KInt versionToken, KInt millis) { - ThrowWorkerUnsupported(); -} - -KInt versionToken() { - ThrowWorkerUnsupported(); -} - -OBJ_GETTER(attachObjectGraphInternal, KNativePtr stable) { - ThrowWorkerUnsupported(); -} - -KNativePtr detachObjectGraphInternal(KInt transferMode, KRef producer) { - ThrowWorkerUnsupported(); -} - -KULong platformThreadId(KInt id) { - ThrowWorkerUnsupported(); -} - -OBJ_GETTER0(activeWorkers) { - ThrowWorkerUnsupported(); -} - -#endif // WITH_WORKERS - } // namespace KInt GetWorkerId(Worker* worker) { -#if WITH_WORKERS return worker->id(); -#else - return 0; -#endif // WITH_WORKERS } Worker* WorkerInit(MemoryState* memoryState) { -#if WITH_WORKERS Worker* worker; if (::g_worker != nullptr) { worker = ::g_worker; @@ -898,46 +812,29 @@ Worker* WorkerInit(MemoryState* memoryState) { worker->setThread(pthread_self()); worker->setMemoryState(memoryState); return worker; -#else - return nullptr; -#endif // WITH_WORKERS } void WorkerDeinit(Worker* worker) { -#if WITH_WORKERS ::g_worker = nullptr; theState()->destroyWorkerUnlocked(worker); -#endif // WITH_WORKERS } void WorkerDestroyThreadDataIfNeeded(KInt id) { -#if WITH_WORKERS theState()->destroyWorkerThreadDataUnlocked(id); -#endif } void WaitNativeWorkersTermination() { -#if WITH_WORKERS theState()->waitNativeWorkersTerminationUnlocked(true, [](KInt worker) { return true; }); -#endif } void WaitNativeWorkerTermination(KInt id) { -#if WITH_WORKERS theState()->waitNativeWorkersTerminationUnlocked(false, [id](KInt worker) { return worker == id; }); -#endif } bool WorkerSchedule(KInt id, KNativePtr jobStablePtr) { -#if WITH_WORKERS return theState()->scheduleJobInWorkerUnlocked(id, jobStablePtr); -#else - return false; -#endif // WITH_WORKERS } -#if WITH_WORKERS - Worker::~Worker() { RuntimeAssert(pthread_equal(thread(), pthread_self()), "Worker destruction must be executed by the worker thread."); @@ -1198,8 +1095,6 @@ JobKind Worker::processQueueElement(bool blocking) { return job.kind; } -#endif // WITH_WORKERS - extern "C" { KInt Kotlin_Worker_startInternal(KBoolean errorReporting, KRef customName) { diff --git a/kotlin-native/runtime/src/main/cpp/dlmalloc/malloc.cpp b/kotlin-native/runtime/src/main/cpp/dlmalloc/malloc.cpp deleted file mode 100644 index 4cccd167fa7..00000000000 --- a/kotlin-native/runtime/src/main/cpp/dlmalloc/malloc.cpp +++ /dev/null @@ -1,6309 +0,0 @@ -// Uses GNU extension on null pointer arithmetic. -#pragma clang diagnostic ignored "-Wnull-pointer-arithmetic" -/* - This is a version (aka dlmalloc) of malloc/free/realloc written by - Doug Lea and released to the public domain, as explained at - http://creativecommons.org/publicdomain/zero/1.0/ Send questions, - comments, complaints, performance data, etc to dl@cs.oswego.edu - -* Version 2.8.6 Wed Aug 29 06:57:58 2012 Doug Lea - Note: There may be an updated version of this malloc obtainable at - ftp://gee.cs.oswego.edu/pub/misc/malloc.c - Check before installing! - -* Quickstart - - This library is all in one file to simplify the most common usage: - ftp it, compile it (-O3), and link it into another program. All of - the compile-time options default to reasonable values for use on - most platforms. You might later want to step through various - compile-time and dynamic tuning options. - - For convenience, an include file for code using this malloc is at: - ftp://gee.cs.oswego.edu/pub/misc/malloc-2.8.6.h - You don't really need this .h file unless you call functions not - defined in your system include files. The .h file contains only the - excerpts from this file needed for using this malloc on ANSI C/C++ - systems, so long as you haven't changed compile-time options about - naming and tuning parameters. If you do, then you can create your - own malloc.h that does include all settings by cutting at the point - indicated below. Note that you may already by default be using a C - library containing a malloc that is based on some version of this - malloc (for example in linux). You might still want to use the one - in this file to customize settings or to avoid overheads associated - with library versions. - -* Vital statistics: - - Supported pointer/size_t representation: 4 or 8 bytes - size_t MUST be an unsigned type of the same width as - pointers. (If you are using an ancient system that declares - size_t as a signed type, or need it to be a different width - than pointers, you can use a previous release of this malloc - (e.g. 2.7.2) supporting these.) - - Alignment: 8 bytes (minimum) - This suffices for nearly all current machines and C compilers. - However, you can define MALLOC_ALIGNMENT to be wider than this - if necessary (up to 128bytes), at the expense of using more space. - - Minimum overhead per allocated chunk: 4 or 8 bytes (if 4byte sizes) - 8 or 16 bytes (if 8byte sizes) - Each malloced chunk has a hidden word of overhead holding size - and status information, and additional cross-check word - if FOOTERS is defined. - - Minimum allocated size: 4-byte ptrs: 16 bytes (including overhead) - 8-byte ptrs: 32 bytes (including overhead) - - Even a request for zero bytes (i.e., malloc(0)) returns a - pointer to something of the minimum allocatable size. - The maximum overhead wastage (i.e., number of extra bytes - allocated than were requested in malloc) is less than or equal - to the minimum size, except for requests >= mmap_threshold that - are serviced via mmap(), where the worst case wastage is about - 32 bytes plus the remainder from a system page (the minimal - mmap unit); typically 4096 or 8192 bytes. - - Security: static-safe; optionally more or less - The "security" of malloc refers to the ability of malicious - code to accentuate the effects of errors (for example, freeing - space that is not currently malloc'ed or overwriting past the - ends of chunks) in code that calls malloc. This malloc - guarantees not to modify any memory locations below the base of - heap, i.e., static variables, even in the presence of usage - errors. The routines additionally detect most improper frees - and reallocs. All this holds as long as the static bookkeeping - for malloc itself is not corrupted by some other means. This - is only one aspect of security -- these checks do not, and - cannot, detect all possible programming errors. - - If FOOTERS is defined nonzero, then each allocated chunk - carries an additional check word to verify that it was malloced - from its space. These check words are the same within each - execution of a program using malloc, but differ across - executions, so externally crafted fake chunks cannot be - freed. This improves security by rejecting frees/reallocs that - could corrupt heap memory, in addition to the checks preventing - writes to statics that are always on. This may further improve - security at the expense of time and space overhead. (Note that - FOOTERS may also be worth using with MSPACES.) - - By default detected errors cause the program to abort (calling - "abort()"). You can override this to instead proceed past - errors by defining PROCEED_ON_ERROR. In this case, a bad free - has no effect, and a malloc that encounters a bad address - caused by user overwrites will ignore the bad address by - dropping pointers and indices to all known memory. This may - be appropriate for programs that should continue if at all - possible in the face of programming errors, although they may - run out of memory because dropped memory is never reclaimed. - - If you don't like either of these options, you can define - CORRUPTION_ERROR_ACTION and USAGE_ERROR_ACTION to do anything - else. And if if you are sure that your program using malloc has - no errors or vulnerabilities, you can define INSECURE to 1, - which might (or might not) provide a small performance improvement. - - It is also possible to limit the maximum total allocatable - space, using malloc_set_footprint_limit. This is not - designed as a security feature in itself (calls to set limits - are not screened or privileged), but may be useful as one - aspect of a secure implementation. - - Thread-safety: NOT thread-safe unless USE_LOCKS defined non-zero - When USE_LOCKS is defined, each public call to malloc, free, - etc is surrounded with a lock. By default, this uses a plain - pthread mutex, win32 critical section, or a spin-lock if if - available for the platform and not disabled by setting - USE_SPIN_LOCKS=0. However, if USE_RECURSIVE_LOCKS is defined, - recursive versions are used instead (which are not required for - base functionality but may be needed in layered extensions). - Using a global lock is not especially fast, and can be a major - bottleneck. It is designed only to provide minimal protection - in concurrent environments, and to provide a basis for - extensions. If you are using malloc in a concurrent program, - consider instead using nedmalloc - (http://www.nedprod.com/programs/portable/nedmalloc/) or - ptmalloc (See http://www.malloc.de), which are derived from - versions of this malloc. - - System requirements: Any combination of MORECORE and/or MMAP/MUNMAP - This malloc can use unix sbrk or any emulation (invoked using - the CALL_MORECORE macro) and/or mmap/munmap or any emulation - (invoked using CALL_MMAP/CALL_MUNMAP) to get and release system - memory. On most unix systems, it tends to work best if both - MORECORE and MMAP are enabled. On Win32, it uses emulations - based on VirtualAlloc. It also uses common C library functions - like memset. - - Compliance: I believe it is compliant with the Single Unix Specification - (See http://www.unix.org). Also SVID/XPG, ANSI C, and probably - others as well. - -* Overview of algorithms - - This is not the fastest, most space-conserving, most portable, or - most tunable malloc ever written. However it is among the fastest - while also being among the most space-conserving, portable and - tunable. Consistent balance across these factors results in a good - general-purpose allocator for malloc-intensive programs. - - In most ways, this malloc is a best-fit allocator. Generally, it - chooses the best-fitting existing chunk for a request, with ties - broken in approximately least-recently-used order. (This strategy - normally maintains low fragmentation.) However, for requests less - than 256bytes, it deviates from best-fit when there is not an - exactly fitting available chunk by preferring to use space adjacent - to that used for the previous small request, as well as by breaking - ties in approximately most-recently-used order. (These enhance - locality of series of small allocations.) And for very large requests - (>= 256Kb by default), it relies on system memory mapping - facilities, if supported. (This helps avoid carrying around and - possibly fragmenting memory used only for large chunks.) - - All operations (except malloc_stats and mallinfo) have execution - times that are bounded by a constant factor of the number of bits in - a size_t, not counting any clearing in calloc or copying in realloc, - or actions surrounding MORECORE and MMAP that have times - proportional to the number of non-contiguous regions returned by - system allocation routines, which is often just 1. In real-time - applications, you can optionally suppress segment traversals using - NO_SEGMENT_TRAVERSAL, which assures bounded execution even when - system allocators return non-contiguous spaces, at the typical - expense of carrying around more memory and increased fragmentation. - - The implementation is not very modular and seriously overuses - macros. Perhaps someday all C compilers will do as good a job - inlining modular code as can now be done by brute-force expansion, - but now, enough of them seem not to. - - Some compilers issue a lot of warnings about code that is - dead/unreachable only on some platforms, and also about intentional - uses of negation on unsigned types. All known cases of each can be - ignored. - - For a longer but out of date high-level description, see - http://gee.cs.oswego.edu/dl/html/malloc.html - -* MSPACES - If MSPACES is defined, then in addition to malloc, free, etc., - this file also defines mspace_malloc, mspace_free, etc. These - are versions of malloc routines that take an "mspace" argument - obtained using create_mspace, to control all internal bookkeeping. - If ONLY_MSPACES is defined, only these versions are compiled. - So if you would like to use this allocator for only some allocations, - and your system malloc for others, you can compile with - ONLY_MSPACES and then do something like... - static mspace mymspace = create_mspace(0,0); // for example - #define mymalloc(bytes) mspace_malloc(mymspace, bytes) - - (Note: If you only need one instance of an mspace, you can instead - use "USE_DL_PREFIX" to relabel the global malloc.) - - You can similarly create thread-local allocators by storing - mspaces as thread-locals. For example: - static __thread mspace tlms = 0; - void* tlmalloc(size_t bytes) { - if (tlms == 0) tlms = create_mspace(0, 0); - return mspace_malloc(tlms, bytes); - } - void tlfree(void* mem) { mspace_free(tlms, mem); } - - Unless FOOTERS is defined, each mspace is completely independent. - You cannot allocate from one and free to another (although - conformance is only weakly checked, so usage errors are not always - caught). If FOOTERS is defined, then each chunk carries around a tag - indicating its originating mspace, and frees are directed to their - originating spaces. Normally, this requires use of locks. - - ------------------------- Compile-time options --------------------------- - -Be careful in setting #define values for numerical constants of type -size_t. On some systems, literal values are not automatically extended -to size_t precision unless they are explicitly casted. You can also -use the symbolic values MAX_SIZE_T, SIZE_T_ONE, etc below. - -WIN32 default: defined if _WIN32 defined - Defining WIN32 sets up defaults for MS environment and compilers. - Otherwise defaults are for unix. Beware that there seem to be some - cases where this malloc might not be a pure drop-in replacement for - Win32 malloc: Random-looking failures from Win32 GDI API's (eg; - SetDIBits()) may be due to bugs in some video driver implementations - when pixel buffers are malloc()ed, and the region spans more than - one VirtualAlloc()ed region. Because dlmalloc uses a small (64Kb) - default granularity, pixel buffers may straddle virtual allocation - regions more often than when using the Microsoft allocator. You can - avoid this by using VirtualAlloc() and VirtualFree() for all pixel - buffers rather than using malloc(). If this is not possible, - recompile this malloc with a larger DEFAULT_GRANULARITY. Note: - in cases where MSC and gcc (cygwin) are known to differ on WIN32, - conditions use _MSC_VER to distinguish them. - -DLMALLOC_EXPORT default: extern - Defines how public APIs are declared. If you want to export via a - Windows DLL, you might define this as - #define DLMALLOC_EXPORT extern __declspec(dllexport) - If you want a POSIX ELF shared object, you might use - #define DLMALLOC_EXPORT extern __attribute__((visibility("default"))) - -MALLOC_ALIGNMENT default: (size_t)(2 * sizeof(void *)) - Controls the minimum alignment for malloc'ed chunks. It must be a - power of two and at least 8, even on machines for which smaller - alignments would suffice. It may be defined as larger than this - though. Note however that code and data structures are optimized for - the case of 8-byte alignment. - -MSPACES default: 0 (false) - If true, compile in support for independent allocation spaces. - This is only supported if HAVE_MMAP is true. - -ONLY_MSPACES default: 0 (false) - If true, only compile in mspace versions, not regular versions. - -USE_LOCKS default: 0 (false) - Causes each call to each public routine to be surrounded with - pthread or WIN32 mutex lock/unlock. (If set true, this can be - overridden on a per-mspace basis for mspace versions.) If set to a - non-zero value other than 1, locks are used, but their - implementation is left out, so lock functions must be supplied manually, - as described below. - -USE_SPIN_LOCKS default: 1 iff USE_LOCKS and spin locks available - If true, uses custom spin locks for locking. This is currently - supported only gcc >= 4.1, older gccs on x86 platforms, and recent - MS compilers. Otherwise, posix locks or win32 critical sections are - used. - -USE_RECURSIVE_LOCKS default: not defined - If defined nonzero, uses recursive (aka reentrant) locks, otherwise - uses plain mutexes. This is not required for malloc proper, but may - be needed for layered allocators such as nedmalloc. - -LOCK_AT_FORK default: not defined - If defined nonzero, performs pthread_atfork upon initialization - to initialize child lock while holding parent lock. The implementation - assumes that pthread locks (not custom locks) are being used. In other - cases, you may need to customize the implementation. - -FOOTERS default: 0 - If true, provide extra checking and dispatching by placing - information in the footers of allocated chunks. This adds - space and time overhead. - -INSECURE default: 0 - If true, omit checks for usage errors and heap space overwrites. - -USE_DL_PREFIX default: NOT defined - Causes compiler to prefix all public routines with the string 'dl'. - This can be useful when you only want to use this malloc in one part - of a program, using your regular system malloc elsewhere. - -MALLOC_INSPECT_ALL default: NOT defined - If defined, compiles malloc_inspect_all and mspace_inspect_all, that - perform traversal of all heap space. Unless access to these - functions is otherwise restricted, you probably do not want to - include them in secure implementations. - -ABORT default: defined as abort() - Defines how to abort on failed checks. On most systems, a failed - check cannot die with an "assert" or even print an informative - message, because the underlying print routines in turn call malloc, - which will fail again. Generally, the best policy is to simply call - abort(). It's not very useful to do more than this because many - errors due to overwriting will show up as address faults (null, odd - addresses etc) rather than malloc-triggered checks, so will also - abort. Also, most compilers know that abort() does not return, so - can better optimize code conditionally calling it. - -PROCEED_ON_ERROR default: defined as 0 (false) - Controls whether detected bad addresses cause them to bypassed - rather than aborting. If set, detected bad arguments to free and - realloc are ignored. And all bookkeeping information is zeroed out - upon a detected overwrite of freed heap space, thus losing the - ability to ever return it from malloc again, but enabling the - application to proceed. If PROCEED_ON_ERROR is defined, the - static variable malloc_corruption_error_count is compiled in - and can be examined to see if errors have occurred. This option - generates slower code than the default abort policy. - -DEBUG default: NOT defined - The DEBUG setting is mainly intended for people trying to modify - this code or diagnose problems when porting to new platforms. - However, it may also be able to better isolate user errors than just - using runtime checks. The assertions in the check routines spell - out in more detail the assumptions and invariants underlying the - algorithms. The checking is fairly extensive, and will slow down - execution noticeably. Calling malloc_stats or mallinfo with DEBUG - set will attempt to check every non-mmapped allocated and free chunk - in the course of computing the summaries. - -ABORT_ON_ASSERT_FAILURE default: defined as 1 (true) - Debugging assertion failures can be nearly impossible if your - version of the assert macro causes malloc to be called, which will - lead to a cascade of further failures, blowing the runtime stack. - ABORT_ON_ASSERT_FAILURE cause assertions failures to call abort(), - which will usually make debugging easier. - -MALLOC_FAILURE_ACTION default: sets errno to ENOMEM, or no-op on win32 - The action to take before "return 0" when malloc fails to be able to - return memory because there is none available. - -HAVE_MORECORE default: 1 (true) unless win32 or ONLY_MSPACES - True if this system supports sbrk or an emulation of it. - -MORECORE default: sbrk - The name of the sbrk-style system routine to call to obtain more - memory. See below for guidance on writing custom MORECORE - functions. The type of the argument to sbrk/MORECORE varies across - systems. It cannot be size_t, because it supports negative - arguments, so it is normally the signed type of the same width as - size_t (sometimes declared as "intptr_t"). It doesn't much matter - though. Internally, we only call it with arguments less than half - the max value of a size_t, which should work across all reasonable - possibilities, although sometimes generating compiler warnings. - -MORECORE_CONTIGUOUS default: 1 (true) if HAVE_MORECORE - If true, take advantage of fact that consecutive calls to MORECORE - with positive arguments always return contiguous increasing - addresses. This is true of unix sbrk. It does not hurt too much to - set it true anyway, since malloc copes with non-contiguities. - Setting it false when definitely non-contiguous saves time - and possibly wasted space it would take to discover this though. - -MORECORE_CANNOT_TRIM default: NOT defined - True if MORECORE cannot release space back to the system when given - negative arguments. This is generally necessary only if you are - using a hand-crafted MORECORE function that cannot handle negative - arguments. - -NO_SEGMENT_TRAVERSAL default: 0 - If non-zero, suppresses traversals of memory segments - returned by either MORECORE or CALL_MMAP. This disables - merging of segments that are contiguous, and selectively - releasing them to the OS if unused, but bounds execution times. - -HAVE_MMAP default: 1 (true) - True if this system supports mmap or an emulation of it. If so, and - HAVE_MORECORE is not true, MMAP is used for all system - allocation. If set and HAVE_MORECORE is true as well, MMAP is - primarily used to directly allocate very large blocks. It is also - used as a backup strategy in cases where MORECORE fails to provide - space from system. Note: A single call to MUNMAP is assumed to be - able to unmap memory that may have be allocated using multiple calls - to MMAP, so long as they are adjacent. - -HAVE_MREMAP default: 1 on linux, else 0 - If true realloc() uses mremap() to re-allocate large blocks and - extend or shrink allocation spaces. - -MMAP_CLEARS default: 1 except on WINCE. - True if mmap clears memory so calloc doesn't need to. This is true - for standard unix mmap using /dev/zero and on WIN32 except for WINCE. - -USE_BUILTIN_FFS default: 0 (i.e., not used) - Causes malloc to use the builtin ffs() function to compute indices. - Some compilers may recognize and intrinsify ffs to be faster than the - supplied C version. Also, the case of x86 using gcc is special-cased - to an asm instruction, so is already as fast as it can be, and so - this setting has no effect. Similarly for Win32 under recent MS compilers. - (On most x86s, the asm version is only slightly faster than the C version.) - -malloc_getpagesize default: derive from system includes, or 4096. - The system page size. To the extent possible, this malloc manages - memory from the system in page-size units. This may be (and - usually is) a function rather than a constant. This is ignored - if WIN32, where page size is determined using getSystemInfo during - initialization. - -USE_DEV_RANDOM default: 0 (i.e., not used) - Causes malloc to use /dev/random to initialize secure magic seed for - stamping footers. Otherwise, the current time is used. - -NO_MALLINFO default: 0 - If defined, don't compile "mallinfo". This can be a simple way - of dealing with mismatches between system declarations and - those in this file. - -MALLINFO_FIELD_TYPE default: size_t - The type of the fields in the mallinfo struct. This was originally - defined as "int" in SVID etc, but is more usefully defined as - size_t. The value is used only if HAVE_USR_INCLUDE_MALLOC_H is not set - -NO_MALLOC_STATS default: 0 - If defined, don't compile "malloc_stats". This avoids calls to - fprintf and bringing in stdio dependencies you might not want. - -REALLOC_ZERO_BYTES_FREES default: not defined - This should be set if a call to realloc with zero bytes should - be the same as a call to free. Some people think it should. Otherwise, - since this malloc returns a unique pointer for malloc(0), so does - realloc(p, 0). - -LACKS_UNISTD_H, LACKS_FCNTL_H, LACKS_SYS_PARAM_H, LACKS_SYS_MMAN_H -LACKS_STRINGS_H, LACKS_STRING_H, LACKS_SYS_TYPES_H, LACKS_ERRNO_H -LACKS_STDLIB_H LACKS_SCHED_H LACKS_TIME_H default: NOT defined unless on WIN32 - Define these if your system does not have these header files. - You might need to manually insert some of the declarations they provide. - -DEFAULT_GRANULARITY default: page size if MORECORE_CONTIGUOUS, - system_info.dwAllocationGranularity in WIN32, - otherwise 64K. - Also settable using mallopt(M_GRANULARITY, x) - The unit for allocating and deallocating memory from the system. On - most systems with contiguous MORECORE, there is no reason to - make this more than a page. However, systems with MMAP tend to - either require or encourage larger granularities. You can increase - this value to prevent system allocation functions to be called so - often, especially if they are slow. The value must be at least one - page and must be a power of two. Setting to 0 causes initialization - to either page size or win32 region size. (Note: In previous - versions of malloc, the equivalent of this option was called - "TOP_PAD") - -DEFAULT_TRIM_THRESHOLD default: 2MB - Also settable using mallopt(M_TRIM_THRESHOLD, x) - The maximum amount of unused top-most memory to keep before - releasing via malloc_trim in free(). Automatic trimming is mainly - useful in long-lived programs using contiguous MORECORE. Because - trimming via sbrk can be slow on some systems, and can sometimes be - wasteful (in cases where programs immediately afterward allocate - more large chunks) the value should be high enough so that your - overall system performance would improve by releasing this much - memory. As a rough guide, you might set to a value close to the - average size of a process (program) running on your system. - Releasing this much memory would allow such a process to run in - memory. Generally, it is worth tuning trim thresholds when a - program undergoes phases where several large chunks are allocated - and released in ways that can reuse each other's storage, perhaps - mixed with phases where there are no such chunks at all. The trim - value must be greater than page size to have any useful effect. To - disable trimming completely, you can set to MAX_SIZE_T. Note that the trick - some people use of mallocing a huge space and then freeing it at - program startup, in an attempt to reserve system memory, doesn't - have the intended effect under automatic trimming, since that memory - will immediately be returned to the system. - -DEFAULT_MMAP_THRESHOLD default: 256K - Also settable using mallopt(M_MMAP_THRESHOLD, x) - The request size threshold for using MMAP to directly service a - request. Requests of at least this size that cannot be allocated - using already-existing space will be serviced via mmap. (If enough - normal freed space already exists it is used instead.) Using mmap - segregates relatively large chunks of memory so that they can be - individually obtained and released from the host system. A request - serviced through mmap is never reused by any other request (at least - not directly; the system may just so happen to remap successive - requests to the same locations). Segregating space in this way has - the benefits that: Mmapped space can always be individually released - back to the system, which helps keep the system level memory demands - of a long-lived program low. Also, mapped memory doesn't become - `locked' between other chunks, as can happen with normally allocated - chunks, which means that even trimming via malloc_trim would not - release them. However, it has the disadvantage that the space - cannot be reclaimed, consolidated, and then used to service later - requests, as happens with normal chunks. The advantages of mmap - nearly always outweigh disadvantages for "large" chunks, but the - value of "large" may vary across systems. The default is an - empirically derived value that works well in most systems. You can - disable mmap by setting to MAX_SIZE_T. - -MAX_RELEASE_CHECK_RATE default: 4095 unless not HAVE_MMAP - The number of consolidated frees between checks to release - unused segments when freeing. When using non-contiguous segments, - especially with multiple mspaces, checking only for topmost space - doesn't always suffice to trigger trimming. To compensate for this, - free() will, with a period of MAX_RELEASE_CHECK_RATE (or the - current number of segments, if greater) try to release unused - segments to the OS when freeing chunks that result in - consolidation. The best value for this parameter is a compromise - between slowing down frees with relatively costly checks that - rarely trigger versus holding on to unused memory. To effectively - disable, set to MAX_SIZE_T. This may lead to a very slight speed - improvement at the expense of carrying around more memory. -*/ - -#if KONAN_INTERNAL_DLMALLOC - -/**** Start of Konan-specific dlmalloc configuration. ****/ -#define USE_DL_PREFIX 1 -#if KONAN_WASM -#define USE_LOCKS 0 -#define LACKS_TIME_H 1 -#define NO_MALLOC_STATS 1 -#define HAVE_MMAP 0 // don't try to allocate large chunks of memory using mmap(). - // It will go to malloc->calloc->sbrk->morecore chain anyways. -#else -#define USE_LOCKS 1 -#endif -#define DLMALLOC_EXPORT extern "C" -#define HAVE_MORECORE 1 -#define MORECORE konan::moreCore -#define malloc_getpagesize konan::getpagesize() -namespace konan { -extern void* moreCore(int size); -extern long getpagesize(); -} // namespace konan - -/**** End of Konan-specific dlmalloc configuration. ****/ - - -/* Version identifier to allow people to support multiple versions */ -#ifndef DLMALLOC_VERSION -#define DLMALLOC_VERSION 20806 -#endif /* DLMALLOC_VERSION */ - -#ifndef DLMALLOC_EXPORT -#define DLMALLOC_EXPORT extern -#endif - -#ifndef WIN32 -#ifdef _WIN32 -#define WIN32 1 -#endif /* _WIN32 */ -#ifdef _WIN32_WCE -#define LACKS_FCNTL_H -#define WIN32 1 -#endif /* _WIN32_WCE */ -#endif /* WIN32 */ -#ifdef WIN32 -#define WIN32_LEAN_AND_MEAN -#include -#include -#define HAVE_MMAP 1 -#define HAVE_MORECORE 0 -#define LACKS_UNISTD_H -#define LACKS_SYS_PARAM_H -#define LACKS_SYS_MMAN_H -#define LACKS_STRING_H -#define LACKS_STRINGS_H -#define LACKS_SYS_TYPES_H -#define LACKS_ERRNO_H -#define LACKS_SCHED_H -#ifndef MALLOC_FAILURE_ACTION -#define MALLOC_FAILURE_ACTION -#endif /* MALLOC_FAILURE_ACTION */ -#ifndef MMAP_CLEARS -#ifdef _WIN32_WCE /* WINCE reportedly does not clear */ -#define MMAP_CLEARS 0 -#else -#define MMAP_CLEARS 1 -#endif /* _WIN32_WCE */ -#endif /*MMAP_CLEARS */ -#endif /* WIN32 */ - -#if defined(DARWIN) || defined(_DARWIN) -/* Mac OSX docs advise not to use sbrk; it seems better to use mmap */ -#ifndef HAVE_MORECORE -#define HAVE_MORECORE 0 -#define HAVE_MMAP 1 -/* OSX allocators provide 16 byte alignment */ -#ifndef MALLOC_ALIGNMENT -#define MALLOC_ALIGNMENT ((size_t)16U) -#endif -#endif /* HAVE_MORECORE */ -#endif /* DARWIN */ - -#ifndef LACKS_SYS_TYPES_H -#include /* For size_t */ -#endif /* LACKS_SYS_TYPES_H */ - -/* The maximum possible size_t value has all bits set */ -#define MAX_SIZE_T (~(size_t)0) - -#ifndef USE_LOCKS /* ensure true if spin or recursive locks set */ -#define USE_LOCKS ((defined(USE_SPIN_LOCKS) && USE_SPIN_LOCKS != 0) || \ - (defined(USE_RECURSIVE_LOCKS) && USE_RECURSIVE_LOCKS != 0)) -#endif /* USE_LOCKS */ - -#if USE_LOCKS /* Spin locks for gcc >= 4.1, older gcc on x86, MSC >= 1310 */ -#if ((defined(__GNUC__) && \ - ((__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 1)) || \ - defined(__i386__) || defined(__x86_64__))) || \ - (defined(_MSC_VER) && _MSC_VER>=1310)) -#ifndef USE_SPIN_LOCKS -#define USE_SPIN_LOCKS 1 -#endif /* USE_SPIN_LOCKS */ -#elif USE_SPIN_LOCKS -#error "USE_SPIN_LOCKS defined without implementation" -#endif /* ... locks available... */ -#elif !defined(USE_SPIN_LOCKS) -#define USE_SPIN_LOCKS 0 -#endif /* USE_LOCKS */ - -#ifndef ONLY_MSPACES -#define ONLY_MSPACES 0 -#endif /* ONLY_MSPACES */ -#ifndef MSPACES -#if ONLY_MSPACES -#define MSPACES 1 -#else /* ONLY_MSPACES */ -#define MSPACES 0 -#endif /* ONLY_MSPACES */ -#endif /* MSPACES */ -#ifndef MALLOC_ALIGNMENT -#define MALLOC_ALIGNMENT ((size_t)(2 * sizeof(void *))) -#endif /* MALLOC_ALIGNMENT */ -#ifndef FOOTERS -#define FOOTERS 0 -#endif /* FOOTERS */ -#ifndef ABORT -#define ABORT abort() -#endif /* ABORT */ -#ifndef ABORT_ON_ASSERT_FAILURE -#define ABORT_ON_ASSERT_FAILURE 1 -#endif /* ABORT_ON_ASSERT_FAILURE */ -#ifndef PROCEED_ON_ERROR -#define PROCEED_ON_ERROR 0 -#endif /* PROCEED_ON_ERROR */ - -#ifndef INSECURE -#define INSECURE 0 -#endif /* INSECURE */ -#ifndef MALLOC_INSPECT_ALL -#define MALLOC_INSPECT_ALL 0 -#endif /* MALLOC_INSPECT_ALL */ -#ifndef HAVE_MMAP -#define HAVE_MMAP 1 -#endif /* HAVE_MMAP */ -#ifndef MMAP_CLEARS -#define MMAP_CLEARS 1 -#endif /* MMAP_CLEARS */ -#ifndef HAVE_MREMAP -#ifdef linux -#define HAVE_MREMAP 1 -#define _GNU_SOURCE /* Turns on mremap() definition */ -#else /* linux */ -#define HAVE_MREMAP 0 -#endif /* linux */ -#endif /* HAVE_MREMAP */ -#ifndef MALLOC_FAILURE_ACTION -#define MALLOC_FAILURE_ACTION errno = ENOMEM; -#endif /* MALLOC_FAILURE_ACTION */ -#ifndef HAVE_MORECORE -#if ONLY_MSPACES -#define HAVE_MORECORE 0 -#else /* ONLY_MSPACES */ -#define HAVE_MORECORE 1 -#endif /* ONLY_MSPACES */ -#endif /* HAVE_MORECORE */ -#if !HAVE_MORECORE -#define MORECORE_CONTIGUOUS 0 -#else /* !HAVE_MORECORE */ -#define MORECORE_DEFAULT sbrk -#ifndef MORECORE_CONTIGUOUS -#define MORECORE_CONTIGUOUS 1 -#endif /* MORECORE_CONTIGUOUS */ -#endif /* HAVE_MORECORE */ -#ifndef DEFAULT_GRANULARITY -#if (MORECORE_CONTIGUOUS || defined(WIN32)) -#define DEFAULT_GRANULARITY (0) /* 0 means to compute in init_mparams */ -#else /* MORECORE_CONTIGUOUS */ -#define DEFAULT_GRANULARITY ((size_t)64U * (size_t)1024U) -#endif /* MORECORE_CONTIGUOUS */ -#endif /* DEFAULT_GRANULARITY */ -#ifndef DEFAULT_TRIM_THRESHOLD -#ifndef MORECORE_CANNOT_TRIM -#define DEFAULT_TRIM_THRESHOLD ((size_t)2U * (size_t)1024U * (size_t)1024U) -#else /* MORECORE_CANNOT_TRIM */ -#define DEFAULT_TRIM_THRESHOLD MAX_SIZE_T -#endif /* MORECORE_CANNOT_TRIM */ -#endif /* DEFAULT_TRIM_THRESHOLD */ -#ifndef DEFAULT_MMAP_THRESHOLD -#if HAVE_MMAP -#define DEFAULT_MMAP_THRESHOLD ((size_t)256U * (size_t)1024U) -#else /* HAVE_MMAP */ -#define DEFAULT_MMAP_THRESHOLD MAX_SIZE_T -#endif /* HAVE_MMAP */ -#endif /* DEFAULT_MMAP_THRESHOLD */ -#ifndef MAX_RELEASE_CHECK_RATE -#if HAVE_MMAP -#define MAX_RELEASE_CHECK_RATE 4095 -#else -#define MAX_RELEASE_CHECK_RATE MAX_SIZE_T -#endif /* HAVE_MMAP */ -#endif /* MAX_RELEASE_CHECK_RATE */ -#ifndef USE_BUILTIN_FFS -#define USE_BUILTIN_FFS 0 -#endif /* USE_BUILTIN_FFS */ -#ifndef USE_DEV_RANDOM -#define USE_DEV_RANDOM 0 -#endif /* USE_DEV_RANDOM */ -#ifndef NO_MALLINFO -#define NO_MALLINFO 0 -#endif /* NO_MALLINFO */ -#ifndef MALLINFO_FIELD_TYPE -#define MALLINFO_FIELD_TYPE size_t -#endif /* MALLINFO_FIELD_TYPE */ -#ifndef NO_MALLOC_STATS -#define NO_MALLOC_STATS 0 -#endif /* NO_MALLOC_STATS */ -#ifndef NO_SEGMENT_TRAVERSAL -#define NO_SEGMENT_TRAVERSAL 0 -#endif /* NO_SEGMENT_TRAVERSAL */ - -/* - mallopt tuning options. SVID/XPG defines four standard parameter - numbers for mallopt, normally defined in malloc.h. None of these - are used in this malloc, so setting them has no effect. But this - malloc does support the following options. -*/ - -#define M_TRIM_THRESHOLD (-1) -#define M_GRANULARITY (-2) -#define M_MMAP_THRESHOLD (-3) - -/* ------------------------ Mallinfo declarations ------------------------ */ - -#if !NO_MALLINFO -/* - This version of malloc supports the standard SVID/XPG mallinfo - routine that returns a struct containing usage properties and - statistics. It should work on any system that has a - /usr/include/malloc.h defining struct mallinfo. The main - declaration needed is the mallinfo struct that is returned (by-copy) - by mallinfo(). The malloinfo struct contains a bunch of fields that - are not even meaningful in this version of malloc. These fields are - are instead filled by mallinfo() with other numbers that might be of - interest. - - HAVE_USR_INCLUDE_MALLOC_H should be set if you have a - /usr/include/malloc.h file that includes a declaration of struct - mallinfo. If so, it is included; else a compliant version is - declared below. These must be precisely the same for mallinfo() to - work. The original SVID version of this struct, defined on most - systems with mallinfo, declares all fields as ints. But some others - define as unsigned long. If your system defines the fields using a - type of different width than listed here, you MUST #include your - system version and #define HAVE_USR_INCLUDE_MALLOC_H. -*/ - -/* #define HAVE_USR_INCLUDE_MALLOC_H */ - -#ifdef HAVE_USR_INCLUDE_MALLOC_H -#include "/usr/include/malloc.h" -#else /* HAVE_USR_INCLUDE_MALLOC_H */ -#ifndef STRUCT_MALLINFO_DECLARED -/* HP-UX (and others?) redefines mallinfo unless _STRUCT_MALLINFO is defined */ -#define _STRUCT_MALLINFO -#define STRUCT_MALLINFO_DECLARED 1 -struct mallinfo { - MALLINFO_FIELD_TYPE arena; /* non-mmapped space allocated from system */ - MALLINFO_FIELD_TYPE ordblks; /* number of free chunks */ - MALLINFO_FIELD_TYPE smblks; /* always 0 */ - MALLINFO_FIELD_TYPE hblks; /* always 0 */ - MALLINFO_FIELD_TYPE hblkhd; /* space in mmapped regions */ - MALLINFO_FIELD_TYPE usmblks; /* maximum total allocated space */ - MALLINFO_FIELD_TYPE fsmblks; /* always 0 */ - MALLINFO_FIELD_TYPE uordblks; /* total allocated space */ - MALLINFO_FIELD_TYPE fordblks; /* total free space */ - MALLINFO_FIELD_TYPE keepcost; /* releasable (via malloc_trim) space */ -}; -#endif /* STRUCT_MALLINFO_DECLARED */ -#endif /* HAVE_USR_INCLUDE_MALLOC_H */ -#endif /* NO_MALLINFO */ - -/* - Try to persuade compilers to inline. The most critical functions for - inlining are defined as macros, so these aren't used for them. -*/ - -#ifndef FORCEINLINE - #if defined(__GNUC__) -#define FORCEINLINE __inline __attribute__ ((always_inline)) - #elif defined(_MSC_VER) - #define FORCEINLINE __forceinline - #endif -#endif -#ifndef NOINLINE - #if defined(__GNUC__) - #define NOINLINE __attribute__ ((noinline)) - #elif defined(_MSC_VER) - #define NOINLINE __declspec(noinline) - #else - #define NOINLINE - #endif -#endif - -#ifdef __cplusplus -extern "C" { -#ifndef FORCEINLINE - #define FORCEINLINE inline -#endif -#endif /* __cplusplus */ -#ifndef FORCEINLINE - #define FORCEINLINE -#endif - -#if !ONLY_MSPACES - -/* ------------------- Declarations of public routines ------------------- */ - -#ifndef USE_DL_PREFIX -#define dlcalloc calloc -#define dlfree free -#define dlmalloc malloc -#define dlmemalign memalign -#define dlposix_memalign posix_memalign -#define dlrealloc realloc -#define dlrealloc_in_place realloc_in_place -#define dlvalloc valloc -#define dlpvalloc pvalloc -#define dlmallinfo mallinfo -#define dlmallopt mallopt -#define dlmalloc_trim malloc_trim -#define dlmalloc_stats malloc_stats -#define dlmalloc_usable_size malloc_usable_size -#define dlmalloc_footprint malloc_footprint -#define dlmalloc_max_footprint malloc_max_footprint -#define dlmalloc_footprint_limit malloc_footprint_limit -#define dlmalloc_set_footprint_limit malloc_set_footprint_limit -#define dlmalloc_inspect_all malloc_inspect_all -#define dlindependent_calloc independent_calloc -#define dlindependent_comalloc independent_comalloc -#define dlbulk_free bulk_free -#endif /* USE_DL_PREFIX */ - -/* - malloc(size_t n) - Returns a pointer to a newly allocated chunk of at least n bytes, or - null if no space is available, in which case errno is set to ENOMEM - on ANSI C systems. - - If n is zero, malloc returns a minimum-sized chunk. (The minimum - size is 16 bytes on most 32bit systems, and 32 bytes on 64bit - systems.) Note that size_t is an unsigned type, so calls with - arguments that would be negative if signed are interpreted as - requests for huge amounts of space, which will often fail. The - maximum supported value of n differs across systems, but is in all - cases less than the maximum representable value of a size_t. -*/ -DLMALLOC_EXPORT void* dlmalloc(size_t); - -/* - free(void* p) - Releases the chunk of memory pointed to by p, that had been previously - allocated using malloc or a related routine such as realloc. - It has no effect if p is null. If p was not malloced or already - freed, free(p) will by default cause the current program to abort. -*/ -DLMALLOC_EXPORT void dlfree(void*); - -/* - calloc(size_t n_elements, size_t element_size); - Returns a pointer to n_elements * element_size bytes, with all locations - set to zero. -*/ -DLMALLOC_EXPORT void* dlcalloc(size_t, size_t); - -/* - realloc(void* p, size_t n) - Returns a pointer to a chunk of size n that contains the same data - as does chunk p up to the minimum of (n, p's size) bytes, or null - if no space is available. - - The returned pointer may or may not be the same as p. The algorithm - prefers extending p in most cases when possible, otherwise it - employs the equivalent of a malloc-copy-free sequence. - - If p is null, realloc is equivalent to malloc. - - If space is not available, realloc returns null, errno is set (if on - ANSI) and p is NOT freed. - - if n is for fewer bytes than already held by p, the newly unused - space is lopped off and freed if possible. realloc with a size - argument of zero (re)allocates a minimum-sized chunk. - - The old unix realloc convention of allowing the last-free'd chunk - to be used as an argument to realloc is not supported. -*/ -DLMALLOC_EXPORT void* dlrealloc(void*, size_t); - -/* - realloc_in_place(void* p, size_t n) - Resizes the space allocated for p to size n, only if this can be - done without moving p (i.e., only if there is adjacent space - available if n is greater than p's current allocated size, or n is - less than or equal to p's size). This may be used instead of plain - realloc if an alternative allocation strategy is needed upon failure - to expand space; for example, reallocation of a buffer that must be - memory-aligned or cleared. You can use realloc_in_place to trigger - these alternatives only when needed. - - Returns p if successful; otherwise null. -*/ -DLMALLOC_EXPORT void* dlrealloc_in_place(void*, size_t); - -/* - memalign(size_t alignment, size_t n); - Returns a pointer to a newly allocated chunk of n bytes, aligned - in accord with the alignment argument. - - The alignment argument should be a power of two. If the argument is - not a power of two, the nearest greater power is used. - 8-byte alignment is guaranteed by normal malloc calls, so don't - bother calling memalign with an argument of 8 or less. - - Overreliance on memalign is a sure way to fragment space. -*/ -DLMALLOC_EXPORT void* dlmemalign(size_t, size_t); - -/* - int posix_memalign(void** pp, size_t alignment, size_t n); - Allocates a chunk of n bytes, aligned in accord with the alignment - argument. Differs from memalign only in that it (1) assigns the - allocated memory to *pp rather than returning it, (2) fails and - returns EINVAL if the alignment is not a power of two (3) fails and - returns ENOMEM if memory cannot be allocated. -*/ -DLMALLOC_EXPORT int dlposix_memalign(void**, size_t, size_t); - -/* - valloc(size_t n); - Equivalent to memalign(pagesize, n), where pagesize is the page - size of the system. If the pagesize is unknown, 4096 is used. -*/ -DLMALLOC_EXPORT void* dlvalloc(size_t); - -/* - mallopt(int parameter_number, int parameter_value) - Sets tunable parameters The format is to provide a - (parameter-number, parameter-value) pair. mallopt then sets the - corresponding parameter to the argument value if it can (i.e., so - long as the value is meaningful), and returns 1 if successful else - 0. To workaround the fact that mallopt is specified to use int, - not size_t parameters, the value -1 is specially treated as the - maximum unsigned size_t value. - - SVID/XPG/ANSI defines four standard param numbers for mallopt, - normally defined in malloc.h. None of these are use in this malloc, - so setting them has no effect. But this malloc also supports other - options in mallopt. See below for details. Briefly, supported - parameters are as follows (listed defaults are for "typical" - configurations). - - Symbol param # default allowed param values - M_TRIM_THRESHOLD -1 2*1024*1024 any (-1 disables) - M_GRANULARITY -2 page size any power of 2 >= page size - M_MMAP_THRESHOLD -3 256*1024 any (or 0 if no MMAP support) -*/ -DLMALLOC_EXPORT int dlmallopt(int, int); - -/* - malloc_footprint(); - Returns the number of bytes obtained from the system. The total - number of bytes allocated by malloc, realloc etc., is less than this - value. Unlike mallinfo, this function returns only a precomputed - result, so can be called frequently to monitor memory consumption. - Even if locks are otherwise defined, this function does not use them, - so results might not be up to date. -*/ -DLMALLOC_EXPORT size_t dlmalloc_footprint(void); - -/* - malloc_max_footprint(); - Returns the maximum number of bytes obtained from the system. This - value will be greater than current footprint if deallocated space - has been reclaimed by the system. The peak number of bytes allocated - by malloc, realloc etc., is less than this value. Unlike mallinfo, - this function returns only a precomputed result, so can be called - frequently to monitor memory consumption. Even if locks are - otherwise defined, this function does not use them, so results might - not be up to date. -*/ -DLMALLOC_EXPORT size_t dlmalloc_max_footprint(void); - -/* - malloc_footprint_limit(); - Returns the number of bytes that the heap is allowed to obtain from - the system, returning the last value returned by - malloc_set_footprint_limit, or the maximum size_t value if - never set. The returned value reflects a permission. There is no - guarantee that this number of bytes can actually be obtained from - the system. -*/ -DLMALLOC_EXPORT size_t dlmalloc_footprint_limit(); - -/* - malloc_set_footprint_limit(); - Sets the maximum number of bytes to obtain from the system, causing - failure returns from malloc and related functions upon attempts to - exceed this value. The argument value may be subject to page - rounding to an enforceable limit; this actual value is returned. - Using an argument of the maximum possible size_t effectively - disables checks. If the argument is less than or equal to the - current malloc_footprint, then all future allocations that require - additional system memory will fail. However, invocation cannot - retroactively deallocate existing used memory. -*/ -DLMALLOC_EXPORT size_t dlmalloc_set_footprint_limit(size_t bytes); - -#if MALLOC_INSPECT_ALL -/* - malloc_inspect_all(void(*handler)(void *start, - void *end, - size_t used_bytes, - void* callback_arg), - void* arg); - Traverses the heap and calls the given handler for each managed - region, skipping all bytes that are (or may be) used for bookkeeping - purposes. Traversal does not include include chunks that have been - directly memory mapped. Each reported region begins at the start - address, and continues up to but not including the end address. The - first used_bytes of the region contain allocated data. If - used_bytes is zero, the region is unallocated. The handler is - invoked with the given callback argument. If locks are defined, they - are held during the entire traversal. It is a bad idea to invoke - other malloc functions from within the handler. - - For example, to count the number of in-use chunks with size greater - than 1000, you could write: - static int count = 0; - void count_chunks(void* start, void* end, size_t used, void* arg) { - if (used >= 1000) ++count; - } - then: - malloc_inspect_all(count_chunks, NULL); - - malloc_inspect_all is compiled only if MALLOC_INSPECT_ALL is defined. -*/ -DLMALLOC_EXPORT void dlmalloc_inspect_all(void(*handler)(void*, void *, size_t, void*), - void* arg); - -#endif /* MALLOC_INSPECT_ALL */ - -#if !NO_MALLINFO -/* - mallinfo() - Returns (by copy) a struct containing various summary statistics: - - arena: current total non-mmapped bytes allocated from system - ordblks: the number of free chunks - smblks: always zero. - hblks: current number of mmapped regions - hblkhd: total bytes held in mmapped regions - usmblks: the maximum total allocated space. This will be greater - than current total if trimming has occurred. - fsmblks: always zero - uordblks: current total allocated space (normal or mmapped) - fordblks: total free space - keepcost: the maximum number of bytes that could ideally be released - back to system via malloc_trim. ("ideally" means that - it ignores page restrictions etc.) - - Because these fields are ints, but internal bookkeeping may - be kept as longs, the reported values may wrap around zero and - thus be inaccurate. -*/ -DLMALLOC_EXPORT struct mallinfo dlmallinfo(void); -#endif /* NO_MALLINFO */ - -/* - independent_calloc(size_t n_elements, size_t element_size, void* chunks[]); - - independent_calloc is similar to calloc, but instead of returning a - single cleared space, it returns an array of pointers to n_elements - independent elements that can hold contents of size elem_size, each - of which starts out cleared, and can be independently freed, - realloc'ed etc. The elements are guaranteed to be adjacently - allocated (this is not guaranteed to occur with multiple callocs or - mallocs), which may also improve cache locality in some - applications. - - The "chunks" argument is optional (i.e., may be null, which is - probably the most typical usage). If it is null, the returned array - is itself dynamically allocated and should also be freed when it is - no longer needed. Otherwise, the chunks array must be of at least - n_elements in length. It is filled in with the pointers to the - chunks. - - In either case, independent_calloc returns this pointer array, or - null if the allocation failed. If n_elements is zero and "chunks" - is null, it returns a chunk representing an array with zero elements - (which should be freed if not wanted). - - Each element must be freed when it is no longer needed. This can be - done all at once using bulk_free. - - independent_calloc simplifies and speeds up implementations of many - kinds of pools. It may also be useful when constructing large data - structures that initially have a fixed number of fixed-sized nodes, - but the number is not known at compile time, and some of the nodes - may later need to be freed. For example: - - struct Node { int item; struct Node* next; }; - - struct Node* build_list() { - struct Node** pool; - int n = read_number_of_nodes_needed(); - if (n <= 0) return 0; - pool = (struct Node**)(independent_calloc(n, sizeof(struct Node), 0); - if (pool == 0) die(); - // organize into a linked list... - struct Node* first = pool[0]; - for (i = 0; i < n-1; ++i) - pool[i]->next = pool[i+1]; - free(pool); // Can now free the array (or not, if it is needed later) - return first; - } -*/ -DLMALLOC_EXPORT void** dlindependent_calloc(size_t, size_t, void**); - -/* - independent_comalloc(size_t n_elements, size_t sizes[], void* chunks[]); - - independent_comalloc allocates, all at once, a set of n_elements - chunks with sizes indicated in the "sizes" array. It returns - an array of pointers to these elements, each of which can be - independently freed, realloc'ed etc. The elements are guaranteed to - be adjacently allocated (this is not guaranteed to occur with - multiple callocs or mallocs), which may also improve cache locality - in some applications. - - The "chunks" argument is optional (i.e., may be null). If it is null - the returned array is itself dynamically allocated and should also - be freed when it is no longer needed. Otherwise, the chunks array - must be of at least n_elements in length. It is filled in with the - pointers to the chunks. - - In either case, independent_comalloc returns this pointer array, or - null if the allocation failed. If n_elements is zero and chunks is - null, it returns a chunk representing an array with zero elements - (which should be freed if not wanted). - - Each element must be freed when it is no longer needed. This can be - done all at once using bulk_free. - - independent_comallac differs from independent_calloc in that each - element may have a different size, and also that it does not - automatically clear elements. - - independent_comalloc can be used to speed up allocation in cases - where several structs or objects must always be allocated at the - same time. For example: - - struct Head { ... } - struct Foot { ... } - - void send_message(char* msg) { - int msglen = strlen(msg); - size_t sizes[3] = { sizeof(struct Head), msglen, sizeof(struct Foot) }; - void* chunks[3]; - if (independent_comalloc(3, sizes, chunks) == 0) - die(); - struct Head* head = (struct Head*)(chunks[0]); - char* body = (char*)(chunks[1]); - struct Foot* foot = (struct Foot*)(chunks[2]); - // ... - } - - In general though, independent_comalloc is worth using only for - larger values of n_elements. For small values, you probably won't - detect enough difference from series of malloc calls to bother. - - Overuse of independent_comalloc can increase overall memory usage, - since it cannot reuse existing noncontiguous small chunks that - might be available for some of the elements. -*/ -DLMALLOC_EXPORT void** dlindependent_comalloc(size_t, size_t*, void**); - -/* - bulk_free(void* array[], size_t n_elements) - Frees and clears (sets to null) each non-null pointer in the given - array. This is likely to be faster than freeing them one-by-one. - If footers are used, pointers that have been allocated in different - mspaces are not freed or cleared, and the count of all such pointers - is returned. For large arrays of pointers with poor locality, it - may be worthwhile to sort this array before calling bulk_free. -*/ -DLMALLOC_EXPORT size_t dlbulk_free(void**, size_t n_elements); - -/* - pvalloc(size_t n); - Equivalent to valloc(minimum-page-that-holds(n)), that is, - round up n to nearest pagesize. - */ -DLMALLOC_EXPORT void* dlpvalloc(size_t); - -/* - malloc_trim(size_t pad); - - If possible, gives memory back to the system (via negative arguments - to sbrk) if there is unused memory at the `high' end of the malloc - pool or in unused MMAP segments. You can call this after freeing - large blocks of memory to potentially reduce the system-level memory - requirements of a program. However, it cannot guarantee to reduce - memory. Under some allocation patterns, some large free blocks of - memory will be locked between two used chunks, so they cannot be - given back to the system. - - The `pad' argument to malloc_trim represents the amount of free - trailing space to leave untrimmed. If this argument is zero, only - the minimum amount of memory to maintain internal data structures - will be left. Non-zero arguments can be supplied to maintain enough - trailing space to service future expected allocations without having - to re-obtain memory from the system. - - Malloc_trim returns 1 if it actually released any memory, else 0. -*/ -DLMALLOC_EXPORT int dlmalloc_trim(size_t); - -/* - malloc_stats(); - Prints on stderr the amount of space obtained from the system (both - via sbrk and mmap), the maximum amount (which may be more than - current if malloc_trim and/or munmap got called), and the current - number of bytes allocated via malloc (or realloc, etc) but not yet - freed. Note that this is the number of bytes allocated, not the - number requested. It will be larger than the number requested - because of alignment and bookkeeping overhead. Because it includes - alignment wastage as being in use, this figure may be greater than - zero even when no user-level chunks are allocated. - - The reported current and maximum system memory can be inaccurate if - a program makes other calls to system memory allocation functions - (normally sbrk) outside of malloc. - - malloc_stats prints only the most commonly interesting statistics. - More information can be obtained by calling mallinfo. -*/ -DLMALLOC_EXPORT void dlmalloc_stats(void); - -/* - malloc_usable_size(void* p); - - Returns the number of bytes you can actually use in - an allocated chunk, which may be more than you requested (although - often not) due to alignment and minimum size constraints. - You can use this many bytes without worrying about - overwriting other allocated objects. This is not a particularly great - programming practice. malloc_usable_size can be more useful in - debugging and assertions, for example: - - p = malloc(n); - assert(malloc_usable_size(p) >= 256); -*/ -size_t dlmalloc_usable_size(void*); - -#endif /* ONLY_MSPACES */ - -#if MSPACES - -/* - mspace is an opaque type representing an independent - region of space that supports mspace_malloc, etc. -*/ -typedef void* mspace; - -/* - create_mspace creates and returns a new independent space with the - given initial capacity, or, if 0, the default granularity size. It - returns null if there is no system memory available to create the - space. If argument locked is non-zero, the space uses a separate - lock to control access. The capacity of the space will grow - dynamically as needed to service mspace_malloc requests. You can - control the sizes of incremental increases of this space by - compiling with a different DEFAULT_GRANULARITY or dynamically - setting with mallopt(M_GRANULARITY, value). -*/ -DLMALLOC_EXPORT mspace create_mspace(size_t capacity, int locked); - -/* - destroy_mspace destroys the given space, and attempts to return all - of its memory back to the system, returning the total number of - bytes freed. After destruction, the results of access to all memory - used by the space become undefined. -*/ -DLMALLOC_EXPORT size_t destroy_mspace(mspace msp); - -/* - create_mspace_with_base uses the memory supplied as the initial base - of a new mspace. Part (less than 128*sizeof(size_t) bytes) of this - space is used for bookkeeping, so the capacity must be at least this - large. (Otherwise 0 is returned.) When this initial space is - exhausted, additional memory will be obtained from the system. - Destroying this space will deallocate all additionally allocated - space (if possible) but not the initial base. -*/ -DLMALLOC_EXPORT mspace create_mspace_with_base(void* base, size_t capacity, int locked); - -/* - mspace_track_large_chunks controls whether requests for large chunks - are allocated in their own untracked mmapped regions, separate from - others in this mspace. By default large chunks are not tracked, - which reduces fragmentation. However, such chunks are not - necessarily released to the system upon destroy_mspace. Enabling - tracking by setting to true may increase fragmentation, but avoids - leakage when relying on destroy_mspace to release all memory - allocated using this space. The function returns the previous - setting. -*/ -DLMALLOC_EXPORT int mspace_track_large_chunks(mspace msp, int enable); - - -/* - mspace_malloc behaves as malloc, but operates within - the given space. -*/ -DLMALLOC_EXPORT void* mspace_malloc(mspace msp, size_t bytes); - -/* - mspace_free behaves as free, but operates within - the given space. - - If compiled with FOOTERS==1, mspace_free is not actually needed. - free may be called instead of mspace_free because freed chunks from - any space are handled by their originating spaces. -*/ -DLMALLOC_EXPORT void mspace_free(mspace msp, void* mem); - -/* - mspace_realloc behaves as realloc, but operates within - the given space. - - If compiled with FOOTERS==1, mspace_realloc is not actually - needed. realloc may be called instead of mspace_realloc because - realloced chunks from any space are handled by their originating - spaces. -*/ -DLMALLOC_EXPORT void* mspace_realloc(mspace msp, void* mem, size_t newsize); - -/* - mspace_calloc behaves as calloc, but operates within - the given space. -*/ -DLMALLOC_EXPORT void* mspace_calloc(mspace msp, size_t n_elements, size_t elem_size); - -/* - mspace_memalign behaves as memalign, but operates within - the given space. -*/ -DLMALLOC_EXPORT void* mspace_memalign(mspace msp, size_t alignment, size_t bytes); - -/* - mspace_independent_calloc behaves as independent_calloc, but - operates within the given space. -*/ -DLMALLOC_EXPORT void** mspace_independent_calloc(mspace msp, size_t n_elements, - size_t elem_size, void* chunks[]); - -/* - mspace_independent_comalloc behaves as independent_comalloc, but - operates within the given space. -*/ -DLMALLOC_EXPORT void** mspace_independent_comalloc(mspace msp, size_t n_elements, - size_t sizes[], void* chunks[]); - -/* - mspace_footprint() returns the number of bytes obtained from the - system for this space. -*/ -DLMALLOC_EXPORT size_t mspace_footprint(mspace msp); - -/* - mspace_max_footprint() returns the peak number of bytes obtained from the - system for this space. -*/ -DLMALLOC_EXPORT size_t mspace_max_footprint(mspace msp); - - -#if !NO_MALLINFO -/* - mspace_mallinfo behaves as mallinfo, but reports properties of - the given space. -*/ -DLMALLOC_EXPORT struct mallinfo mspace_mallinfo(mspace msp); -#endif /* NO_MALLINFO */ - -/* - malloc_usable_size(void* p) behaves the same as malloc_usable_size; -*/ -DLMALLOC_EXPORT size_t mspace_usable_size(const void* mem); - -/* - mspace_malloc_stats behaves as malloc_stats, but reports - properties of the given space. -*/ -DLMALLOC_EXPORT void mspace_malloc_stats(mspace msp); - -/* - mspace_trim behaves as malloc_trim, but - operates within the given space. -*/ -DLMALLOC_EXPORT int mspace_trim(mspace msp, size_t pad); - -/* - An alias for mallopt. -*/ -DLMALLOC_EXPORT int mspace_mallopt(int, int); - -#endif /* MSPACES */ - -#ifdef __cplusplus -} /* end of extern "C" */ -#endif /* __cplusplus */ - -/* - ======================================================================== - To make a fully customizable malloc.h header file, cut everything - above this line, put into file malloc.h, edit to suit, and #include it - on the next line, as well as in programs that use this malloc. - ======================================================================== -*/ - -/* #include "malloc.h" */ - -/*------------------------------ internal #includes ---------------------- */ - -#ifdef _MSC_VER -#pragma warning( disable : 4146 ) /* no "unsigned" warnings */ -#endif /* _MSC_VER */ -#if !NO_MALLOC_STATS -#include /* for printing in malloc_stats */ -#endif /* NO_MALLOC_STATS */ -#ifndef LACKS_ERRNO_H -#include /* for MALLOC_FAILURE_ACTION */ -#endif /* LACKS_ERRNO_H */ -#ifdef DEBUG -#if ABORT_ON_ASSERT_FAILURE -#undef assert -#define assert(x) if(!(x)) ABORT -#else /* ABORT_ON_ASSERT_FAILURE */ -#include -#endif /* ABORT_ON_ASSERT_FAILURE */ -#else /* DEBUG */ -#ifndef assert -#define assert(x) -#endif -#define DEBUG 0 -#endif /* DEBUG */ -#if !defined(WIN32) && !defined(LACKS_TIME_H) -#include /* for magic initialization */ -#endif /* WIN32 */ -#ifndef LACKS_STDLIB_H -#include /* for abort() */ -#endif /* LACKS_STDLIB_H */ -#ifndef LACKS_STRING_H -#include /* for memset etc */ -#endif /* LACKS_STRING_H */ -#if USE_BUILTIN_FFS -#ifndef LACKS_STRINGS_H -#include /* for ffs */ -#endif /* LACKS_STRINGS_H */ -#endif /* USE_BUILTIN_FFS */ -#if HAVE_MMAP -#ifndef LACKS_SYS_MMAN_H -/* On some versions of linux, mremap decl in mman.h needs __USE_GNU set */ -#if (defined(linux) && !defined(__USE_GNU)) -#define __USE_GNU 1 -#include /* for mmap */ -#undef __USE_GNU -#else -#include /* for mmap */ -#endif /* linux */ -#endif /* LACKS_SYS_MMAN_H */ -#ifndef LACKS_FCNTL_H -#include -#endif /* LACKS_FCNTL_H */ -#endif /* HAVE_MMAP */ -#ifndef LACKS_UNISTD_H -#include /* for sbrk, sysconf */ -#else /* LACKS_UNISTD_H */ -#if !defined(__FreeBSD__) && !defined(__OpenBSD__) && !defined(__NetBSD__) -extern void* sbrk(ptrdiff_t); -#endif /* FreeBSD etc */ -#endif /* LACKS_UNISTD_H */ - -/* Declarations for locking */ -#if USE_LOCKS -#ifndef WIN32 -#if defined (__SVR4) && defined (__sun) /* solaris */ -#include -#elif !defined(LACKS_SCHED_H) -#include -#endif /* solaris or LACKS_SCHED_H */ -#if (defined(USE_RECURSIVE_LOCKS) && USE_RECURSIVE_LOCKS != 0) || !USE_SPIN_LOCKS -#include -#endif /* USE_RECURSIVE_LOCKS ... */ -#elif defined(_MSC_VER) -#ifndef _M_AMD64 -/* These are already defined on AMD64 builds */ -#ifdef __cplusplus -extern "C" { -#endif /* __cplusplus */ -LONG __cdecl _InterlockedCompareExchange(LONG volatile *Dest, LONG Exchange, LONG Comp); -LONG __cdecl _InterlockedExchange(LONG volatile *Target, LONG Value); -#ifdef __cplusplus -} -#endif /* __cplusplus */ -#endif /* _M_AMD64 */ -#pragma intrinsic (_InterlockedCompareExchange) -#pragma intrinsic (_InterlockedExchange) -#define interlockedcompareexchange _InterlockedCompareExchange -#define interlockedexchange _InterlockedExchange -#elif defined(WIN32) && defined(__GNUC__) -#define interlockedcompareexchange(a, b, c) __sync_val_compare_and_swap(a, c, b) -#define interlockedexchange __sync_lock_test_and_set -#endif /* Win32 */ -#else /* USE_LOCKS */ -#endif /* USE_LOCKS */ - -#ifndef LOCK_AT_FORK -#define LOCK_AT_FORK 0 -#endif - -/* Declarations for bit scanning on win32 */ -#if defined(_MSC_VER) && _MSC_VER>=1300 -#ifndef BitScanForward /* Try to avoid pulling in WinNT.h */ -#ifdef __cplusplus -extern "C" { -#endif /* __cplusplus */ -unsigned char _BitScanForward(unsigned long *index, unsigned long mask); -unsigned char _BitScanReverse(unsigned long *index, unsigned long mask); -#ifdef __cplusplus -} -#endif /* __cplusplus */ - -#define BitScanForward _BitScanForward -#define BitScanReverse _BitScanReverse -#pragma intrinsic(_BitScanForward) -#pragma intrinsic(_BitScanReverse) -#endif /* BitScanForward */ -#endif /* defined(_MSC_VER) && _MSC_VER>=1300 */ - -#ifndef WIN32 -#ifndef malloc_getpagesize -# ifdef _SC_PAGESIZE /* some SVR4 systems omit an underscore */ -# ifndef _SC_PAGE_SIZE -# define _SC_PAGE_SIZE _SC_PAGESIZE -# endif -# endif -# ifdef _SC_PAGE_SIZE -# define malloc_getpagesize sysconf(_SC_PAGE_SIZE) -# else -# if defined(BSD) || defined(DGUX) || defined(HAVE_GETPAGESIZE) - extern size_t getpagesize(); -# define malloc_getpagesize getpagesize() -# else -# ifdef WIN32 /* use supplied emulation of getpagesize */ -# define malloc_getpagesize getpagesize() -# else -# ifndef LACKS_SYS_PARAM_H -# include -# endif -# ifdef EXEC_PAGESIZE -# define malloc_getpagesize EXEC_PAGESIZE -# else -# ifdef NBPG -# ifndef CLSIZE -# define malloc_getpagesize NBPG -# else -# define malloc_getpagesize (NBPG * CLSIZE) -# endif -# else -# ifdef NBPC -# define malloc_getpagesize NBPC -# else -# ifdef PAGESIZE -# define malloc_getpagesize PAGESIZE -# else /* just guess */ -# define malloc_getpagesize ((size_t)4096U) -# endif -# endif -# endif -# endif -# endif -# endif -# endif -#endif -#endif - -/* ------------------- size_t and alignment properties -------------------- */ - -/* The byte and bit size of a size_t */ -#define SIZE_T_SIZE (sizeof(size_t)) -#define SIZE_T_BITSIZE (sizeof(size_t) << 3) - -/* Some constants coerced to size_t */ -/* Annoying but necessary to avoid errors on some platforms */ -#define SIZE_T_ZERO ((size_t)0) -#define SIZE_T_ONE ((size_t)1) -#define SIZE_T_TWO ((size_t)2) -#define SIZE_T_FOUR ((size_t)4) -#define TWO_SIZE_T_SIZES (SIZE_T_SIZE<<1) -#define FOUR_SIZE_T_SIZES (SIZE_T_SIZE<<2) -#define SIX_SIZE_T_SIZES (FOUR_SIZE_T_SIZES+TWO_SIZE_T_SIZES) -#define HALF_MAX_SIZE_T (MAX_SIZE_T / 2U) - -/* The bit mask value corresponding to MALLOC_ALIGNMENT */ -#define CHUNK_ALIGN_MASK (MALLOC_ALIGNMENT - SIZE_T_ONE) - -/* True if address a has acceptable alignment */ -#define is_aligned(A) (((size_t)((A)) & (CHUNK_ALIGN_MASK)) == 0) - -/* the number of bytes to offset an address to align it */ -#define align_offset(A)\ - ((((size_t)(A) & CHUNK_ALIGN_MASK) == 0)? 0 :\ - ((MALLOC_ALIGNMENT - ((size_t)(A) & CHUNK_ALIGN_MASK)) & CHUNK_ALIGN_MASK)) - -/* -------------------------- MMAP preliminaries ------------------------- */ - -/* - If HAVE_MORECORE or HAVE_MMAP are false, we just define calls and - checks to fail so compiler optimizer can delete code rather than - using so many "#if"s. -*/ - - -/* MORECORE and MMAP must return MFAIL on failure */ -#define MFAIL ((void*)(MAX_SIZE_T)) -#define CMFAIL ((char*)(MFAIL)) /* defined for convenience */ - -#if HAVE_MMAP - -#ifndef WIN32 -#define MUNMAP_DEFAULT(a, s) munmap((a), (s)) -#define MMAP_PROT (PROT_READ|PROT_WRITE) -#if !defined(MAP_ANONYMOUS) && defined(MAP_ANON) -#define MAP_ANONYMOUS MAP_ANON -#endif /* MAP_ANON */ -#ifdef MAP_ANONYMOUS -#define MMAP_FLAGS (MAP_PRIVATE|MAP_ANONYMOUS) -#define MMAP_DEFAULT(s) mmap(0, (s), MMAP_PROT, MMAP_FLAGS, -1, 0) -#else /* MAP_ANONYMOUS */ -/* - Nearly all versions of mmap support MAP_ANONYMOUS, so the following - is unlikely to be needed, but is supplied just in case. -*/ -#define MMAP_FLAGS (MAP_PRIVATE) -static int dev_zero_fd = -1; /* Cached file descriptor for /dev/zero. */ -#define MMAP_DEFAULT(s) ((dev_zero_fd < 0) ? \ - (dev_zero_fd = open("/dev/zero", O_RDWR), \ - mmap(0, (s), MMAP_PROT, MMAP_FLAGS, dev_zero_fd, 0)) : \ - mmap(0, (s), MMAP_PROT, MMAP_FLAGS, dev_zero_fd, 0)) -#endif /* MAP_ANONYMOUS */ - -#define DIRECT_MMAP_DEFAULT(s) MMAP_DEFAULT(s) - -#else /* WIN32 */ - -/* Win32 MMAP via VirtualAlloc */ -static FORCEINLINE void* win32mmap(size_t size) { - void* ptr = VirtualAlloc(0, size, MEM_RESERVE|MEM_COMMIT, PAGE_READWRITE); - return (ptr != 0)? ptr: MFAIL; -} - -/* For direct MMAP, use MEM_TOP_DOWN to minimize interference */ -static FORCEINLINE void* win32direct_mmap(size_t size) { - void* ptr = VirtualAlloc(0, size, MEM_RESERVE|MEM_COMMIT|MEM_TOP_DOWN, - PAGE_READWRITE); - return (ptr != 0)? ptr: MFAIL; -} - -/* This function supports releasing coalesed segments */ -static FORCEINLINE int win32munmap(void* ptr, size_t size) { - MEMORY_BASIC_INFORMATION minfo; - char* cptr = (char*)ptr; - while (size) { - if (VirtualQuery(cptr, &minfo, sizeof(minfo)) == 0) - return -1; - if (minfo.BaseAddress != cptr || minfo.AllocationBase != cptr || - minfo.State != MEM_COMMIT || minfo.RegionSize > size) - return -1; - if (VirtualFree(cptr, 0, MEM_RELEASE) == 0) - return -1; - cptr += minfo.RegionSize; - size -= minfo.RegionSize; - } - return 0; -} - -#define MMAP_DEFAULT(s) win32mmap(s) -#define MUNMAP_DEFAULT(a, s) win32munmap((a), (s)) -#define DIRECT_MMAP_DEFAULT(s) win32direct_mmap(s) -#endif /* WIN32 */ -#endif /* HAVE_MMAP */ - -#if HAVE_MREMAP -#ifndef WIN32 -#define MREMAP_DEFAULT(addr, osz, nsz, mv) mremap((addr), (osz), (nsz), (mv)) -#endif /* WIN32 */ -#endif /* HAVE_MREMAP */ - -/** - * Define CALL_MORECORE - */ -#if HAVE_MORECORE - #ifdef MORECORE - #define CALL_MORECORE(S) MORECORE(S) - #else /* MORECORE */ - #define CALL_MORECORE(S) MORECORE_DEFAULT(S) - #endif /* MORECORE */ -#else /* HAVE_MORECORE */ - #define CALL_MORECORE(S) MFAIL -#endif /* HAVE_MORECORE */ - -/** - * Define CALL_MMAP/CALL_MUNMAP/CALL_DIRECT_MMAP - */ -#if HAVE_MMAP - #define USE_MMAP_BIT (SIZE_T_ONE) - - #ifdef MMAP - #define CALL_MMAP(s) MMAP(s) - #else /* MMAP */ - #define CALL_MMAP(s) MMAP_DEFAULT(s) - #endif /* MMAP */ - #ifdef MUNMAP - #define CALL_MUNMAP(a, s) MUNMAP((a), (s)) - #else /* MUNMAP */ - #define CALL_MUNMAP(a, s) MUNMAP_DEFAULT((a), (s)) - #endif /* MUNMAP */ - #ifdef DIRECT_MMAP - #define CALL_DIRECT_MMAP(s) DIRECT_MMAP(s) - #else /* DIRECT_MMAP */ - #define CALL_DIRECT_MMAP(s) DIRECT_MMAP_DEFAULT(s) - #endif /* DIRECT_MMAP */ -#else /* HAVE_MMAP */ - #define USE_MMAP_BIT (SIZE_T_ZERO) - - #define MMAP(s) MFAIL - #define MUNMAP(a, s) (-1) - #define DIRECT_MMAP(s) MFAIL - #define CALL_DIRECT_MMAP(s) DIRECT_MMAP(s) - #define CALL_MMAP(s) MMAP(s) - #define CALL_MUNMAP(a, s) MUNMAP((a), (s)) -#endif /* HAVE_MMAP */ - -/** - * Define CALL_MREMAP - */ -#if HAVE_MMAP && HAVE_MREMAP - #ifdef MREMAP - #define CALL_MREMAP(addr, osz, nsz, mv) MREMAP((addr), (osz), (nsz), (mv)) - #else /* MREMAP */ - #define CALL_MREMAP(addr, osz, nsz, mv) MREMAP_DEFAULT((addr), (osz), (nsz), (mv)) - #endif /* MREMAP */ -#else /* HAVE_MMAP && HAVE_MREMAP */ - #define CALL_MREMAP(addr, osz, nsz, mv) MFAIL -#endif /* HAVE_MMAP && HAVE_MREMAP */ - -/* mstate bit set if continguous morecore disabled or failed */ -#define USE_NONCONTIGUOUS_BIT (4U) - -/* segment bit set in create_mspace_with_base */ -#define EXTERN_BIT (8U) - - -/* --------------------------- Lock preliminaries ------------------------ */ - -/* - When locks are defined, there is one global lock, plus - one per-mspace lock. - - The global lock_ensures that mparams.magic and other unique - mparams values are initialized only once. It also protects - sequences of calls to MORECORE. In many cases sys_alloc requires - two calls, that should not be interleaved with calls by other - threads. This does not protect against direct calls to MORECORE - by other threads not using this lock, so there is still code to - cope the best we can on interference. - - Per-mspace locks surround calls to malloc, free, etc. - By default, locks are simple non-reentrant mutexes. - - Because lock-protected regions generally have bounded times, it is - OK to use the supplied simple spinlocks. Spinlocks are likely to - improve performance for lightly contended applications, but worsen - performance under heavy contention. - - If USE_LOCKS is > 1, the definitions of lock routines here are - bypassed, in which case you will need to define the type MLOCK_T, - and at least INITIAL_LOCK, DESTROY_LOCK, ACQUIRE_LOCK, RELEASE_LOCK - and TRY_LOCK. You must also declare a - static MLOCK_T malloc_global_mutex = { initialization values };. - -*/ - -#if !USE_LOCKS -#define USE_LOCK_BIT (0U) -#define INITIAL_LOCK(l) (0) -#define DESTROY_LOCK(l) (0) -#define ACQUIRE_MALLOC_GLOBAL_LOCK() -#define RELEASE_MALLOC_GLOBAL_LOCK() - -#else -#if USE_LOCKS > 1 -/* ----------------------- User-defined locks ------------------------ */ -/* Define your own lock implementation here */ -/* #define INITIAL_LOCK(lk) ... */ -/* #define DESTROY_LOCK(lk) ... */ -/* #define ACQUIRE_LOCK(lk) ... */ -/* #define RELEASE_LOCK(lk) ... */ -/* #define TRY_LOCK(lk) ... */ -/* static MLOCK_T malloc_global_mutex = ... */ - -#elif USE_SPIN_LOCKS - -/* First, define CAS_LOCK and CLEAR_LOCK on ints */ -/* Note CAS_LOCK defined to return 0 on success */ - -#if defined(__GNUC__)&& (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 1)) -#define CAS_LOCK(sl) __sync_lock_test_and_set(sl, 1) -#define CLEAR_LOCK(sl) __sync_lock_release(sl) - -#elif (defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__))) -/* Custom spin locks for older gcc on x86 */ -static FORCEINLINE int x86_cas_lock(int *sl) { - int ret; - int val = 1; - int cmp = 0; - __asm__ __volatile__ ("lock; cmpxchgl %1, %2" - : "=a" (ret) - : "r" (val), "m" (*(sl)), "0"(cmp) - : "memory", "cc"); - return ret; -} - -static FORCEINLINE void x86_clear_lock(int* sl) { - assert(*sl != 0); - int prev = 0; - int ret; - __asm__ __volatile__ ("lock; xchgl %0, %1" - : "=r" (ret) - : "m" (*(sl)), "0"(prev) - : "memory"); -} - -#define CAS_LOCK(sl) x86_cas_lock(sl) -#define CLEAR_LOCK(sl) x86_clear_lock(sl) - -#else /* Win32 MSC */ -#define CAS_LOCK(sl) interlockedexchange(sl, (LONG)1) -#define CLEAR_LOCK(sl) interlockedexchange (sl, (LONG)0) - -#endif /* ... gcc spins locks ... */ - -/* How to yield for a spin lock */ -#define SPINS_PER_YIELD 63 -#if defined(_MSC_VER) -#define SLEEP_EX_DURATION 50 /* delay for yield/sleep */ -#define SPIN_LOCK_YIELD SleepEx(SLEEP_EX_DURATION, FALSE) -#elif defined (__SVR4) && defined (__sun) /* solaris */ -#define SPIN_LOCK_YIELD thr_yield(); -#elif !defined(LACKS_SCHED_H) -#define SPIN_LOCK_YIELD sched_yield(); -#else -#define SPIN_LOCK_YIELD -#endif /* ... yield ... */ - -#if !defined(USE_RECURSIVE_LOCKS) || USE_RECURSIVE_LOCKS == 0 -/* Plain spin locks use single word (embedded in malloc_states) */ -static int spin_acquire_lock(int *sl) { - int spins = 0; - while (*(volatile int *)sl != 0 || CAS_LOCK(sl)) { - if ((++spins & SPINS_PER_YIELD) == 0) { - SPIN_LOCK_YIELD; - } - } - return 0; -} - -#define MLOCK_T int -#define TRY_LOCK(sl) !CAS_LOCK(sl) -#define RELEASE_LOCK(sl) CLEAR_LOCK(sl) -#define ACQUIRE_LOCK(sl) (CAS_LOCK(sl)? spin_acquire_lock(sl) : 0) -#define INITIAL_LOCK(sl) (*sl = 0) -#define DESTROY_LOCK(sl) (0) -static MLOCK_T malloc_global_mutex = 0; - -#else /* USE_RECURSIVE_LOCKS */ -/* types for lock owners */ -#ifdef WIN32 -#define THREAD_ID_T DWORD -#define CURRENT_THREAD GetCurrentThreadId() -#define EQ_OWNER(X,Y) ((X) == (Y)) -#else -/* - Note: the following assume that pthread_t is a type that can be - initialized to (casted) zero. If this is not the case, you will need to - somehow redefine these or not use spin locks. -*/ -#define THREAD_ID_T pthread_t -#define CURRENT_THREAD pthread_self() -#define EQ_OWNER(X,Y) pthread_equal(X, Y) -#endif - -struct malloc_recursive_lock { - int sl; - unsigned int c; - THREAD_ID_T threadid; -}; - -#define MLOCK_T struct malloc_recursive_lock -static MLOCK_T malloc_global_mutex = { 0, 0, (THREAD_ID_T)0}; - -static FORCEINLINE void recursive_release_lock(MLOCK_T *lk) { - assert(lk->sl != 0); - if (--lk->c == 0) { - CLEAR_LOCK(&lk->sl); - } -} - -static FORCEINLINE int recursive_acquire_lock(MLOCK_T *lk) { - THREAD_ID_T mythreadid = CURRENT_THREAD; - int spins = 0; - for (;;) { - if (*((volatile int *)(&lk->sl)) == 0) { - if (!CAS_LOCK(&lk->sl)) { - lk->threadid = mythreadid; - lk->c = 1; - return 0; - } - } - else if (EQ_OWNER(lk->threadid, mythreadid)) { - ++lk->c; - return 0; - } - if ((++spins & SPINS_PER_YIELD) == 0) { - SPIN_LOCK_YIELD; - } - } -} - -static FORCEINLINE int recursive_try_lock(MLOCK_T *lk) { - THREAD_ID_T mythreadid = CURRENT_THREAD; - if (*((volatile int *)(&lk->sl)) == 0) { - if (!CAS_LOCK(&lk->sl)) { - lk->threadid = mythreadid; - lk->c = 1; - return 1; - } - } - else if (EQ_OWNER(lk->threadid, mythreadid)) { - ++lk->c; - return 1; - } - return 0; -} - -#define RELEASE_LOCK(lk) recursive_release_lock(lk) -#define TRY_LOCK(lk) recursive_try_lock(lk) -#define ACQUIRE_LOCK(lk) recursive_acquire_lock(lk) -#define INITIAL_LOCK(lk) ((lk)->threadid = (THREAD_ID_T)0, (lk)->sl = 0, (lk)->c = 0) -#define DESTROY_LOCK(lk) (0) -#endif /* USE_RECURSIVE_LOCKS */ - -#elif defined(WIN32) /* Win32 critical sections */ -#define MLOCK_T CRITICAL_SECTION -#define ACQUIRE_LOCK(lk) (EnterCriticalSection(lk), 0) -#define RELEASE_LOCK(lk) LeaveCriticalSection(lk) -#define TRY_LOCK(lk) TryEnterCriticalSection(lk) -#define INITIAL_LOCK(lk) (!InitializeCriticalSectionAndSpinCount((lk), 0x80000000|4000)) -#define DESTROY_LOCK(lk) (DeleteCriticalSection(lk), 0) -#define NEED_GLOBAL_LOCK_INIT - -static MLOCK_T malloc_global_mutex; -static volatile LONG malloc_global_mutex_status; - -/* Use spin loop to initialize global lock */ -static void init_malloc_global_mutex() { - for (;;) { - long stat = malloc_global_mutex_status; - if (stat > 0) - return; - /* transition to < 0 while initializing, then to > 0) */ - if (stat == 0 && - interlockedcompareexchange(&malloc_global_mutex_status, (LONG)-1, (LONG)0) == 0) { - InitializeCriticalSection(&malloc_global_mutex); - interlockedexchange(&malloc_global_mutex_status, (LONG)1); - return; - } - SleepEx(0, FALSE); - } -} - -#else /* pthreads-based locks */ -#define MLOCK_T pthread_mutex_t -#define ACQUIRE_LOCK(lk) pthread_mutex_lock(lk) -#define RELEASE_LOCK(lk) pthread_mutex_unlock(lk) -#define TRY_LOCK(lk) (!pthread_mutex_trylock(lk)) -#define INITIAL_LOCK(lk) pthread_init_lock(lk) -#define DESTROY_LOCK(lk) pthread_mutex_destroy(lk) - -#if defined(USE_RECURSIVE_LOCKS) && USE_RECURSIVE_LOCKS != 0 && defined(linux) && !defined(PTHREAD_MUTEX_RECURSIVE) -/* Cope with old-style linux recursive lock initialization by adding */ -/* skipped internal declaration from pthread.h */ -extern int pthread_mutexattr_setkind_np __P ((pthread_mutexattr_t *__attr, - int __kind)); -#define PTHREAD_MUTEX_RECURSIVE PTHREAD_MUTEX_RECURSIVE_NP -#define pthread_mutexattr_settype(x,y) pthread_mutexattr_setkind_np(x,y) -#endif /* USE_RECURSIVE_LOCKS ... */ - -static MLOCK_T malloc_global_mutex = PTHREAD_MUTEX_INITIALIZER; - -static int pthread_init_lock (MLOCK_T *lk) { - pthread_mutexattr_t attr; - if (pthread_mutexattr_init(&attr)) return 1; -#if defined(USE_RECURSIVE_LOCKS) && USE_RECURSIVE_LOCKS != 0 - if (pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE)) return 1; -#endif - if (pthread_mutex_init(lk, &attr)) return 1; - if (pthread_mutexattr_destroy(&attr)) return 1; - return 0; -} - -#endif /* ... lock types ... */ - -/* Common code for all lock types */ -#define USE_LOCK_BIT (2U) - -#ifndef ACQUIRE_MALLOC_GLOBAL_LOCK -#define ACQUIRE_MALLOC_GLOBAL_LOCK() ACQUIRE_LOCK(&malloc_global_mutex); -#endif - -#ifndef RELEASE_MALLOC_GLOBAL_LOCK -#define RELEASE_MALLOC_GLOBAL_LOCK() RELEASE_LOCK(&malloc_global_mutex); -#endif - -#endif /* USE_LOCKS */ - -/* ----------------------- Chunk representations ------------------------ */ - -/* - (The following includes lightly edited explanations by Colin Plumb.) - - The malloc_chunk declaration below is misleading (but accurate and - necessary). It declares a "view" into memory allowing access to - necessary fields at known offsets from a given base. - - Chunks of memory are maintained using a `boundary tag' method as - originally described by Knuth. (See the paper by Paul Wilson - ftp://ftp.cs.utexas.edu/pub/garbage/allocsrv.ps for a survey of such - techniques.) Sizes of free chunks are stored both in the front of - each chunk and at the end. This makes consolidating fragmented - chunks into bigger chunks fast. The head fields also hold bits - representing whether chunks are free or in use. - - Here are some pictures to make it clearer. They are "exploded" to - show that the state of a chunk can be thought of as extending from - the high 31 bits of the head field of its header through the - prev_foot and PINUSE_BIT bit of the following chunk header. - - A chunk that's in use looks like: - - chunk-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - | Size of previous chunk (if P = 0) | - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |P| - | Size of this chunk 1| +-+ - mem-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - | | - +- -+ - | | - +- -+ - | : - +- size - sizeof(size_t) available payload bytes -+ - : | - chunk-> +- -+ - | | - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |1| - | Size of next chunk (may or may not be in use) | +-+ - mem-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - - And if it's free, it looks like this: - - chunk-> +- -+ - | User payload (must be in use, or we would have merged!) | - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |P| - | Size of this chunk 0| +-+ - mem-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - | Next pointer | - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - | Prev pointer | - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - | : - +- size - sizeof(struct chunk) unused bytes -+ - : | - chunk-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - | Size of this chunk | - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |0| - | Size of next chunk (must be in use, or we would have merged)| +-+ - mem-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - | : - +- User payload -+ - : | - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - |0| - +-+ - Note that since we always merge adjacent free chunks, the chunks - adjacent to a free chunk must be in use. - - Given a pointer to a chunk (which can be derived trivially from the - payload pointer) we can, in O(1) time, find out whether the adjacent - chunks are free, and if so, unlink them from the lists that they - are on and merge them with the current chunk. - - Chunks always begin on even word boundaries, so the mem portion - (which is returned to the user) is also on an even word boundary, and - thus at least double-word aligned. - - The P (PINUSE_BIT) bit, stored in the unused low-order bit of the - chunk size (which is always a multiple of two words), is an in-use - bit for the *previous* chunk. If that bit is *clear*, then the - word before the current chunk size contains the previous chunk - size, and can be used to find the front of the previous chunk. - The very first chunk allocated always has this bit set, preventing - access to non-existent (or non-owned) memory. If pinuse is set for - any given chunk, then you CANNOT determine the size of the - previous chunk, and might even get a memory addressing fault when - trying to do so. - - The C (CINUSE_BIT) bit, stored in the unused second-lowest bit of - the chunk size redundantly records whether the current chunk is - inuse (unless the chunk is mmapped). This redundancy enables usage - checks within free and realloc, and reduces indirection when freeing - and consolidating chunks. - - Each freshly allocated chunk must have both cinuse and pinuse set. - That is, each allocated chunk borders either a previously allocated - and still in-use chunk, or the base of its memory arena. This is - ensured by making all allocations from the `lowest' part of any - found chunk. Further, no free chunk physically borders another one, - so each free chunk is known to be preceded and followed by either - inuse chunks or the ends of memory. - - Note that the `foot' of the current chunk is actually represented - as the prev_foot of the NEXT chunk. This makes it easier to - deal with alignments etc but can be very confusing when trying - to extend or adapt this code. - - The exceptions to all this are - - 1. The special chunk `top' is the top-most available chunk (i.e., - the one bordering the end of available memory). It is treated - specially. Top is never included in any bin, is used only if - no other chunk is available, and is released back to the - system if it is very large (see M_TRIM_THRESHOLD). In effect, - the top chunk is treated as larger (and thus less well - fitting) than any other available chunk. The top chunk - doesn't update its trailing size field since there is no next - contiguous chunk that would have to index off it. However, - space is still allocated for it (TOP_FOOT_SIZE) to enable - separation or merging when space is extended. - - 3. Chunks allocated via mmap, have both cinuse and pinuse bits - cleared in their head fields. Because they are allocated - one-by-one, each must carry its own prev_foot field, which is - also used to hold the offset this chunk has within its mmapped - region, which is needed to preserve alignment. Each mmapped - chunk is trailed by the first two fields of a fake next-chunk - for sake of usage checks. - -*/ - -struct malloc_chunk { - size_t prev_foot; /* Size of previous chunk (if free). */ - size_t head; /* Size and inuse bits. */ - struct malloc_chunk* fd; /* double links -- used only if free. */ - struct malloc_chunk* bk; -}; - -typedef struct malloc_chunk mchunk; -typedef struct malloc_chunk* mchunkptr; -typedef struct malloc_chunk* sbinptr; /* The type of bins of chunks */ -typedef unsigned int bindex_t; /* Described below */ -typedef unsigned int binmap_t; /* Described below */ -typedef unsigned int flag_t; /* The type of various bit flag sets */ - -/* ------------------- Chunks sizes and alignments ----------------------- */ - -#define MCHUNK_SIZE (sizeof(mchunk)) - -#if FOOTERS -#define CHUNK_OVERHEAD (TWO_SIZE_T_SIZES) -#else /* FOOTERS */ -#define CHUNK_OVERHEAD (SIZE_T_SIZE) -#endif /* FOOTERS */ - -/* MMapped chunks need a second word of overhead ... */ -#define MMAP_CHUNK_OVERHEAD (TWO_SIZE_T_SIZES) -/* ... and additional padding for fake next-chunk at foot */ -#define MMAP_FOOT_PAD (FOUR_SIZE_T_SIZES) - -/* The smallest size we can malloc is an aligned minimal chunk */ -#define MIN_CHUNK_SIZE\ - ((MCHUNK_SIZE + CHUNK_ALIGN_MASK) & ~CHUNK_ALIGN_MASK) - -/* conversion from malloc headers to user pointers, and back */ -#define chunk2mem(p) ((void*)((char*)(p) + TWO_SIZE_T_SIZES)) -#define mem2chunk(mem) ((mchunkptr)((char*)(mem) - TWO_SIZE_T_SIZES)) -/* chunk associated with aligned address A */ -#define align_as_chunk(A) (mchunkptr)((A) + align_offset(chunk2mem(A))) - -/* Bounds on request (not chunk) sizes. */ -#define MAX_REQUEST ((-MIN_CHUNK_SIZE) << 2) -#define MIN_REQUEST (MIN_CHUNK_SIZE - CHUNK_OVERHEAD - SIZE_T_ONE) - -/* pad request bytes into a usable size */ -#define pad_request(req) \ - (((req) + CHUNK_OVERHEAD + CHUNK_ALIGN_MASK) & ~CHUNK_ALIGN_MASK) - -/* pad request, checking for minimum (but not maximum) */ -#define request2size(req) \ - (((req) < MIN_REQUEST)? MIN_CHUNK_SIZE : pad_request(req)) - - -/* ------------------ Operations on head and foot fields ----------------- */ - -/* - The head field of a chunk is or'ed with PINUSE_BIT when previous - adjacent chunk in use, and or'ed with CINUSE_BIT if this chunk is in - use, unless mmapped, in which case both bits are cleared. - - FLAG4_BIT is not used by this malloc, but might be useful in extensions. -*/ - -#define PINUSE_BIT (SIZE_T_ONE) -#define CINUSE_BIT (SIZE_T_TWO) -#define FLAG4_BIT (SIZE_T_FOUR) -#define INUSE_BITS (PINUSE_BIT|CINUSE_BIT) -#define FLAG_BITS (PINUSE_BIT|CINUSE_BIT|FLAG4_BIT) - -/* Head value for fenceposts */ -#define FENCEPOST_HEAD (INUSE_BITS|SIZE_T_SIZE) - -/* extraction of fields from head words */ -#define cinuse(p) ((p)->head & CINUSE_BIT) -#define pinuse(p) ((p)->head & PINUSE_BIT) -#define flag4inuse(p) ((p)->head & FLAG4_BIT) -#define is_inuse(p) (((p)->head & INUSE_BITS) != PINUSE_BIT) -#define is_mmapped(p) (((p)->head & INUSE_BITS) == 0) - -#define chunksize(p) ((p)->head & ~(FLAG_BITS)) - -#define clear_pinuse(p) ((p)->head &= ~PINUSE_BIT) -#define set_flag4(p) ((p)->head |= FLAG4_BIT) -#define clear_flag4(p) ((p)->head &= ~FLAG4_BIT) - -/* Treat space at ptr +/- offset as a chunk */ -#define chunk_plus_offset(p, s) ((mchunkptr)(((char*)(p)) + (s))) -#define chunk_minus_offset(p, s) ((mchunkptr)(((char*)(p)) - (s))) - -/* Ptr to next or previous physical malloc_chunk. */ -#define next_chunk(p) ((mchunkptr)( ((char*)(p)) + ((p)->head & ~FLAG_BITS))) -#define prev_chunk(p) ((mchunkptr)( ((char*)(p)) - ((p)->prev_foot) )) - -/* extract next chunk's pinuse bit */ -#define next_pinuse(p) ((next_chunk(p)->head) & PINUSE_BIT) - -/* Get/set size at footer */ -#define get_foot(p, s) (((mchunkptr)((char*)(p) + (s)))->prev_foot) -#define set_foot(p, s) (((mchunkptr)((char*)(p) + (s)))->prev_foot = (s)) - -/* Set size, pinuse bit, and foot */ -#define set_size_and_pinuse_of_free_chunk(p, s)\ - ((p)->head = (s|PINUSE_BIT), set_foot(p, s)) - -/* Set size, pinuse bit, foot, and clear next pinuse */ -#define set_free_with_pinuse(p, s, n)\ - (clear_pinuse(n), set_size_and_pinuse_of_free_chunk(p, s)) - -/* Get the internal overhead associated with chunk p */ -#define overhead_for(p)\ - (is_mmapped(p)? MMAP_CHUNK_OVERHEAD : CHUNK_OVERHEAD) - -/* Return true if malloced space is not necessarily cleared */ -#if MMAP_CLEARS -#define calloc_must_clear(p) (!is_mmapped(p)) -#else /* MMAP_CLEARS */ -#define calloc_must_clear(p) (1) -#endif /* MMAP_CLEARS */ - -/* ---------------------- Overlaid data structures ----------------------- */ - -/* - When chunks are not in use, they are treated as nodes of either - lists or trees. - - "Small" chunks are stored in circular doubly-linked lists, and look - like this: - - chunk-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - | Size of previous chunk | - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - `head:' | Size of chunk, in bytes |P| - mem-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - | Forward pointer to next chunk in list | - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - | Back pointer to previous chunk in list | - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - | Unused space (may be 0 bytes long) . - . . - . | -nextchunk-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - `foot:' | Size of chunk, in bytes | - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - - Larger chunks are kept in a form of bitwise digital trees (aka - tries) keyed on chunksizes. Because malloc_tree_chunks are only for - free chunks greater than 256 bytes, their size doesn't impose any - constraints on user chunk sizes. Each node looks like: - - chunk-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - | Size of previous chunk | - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - `head:' | Size of chunk, in bytes |P| - mem-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - | Forward pointer to next chunk of same size | - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - | Back pointer to previous chunk of same size | - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - | Pointer to left child (child[0]) | - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - | Pointer to right child (child[1]) | - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - | Pointer to parent | - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - | bin index of this chunk | - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - | Unused space . - . | -nextchunk-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - `foot:' | Size of chunk, in bytes | - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - - Each tree holding treenodes is a tree of unique chunk sizes. Chunks - of the same size are arranged in a circularly-linked list, with only - the oldest chunk (the next to be used, in our FIFO ordering) - actually in the tree. (Tree members are distinguished by a non-null - parent pointer.) If a chunk with the same size an an existing node - is inserted, it is linked off the existing node using pointers that - work in the same way as fd/bk pointers of small chunks. - - Each tree contains a power of 2 sized range of chunk sizes (the - smallest is 0x100 <= x < 0x180), which is is divided in half at each - tree level, with the chunks in the smaller half of the range (0x100 - <= x < 0x140 for the top nose) in the left subtree and the larger - half (0x140 <= x < 0x180) in the right subtree. This is, of course, - done by inspecting individual bits. - - Using these rules, each node's left subtree contains all smaller - sizes than its right subtree. However, the node at the root of each - subtree has no particular ordering relationship to either. (The - dividing line between the subtree sizes is based on trie relation.) - If we remove the last chunk of a given size from the interior of the - tree, we need to replace it with a leaf node. The tree ordering - rules permit a node to be replaced by any leaf below it. - - The smallest chunk in a tree (a common operation in a best-fit - allocator) can be found by walking a path to the leftmost leaf in - the tree. Unlike a usual binary tree, where we follow left child - pointers until we reach a null, here we follow the right child - pointer any time the left one is null, until we reach a leaf with - both child pointers null. The smallest chunk in the tree will be - somewhere along that path. - - The worst case number of steps to add, find, or remove a node is - bounded by the number of bits differentiating chunks within - bins. Under current bin calculations, this ranges from 6 up to 21 - (for 32 bit sizes) or up to 53 (for 64 bit sizes). The typical case - is of course much better. -*/ - -struct malloc_tree_chunk { - /* The first four fields must be compatible with malloc_chunk */ - size_t prev_foot; - size_t head; - struct malloc_tree_chunk* fd; - struct malloc_tree_chunk* bk; - - struct malloc_tree_chunk* child[2]; - struct malloc_tree_chunk* parent; - bindex_t index; -}; - -typedef struct malloc_tree_chunk tchunk; -typedef struct malloc_tree_chunk* tchunkptr; -typedef struct malloc_tree_chunk* tbinptr; /* The type of bins of trees */ - -/* A little helper macro for trees */ -#define leftmost_child(t) ((t)->child[0] != 0? (t)->child[0] : (t)->child[1]) - -/* ----------------------------- Segments -------------------------------- */ - -/* - Each malloc space may include non-contiguous segments, held in a - list headed by an embedded malloc_segment record representing the - top-most space. Segments also include flags holding properties of - the space. Large chunks that are directly allocated by mmap are not - included in this list. They are instead independently created and - destroyed without otherwise keeping track of them. - - Segment management mainly comes into play for spaces allocated by - MMAP. Any call to MMAP might or might not return memory that is - adjacent to an existing segment. MORECORE normally contiguously - extends the current space, so this space is almost always adjacent, - which is simpler and faster to deal with. (This is why MORECORE is - used preferentially to MMAP when both are available -- see - sys_alloc.) When allocating using MMAP, we don't use any of the - hinting mechanisms (inconsistently) supported in various - implementations of unix mmap, or distinguish reserving from - committing memory. Instead, we just ask for space, and exploit - contiguity when we get it. It is probably possible to do - better than this on some systems, but no general scheme seems - to be significantly better. - - Management entails a simpler variant of the consolidation scheme - used for chunks to reduce fragmentation -- new adjacent memory is - normally prepended or appended to an existing segment. However, - there are limitations compared to chunk consolidation that mostly - reflect the fact that segment processing is relatively infrequent - (occurring only when getting memory from system) and that we - don't expect to have huge numbers of segments: - - * Segments are not indexed, so traversal requires linear scans. (It - would be possible to index these, but is not worth the extra - overhead and complexity for most programs on most platforms.) - * New segments are only appended to old ones when holding top-most - memory; if they cannot be prepended to others, they are held in - different segments. - - Except for the top-most segment of an mstate, each segment record - is kept at the tail of its segment. Segments are added by pushing - segment records onto the list headed by &mstate.seg for the - containing mstate. - - Segment flags control allocation/merge/deallocation policies: - * If EXTERN_BIT set, then we did not allocate this segment, - and so should not try to deallocate or merge with others. - (This currently holds only for the initial segment passed - into create_mspace_with_base.) - * If USE_MMAP_BIT set, the segment may be merged with - other surrounding mmapped segments and trimmed/de-allocated - using munmap. - * If neither bit is set, then the segment was obtained using - MORECORE so can be merged with surrounding MORECORE'd segments - and deallocated/trimmed using MORECORE with negative arguments. -*/ - -struct malloc_segment { - char* base; /* base address */ - size_t size; /* allocated size */ - struct malloc_segment* next; /* ptr to next segment */ - flag_t sflags; /* mmap and extern flag */ -}; - -#define is_mmapped_segment(S) ((S)->sflags & USE_MMAP_BIT) -#define is_extern_segment(S) ((S)->sflags & EXTERN_BIT) - -typedef struct malloc_segment msegment; -typedef struct malloc_segment* msegmentptr; - -/* ---------------------------- malloc_state ----------------------------- */ - -/* - A malloc_state holds all of the bookkeeping for a space. - The main fields are: - - Top - The topmost chunk of the currently active segment. Its size is - cached in topsize. The actual size of topmost space is - topsize+TOP_FOOT_SIZE, which includes space reserved for adding - fenceposts and segment records if necessary when getting more - space from the system. The size at which to autotrim top is - cached from mparams in trim_check, except that it is disabled if - an autotrim fails. - - Designated victim (dv) - This is the preferred chunk for servicing small requests that - don't have exact fits. It is normally the chunk split off most - recently to service another small request. Its size is cached in - dvsize. The link fields of this chunk are not maintained since it - is not kept in a bin. - - SmallBins - An array of bin headers for free chunks. These bins hold chunks - with sizes less than MIN_LARGE_SIZE bytes. Each bin contains - chunks of all the same size, spaced 8 bytes apart. To simplify - use in double-linked lists, each bin header acts as a malloc_chunk - pointing to the real first node, if it exists (else pointing to - itself). This avoids special-casing for headers. But to avoid - waste, we allocate only the fd/bk pointers of bins, and then use - repositioning tricks to treat these as the fields of a chunk. - - TreeBins - Treebins are pointers to the roots of trees holding a range of - sizes. There are 2 equally spaced treebins for each power of two - from TREE_SHIFT to TREE_SHIFT+16. The last bin holds anything - larger. - - Bin maps - There is one bit map for small bins ("smallmap") and one for - treebins ("treemap). Each bin sets its bit when non-empty, and - clears the bit when empty. Bit operations are then used to avoid - bin-by-bin searching -- nearly all "search" is done without ever - looking at bins that won't be selected. The bit maps - conservatively use 32 bits per map word, even if on 64bit system. - For a good description of some of the bit-based techniques used - here, see Henry S. Warren Jr's book "Hacker's Delight" (and - supplement at http://hackersdelight.org/). Many of these are - intended to reduce the branchiness of paths through malloc etc, as - well as to reduce the number of memory locations read or written. - - Segments - A list of segments headed by an embedded malloc_segment record - representing the initial space. - - Address check support - The least_addr field is the least address ever obtained from - MORECORE or MMAP. Attempted frees and reallocs of any address less - than this are trapped (unless INSECURE is defined). - - Magic tag - A cross-check field that should always hold same value as mparams.magic. - - Max allowed footprint - The maximum allowed bytes to allocate from system (zero means no limit) - - Flags - Bits recording whether to use MMAP, locks, or contiguous MORECORE - - Statistics - Each space keeps track of current and maximum system memory - obtained via MORECORE or MMAP. - - Trim support - Fields holding the amount of unused topmost memory that should trigger - trimming, and a counter to force periodic scanning to release unused - non-topmost segments. - - Locking - If USE_LOCKS is defined, the "mutex" lock is acquired and released - around every public call using this mspace. - - Extension support - A void* pointer and a size_t field that can be used to help implement - extensions to this malloc. -*/ - -/* Bin types, widths and sizes */ -#define NSMALLBINS (32U) -#define NTREEBINS (32U) -#define SMALLBIN_SHIFT (3U) -#define SMALLBIN_WIDTH (SIZE_T_ONE << SMALLBIN_SHIFT) -#define TREEBIN_SHIFT (8U) -#define MIN_LARGE_SIZE (SIZE_T_ONE << TREEBIN_SHIFT) -#define MAX_SMALL_SIZE (MIN_LARGE_SIZE - SIZE_T_ONE) -#define MAX_SMALL_REQUEST (MAX_SMALL_SIZE - CHUNK_ALIGN_MASK - CHUNK_OVERHEAD) - -struct malloc_state { - binmap_t smallmap; - binmap_t treemap; - size_t dvsize; - size_t topsize; - char* least_addr; - mchunkptr dv; - mchunkptr top; - size_t trim_check; - size_t release_checks; - size_t magic; - mchunkptr smallbins[(NSMALLBINS+1)*2]; - tbinptr treebins[NTREEBINS]; - size_t footprint; - size_t max_footprint; - size_t footprint_limit; /* zero means no limit */ - flag_t mflags; -#if USE_LOCKS - MLOCK_T mutex; /* locate lock among fields that rarely change */ -#endif /* USE_LOCKS */ - msegment seg; - void* extp; /* Unused but available for extensions */ - size_t exts; -}; - -typedef struct malloc_state* mstate; - -/* ------------- Global malloc_state and malloc_params ------------------- */ - -/* - malloc_params holds global properties, including those that can be - dynamically set using mallopt. There is a single instance, mparams, - initialized in init_mparams. Note that the non-zeroness of "magic" - also serves as an initialization flag. -*/ - -struct malloc_params { - size_t magic; - size_t page_size; - size_t granularity; - size_t mmap_threshold; - size_t trim_threshold; - flag_t default_mflags; -}; - -static struct malloc_params mparams; - -/* Ensure mparams initialized */ -#define ensure_initialization() (void)(mparams.magic != 0 || init_mparams()) - -#if !ONLY_MSPACES - -/* The global malloc_state used for all non-"mspace" calls */ -static struct malloc_state _gm_; -#define gm (&_gm_) -#define is_global(M) ((M) == &_gm_) - -#endif /* !ONLY_MSPACES */ - -#define is_initialized(M) ((M)->top != 0) - -/* -------------------------- system alloc setup ------------------------- */ - -/* Operations on mflags */ - -#define use_lock(M) ((M)->mflags & USE_LOCK_BIT) -#define enable_lock(M) ((M)->mflags |= USE_LOCK_BIT) -#if USE_LOCKS -#define disable_lock(M) ((M)->mflags &= ~USE_LOCK_BIT) -#else -#define disable_lock(M) -#endif - -#define use_mmap(M) ((M)->mflags & USE_MMAP_BIT) -#define enable_mmap(M) ((M)->mflags |= USE_MMAP_BIT) -#if HAVE_MMAP -#define disable_mmap(M) ((M)->mflags &= ~USE_MMAP_BIT) -#else -#define disable_mmap(M) -#endif - -#define use_noncontiguous(M) ((M)->mflags & USE_NONCONTIGUOUS_BIT) -#define disable_contiguous(M) ((M)->mflags |= USE_NONCONTIGUOUS_BIT) - -#define set_lock(M,L)\ - ((M)->mflags = (L)?\ - ((M)->mflags | USE_LOCK_BIT) :\ - ((M)->mflags & ~USE_LOCK_BIT)) - -/* page-align a size */ -#define page_align(S)\ - (((S) + (mparams.page_size - SIZE_T_ONE)) & ~(mparams.page_size - SIZE_T_ONE)) - -/* granularity-align a size */ -#define granularity_align(S)\ - (((S) + (mparams.granularity - SIZE_T_ONE))\ - & ~(mparams.granularity - SIZE_T_ONE)) - - -/* For mmap, use granularity alignment on windows, else page-align */ -#ifdef WIN32 -#define mmap_align(S) granularity_align(S) -#else -#define mmap_align(S) page_align(S) -#endif - -/* For sys_alloc, enough padding to ensure can malloc request on success */ -#define SYS_ALLOC_PADDING (TOP_FOOT_SIZE + MALLOC_ALIGNMENT) - -#define is_page_aligned(S)\ - (((size_t)(S) & (mparams.page_size - SIZE_T_ONE)) == 0) -#define is_granularity_aligned(S)\ - (((size_t)(S) & (mparams.granularity - SIZE_T_ONE)) == 0) - -/* True if segment S holds address A */ -#define segment_holds(S, A)\ - ((char*)(A) >= S->base && (char*)(A) < S->base + S->size) - -/* Return segment holding given address */ -static msegmentptr segment_holding(mstate m, char* addr) { - msegmentptr sp = &m->seg; - for (;;) { - if (addr >= sp->base && addr < sp->base + sp->size) - return sp; - if ((sp = sp->next) == 0) - return 0; - } -} - -/* Return true if segment contains a segment link */ -static int has_segment_link(mstate m, msegmentptr ss) { - msegmentptr sp = &m->seg; - for (;;) { - if ((char*)sp >= ss->base && (char*)sp < ss->base + ss->size) - return 1; - if ((sp = sp->next) == 0) - return 0; - } -} - -#ifndef MORECORE_CANNOT_TRIM -#define should_trim(M,s) ((s) > (M)->trim_check) -#else /* MORECORE_CANNOT_TRIM */ -#define should_trim(M,s) (0) -#endif /* MORECORE_CANNOT_TRIM */ - -/* - TOP_FOOT_SIZE is padding at the end of a segment, including space - that may be needed to place segment records and fenceposts when new - noncontiguous segments are added. -*/ -#define TOP_FOOT_SIZE\ - (align_offset(chunk2mem(0))+pad_request(sizeof(struct malloc_segment))+MIN_CHUNK_SIZE) - - -/* ------------------------------- Hooks -------------------------------- */ - -/* - PREACTION should be defined to return 0 on success, and nonzero on - failure. If you are not using locking, you can redefine these to do - anything you like. -*/ - -#if USE_LOCKS -#define PREACTION(M) ((use_lock(M))? ACQUIRE_LOCK(&(M)->mutex) : 0) -#define POSTACTION(M) { if (use_lock(M)) RELEASE_LOCK(&(M)->mutex); } -#else /* USE_LOCKS */ - -#ifndef PREACTION -#define PREACTION(M) (0) -#endif /* PREACTION */ - -#ifndef POSTACTION -#define POSTACTION(M) -#endif /* POSTACTION */ - -#endif /* USE_LOCKS */ - -/* - CORRUPTION_ERROR_ACTION is triggered upon detected bad addresses. - USAGE_ERROR_ACTION is triggered on detected bad frees and - reallocs. The argument p is an address that might have triggered the - fault. It is ignored by the two predefined actions, but might be - useful in custom actions that try to help diagnose errors. -*/ - -#if PROCEED_ON_ERROR - -/* A count of the number of corruption errors causing resets */ -int malloc_corruption_error_count; - -/* default corruption action */ -static void reset_on_error(mstate m); - -#define CORRUPTION_ERROR_ACTION(m) reset_on_error(m) -#define USAGE_ERROR_ACTION(m, p) - -#else /* PROCEED_ON_ERROR */ - -#ifndef CORRUPTION_ERROR_ACTION -#define CORRUPTION_ERROR_ACTION(m) ABORT -#endif /* CORRUPTION_ERROR_ACTION */ - -#ifndef USAGE_ERROR_ACTION -#define USAGE_ERROR_ACTION(m,p) ABORT -#endif /* USAGE_ERROR_ACTION */ - -#endif /* PROCEED_ON_ERROR */ - - -/* -------------------------- Debugging setup ---------------------------- */ - -#if ! DEBUG - -#define check_free_chunk(M,P) -#define check_inuse_chunk(M,P) -#define check_malloced_chunk(M,P,N) -#define check_mmapped_chunk(M,P) -#define check_malloc_state(M) -#define check_top_chunk(M,P) - -#else /* DEBUG */ -#define check_free_chunk(M,P) do_check_free_chunk(M,P) -#define check_inuse_chunk(M,P) do_check_inuse_chunk(M,P) -#define check_top_chunk(M,P) do_check_top_chunk(M,P) -#define check_malloced_chunk(M,P,N) do_check_malloced_chunk(M,P,N) -#define check_mmapped_chunk(M,P) do_check_mmapped_chunk(M,P) -#define check_malloc_state(M) do_check_malloc_state(M) - -static void do_check_any_chunk(mstate m, mchunkptr p); -static void do_check_top_chunk(mstate m, mchunkptr p); -static void do_check_mmapped_chunk(mstate m, mchunkptr p); -static void do_check_inuse_chunk(mstate m, mchunkptr p); -static void do_check_free_chunk(mstate m, mchunkptr p); -static void do_check_malloced_chunk(mstate m, void* mem, size_t s); -static void do_check_tree(mstate m, tchunkptr t); -static void do_check_treebin(mstate m, bindex_t i); -static void do_check_smallbin(mstate m, bindex_t i); -static void do_check_malloc_state(mstate m); -static int bin_find(mstate m, mchunkptr x); -static size_t traverse_and_check(mstate m); -#endif /* DEBUG */ - -/* ---------------------------- Indexing Bins ---------------------------- */ - -#define is_small(s) (((s) >> SMALLBIN_SHIFT) < NSMALLBINS) -#define small_index(s) (bindex_t)((s) >> SMALLBIN_SHIFT) -#define small_index2size(i) ((i) << SMALLBIN_SHIFT) -#define MIN_SMALL_INDEX (small_index(MIN_CHUNK_SIZE)) - -/* addressing by index. See above about smallbin repositioning */ -#define smallbin_at(M, i) ((sbinptr)((char*)&((M)->smallbins[(i)<<1]))) -#define treebin_at(M,i) (&((M)->treebins[i])) - -/* assign tree index for size S to variable I. Use x86 asm if possible */ -#if defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__)) -#define compute_tree_index(S, I)\ -{\ - unsigned int X = S >> TREEBIN_SHIFT;\ - if (X == 0)\ - I = 0;\ - else if (X > 0xFFFF)\ - I = NTREEBINS-1;\ - else {\ - unsigned int K = (unsigned) sizeof(X)*__CHAR_BIT__ - 1 - (unsigned) __builtin_clz(X); \ - I = (bindex_t)((K << 1) + ((S >> (K + (TREEBIN_SHIFT-1)) & 1)));\ - }\ -} - -#elif defined (__INTEL_COMPILER) -#define compute_tree_index(S, I)\ -{\ - size_t X = S >> TREEBIN_SHIFT;\ - if (X == 0)\ - I = 0;\ - else if (X > 0xFFFF)\ - I = NTREEBINS-1;\ - else {\ - unsigned int K = _bit_scan_reverse (X); \ - I = (bindex_t)((K << 1) + ((S >> (K + (TREEBIN_SHIFT-1)) & 1)));\ - }\ -} - -#elif defined(_MSC_VER) && _MSC_VER>=1300 -#define compute_tree_index(S, I)\ -{\ - size_t X = S >> TREEBIN_SHIFT;\ - if (X == 0)\ - I = 0;\ - else if (X > 0xFFFF)\ - I = NTREEBINS-1;\ - else {\ - unsigned int K;\ - _BitScanReverse((DWORD *) &K, (DWORD) X);\ - I = (bindex_t)((K << 1) + ((S >> (K + (TREEBIN_SHIFT-1)) & 1)));\ - }\ -} - -#else /* GNUC */ -#define compute_tree_index(S, I)\ -{\ - size_t X = S >> TREEBIN_SHIFT;\ - if (X == 0)\ - I = 0;\ - else if (X > 0xFFFF)\ - I = NTREEBINS-1;\ - else {\ - unsigned int Y = (unsigned int)X;\ - unsigned int N = ((Y - 0x100) >> 16) & 8;\ - unsigned int K = (((Y <<= N) - 0x1000) >> 16) & 4;\ - N += K;\ - N += K = (((Y <<= K) - 0x4000) >> 16) & 2;\ - K = 14 - N + ((Y <<= K) >> 15);\ - I = (K << 1) + ((S >> (K + (TREEBIN_SHIFT-1)) & 1));\ - }\ -} -#endif /* GNUC */ - -/* Bit representing maximum resolved size in a treebin at i */ -#define bit_for_tree_index(i) \ - (i == NTREEBINS-1)? (SIZE_T_BITSIZE-1) : (((i) >> 1) + TREEBIN_SHIFT - 2) - -/* Shift placing maximum resolved bit in a treebin at i as sign bit */ -#define leftshift_for_tree_index(i) \ - ((i == NTREEBINS-1)? 0 : \ - ((SIZE_T_BITSIZE-SIZE_T_ONE) - (((i) >> 1) + TREEBIN_SHIFT - 2))) - -/* The size of the smallest chunk held in bin with index i */ -#define minsize_for_tree_index(i) \ - ((SIZE_T_ONE << (((i) >> 1) + TREEBIN_SHIFT)) | \ - (((size_t)((i) & SIZE_T_ONE)) << (((i) >> 1) + TREEBIN_SHIFT - 1))) - - -/* ------------------------ Operations on bin maps ----------------------- */ - -/* bit corresponding to given index */ -#define idx2bit(i) ((binmap_t)(1) << (i)) - -/* Mark/Clear bits with given index */ -#define mark_smallmap(M,i) ((M)->smallmap |= idx2bit(i)) -#define clear_smallmap(M,i) ((M)->smallmap &= ~idx2bit(i)) -#define smallmap_is_marked(M,i) ((M)->smallmap & idx2bit(i)) - -#define mark_treemap(M,i) ((M)->treemap |= idx2bit(i)) -#define clear_treemap(M,i) ((M)->treemap &= ~idx2bit(i)) -#define treemap_is_marked(M,i) ((M)->treemap & idx2bit(i)) - -/* isolate the least set bit of a bitmap */ -#define least_bit(x) ((x) & -(x)) - -/* mask with all bits to left of least bit of x on */ -#define left_bits(x) ((x<<1) | -(x<<1)) - -/* mask with all bits to left of or equal to least bit of x on */ -#define same_or_left_bits(x) ((x) | -(x)) - -/* index corresponding to given bit. Use x86 asm if possible */ - -#if defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__)) -#define compute_bit2idx(X, I)\ -{\ - unsigned int J;\ - J = __builtin_ctz(X); \ - I = (bindex_t)J;\ -} - -#elif defined (__INTEL_COMPILER) -#define compute_bit2idx(X, I)\ -{\ - unsigned int J;\ - J = _bit_scan_forward (X); \ - I = (bindex_t)J;\ -} - -#elif defined(_MSC_VER) && _MSC_VER>=1300 -#define compute_bit2idx(X, I)\ -{\ - unsigned int J;\ - _BitScanForward((DWORD *) &J, X);\ - I = (bindex_t)J;\ -} - -#elif USE_BUILTIN_FFS -#define compute_bit2idx(X, I) I = ffs(X)-1 - -#else -#define compute_bit2idx(X, I)\ -{\ - unsigned int Y = X - 1;\ - unsigned int K = Y >> (16-4) & 16;\ - unsigned int N = K; Y >>= K;\ - N += K = Y >> (8-3) & 8; Y >>= K;\ - N += K = Y >> (4-2) & 4; Y >>= K;\ - N += K = Y >> (2-1) & 2; Y >>= K;\ - N += K = Y >> (1-0) & 1; Y >>= K;\ - I = (bindex_t)(N + Y);\ -} -#endif /* GNUC */ - - -/* ----------------------- Runtime Check Support ------------------------- */ - -/* - For security, the main invariant is that malloc/free/etc never - writes to a static address other than malloc_state, unless static - malloc_state itself has been corrupted, which cannot occur via - malloc (because of these checks). In essence this means that we - believe all pointers, sizes, maps etc held in malloc_state, but - check all of those linked or offsetted from other embedded data - structures. These checks are interspersed with main code in a way - that tends to minimize their run-time cost. - - When FOOTERS is defined, in addition to range checking, we also - verify footer fields of inuse chunks, which can be used guarantee - that the mstate controlling malloc/free is intact. This is a - streamlined version of the approach described by William Robertson - et al in "Run-time Detection of Heap-based Overflows" LISA'03 - http://www.usenix.org/events/lisa03/tech/robertson.html The footer - of an inuse chunk holds the xor of its mstate and a random seed, - that is checked upon calls to free() and realloc(). This is - (probabalistically) unguessable from outside the program, but can be - computed by any code successfully malloc'ing any chunk, so does not - itself provide protection against code that has already broken - security through some other means. Unlike Robertson et al, we - always dynamically check addresses of all offset chunks (previous, - next, etc). This turns out to be cheaper than relying on hashes. -*/ - -#if !INSECURE -/* Check if address a is at least as high as any from MORECORE or MMAP */ -#define ok_address(M, a) ((char*)(a) >= (M)->least_addr) -/* Check if address of next chunk n is higher than base chunk p */ -#define ok_next(p, n) ((char*)(p) < (char*)(n)) -/* Check if p has inuse status */ -#define ok_inuse(p) is_inuse(p) -/* Check if p has its pinuse bit on */ -#define ok_pinuse(p) pinuse(p) - -#else /* !INSECURE */ -#define ok_address(M, a) (1) -#define ok_next(b, n) (1) -#define ok_inuse(p) (1) -#define ok_pinuse(p) (1) -#endif /* !INSECURE */ - -#if (FOOTERS && !INSECURE) -/* Check if (alleged) mstate m has expected magic field */ -#define ok_magic(M) ((M)->magic == mparams.magic) -#else /* (FOOTERS && !INSECURE) */ -#define ok_magic(M) (1) -#endif /* (FOOTERS && !INSECURE) */ - -/* In gcc, use __builtin_expect to minimize impact of checks */ -#if !INSECURE -#if defined(__GNUC__) && __GNUC__ >= 3 -#define RTCHECK(e) __builtin_expect(e, 1) -#else /* GNUC */ -#define RTCHECK(e) (e) -#endif /* GNUC */ -#else /* !INSECURE */ -#define RTCHECK(e) (1) -#endif /* !INSECURE */ - -/* macros to set up inuse chunks with or without footers */ - -#if !FOOTERS - -#define mark_inuse_foot(M,p,s) - -/* Macros for setting head/foot of non-mmapped chunks */ - -/* Set cinuse bit and pinuse bit of next chunk */ -#define set_inuse(M,p,s)\ - ((p)->head = (((p)->head & PINUSE_BIT)|s|CINUSE_BIT),\ - ((mchunkptr)(((char*)(p)) + (s)))->head |= PINUSE_BIT) - -/* Set cinuse and pinuse of this chunk and pinuse of next chunk */ -#define set_inuse_and_pinuse(M,p,s)\ - ((p)->head = (s|PINUSE_BIT|CINUSE_BIT),\ - ((mchunkptr)(((char*)(p)) + (s)))->head |= PINUSE_BIT) - -/* Set size, cinuse and pinuse bit of this chunk */ -#define set_size_and_pinuse_of_inuse_chunk(M, p, s)\ - ((p)->head = (s|PINUSE_BIT|CINUSE_BIT)) - -#else /* FOOTERS */ - -/* Set foot of inuse chunk to be xor of mstate and seed */ -#define mark_inuse_foot(M,p,s)\ - (((mchunkptr)((char*)(p) + (s)))->prev_foot = ((size_t)(M) ^ mparams.magic)) - -#define get_mstate_for(p)\ - ((mstate)(((mchunkptr)((char*)(p) +\ - (chunksize(p))))->prev_foot ^ mparams.magic)) - -#define set_inuse(M,p,s)\ - ((p)->head = (((p)->head & PINUSE_BIT)|s|CINUSE_BIT),\ - (((mchunkptr)(((char*)(p)) + (s)))->head |= PINUSE_BIT), \ - mark_inuse_foot(M,p,s)) - -#define set_inuse_and_pinuse(M,p,s)\ - ((p)->head = (s|PINUSE_BIT|CINUSE_BIT),\ - (((mchunkptr)(((char*)(p)) + (s)))->head |= PINUSE_BIT),\ - mark_inuse_foot(M,p,s)) - -#define set_size_and_pinuse_of_inuse_chunk(M, p, s)\ - ((p)->head = (s|PINUSE_BIT|CINUSE_BIT),\ - mark_inuse_foot(M, p, s)) - -#endif /* !FOOTERS */ - -/* ---------------------------- setting mparams -------------------------- */ - -#if LOCK_AT_FORK -static void pre_fork(void) { ACQUIRE_LOCK(&(gm)->mutex); } -static void post_fork_parent(void) { RELEASE_LOCK(&(gm)->mutex); } -static void post_fork_child(void) { INITIAL_LOCK(&(gm)->mutex); } -#endif /* LOCK_AT_FORK */ - -/* Initialize mparams */ -static int init_mparams(void) { -#ifdef NEED_GLOBAL_LOCK_INIT - if (malloc_global_mutex_status <= 0) - init_malloc_global_mutex(); -#endif - - ACQUIRE_MALLOC_GLOBAL_LOCK(); - if (mparams.magic == 0) { - size_t magic; - size_t psize; - size_t gsize; - -#ifndef WIN32 - psize = malloc_getpagesize; - gsize = ((DEFAULT_GRANULARITY != 0)? DEFAULT_GRANULARITY : psize); -#else /* WIN32 */ - { - SYSTEM_INFO system_info; - GetSystemInfo(&system_info); - psize = system_info.dwPageSize; - gsize = ((DEFAULT_GRANULARITY != 0)? - DEFAULT_GRANULARITY : system_info.dwAllocationGranularity); - } -#endif /* WIN32 */ - - /* Sanity-check configuration: - size_t must be unsigned and as wide as pointer type. - ints must be at least 4 bytes. - alignment must be at least 8. - Alignment, min chunk size, and page size must all be powers of 2. - */ - if ((sizeof(size_t) != sizeof(char*)) || - (MAX_SIZE_T < MIN_CHUNK_SIZE) || - (sizeof(int) < 4) || - (MALLOC_ALIGNMENT < (size_t)8U) || - ((MALLOC_ALIGNMENT & (MALLOC_ALIGNMENT-SIZE_T_ONE)) != 0) || - ((MCHUNK_SIZE & (MCHUNK_SIZE-SIZE_T_ONE)) != 0) || - ((gsize & (gsize-SIZE_T_ONE)) != 0) || - ((psize & (psize-SIZE_T_ONE)) != 0)) - ABORT; - mparams.granularity = gsize; - mparams.page_size = psize; - mparams.mmap_threshold = DEFAULT_MMAP_THRESHOLD; - mparams.trim_threshold = DEFAULT_TRIM_THRESHOLD; -#if MORECORE_CONTIGUOUS - mparams.default_mflags = USE_LOCK_BIT|USE_MMAP_BIT; -#else /* MORECORE_CONTIGUOUS */ - mparams.default_mflags = USE_LOCK_BIT|USE_MMAP_BIT|USE_NONCONTIGUOUS_BIT; -#endif /* MORECORE_CONTIGUOUS */ - -#if !ONLY_MSPACES - /* Set up lock for main malloc area */ - gm->mflags = mparams.default_mflags; - (void)INITIAL_LOCK(&gm->mutex); -#endif -#if LOCK_AT_FORK - pthread_atfork(&pre_fork, &post_fork_parent, &post_fork_child); -#endif - - { -#if USE_DEV_RANDOM - int fd; - unsigned char buf[sizeof(size_t)]; - /* Try to use /dev/urandom, else fall back on using time */ - if ((fd = open("/dev/urandom", O_RDONLY)) >= 0 && - read(fd, buf, sizeof(buf)) == sizeof(buf)) { - magic = *((size_t *) buf); - close(fd); - } - else -#endif /* USE_DEV_RANDOM */ -#ifdef WIN32 - magic = (size_t)(GetTickCount() ^ (size_t)0x55555555U); -#elif defined(LACKS_TIME_H) - magic = (size_t)&magic ^ (size_t)0x55555555U; -#else - magic = (size_t)(time(0) ^ (size_t)0x55555555U); -#endif - magic |= (size_t)8U; /* ensure nonzero */ - magic &= ~(size_t)7U; /* improve chances of fault for bad values */ - /* Until memory modes commonly available, use volatile-write */ - (*(volatile size_t *)(&(mparams.magic))) = magic; - } - } - - RELEASE_MALLOC_GLOBAL_LOCK(); - return 1; -} - -/* support for mallopt */ -static int change_mparam(int param_number, int value) { - size_t val; - ensure_initialization(); - val = (value == -1)? MAX_SIZE_T : (size_t)value; - switch(param_number) { - case M_TRIM_THRESHOLD: - mparams.trim_threshold = val; - return 1; - case M_GRANULARITY: - if (val >= mparams.page_size && ((val & (val-1)) == 0)) { - mparams.granularity = val; - return 1; - } - else - return 0; - case M_MMAP_THRESHOLD: - mparams.mmap_threshold = val; - return 1; - default: - return 0; - } -} - -#if DEBUG -/* ------------------------- Debugging Support --------------------------- */ - -/* Check properties of any chunk, whether free, inuse, mmapped etc */ -static void do_check_any_chunk(mstate m, mchunkptr p) { - assert((is_aligned(chunk2mem(p))) || (p->head == FENCEPOST_HEAD)); - assert(ok_address(m, p)); -} - -/* Check properties of top chunk */ -static void do_check_top_chunk(mstate m, mchunkptr p) { - msegmentptr sp = segment_holding(m, (char*)p); - size_t sz = p->head & ~INUSE_BITS; /* third-lowest bit can be set! */ - assert(sp != 0); - assert((is_aligned(chunk2mem(p))) || (p->head == FENCEPOST_HEAD)); - assert(ok_address(m, p)); - assert(sz == m->topsize); - assert(sz > 0); - assert(sz == ((sp->base + sp->size) - (char*)p) - TOP_FOOT_SIZE); - assert(pinuse(p)); - assert(!pinuse(chunk_plus_offset(p, sz))); -} - -/* Check properties of (inuse) mmapped chunks */ -static void do_check_mmapped_chunk(mstate m, mchunkptr p) { - size_t sz = chunksize(p); - size_t len = (sz + (p->prev_foot) + MMAP_FOOT_PAD); - assert(is_mmapped(p)); - assert(use_mmap(m)); - assert((is_aligned(chunk2mem(p))) || (p->head == FENCEPOST_HEAD)); - assert(ok_address(m, p)); - assert(!is_small(sz)); - assert((len & (mparams.page_size-SIZE_T_ONE)) == 0); - assert(chunk_plus_offset(p, sz)->head == FENCEPOST_HEAD); - assert(chunk_plus_offset(p, sz+SIZE_T_SIZE)->head == 0); -} - -/* Check properties of inuse chunks */ -static void do_check_inuse_chunk(mstate m, mchunkptr p) { - do_check_any_chunk(m, p); - assert(is_inuse(p)); - assert(next_pinuse(p)); - /* If not pinuse and not mmapped, previous chunk has OK offset */ - assert(is_mmapped(p) || pinuse(p) || next_chunk(prev_chunk(p)) == p); - if (is_mmapped(p)) - do_check_mmapped_chunk(m, p); -} - -/* Check properties of free chunks */ -static void do_check_free_chunk(mstate m, mchunkptr p) { - size_t sz = chunksize(p); - mchunkptr next = chunk_plus_offset(p, sz); - do_check_any_chunk(m, p); - assert(!is_inuse(p)); - assert(!next_pinuse(p)); - assert (!is_mmapped(p)); - if (p != m->dv && p != m->top) { - if (sz >= MIN_CHUNK_SIZE) { - assert((sz & CHUNK_ALIGN_MASK) == 0); - assert(is_aligned(chunk2mem(p))); - assert(next->prev_foot == sz); - assert(pinuse(p)); - assert (next == m->top || is_inuse(next)); - assert(p->fd->bk == p); - assert(p->bk->fd == p); - } - else /* markers are always of size SIZE_T_SIZE */ - assert(sz == SIZE_T_SIZE); - } -} - -/* Check properties of malloced chunks at the point they are malloced */ -static void do_check_malloced_chunk(mstate m, void* mem, size_t s) { - if (mem != 0) { - mchunkptr p = mem2chunk(mem); - size_t sz = p->head & ~INUSE_BITS; - do_check_inuse_chunk(m, p); - assert((sz & CHUNK_ALIGN_MASK) == 0); - assert(sz >= MIN_CHUNK_SIZE); - assert(sz >= s); - /* unless mmapped, size is less than MIN_CHUNK_SIZE more than request */ - assert(is_mmapped(p) || sz < (s + MIN_CHUNK_SIZE)); - } -} - -/* Check a tree and its subtrees. */ -static void do_check_tree(mstate m, tchunkptr t) { - tchunkptr head = 0; - tchunkptr u = t; - bindex_t tindex = t->index; - size_t tsize = chunksize(t); - bindex_t idx; - compute_tree_index(tsize, idx); - assert(tindex == idx); - assert(tsize >= MIN_LARGE_SIZE); - assert(tsize >= minsize_for_tree_index(idx)); - assert((idx == NTREEBINS-1) || (tsize < minsize_for_tree_index((idx+1)))); - - do { /* traverse through chain of same-sized nodes */ - do_check_any_chunk(m, ((mchunkptr)u)); - assert(u->index == tindex); - assert(chunksize(u) == tsize); - assert(!is_inuse(u)); - assert(!next_pinuse(u)); - assert(u->fd->bk == u); - assert(u->bk->fd == u); - if (u->parent == 0) { - assert(u->child[0] == 0); - assert(u->child[1] == 0); - } - else { - assert(head == 0); /* only one node on chain has parent */ - head = u; - assert(u->parent != u); - assert (u->parent->child[0] == u || - u->parent->child[1] == u || - *((tbinptr*)(u->parent)) == u); - if (u->child[0] != 0) { - assert(u->child[0]->parent == u); - assert(u->child[0] != u); - do_check_tree(m, u->child[0]); - } - if (u->child[1] != 0) { - assert(u->child[1]->parent == u); - assert(u->child[1] != u); - do_check_tree(m, u->child[1]); - } - if (u->child[0] != 0 && u->child[1] != 0) { - assert(chunksize(u->child[0]) < chunksize(u->child[1])); - } - } - u = u->fd; - } while (u != t); - assert(head != 0); -} - -/* Check all the chunks in a treebin. */ -static void do_check_treebin(mstate m, bindex_t i) { - tbinptr* tb = treebin_at(m, i); - tchunkptr t = *tb; - int empty = (m->treemap & (1U << i)) == 0; - if (t == 0) - assert(empty); - if (!empty) - do_check_tree(m, t); -} - -/* Check all the chunks in a smallbin. */ -static void do_check_smallbin(mstate m, bindex_t i) { - sbinptr b = smallbin_at(m, i); - mchunkptr p = b->bk; - unsigned int empty = (m->smallmap & (1U << i)) == 0; - if (p == b) - assert(empty); - if (!empty) { - for (; p != b; p = p->bk) { - size_t size = chunksize(p); - mchunkptr q; - /* each chunk claims to be free */ - do_check_free_chunk(m, p); - /* chunk belongs in bin */ - assert(small_index(size) == i); - assert(p->bk == b || chunksize(p->bk) == chunksize(p)); - /* chunk is followed by an inuse chunk */ - q = next_chunk(p); - if (q->head != FENCEPOST_HEAD) - do_check_inuse_chunk(m, q); - } - } -} - -/* Find x in a bin. Used in other check functions. */ -static int bin_find(mstate m, mchunkptr x) { - size_t size = chunksize(x); - if (is_small(size)) { - bindex_t sidx = small_index(size); - sbinptr b = smallbin_at(m, sidx); - if (smallmap_is_marked(m, sidx)) { - mchunkptr p = b; - do { - if (p == x) - return 1; - } while ((p = p->fd) != b); - } - } - else { - bindex_t tidx; - compute_tree_index(size, tidx); - if (treemap_is_marked(m, tidx)) { - tchunkptr t = *treebin_at(m, tidx); - size_t sizebits = size << leftshift_for_tree_index(tidx); - while (t != 0 && chunksize(t) != size) { - t = t->child[(sizebits >> (SIZE_T_BITSIZE-SIZE_T_ONE)) & 1]; - sizebits <<= 1; - } - if (t != 0) { - tchunkptr u = t; - do { - if (u == (tchunkptr)x) - return 1; - } while ((u = u->fd) != t); - } - } - } - return 0; -} - -/* Traverse each chunk and check it; return total */ -static size_t traverse_and_check(mstate m) { - size_t sum = 0; - if (is_initialized(m)) { - msegmentptr s = &m->seg; - sum += m->topsize + TOP_FOOT_SIZE; - while (s != 0) { - mchunkptr q = align_as_chunk(s->base); - mchunkptr lastq = 0; - assert(pinuse(q)); - while (segment_holds(s, q) && - q != m->top && q->head != FENCEPOST_HEAD) { - sum += chunksize(q); - if (is_inuse(q)) { - assert(!bin_find(m, q)); - do_check_inuse_chunk(m, q); - } - else { - assert(q == m->dv || bin_find(m, q)); - assert(lastq == 0 || is_inuse(lastq)); /* Not 2 consecutive free */ - do_check_free_chunk(m, q); - } - lastq = q; - q = next_chunk(q); - } - s = s->next; - } - } - return sum; -} - - -/* Check all properties of malloc_state. */ -static void do_check_malloc_state(mstate m) { - bindex_t i; - size_t total; - /* check bins */ - for (i = 0; i < NSMALLBINS; ++i) - do_check_smallbin(m, i); - for (i = 0; i < NTREEBINS; ++i) - do_check_treebin(m, i); - - if (m->dvsize != 0) { /* check dv chunk */ - do_check_any_chunk(m, m->dv); - assert(m->dvsize == chunksize(m->dv)); - assert(m->dvsize >= MIN_CHUNK_SIZE); - assert(bin_find(m, m->dv) == 0); - } - - if (m->top != 0) { /* check top chunk */ - do_check_top_chunk(m, m->top); - /*assert(m->topsize == chunksize(m->top)); redundant */ - assert(m->topsize > 0); - assert(bin_find(m, m->top) == 0); - } - - total = traverse_and_check(m); - assert(total <= m->footprint); - assert(m->footprint <= m->max_footprint); -} -#endif /* DEBUG */ - -/* ----------------------------- statistics ------------------------------ */ - -#if !NO_MALLINFO -static struct mallinfo internal_mallinfo(mstate m) { - struct mallinfo nm = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; - ensure_initialization(); - if (!PREACTION(m)) { - check_malloc_state(m); - if (is_initialized(m)) { - size_t nfree = SIZE_T_ONE; /* top always free */ - size_t mfree = m->topsize + TOP_FOOT_SIZE; - size_t sum = mfree; - msegmentptr s = &m->seg; - while (s != 0) { - mchunkptr q = align_as_chunk(s->base); - while (segment_holds(s, q) && - q != m->top && q->head != FENCEPOST_HEAD) { - size_t sz = chunksize(q); - sum += sz; - if (!is_inuse(q)) { - mfree += sz; - ++nfree; - } - q = next_chunk(q); - } - s = s->next; - } - - nm.arena = sum; - nm.ordblks = nfree; - nm.hblkhd = m->footprint - sum; - nm.usmblks = m->max_footprint; - nm.uordblks = m->footprint - mfree; - nm.fordblks = mfree; - nm.keepcost = m->topsize; - } - - POSTACTION(m); - } - return nm; -} -#endif /* !NO_MALLINFO */ - -#if !NO_MALLOC_STATS -static void internal_malloc_stats(mstate m) { - ensure_initialization(); - if (!PREACTION(m)) { - size_t maxfp = 0; - size_t fp = 0; - size_t used = 0; - check_malloc_state(m); - if (is_initialized(m)) { - msegmentptr s = &m->seg; - maxfp = m->max_footprint; - fp = m->footprint; - used = fp - (m->topsize + TOP_FOOT_SIZE); - - while (s != 0) { - mchunkptr q = align_as_chunk(s->base); - while (segment_holds(s, q) && - q != m->top && q->head != FENCEPOST_HEAD) { - if (!is_inuse(q)) - used -= chunksize(q); - q = next_chunk(q); - } - s = s->next; - } - } - POSTACTION(m); /* drop lock */ - fprintf(stderr, "max system bytes = %10lu\n", (unsigned long)(maxfp)); - fprintf(stderr, "system bytes = %10lu\n", (unsigned long)(fp)); - fprintf(stderr, "in use bytes = %10lu\n", (unsigned long)(used)); - } -} -#endif /* NO_MALLOC_STATS */ - -/* ----------------------- Operations on smallbins ----------------------- */ - -/* - Various forms of linking and unlinking are defined as macros. Even - the ones for trees, which are very long but have very short typical - paths. This is ugly but reduces reliance on inlining support of - compilers. -*/ - -/* Link a free chunk into a smallbin */ -#define insert_small_chunk(M, P, S) {\ - bindex_t I = small_index(S);\ - mchunkptr B = smallbin_at(M, I);\ - mchunkptr F = B;\ - assert(S >= MIN_CHUNK_SIZE);\ - if (!smallmap_is_marked(M, I))\ - mark_smallmap(M, I);\ - else if (RTCHECK(ok_address(M, B->fd)))\ - F = B->fd;\ - else {\ - CORRUPTION_ERROR_ACTION(M);\ - }\ - B->fd = P;\ - F->bk = P;\ - P->fd = F;\ - P->bk = B;\ -} - -/* Unlink a chunk from a smallbin */ -#define unlink_small_chunk(M, P, S) {\ - mchunkptr F = P->fd;\ - mchunkptr B = P->bk;\ - bindex_t I = small_index(S);\ - assert(P != B);\ - assert(P != F);\ - assert(chunksize(P) == small_index2size(I));\ - if (RTCHECK(F == smallbin_at(M,I) || (ok_address(M, F) && F->bk == P))) { \ - if (B == F) {\ - clear_smallmap(M, I);\ - }\ - else if (RTCHECK(B == smallbin_at(M,I) ||\ - (ok_address(M, B) && B->fd == P))) {\ - F->bk = B;\ - B->fd = F;\ - }\ - else {\ - CORRUPTION_ERROR_ACTION(M);\ - }\ - }\ - else {\ - CORRUPTION_ERROR_ACTION(M);\ - }\ -} - -/* Unlink the first chunk from a smallbin */ -#define unlink_first_small_chunk(M, B, P, I) {\ - mchunkptr F = P->fd;\ - assert(P != B);\ - assert(P != F);\ - assert(chunksize(P) == small_index2size(I));\ - if (B == F) {\ - clear_smallmap(M, I);\ - }\ - else if (RTCHECK(ok_address(M, F) && F->bk == P)) {\ - F->bk = B;\ - B->fd = F;\ - }\ - else {\ - CORRUPTION_ERROR_ACTION(M);\ - }\ -} - -/* Replace dv node, binning the old one */ -/* Used only when dvsize known to be small */ -#define replace_dv(M, P, S) {\ - size_t DVS = M->dvsize;\ - assert(is_small(DVS));\ - if (DVS != 0) {\ - mchunkptr DV = M->dv;\ - insert_small_chunk(M, DV, DVS);\ - }\ - M->dvsize = S;\ - M->dv = P;\ -} - -/* ------------------------- Operations on trees ------------------------- */ - -/* Insert chunk into tree */ -#define insert_large_chunk(M, X, S) {\ - tbinptr* H;\ - bindex_t I;\ - compute_tree_index(S, I);\ - H = treebin_at(M, I);\ - X->index = I;\ - X->child[0] = X->child[1] = 0;\ - if (!treemap_is_marked(M, I)) {\ - mark_treemap(M, I);\ - *H = X;\ - X->parent = (tchunkptr)H;\ - X->fd = X->bk = X;\ - }\ - else {\ - tchunkptr T = *H;\ - size_t K = S << leftshift_for_tree_index(I);\ - for (;;) {\ - if (chunksize(T) != S) {\ - tchunkptr* C = &(T->child[(K >> (SIZE_T_BITSIZE-SIZE_T_ONE)) & 1]);\ - K <<= 1;\ - if (*C != 0)\ - T = *C;\ - else if (RTCHECK(ok_address(M, C))) {\ - *C = X;\ - X->parent = T;\ - X->fd = X->bk = X;\ - break;\ - }\ - else {\ - CORRUPTION_ERROR_ACTION(M);\ - break;\ - }\ - }\ - else {\ - tchunkptr F = T->fd;\ - if (RTCHECK(ok_address(M, T) && ok_address(M, F))) {\ - T->fd = F->bk = X;\ - X->fd = F;\ - X->bk = T;\ - X->parent = 0;\ - break;\ - }\ - else {\ - CORRUPTION_ERROR_ACTION(M);\ - break;\ - }\ - }\ - }\ - }\ -} - -/* - Unlink steps: - - 1. If x is a chained node, unlink it from its same-sized fd/bk links - and choose its bk node as its replacement. - 2. If x was the last node of its size, but not a leaf node, it must - be replaced with a leaf node (not merely one with an open left or - right), to make sure that lefts and rights of descendents - correspond properly to bit masks. We use the rightmost descendent - of x. We could use any other leaf, but this is easy to locate and - tends to counteract removal of leftmosts elsewhere, and so keeps - paths shorter than minimally guaranteed. This doesn't loop much - because on average a node in a tree is near the bottom. - 3. If x is the base of a chain (i.e., has parent links) relink - x's parent and children to x's replacement (or null if none). -*/ - -#define unlink_large_chunk(M, X) {\ - tchunkptr XP = X->parent;\ - tchunkptr R;\ - if (X->bk != X) {\ - tchunkptr F = X->fd;\ - R = X->bk;\ - if (RTCHECK(ok_address(M, F) && F->bk == X && R->fd == X)) {\ - F->bk = R;\ - R->fd = F;\ - }\ - else {\ - CORRUPTION_ERROR_ACTION(M);\ - }\ - }\ - else {\ - tchunkptr* RP;\ - if (((R = *(RP = &(X->child[1]))) != 0) ||\ - ((R = *(RP = &(X->child[0]))) != 0)) {\ - tchunkptr* CP;\ - while ((*(CP = &(R->child[1])) != 0) ||\ - (*(CP = &(R->child[0])) != 0)) {\ - R = *(RP = CP);\ - }\ - if (RTCHECK(ok_address(M, RP)))\ - *RP = 0;\ - else {\ - CORRUPTION_ERROR_ACTION(M);\ - }\ - }\ - }\ - if (XP != 0) {\ - tbinptr* H = treebin_at(M, X->index);\ - if (X == *H) {\ - if ((*H = R) == 0) \ - clear_treemap(M, X->index);\ - }\ - else if (RTCHECK(ok_address(M, XP))) {\ - if (XP->child[0] == X) \ - XP->child[0] = R;\ - else \ - XP->child[1] = R;\ - }\ - else\ - CORRUPTION_ERROR_ACTION(M);\ - if (R != 0) {\ - if (RTCHECK(ok_address(M, R))) {\ - tchunkptr C0, C1;\ - R->parent = XP;\ - if ((C0 = X->child[0]) != 0) {\ - if (RTCHECK(ok_address(M, C0))) {\ - R->child[0] = C0;\ - C0->parent = R;\ - }\ - else\ - CORRUPTION_ERROR_ACTION(M);\ - }\ - if ((C1 = X->child[1]) != 0) {\ - if (RTCHECK(ok_address(M, C1))) {\ - R->child[1] = C1;\ - C1->parent = R;\ - }\ - else\ - CORRUPTION_ERROR_ACTION(M);\ - }\ - }\ - else\ - CORRUPTION_ERROR_ACTION(M);\ - }\ - }\ -} - -/* Relays to large vs small bin operations */ - -#define insert_chunk(M, P, S)\ - if (is_small(S)) insert_small_chunk(M, P, S)\ - else { tchunkptr TP = (tchunkptr)(P); insert_large_chunk(M, TP, S); } - -#define unlink_chunk(M, P, S)\ - if (is_small(S)) unlink_small_chunk(M, P, S)\ - else { tchunkptr TP = (tchunkptr)(P); unlink_large_chunk(M, TP); } - - -/* Relays to internal calls to malloc/free from realloc, memalign etc */ - -#if ONLY_MSPACES -#define internal_malloc(m, b) mspace_malloc(m, b) -#define internal_free(m, mem) mspace_free(m,mem); -#else /* ONLY_MSPACES */ -#if MSPACES -#define internal_malloc(m, b)\ - ((m == gm)? dlmalloc(b) : mspace_malloc(m, b)) -#define internal_free(m, mem)\ - if (m == gm) dlfree(mem); else mspace_free(m,mem); -#else /* MSPACES */ -#define internal_malloc(m, b) dlmalloc(b) -#define internal_free(m, mem) dlfree(mem) -#endif /* MSPACES */ -#endif /* ONLY_MSPACES */ - -/* ----------------------- Direct-mmapping chunks ----------------------- */ - -/* - Directly mmapped chunks are set up with an offset to the start of - the mmapped region stored in the prev_foot field of the chunk. This - allows reconstruction of the required argument to MUNMAP when freed, - and also allows adjustment of the returned chunk to meet alignment - requirements (especially in memalign). -*/ - -/* Malloc using mmap */ -static void* mmap_alloc(mstate m, size_t nb) { - size_t mmsize = mmap_align(nb + SIX_SIZE_T_SIZES + CHUNK_ALIGN_MASK); - if (m->footprint_limit != 0) { - size_t fp = m->footprint + mmsize; - if (fp <= m->footprint || fp > m->footprint_limit) - return 0; - } - if (mmsize > nb) { /* Check for wrap around 0 */ - char* mm = (char*)(CALL_DIRECT_MMAP(mmsize)); - if (mm != CMFAIL) { - size_t offset = align_offset(chunk2mem(mm)); - size_t psize = mmsize - offset - MMAP_FOOT_PAD; - mchunkptr p = (mchunkptr)(mm + offset); - p->prev_foot = offset; - p->head = psize; - mark_inuse_foot(m, p, psize); - chunk_plus_offset(p, psize)->head = FENCEPOST_HEAD; - chunk_plus_offset(p, psize+SIZE_T_SIZE)->head = 0; - - if (m->least_addr == 0 || mm < m->least_addr) - m->least_addr = mm; - if ((m->footprint += mmsize) > m->max_footprint) - m->max_footprint = m->footprint; - assert(is_aligned(chunk2mem(p))); - check_mmapped_chunk(m, p); - return chunk2mem(p); - } - } - return 0; -} - -/* Realloc using mmap */ -static mchunkptr mmap_resize(mstate m, mchunkptr oldp, size_t nb, int flags) { - size_t oldsize = chunksize(oldp); - (void)flags; /* placate people compiling -Wunused */ - if (is_small(nb)) /* Can't shrink mmap regions below small size */ - return 0; - /* Keep old chunk if big enough but not too big */ - if (oldsize >= nb + SIZE_T_SIZE && - (oldsize - nb) <= (mparams.granularity << 1)) - return oldp; - else { - size_t offset = oldp->prev_foot; - size_t oldmmsize = oldsize + offset + MMAP_FOOT_PAD; - size_t newmmsize = mmap_align(nb + SIX_SIZE_T_SIZES + CHUNK_ALIGN_MASK); - char* cp = (char*)CALL_MREMAP((char*)oldp - offset, - oldmmsize, newmmsize, flags); - if (cp != CMFAIL) { - mchunkptr newp = (mchunkptr)(cp + offset); - size_t psize = newmmsize - offset - MMAP_FOOT_PAD; - newp->head = psize; - mark_inuse_foot(m, newp, psize); - chunk_plus_offset(newp, psize)->head = FENCEPOST_HEAD; - chunk_plus_offset(newp, psize+SIZE_T_SIZE)->head = 0; - - if (cp < m->least_addr) - m->least_addr = cp; - if ((m->footprint += newmmsize - oldmmsize) > m->max_footprint) - m->max_footprint = m->footprint; - check_mmapped_chunk(m, newp); - return newp; - } - } - return 0; -} - - -/* -------------------------- mspace management -------------------------- */ - -/* Initialize top chunk and its size */ -static void init_top(mstate m, mchunkptr p, size_t psize) { - /* Ensure alignment */ - size_t offset = align_offset(chunk2mem(p)); - p = (mchunkptr)((char*)p + offset); - psize -= offset; - - m->top = p; - m->topsize = psize; - p->head = psize | PINUSE_BIT; - /* set size of fake trailing chunk holding overhead space only once */ - chunk_plus_offset(p, psize)->head = TOP_FOOT_SIZE; - m->trim_check = mparams.trim_threshold; /* reset on each update */ -} - -/* Initialize bins for a new mstate that is otherwise zeroed out */ -static void init_bins(mstate m) { - /* Establish circular links for smallbins */ - bindex_t i; - for (i = 0; i < NSMALLBINS; ++i) { - sbinptr bin = smallbin_at(m,i); - bin->fd = bin->bk = bin; - } -} - -#if PROCEED_ON_ERROR - -/* default corruption action */ -static void reset_on_error(mstate m) { - int i; - ++malloc_corruption_error_count; - /* Reinitialize fields to forget about all memory */ - m->smallmap = m->treemap = 0; - m->dvsize = m->topsize = 0; - m->seg.base = 0; - m->seg.size = 0; - m->seg.next = 0; - m->top = m->dv = 0; - for (i = 0; i < NTREEBINS; ++i) - *treebin_at(m, i) = 0; - init_bins(m); -} -#endif /* PROCEED_ON_ERROR */ - -/* Allocate chunk and prepend remainder with chunk in successor base. */ -static void* prepend_alloc(mstate m, char* newbase, char* oldbase, - size_t nb) { - mchunkptr p = align_as_chunk(newbase); - mchunkptr oldfirst = align_as_chunk(oldbase); - size_t psize = (char*)oldfirst - (char*)p; - mchunkptr q = chunk_plus_offset(p, nb); - size_t qsize = psize - nb; - set_size_and_pinuse_of_inuse_chunk(m, p, nb); - - assert((char*)oldfirst > (char*)q); - assert(pinuse(oldfirst)); - assert(qsize >= MIN_CHUNK_SIZE); - - /* consolidate remainder with first chunk of old base */ - if (oldfirst == m->top) { - size_t tsize = m->topsize += qsize; - m->top = q; - q->head = tsize | PINUSE_BIT; - check_top_chunk(m, q); - } - else if (oldfirst == m->dv) { - size_t dsize = m->dvsize += qsize; - m->dv = q; - set_size_and_pinuse_of_free_chunk(q, dsize); - } - else { - if (!is_inuse(oldfirst)) { - size_t nsize = chunksize(oldfirst); - unlink_chunk(m, oldfirst, nsize); - oldfirst = chunk_plus_offset(oldfirst, nsize); - qsize += nsize; - } - set_free_with_pinuse(q, qsize, oldfirst); - insert_chunk(m, q, qsize); - check_free_chunk(m, q); - } - - check_malloced_chunk(m, chunk2mem(p), nb); - return chunk2mem(p); -} - -/* Add a segment to hold a new noncontiguous region */ -static void add_segment(mstate m, char* tbase, size_t tsize, flag_t mmapped) { - /* Determine locations and sizes of segment, fenceposts, old top */ - char* old_top = (char*)m->top; - msegmentptr oldsp = segment_holding(m, old_top); - char* old_end = oldsp->base + oldsp->size; - size_t ssize = pad_request(sizeof(struct malloc_segment)); - char* rawsp = old_end - (ssize + FOUR_SIZE_T_SIZES + CHUNK_ALIGN_MASK); - size_t offset = align_offset(chunk2mem(rawsp)); - char* asp = rawsp + offset; - char* csp = (asp < (old_top + MIN_CHUNK_SIZE))? old_top : asp; - mchunkptr sp = (mchunkptr)csp; - msegmentptr ss = (msegmentptr)(chunk2mem(sp)); - mchunkptr tnext = chunk_plus_offset(sp, ssize); - mchunkptr p = tnext; - int nfences = 0; - - /* reset top to new space */ - init_top(m, (mchunkptr)tbase, tsize - TOP_FOOT_SIZE); - - /* Set up segment record */ - assert(is_aligned(ss)); - set_size_and_pinuse_of_inuse_chunk(m, sp, ssize); - *ss = m->seg; /* Push current record */ - m->seg.base = tbase; - m->seg.size = tsize; - m->seg.sflags = mmapped; - m->seg.next = ss; - - /* Insert trailing fenceposts */ - for (;;) { - mchunkptr nextp = chunk_plus_offset(p, SIZE_T_SIZE); - p->head = FENCEPOST_HEAD; - ++nfences; - if ((char*)(&(nextp->head)) < old_end) - p = nextp; - else - break; - } - assert(nfences >= 2); - - /* Insert the rest of old top into a bin as an ordinary free chunk */ - if (csp != old_top) { - mchunkptr q = (mchunkptr)old_top; - size_t psize = csp - old_top; - mchunkptr tn = chunk_plus_offset(q, psize); - set_free_with_pinuse(q, psize, tn); - insert_chunk(m, q, psize); - } - - check_top_chunk(m, m->top); -} - -/* -------------------------- System allocation -------------------------- */ - -/* Get memory from system using MORECORE or MMAP */ -static void* sys_alloc(mstate m, size_t nb) { - char* tbase = CMFAIL; - size_t tsize = 0; - flag_t mmap_flag = 0; - size_t asize; /* allocation size */ - - ensure_initialization(); - - /* Directly map large chunks, but only if already initialized */ - if (use_mmap(m) && nb >= mparams.mmap_threshold && m->topsize != 0) { - void* mem = mmap_alloc(m, nb); - if (mem != 0) - return mem; - } - - asize = granularity_align(nb + SYS_ALLOC_PADDING); - if (asize <= nb) - return 0; /* wraparound */ - if (m->footprint_limit != 0) { - size_t fp = m->footprint + asize; - if (fp <= m->footprint || fp > m->footprint_limit) - return 0; - } - - /* - Try getting memory in any of three ways (in most-preferred to - least-preferred order): - 1. A call to MORECORE that can normally contiguously extend memory. - (disabled if not MORECORE_CONTIGUOUS or not HAVE_MORECORE or - or main space is mmapped or a previous contiguous call failed) - 2. A call to MMAP new space (disabled if not HAVE_MMAP). - Note that under the default settings, if MORECORE is unable to - fulfill a request, and HAVE_MMAP is true, then mmap is - used as a noncontiguous system allocator. This is a useful backup - strategy for systems with holes in address spaces -- in this case - sbrk cannot contiguously expand the heap, but mmap may be able to - find space. - 3. A call to MORECORE that cannot usually contiguously extend memory. - (disabled if not HAVE_MORECORE) - - In all cases, we need to request enough bytes from system to ensure - we can malloc nb bytes upon success, so pad with enough space for - top_foot, plus alignment-pad to make sure we don't lose bytes if - not on boundary, and round this up to a granularity unit. - */ - - if (MORECORE_CONTIGUOUS && !use_noncontiguous(m)) { - char* br = CMFAIL; - size_t ssize = asize; /* sbrk call size */ - msegmentptr ss = (m->top == 0)? 0 : segment_holding(m, (char*)m->top); - ACQUIRE_MALLOC_GLOBAL_LOCK(); - - if (ss == 0) { /* First time through or recovery */ - char* base = (char*)CALL_MORECORE(0); - if (base != CMFAIL) { - size_t fp; - /* Adjust to end on a page boundary */ - if (!is_page_aligned(base)) - ssize += (page_align((size_t)base) - (size_t)base); - fp = m->footprint + ssize; /* recheck limits */ - if (ssize > nb && ssize < HALF_MAX_SIZE_T && - (m->footprint_limit == 0 || - (fp > m->footprint && fp <= m->footprint_limit)) && - (br = (char*)(CALL_MORECORE(ssize))) == base) { - tbase = base; - tsize = ssize; - } - } - } - else { - /* Subtract out existing available top space from MORECORE request. */ - ssize = granularity_align(nb - m->topsize + SYS_ALLOC_PADDING); - /* Use mem here only if it did continuously extend old space */ - if (ssize < HALF_MAX_SIZE_T && - (br = (char*)(CALL_MORECORE(ssize))) == ss->base+ss->size) { - tbase = br; - tsize = ssize; - } - } - - if (tbase == CMFAIL) { /* Cope with partial failure */ - if (br != CMFAIL) { /* Try to use/extend the space we did get */ - if (ssize < HALF_MAX_SIZE_T && - ssize < nb + SYS_ALLOC_PADDING) { - size_t esize = granularity_align(nb + SYS_ALLOC_PADDING - ssize); - if (esize < HALF_MAX_SIZE_T) { - char* end = (char*)CALL_MORECORE(esize); - if (end != CMFAIL) - ssize += esize; - else { /* Can't use; try to release */ - (void) CALL_MORECORE(-ssize); - br = CMFAIL; - } - } - } - } - if (br != CMFAIL) { /* Use the space we did get */ - tbase = br; - tsize = ssize; - } - else - disable_contiguous(m); /* Don't try contiguous path in the future */ - } - - RELEASE_MALLOC_GLOBAL_LOCK(); - } - - if (HAVE_MMAP && tbase == CMFAIL) { /* Try MMAP */ - char* mp = (char*)(CALL_MMAP(asize)); - if (mp != CMFAIL) { - tbase = mp; - tsize = asize; - mmap_flag = USE_MMAP_BIT; - } - } - - if (HAVE_MORECORE && tbase == CMFAIL) { /* Try noncontiguous MORECORE */ - if (asize < HALF_MAX_SIZE_T) { - char* br = CMFAIL; - char* end = CMFAIL; - ACQUIRE_MALLOC_GLOBAL_LOCK(); - br = (char*)(CALL_MORECORE(asize)); - end = (char*)(CALL_MORECORE(0)); - RELEASE_MALLOC_GLOBAL_LOCK(); - if (br != CMFAIL && end != CMFAIL && br < end) { - size_t ssize = end - br; - if (ssize > nb + TOP_FOOT_SIZE) { - tbase = br; - tsize = ssize; - } - } - } - } - - if (tbase != CMFAIL) { - - if ((m->footprint += tsize) > m->max_footprint) - m->max_footprint = m->footprint; - - if (!is_initialized(m)) { /* first-time initialization */ - if (m->least_addr == 0 || tbase < m->least_addr) - m->least_addr = tbase; - m->seg.base = tbase; - m->seg.size = tsize; - m->seg.sflags = mmap_flag; - m->magic = mparams.magic; - m->release_checks = MAX_RELEASE_CHECK_RATE; - init_bins(m); -#if !ONLY_MSPACES - if (is_global(m)) - init_top(m, (mchunkptr)tbase, tsize - TOP_FOOT_SIZE); - else -#endif - { - /* Offset top by embedded malloc_state */ - mchunkptr mn = next_chunk(mem2chunk(m)); - init_top(m, mn, (size_t)((tbase + tsize) - (char*)mn) -TOP_FOOT_SIZE); - } - } - - else { - /* Try to merge with an existing segment */ - msegmentptr sp = &m->seg; - /* Only consider most recent segment if traversal suppressed */ - while (sp != 0 && tbase != sp->base + sp->size) - sp = (NO_SEGMENT_TRAVERSAL) ? 0 : sp->next; - if (sp != 0 && - !is_extern_segment(sp) && - (sp->sflags & USE_MMAP_BIT) == mmap_flag && - segment_holds(sp, m->top)) { /* append */ - sp->size += tsize; - init_top(m, m->top, m->topsize + tsize); - } - else { - if (tbase < m->least_addr) - m->least_addr = tbase; - sp = &m->seg; - while (sp != 0 && sp->base != tbase + tsize) - sp = (NO_SEGMENT_TRAVERSAL) ? 0 : sp->next; - if (sp != 0 && - !is_extern_segment(sp) && - (sp->sflags & USE_MMAP_BIT) == mmap_flag) { - char* oldbase = sp->base; - sp->base = tbase; - sp->size += tsize; - return prepend_alloc(m, tbase, oldbase, nb); - } - else - add_segment(m, tbase, tsize, mmap_flag); - } - } - - if (nb < m->topsize) { /* Allocate from new or extended top space */ - size_t rsize = m->topsize -= nb; - mchunkptr p = m->top; - mchunkptr r = m->top = chunk_plus_offset(p, nb); - r->head = rsize | PINUSE_BIT; - set_size_and_pinuse_of_inuse_chunk(m, p, nb); - check_top_chunk(m, m->top); - check_malloced_chunk(m, chunk2mem(p), nb); - return chunk2mem(p); - } - } - - MALLOC_FAILURE_ACTION; - return 0; -} - -/* ----------------------- system deallocation -------------------------- */ - -/* Unmap and unlink any mmapped segments that don't contain used chunks */ -static size_t release_unused_segments(mstate m) { - size_t released = 0; - int nsegs = 0; - msegmentptr pred = &m->seg; - msegmentptr sp = pred->next; - while (sp != 0) { - char* base = sp->base; - size_t size = sp->size; - msegmentptr next = sp->next; - ++nsegs; - if (is_mmapped_segment(sp) && !is_extern_segment(sp)) { - mchunkptr p = align_as_chunk(base); - size_t psize = chunksize(p); - /* Can unmap if first chunk holds entire segment and not pinned */ - if (!is_inuse(p) && (char*)p + psize >= base + size - TOP_FOOT_SIZE) { - tchunkptr tp = (tchunkptr)p; - assert(segment_holds(sp, (char*)sp)); - if (p == m->dv) { - m->dv = 0; - m->dvsize = 0; - } - else { - unlink_large_chunk(m, tp); - } - if (CALL_MUNMAP(base, size) == 0) { - released += size; - m->footprint -= size; - /* unlink obsoleted record */ - sp = pred; - sp->next = next; - } - else { /* back out if cannot unmap */ - insert_large_chunk(m, tp, psize); - } - } - } - if (NO_SEGMENT_TRAVERSAL) /* scan only first segment */ - break; - pred = sp; - sp = next; - } - /* Reset check counter */ - m->release_checks = (((size_t) nsegs > (size_t) MAX_RELEASE_CHECK_RATE)? - (size_t) nsegs : (size_t) MAX_RELEASE_CHECK_RATE); - return released; -} - -static int sys_trim(mstate m, size_t pad) { - size_t released = 0; - ensure_initialization(); - if (pad < MAX_REQUEST && is_initialized(m)) { - pad += TOP_FOOT_SIZE; /* ensure enough room for segment overhead */ - - if (m->topsize > pad) { - /* Shrink top space in granularity-size units, keeping at least one */ - size_t unit = mparams.granularity; - size_t extra = ((m->topsize - pad + (unit - SIZE_T_ONE)) / unit - - SIZE_T_ONE) * unit; - msegmentptr sp = segment_holding(m, (char*)m->top); - - if (!is_extern_segment(sp)) { - if (is_mmapped_segment(sp)) { - if (HAVE_MMAP && - sp->size >= extra && - !has_segment_link(m, sp)) { /* can't shrink if pinned */ - size_t newsize = sp->size - extra; - (void)newsize; /* placate people compiling -Wunused-variable */ - /* Prefer mremap, fall back to munmap */ - if ((CALL_MREMAP(sp->base, sp->size, newsize, 0) != MFAIL) || - (CALL_MUNMAP(sp->base + newsize, extra) == 0)) { - released = extra; - } - } - } - else if (HAVE_MORECORE) { - if (extra >= HALF_MAX_SIZE_T) /* Avoid wrapping negative */ - extra = (HALF_MAX_SIZE_T) + SIZE_T_ONE - unit; - ACQUIRE_MALLOC_GLOBAL_LOCK(); - { - /* Make sure end of memory is where we last set it. */ - char* old_br = (char*)(CALL_MORECORE(0)); - if (old_br == sp->base + sp->size) { - char* rel_br = (char*)(CALL_MORECORE(-extra)); - char* new_br = (char*)(CALL_MORECORE(0)); - if (rel_br != CMFAIL && new_br < old_br) - released = old_br - new_br; - } - } - RELEASE_MALLOC_GLOBAL_LOCK(); - } - } - - if (released != 0) { - sp->size -= released; - m->footprint -= released; - init_top(m, m->top, m->topsize - released); - check_top_chunk(m, m->top); - } - } - - /* Unmap any unused mmapped segments */ - if (HAVE_MMAP) - released += release_unused_segments(m); - - /* On failure, disable autotrim to avoid repeated failed future calls */ - if (released == 0 && m->topsize > m->trim_check) - m->trim_check = MAX_SIZE_T; - } - - return (released != 0)? 1 : 0; -} - -/* Consolidate and bin a chunk. Differs from exported versions - of free mainly in that the chunk need not be marked as inuse. -*/ -static void dispose_chunk(mstate m, mchunkptr p, size_t psize) { - mchunkptr next = chunk_plus_offset(p, psize); - if (!pinuse(p)) { - mchunkptr prev; - size_t prevsize = p->prev_foot; - if (is_mmapped(p)) { - psize += prevsize + MMAP_FOOT_PAD; - if (CALL_MUNMAP((char*)p - prevsize, psize) == 0) - m->footprint -= psize; - return; - } - prev = chunk_minus_offset(p, prevsize); - psize += prevsize; - p = prev; - if (RTCHECK(ok_address(m, prev))) { /* consolidate backward */ - if (p != m->dv) { - unlink_chunk(m, p, prevsize); - } - else if ((next->head & INUSE_BITS) == INUSE_BITS) { - m->dvsize = psize; - set_free_with_pinuse(p, psize, next); - return; - } - } - else { - CORRUPTION_ERROR_ACTION(m); - return; - } - } - if (RTCHECK(ok_address(m, next))) { - if (!cinuse(next)) { /* consolidate forward */ - if (next == m->top) { - size_t tsize = m->topsize += psize; - m->top = p; - p->head = tsize | PINUSE_BIT; - if (p == m->dv) { - m->dv = 0; - m->dvsize = 0; - } - return; - } - else if (next == m->dv) { - size_t dsize = m->dvsize += psize; - m->dv = p; - set_size_and_pinuse_of_free_chunk(p, dsize); - return; - } - else { - size_t nsize = chunksize(next); - psize += nsize; - unlink_chunk(m, next, nsize); - set_size_and_pinuse_of_free_chunk(p, psize); - if (p == m->dv) { - m->dvsize = psize; - return; - } - } - } - else { - set_free_with_pinuse(p, psize, next); - } - insert_chunk(m, p, psize); - } - else { - CORRUPTION_ERROR_ACTION(m); - } -} - -/* ---------------------------- malloc --------------------------- */ - -/* allocate a large request from the best fitting chunk in a treebin */ -static void* tmalloc_large(mstate m, size_t nb) { - tchunkptr v = 0; - size_t rsize = -nb; /* Unsigned negation */ - tchunkptr t; - bindex_t idx; - compute_tree_index(nb, idx); - if ((t = *treebin_at(m, idx)) != 0) { - /* Traverse tree for this bin looking for node with size == nb */ - size_t sizebits = nb << leftshift_for_tree_index(idx); - tchunkptr rst = 0; /* The deepest untaken right subtree */ - for (;;) { - tchunkptr rt; - size_t trem = chunksize(t) - nb; - if (trem < rsize) { - v = t; - if ((rsize = trem) == 0) - break; - } - rt = t->child[1]; - t = t->child[(sizebits >> (SIZE_T_BITSIZE-SIZE_T_ONE)) & 1]; - if (rt != 0 && rt != t) - rst = rt; - if (t == 0) { - t = rst; /* set t to least subtree holding sizes > nb */ - break; - } - sizebits <<= 1; - } - } - if (t == 0 && v == 0) { /* set t to root of next non-empty treebin */ - binmap_t leftbits = left_bits(idx2bit(idx)) & m->treemap; - if (leftbits != 0) { - bindex_t i; - binmap_t leastbit = least_bit(leftbits); - compute_bit2idx(leastbit, i); - t = *treebin_at(m, i); - } - } - - while (t != 0) { /* find smallest of tree or subtree */ - size_t trem = chunksize(t) - nb; - if (trem < rsize) { - rsize = trem; - v = t; - } - t = leftmost_child(t); - } - - /* If dv is a better fit, return 0 so malloc will use it */ - if (v != 0 && rsize < (size_t)(m->dvsize - nb)) { - if (RTCHECK(ok_address(m, v))) { /* split */ - mchunkptr r = chunk_plus_offset(v, nb); - assert(chunksize(v) == rsize + nb); - if (RTCHECK(ok_next(v, r))) { - unlink_large_chunk(m, v); - if (rsize < MIN_CHUNK_SIZE) - set_inuse_and_pinuse(m, v, (rsize + nb)); - else { - set_size_and_pinuse_of_inuse_chunk(m, v, nb); - set_size_and_pinuse_of_free_chunk(r, rsize); - insert_chunk(m, r, rsize); - } - return chunk2mem(v); - } - } - CORRUPTION_ERROR_ACTION(m); - } - return 0; -} - -/* allocate a small request from the best fitting chunk in a treebin */ -static void* tmalloc_small(mstate m, size_t nb) { - tchunkptr t, v; - size_t rsize; - bindex_t i; - binmap_t leastbit = least_bit(m->treemap); - compute_bit2idx(leastbit, i); - v = t = *treebin_at(m, i); - rsize = chunksize(t) - nb; - - while ((t = leftmost_child(t)) != 0) { - size_t trem = chunksize(t) - nb; - if (trem < rsize) { - rsize = trem; - v = t; - } - } - - if (RTCHECK(ok_address(m, v))) { - mchunkptr r = chunk_plus_offset(v, nb); - assert(chunksize(v) == rsize + nb); - if (RTCHECK(ok_next(v, r))) { - unlink_large_chunk(m, v); - if (rsize < MIN_CHUNK_SIZE) - set_inuse_and_pinuse(m, v, (rsize + nb)); - else { - set_size_and_pinuse_of_inuse_chunk(m, v, nb); - set_size_and_pinuse_of_free_chunk(r, rsize); - replace_dv(m, r, rsize); - } - return chunk2mem(v); - } - } - - CORRUPTION_ERROR_ACTION(m); - return 0; -} - -#if !ONLY_MSPACES - -void* dlmalloc(size_t bytes) { - /* - Basic algorithm: - If a small request (< 256 bytes minus per-chunk overhead): - 1. If one exists, use a remainderless chunk in associated smallbin. - (Remainderless means that there are too few excess bytes to - represent as a chunk.) - 2. If it is big enough, use the dv chunk, which is normally the - chunk adjacent to the one used for the most recent small request. - 3. If one exists, split the smallest available chunk in a bin, - saving remainder in dv. - 4. If it is big enough, use the top chunk. - 5. If available, get memory from system and use it - Otherwise, for a large request: - 1. Find the smallest available binned chunk that fits, and use it - if it is better fitting than dv chunk, splitting if necessary. - 2. If better fitting than any binned chunk, use the dv chunk. - 3. If it is big enough, use the top chunk. - 4. If request size >= mmap threshold, try to directly mmap this chunk. - 5. If available, get memory from system and use it - - The ugly goto's here ensure that postaction occurs along all paths. - */ - -#if USE_LOCKS - ensure_initialization(); /* initialize in sys_alloc if not using locks */ -#endif - - if (!PREACTION(gm)) { - void* mem; - size_t nb; - if (bytes <= MAX_SMALL_REQUEST) { - bindex_t idx; - binmap_t smallbits; - nb = (bytes < MIN_REQUEST)? MIN_CHUNK_SIZE : pad_request(bytes); - idx = small_index(nb); - smallbits = gm->smallmap >> idx; - - if ((smallbits & 0x3U) != 0) { /* Remainderless fit to a smallbin. */ - mchunkptr b, p; - idx += ~smallbits & 1; /* Uses next bin if idx empty */ - b = smallbin_at(gm, idx); - p = b->fd; - assert(chunksize(p) == small_index2size(idx)); - unlink_first_small_chunk(gm, b, p, idx); - set_inuse_and_pinuse(gm, p, small_index2size(idx)); - mem = chunk2mem(p); - check_malloced_chunk(gm, mem, nb); - goto postaction; - } - - else if (nb > gm->dvsize) { - if (smallbits != 0) { /* Use chunk in next nonempty smallbin */ - mchunkptr b, p, r; - size_t rsize; - bindex_t i; - binmap_t leftbits = (smallbits << idx) & left_bits(idx2bit(idx)); - binmap_t leastbit = least_bit(leftbits); - compute_bit2idx(leastbit, i); - b = smallbin_at(gm, i); - p = b->fd; - assert(chunksize(p) == small_index2size(i)); - unlink_first_small_chunk(gm, b, p, i); - rsize = small_index2size(i) - nb; - /* Fit here cannot be remainderless if 4byte sizes */ - if (SIZE_T_SIZE != 4 && rsize < MIN_CHUNK_SIZE) - set_inuse_and_pinuse(gm, p, small_index2size(i)); - else { - set_size_and_pinuse_of_inuse_chunk(gm, p, nb); - r = chunk_plus_offset(p, nb); - set_size_and_pinuse_of_free_chunk(r, rsize); - replace_dv(gm, r, rsize); - } - mem = chunk2mem(p); - check_malloced_chunk(gm, mem, nb); - goto postaction; - } - - else if (gm->treemap != 0 && (mem = tmalloc_small(gm, nb)) != 0) { - check_malloced_chunk(gm, mem, nb); - goto postaction; - } - } - } - else if (bytes >= MAX_REQUEST) - nb = MAX_SIZE_T; /* Too big to allocate. Force failure (in sys alloc) */ - else { - nb = pad_request(bytes); - if (gm->treemap != 0 && (mem = tmalloc_large(gm, nb)) != 0) { - check_malloced_chunk(gm, mem, nb); - goto postaction; - } - } - - if (nb <= gm->dvsize) { - size_t rsize = gm->dvsize - nb; - mchunkptr p = gm->dv; - if (rsize >= MIN_CHUNK_SIZE) { /* split dv */ - mchunkptr r = gm->dv = chunk_plus_offset(p, nb); - gm->dvsize = rsize; - set_size_and_pinuse_of_free_chunk(r, rsize); - set_size_and_pinuse_of_inuse_chunk(gm, p, nb); - } - else { /* exhaust dv */ - size_t dvs = gm->dvsize; - gm->dvsize = 0; - gm->dv = 0; - set_inuse_and_pinuse(gm, p, dvs); - } - mem = chunk2mem(p); - check_malloced_chunk(gm, mem, nb); - goto postaction; - } - - else if (nb < gm->topsize) { /* Split top */ - size_t rsize = gm->topsize -= nb; - mchunkptr p = gm->top; - mchunkptr r = gm->top = chunk_plus_offset(p, nb); - r->head = rsize | PINUSE_BIT; - set_size_and_pinuse_of_inuse_chunk(gm, p, nb); - mem = chunk2mem(p); - check_top_chunk(gm, gm->top); - check_malloced_chunk(gm, mem, nb); - goto postaction; - } - - mem = sys_alloc(gm, nb); - - postaction: - POSTACTION(gm); - return mem; - } - - return 0; -} - -/* ---------------------------- free --------------------------- */ - -void dlfree(void* mem) { - /* - Consolidate freed chunks with preceeding or succeeding bordering - free chunks, if they exist, and then place in a bin. Intermixed - with special cases for top, dv, mmapped chunks, and usage errors. - */ - - if (mem != 0) { - mchunkptr p = mem2chunk(mem); -#if FOOTERS - mstate fm = get_mstate_for(p); - if (!ok_magic(fm)) { - USAGE_ERROR_ACTION(fm, p); - return; - } -#else /* FOOTERS */ -#define fm gm -#endif /* FOOTERS */ - if (!PREACTION(fm)) { - check_inuse_chunk(fm, p); - if (RTCHECK(ok_address(fm, p) && ok_inuse(p))) { - size_t psize = chunksize(p); - mchunkptr next = chunk_plus_offset(p, psize); - if (!pinuse(p)) { - size_t prevsize = p->prev_foot; - if (is_mmapped(p)) { - psize += prevsize + MMAP_FOOT_PAD; - if (CALL_MUNMAP((char*)p - prevsize, psize) == 0) - fm->footprint -= psize; - goto postaction; - } - else { - mchunkptr prev = chunk_minus_offset(p, prevsize); - psize += prevsize; - p = prev; - if (RTCHECK(ok_address(fm, prev))) { /* consolidate backward */ - if (p != fm->dv) { - unlink_chunk(fm, p, prevsize); - } - else if ((next->head & INUSE_BITS) == INUSE_BITS) { - fm->dvsize = psize; - set_free_with_pinuse(p, psize, next); - goto postaction; - } - } - else - goto erroraction; - } - } - - if (RTCHECK(ok_next(p, next) && ok_pinuse(next))) { - if (!cinuse(next)) { /* consolidate forward */ - if (next == fm->top) { - size_t tsize = fm->topsize += psize; - fm->top = p; - p->head = tsize | PINUSE_BIT; - if (p == fm->dv) { - fm->dv = 0; - fm->dvsize = 0; - } - if (should_trim(fm, tsize)) - sys_trim(fm, 0); - goto postaction; - } - else if (next == fm->dv) { - size_t dsize = fm->dvsize += psize; - fm->dv = p; - set_size_and_pinuse_of_free_chunk(p, dsize); - goto postaction; - } - else { - size_t nsize = chunksize(next); - psize += nsize; - unlink_chunk(fm, next, nsize); - set_size_and_pinuse_of_free_chunk(p, psize); - if (p == fm->dv) { - fm->dvsize = psize; - goto postaction; - } - } - } - else - set_free_with_pinuse(p, psize, next); - - if (is_small(psize)) { - insert_small_chunk(fm, p, psize); - check_free_chunk(fm, p); - } - else { - tchunkptr tp = (tchunkptr)p; - insert_large_chunk(fm, tp, psize); - check_free_chunk(fm, p); - if (--fm->release_checks == 0) - release_unused_segments(fm); - } - goto postaction; - } - } - erroraction: - USAGE_ERROR_ACTION(fm, p); - postaction: - POSTACTION(fm); - } - } -#if !FOOTERS -#undef fm -#endif /* FOOTERS */ -} - -void* dlcalloc(size_t n_elements, size_t elem_size) { - void* mem; - size_t req = 0; - if (n_elements != 0) { - req = n_elements * elem_size; - if (((n_elements | elem_size) & ~(size_t)0xffff) && - (req / n_elements != elem_size)) - req = MAX_SIZE_T; /* force downstream failure on overflow */ - } - mem = dlmalloc(req); - if (mem != 0 && calloc_must_clear(mem2chunk(mem))) - memset(mem, 0, req); - return mem; -} - -#endif /* !ONLY_MSPACES */ - -/* ------------ Internal support for realloc, memalign, etc -------------- */ - -/* Try to realloc; only in-place unless can_move true */ -static mchunkptr try_realloc_chunk(mstate m, mchunkptr p, size_t nb, - int can_move) { - mchunkptr newp = 0; - size_t oldsize = chunksize(p); - mchunkptr next = chunk_plus_offset(p, oldsize); - if (RTCHECK(ok_address(m, p) && ok_inuse(p) && - ok_next(p, next) && ok_pinuse(next))) { - if (is_mmapped(p)) { - newp = mmap_resize(m, p, nb, can_move); - } - else if (oldsize >= nb) { /* already big enough */ - size_t rsize = oldsize - nb; - if (rsize >= MIN_CHUNK_SIZE) { /* split off remainder */ - mchunkptr r = chunk_plus_offset(p, nb); - set_inuse(m, p, nb); - set_inuse(m, r, rsize); - dispose_chunk(m, r, rsize); - } - newp = p; - } - else if (next == m->top) { /* extend into top */ - if (oldsize + m->topsize > nb) { - size_t newsize = oldsize + m->topsize; - size_t newtopsize = newsize - nb; - mchunkptr newtop = chunk_plus_offset(p, nb); - set_inuse(m, p, nb); - newtop->head = newtopsize |PINUSE_BIT; - m->top = newtop; - m->topsize = newtopsize; - newp = p; - } - } - else if (next == m->dv) { /* extend into dv */ - size_t dvs = m->dvsize; - if (oldsize + dvs >= nb) { - size_t dsize = oldsize + dvs - nb; - if (dsize >= MIN_CHUNK_SIZE) { - mchunkptr r = chunk_plus_offset(p, nb); - mchunkptr n = chunk_plus_offset(r, dsize); - set_inuse(m, p, nb); - set_size_and_pinuse_of_free_chunk(r, dsize); - clear_pinuse(n); - m->dvsize = dsize; - m->dv = r; - } - else { /* exhaust dv */ - size_t newsize = oldsize + dvs; - set_inuse(m, p, newsize); - m->dvsize = 0; - m->dv = 0; - } - newp = p; - } - } - else if (!cinuse(next)) { /* extend into next free chunk */ - size_t nextsize = chunksize(next); - if (oldsize + nextsize >= nb) { - size_t rsize = oldsize + nextsize - nb; - unlink_chunk(m, next, nextsize); - if (rsize < MIN_CHUNK_SIZE) { - size_t newsize = oldsize + nextsize; - set_inuse(m, p, newsize); - } - else { - mchunkptr r = chunk_plus_offset(p, nb); - set_inuse(m, p, nb); - set_inuse(m, r, rsize); - dispose_chunk(m, r, rsize); - } - newp = p; - } - } - } - else { - USAGE_ERROR_ACTION(m, chunk2mem(p)); - } - return newp; -} - -static void* internal_memalign(mstate m, size_t alignment, size_t bytes) { - void* mem = 0; - if (alignment < MIN_CHUNK_SIZE) /* must be at least a minimum chunk size */ - alignment = MIN_CHUNK_SIZE; - if ((alignment & (alignment-SIZE_T_ONE)) != 0) {/* Ensure a power of 2 */ - size_t a = MALLOC_ALIGNMENT << 1; - while (a < alignment) a <<= 1; - alignment = a; - } - if (bytes >= MAX_REQUEST - alignment) { - if (m != 0) { /* Test isn't needed but avoids compiler warning */ - MALLOC_FAILURE_ACTION; - } - } - else { - size_t nb = request2size(bytes); - size_t req = nb + alignment + MIN_CHUNK_SIZE - CHUNK_OVERHEAD; - mem = internal_malloc(m, req); - if (mem != 0) { - mchunkptr p = mem2chunk(mem); - if (PREACTION(m)) - return 0; - if ((((size_t)(mem)) & (alignment - 1)) != 0) { /* misaligned */ - /* - Find an aligned spot inside chunk. Since we need to give - back leading space in a chunk of at least MIN_CHUNK_SIZE, if - the first calculation places us at a spot with less than - MIN_CHUNK_SIZE leader, we can move to the next aligned spot. - We've allocated enough total room so that this is always - possible. - */ - char* br = (char*)mem2chunk((size_t)(((size_t)((char*)mem + alignment - - SIZE_T_ONE)) & - -alignment)); - char* pos = ((size_t)(br - (char*)(p)) >= MIN_CHUNK_SIZE)? - br : br+alignment; - mchunkptr newp = (mchunkptr)pos; - size_t leadsize = pos - (char*)(p); - size_t newsize = chunksize(p) - leadsize; - - if (is_mmapped(p)) { /* For mmapped chunks, just adjust offset */ - newp->prev_foot = p->prev_foot + leadsize; - newp->head = newsize; - } - else { /* Otherwise, give back leader, use the rest */ - set_inuse(m, newp, newsize); - set_inuse(m, p, leadsize); - dispose_chunk(m, p, leadsize); - } - p = newp; - } - - /* Give back spare room at the end */ - if (!is_mmapped(p)) { - size_t size = chunksize(p); - if (size > nb + MIN_CHUNK_SIZE) { - size_t remainder_size = size - nb; - mchunkptr remainder = chunk_plus_offset(p, nb); - set_inuse(m, p, nb); - set_inuse(m, remainder, remainder_size); - dispose_chunk(m, remainder, remainder_size); - } - } - - mem = chunk2mem(p); - assert (chunksize(p) >= nb); - assert(((size_t)mem & (alignment - 1)) == 0); - check_inuse_chunk(m, p); - POSTACTION(m); - } - } - return mem; -} - -/* - Common support for independent_X routines, handling - all of the combinations that can result. - The opts arg has: - bit 0 set if all elements are same size (using sizes[0]) - bit 1 set if elements should be zeroed -*/ -static void** ialloc(mstate m, - size_t n_elements, - size_t* sizes, - int opts, - void* chunks[]) { - - size_t element_size; /* chunksize of each element, if all same */ - size_t contents_size; /* total size of elements */ - size_t array_size; /* request size of pointer array */ - void* mem; /* malloced aggregate space */ - mchunkptr p; /* corresponding chunk */ - size_t remainder_size; /* remaining bytes while splitting */ - void** marray; /* either "chunks" or malloced ptr array */ - mchunkptr array_chunk; /* chunk for malloced ptr array */ - flag_t was_enabled; /* to disable mmap */ - size_t size; - size_t i; - - ensure_initialization(); - /* compute array length, if needed */ - if (chunks != 0) { - if (n_elements == 0) - return chunks; /* nothing to do */ - marray = chunks; - array_size = 0; - } - else { - /* if empty req, must still return chunk representing empty array */ - if (n_elements == 0) - return (void**)internal_malloc(m, 0); - marray = 0; - array_size = request2size(n_elements * (sizeof(void*))); - } - - /* compute total element size */ - if (opts & 0x1) { /* all-same-size */ - element_size = request2size(*sizes); - contents_size = n_elements * element_size; - } - else { /* add up all the sizes */ - element_size = 0; - contents_size = 0; - for (i = 0; i != n_elements; ++i) - contents_size += request2size(sizes[i]); - } - - size = contents_size + array_size; - - /* - Allocate the aggregate chunk. First disable direct-mmapping so - malloc won't use it, since we would not be able to later - free/realloc space internal to a segregated mmap region. - */ - was_enabled = use_mmap(m); - disable_mmap(m); - mem = internal_malloc(m, size - CHUNK_OVERHEAD); - if (was_enabled) - enable_mmap(m); - if (mem == 0) - return 0; - - if (PREACTION(m)) return 0; - p = mem2chunk(mem); - remainder_size = chunksize(p); - - assert(!is_mmapped(p)); - - if (opts & 0x2) { /* optionally clear the elements */ - memset((size_t*)mem, 0, remainder_size - SIZE_T_SIZE - array_size); - } - - /* If not provided, allocate the pointer array as final part of chunk */ - if (marray == 0) { - size_t array_chunk_size; - array_chunk = chunk_plus_offset(p, contents_size); - array_chunk_size = remainder_size - contents_size; - marray = (void**) (chunk2mem(array_chunk)); - set_size_and_pinuse_of_inuse_chunk(m, array_chunk, array_chunk_size); - remainder_size = contents_size; - } - - /* split out elements */ - for (i = 0; ; ++i) { - marray[i] = chunk2mem(p); - if (i != n_elements-1) { - if (element_size != 0) - size = element_size; - else - size = request2size(sizes[i]); - remainder_size -= size; - set_size_and_pinuse_of_inuse_chunk(m, p, size); - p = chunk_plus_offset(p, size); - } - else { /* the final element absorbs any overallocation slop */ - set_size_and_pinuse_of_inuse_chunk(m, p, remainder_size); - break; - } - } - -#if DEBUG - if (marray != chunks) { - /* final element must have exactly exhausted chunk */ - if (element_size != 0) { - assert(remainder_size == element_size); - } - else { - assert(remainder_size == request2size(sizes[i])); - } - check_inuse_chunk(m, mem2chunk(marray)); - } - for (i = 0; i != n_elements; ++i) - check_inuse_chunk(m, mem2chunk(marray[i])); - -#endif /* DEBUG */ - - POSTACTION(m); - return marray; -} - -/* Try to free all pointers in the given array. - Note: this could be made faster, by delaying consolidation, - at the price of disabling some user integrity checks, We - still optimize some consolidations by combining adjacent - chunks before freeing, which will occur often if allocated - with ialloc or the array is sorted. -*/ -static size_t internal_bulk_free(mstate m, void* array[], size_t nelem) { - size_t unfreed = 0; - if (!PREACTION(m)) { - void** a; - void** fence = &(array[nelem]); - for (a = array; a != fence; ++a) { - void* mem = *a; - if (mem != 0) { - mchunkptr p = mem2chunk(mem); - size_t psize = chunksize(p); -#if FOOTERS - if (get_mstate_for(p) != m) { - ++unfreed; - continue; - } -#endif - check_inuse_chunk(m, p); - *a = 0; - if (RTCHECK(ok_address(m, p) && ok_inuse(p))) { - void ** b = a + 1; /* try to merge with next chunk */ - mchunkptr next = next_chunk(p); - if (b != fence && *b == chunk2mem(next)) { - size_t newsize = chunksize(next) + psize; - set_inuse(m, p, newsize); - *b = chunk2mem(p); - } - else - dispose_chunk(m, p, psize); - } - else { - CORRUPTION_ERROR_ACTION(m); - break; - } - } - } - if (should_trim(m, m->topsize)) - sys_trim(m, 0); - POSTACTION(m); - } - return unfreed; -} - -/* Traversal */ -#if MALLOC_INSPECT_ALL -static void internal_inspect_all(mstate m, - void(*handler)(void *start, - void *end, - size_t used_bytes, - void* callback_arg), - void* arg) { - if (is_initialized(m)) { - mchunkptr top = m->top; - msegmentptr s; - for (s = &m->seg; s != 0; s = s->next) { - mchunkptr q = align_as_chunk(s->base); - while (segment_holds(s, q) && q->head != FENCEPOST_HEAD) { - mchunkptr next = next_chunk(q); - size_t sz = chunksize(q); - size_t used; - void* start; - if (is_inuse(q)) { - used = sz - CHUNK_OVERHEAD; /* must not be mmapped */ - start = chunk2mem(q); - } - else { - used = 0; - if (is_small(sz)) { /* offset by possible bookkeeping */ - start = (void*)((char*)q + sizeof(struct malloc_chunk)); - } - else { - start = (void*)((char*)q + sizeof(struct malloc_tree_chunk)); - } - } - if (start < (void*)next) /* skip if all space is bookkeeping */ - handler(start, next, used, arg); - if (q == top) - break; - q = next; - } - } - } -} -#endif /* MALLOC_INSPECT_ALL */ - -/* ------------------ Exported realloc, memalign, etc -------------------- */ - -#if !ONLY_MSPACES - -void* dlrealloc(void* oldmem, size_t bytes) { - void* mem = 0; - if (oldmem == 0) { - mem = dlmalloc(bytes); - } - else if (bytes >= MAX_REQUEST) { - MALLOC_FAILURE_ACTION; - } -#ifdef REALLOC_ZERO_BYTES_FREES - else if (bytes == 0) { - dlfree(oldmem); - } -#endif /* REALLOC_ZERO_BYTES_FREES */ - else { - size_t nb = request2size(bytes); - mchunkptr oldp = mem2chunk(oldmem); -#if ! FOOTERS - mstate m = gm; -#else /* FOOTERS */ - mstate m = get_mstate_for(oldp); - if (!ok_magic(m)) { - USAGE_ERROR_ACTION(m, oldmem); - return 0; - } -#endif /* FOOTERS */ - if (!PREACTION(m)) { - mchunkptr newp = try_realloc_chunk(m, oldp, nb, 1); - POSTACTION(m); - if (newp != 0) { - check_inuse_chunk(m, newp); - mem = chunk2mem(newp); - } - else { - mem = internal_malloc(m, bytes); - if (mem != 0) { - size_t oc = chunksize(oldp) - overhead_for(oldp); - memcpy(mem, oldmem, (oc < bytes)? oc : bytes); - internal_free(m, oldmem); - } - } - } - } - return mem; -} - -void* dlrealloc_in_place(void* oldmem, size_t bytes) { - void* mem = 0; - if (oldmem != 0) { - if (bytes >= MAX_REQUEST) { - MALLOC_FAILURE_ACTION; - } - else { - size_t nb = request2size(bytes); - mchunkptr oldp = mem2chunk(oldmem); -#if ! FOOTERS - mstate m = gm; -#else /* FOOTERS */ - mstate m = get_mstate_for(oldp); - if (!ok_magic(m)) { - USAGE_ERROR_ACTION(m, oldmem); - return 0; - } -#endif /* FOOTERS */ - if (!PREACTION(m)) { - mchunkptr newp = try_realloc_chunk(m, oldp, nb, 0); - POSTACTION(m); - if (newp == oldp) { - check_inuse_chunk(m, newp); - mem = oldmem; - } - } - } - } - return mem; -} - -void* dlmemalign(size_t alignment, size_t bytes) { - if (alignment <= MALLOC_ALIGNMENT) { - return dlmalloc(bytes); - } - return internal_memalign(gm, alignment, bytes); -} - -int dlposix_memalign(void** pp, size_t alignment, size_t bytes) { - void* mem = 0; - if (alignment == MALLOC_ALIGNMENT) - mem = dlmalloc(bytes); - else { - size_t d = alignment / sizeof(void*); - size_t r = alignment % sizeof(void*); - if (r != 0 || d == 0 || (d & (d-SIZE_T_ONE)) != 0) - return EINVAL; - else if (bytes <= MAX_REQUEST - alignment) { - if (alignment < MIN_CHUNK_SIZE) - alignment = MIN_CHUNK_SIZE; - mem = internal_memalign(gm, alignment, bytes); - } - } - if (mem == 0) - return ENOMEM; - else { - *pp = mem; - return 0; - } -} - -void* dlvalloc(size_t bytes) { - size_t pagesz; - ensure_initialization(); - pagesz = mparams.page_size; - return dlmemalign(pagesz, bytes); -} - -void* dlpvalloc(size_t bytes) { - size_t pagesz; - ensure_initialization(); - pagesz = mparams.page_size; - return dlmemalign(pagesz, (bytes + pagesz - SIZE_T_ONE) & ~(pagesz - SIZE_T_ONE)); -} - -void** dlindependent_calloc(size_t n_elements, size_t elem_size, - void* chunks[]) { - size_t sz = elem_size; /* serves as 1-element array */ - return ialloc(gm, n_elements, &sz, 3, chunks); -} - -void** dlindependent_comalloc(size_t n_elements, size_t sizes[], - void* chunks[]) { - return ialloc(gm, n_elements, sizes, 0, chunks); -} - -size_t dlbulk_free(void* array[], size_t nelem) { - return internal_bulk_free(gm, array, nelem); -} - -#if MALLOC_INSPECT_ALL -void dlmalloc_inspect_all(void(*handler)(void *start, - void *end, - size_t used_bytes, - void* callback_arg), - void* arg) { - ensure_initialization(); - if (!PREACTION(gm)) { - internal_inspect_all(gm, handler, arg); - POSTACTION(gm); - } -} -#endif /* MALLOC_INSPECT_ALL */ - -int dlmalloc_trim(size_t pad) { - int result = 0; - ensure_initialization(); - if (!PREACTION(gm)) { - result = sys_trim(gm, pad); - POSTACTION(gm); - } - return result; -} - -size_t dlmalloc_footprint(void) { - return gm->footprint; -} - -size_t dlmalloc_max_footprint(void) { - return gm->max_footprint; -} - -size_t dlmalloc_footprint_limit(void) { - size_t maf = gm->footprint_limit; - return maf == 0 ? MAX_SIZE_T : maf; -} - -size_t dlmalloc_set_footprint_limit(size_t bytes) { - size_t result; /* invert sense of 0 */ - if (bytes == 0) - result = granularity_align(1); /* Use minimal size */ - if (bytes == MAX_SIZE_T) - result = 0; /* disable */ - else - result = granularity_align(bytes); - return gm->footprint_limit = result; -} - -#if !NO_MALLINFO -struct mallinfo dlmallinfo(void) { - return internal_mallinfo(gm); -} -#endif /* NO_MALLINFO */ - -#if !NO_MALLOC_STATS -void dlmalloc_stats() { - internal_malloc_stats(gm); -} -#endif /* NO_MALLOC_STATS */ - -int dlmallopt(int param_number, int value) { - return change_mparam(param_number, value); -} - -size_t dlmalloc_usable_size(void* mem) { - if (mem != 0) { - mchunkptr p = mem2chunk(mem); - if (is_inuse(p)) - return chunksize(p) - overhead_for(p); - } - return 0; -} - -#endif /* !ONLY_MSPACES */ - -/* ----------------------------- user mspaces ---------------------------- */ - -#if MSPACES - -static mstate init_user_mstate(char* tbase, size_t tsize) { - size_t msize = pad_request(sizeof(struct malloc_state)); - mchunkptr mn; - mchunkptr msp = align_as_chunk(tbase); - mstate m = (mstate)(chunk2mem(msp)); - memset(m, 0, msize); - (void)INITIAL_LOCK(&m->mutex); - msp->head = (msize|INUSE_BITS); - m->seg.base = m->least_addr = tbase; - m->seg.size = m->footprint = m->max_footprint = tsize; - m->magic = mparams.magic; - m->release_checks = MAX_RELEASE_CHECK_RATE; - m->mflags = mparams.default_mflags; - m->extp = 0; - m->exts = 0; - disable_contiguous(m); - init_bins(m); - mn = next_chunk(mem2chunk(m)); - init_top(m, mn, (size_t)((tbase + tsize) - (char*)mn) - TOP_FOOT_SIZE); - check_top_chunk(m, m->top); - return m; -} - -mspace create_mspace(size_t capacity, int locked) { - mstate m = 0; - size_t msize; - ensure_initialization(); - msize = pad_request(sizeof(struct malloc_state)); - if (capacity < (size_t) -(msize + TOP_FOOT_SIZE + mparams.page_size)) { - size_t rs = ((capacity == 0)? mparams.granularity : - (capacity + TOP_FOOT_SIZE + msize)); - size_t tsize = granularity_align(rs); - char* tbase = (char*)(CALL_MMAP(tsize)); - if (tbase != CMFAIL) { - m = init_user_mstate(tbase, tsize); - m->seg.sflags = USE_MMAP_BIT; - set_lock(m, locked); - } - } - return (mspace)m; -} - -mspace create_mspace_with_base(void* base, size_t capacity, int locked) { - mstate m = 0; - size_t msize; - ensure_initialization(); - msize = pad_request(sizeof(struct malloc_state)); - if (capacity > msize + TOP_FOOT_SIZE && - capacity < (size_t) -(msize + TOP_FOOT_SIZE + mparams.page_size)) { - m = init_user_mstate((char*)base, capacity); - m->seg.sflags = EXTERN_BIT; - set_lock(m, locked); - } - return (mspace)m; -} - -int mspace_track_large_chunks(mspace msp, int enable) { - int ret = 0; - mstate ms = (mstate)msp; - if (!PREACTION(ms)) { - if (!use_mmap(ms)) { - ret = 1; - } - if (!enable) { - enable_mmap(ms); - } else { - disable_mmap(ms); - } - POSTACTION(ms); - } - return ret; -} - -size_t destroy_mspace(mspace msp) { - size_t freed = 0; - mstate ms = (mstate)msp; - if (ok_magic(ms)) { - msegmentptr sp = &ms->seg; - (void)DESTROY_LOCK(&ms->mutex); /* destroy before unmapped */ - while (sp != 0) { - char* base = sp->base; - size_t size = sp->size; - flag_t flag = sp->sflags; - (void)base; /* placate people compiling -Wunused-variable */ - sp = sp->next; - if ((flag & USE_MMAP_BIT) && !(flag & EXTERN_BIT) && - CALL_MUNMAP(base, size) == 0) - freed += size; - } - } - else { - USAGE_ERROR_ACTION(ms,ms); - } - return freed; -} - -/* - mspace versions of routines are near-clones of the global - versions. This is not so nice but better than the alternatives. -*/ - -void* mspace_malloc(mspace msp, size_t bytes) { - mstate ms = (mstate)msp; - if (!ok_magic(ms)) { - USAGE_ERROR_ACTION(ms,ms); - return 0; - } - if (!PREACTION(ms)) { - void* mem; - size_t nb; - if (bytes <= MAX_SMALL_REQUEST) { - bindex_t idx; - binmap_t smallbits; - nb = (bytes < MIN_REQUEST)? MIN_CHUNK_SIZE : pad_request(bytes); - idx = small_index(nb); - smallbits = ms->smallmap >> idx; - - if ((smallbits & 0x3U) != 0) { /* Remainderless fit to a smallbin. */ - mchunkptr b, p; - idx += ~smallbits & 1; /* Uses next bin if idx empty */ - b = smallbin_at(ms, idx); - p = b->fd; - assert(chunksize(p) == small_index2size(idx)); - unlink_first_small_chunk(ms, b, p, idx); - set_inuse_and_pinuse(ms, p, small_index2size(idx)); - mem = chunk2mem(p); - check_malloced_chunk(ms, mem, nb); - goto postaction; - } - - else if (nb > ms->dvsize) { - if (smallbits != 0) { /* Use chunk in next nonempty smallbin */ - mchunkptr b, p, r; - size_t rsize; - bindex_t i; - binmap_t leftbits = (smallbits << idx) & left_bits(idx2bit(idx)); - binmap_t leastbit = least_bit(leftbits); - compute_bit2idx(leastbit, i); - b = smallbin_at(ms, i); - p = b->fd; - assert(chunksize(p) == small_index2size(i)); - unlink_first_small_chunk(ms, b, p, i); - rsize = small_index2size(i) - nb; - /* Fit here cannot be remainderless if 4byte sizes */ - if (SIZE_T_SIZE != 4 && rsize < MIN_CHUNK_SIZE) - set_inuse_and_pinuse(ms, p, small_index2size(i)); - else { - set_size_and_pinuse_of_inuse_chunk(ms, p, nb); - r = chunk_plus_offset(p, nb); - set_size_and_pinuse_of_free_chunk(r, rsize); - replace_dv(ms, r, rsize); - } - mem = chunk2mem(p); - check_malloced_chunk(ms, mem, nb); - goto postaction; - } - - else if (ms->treemap != 0 && (mem = tmalloc_small(ms, nb)) != 0) { - check_malloced_chunk(ms, mem, nb); - goto postaction; - } - } - } - else if (bytes >= MAX_REQUEST) - nb = MAX_SIZE_T; /* Too big to allocate. Force failure (in sys alloc) */ - else { - nb = pad_request(bytes); - if (ms->treemap != 0 && (mem = tmalloc_large(ms, nb)) != 0) { - check_malloced_chunk(ms, mem, nb); - goto postaction; - } - } - - if (nb <= ms->dvsize) { - size_t rsize = ms->dvsize - nb; - mchunkptr p = ms->dv; - if (rsize >= MIN_CHUNK_SIZE) { /* split dv */ - mchunkptr r = ms->dv = chunk_plus_offset(p, nb); - ms->dvsize = rsize; - set_size_and_pinuse_of_free_chunk(r, rsize); - set_size_and_pinuse_of_inuse_chunk(ms, p, nb); - } - else { /* exhaust dv */ - size_t dvs = ms->dvsize; - ms->dvsize = 0; - ms->dv = 0; - set_inuse_and_pinuse(ms, p, dvs); - } - mem = chunk2mem(p); - check_malloced_chunk(ms, mem, nb); - goto postaction; - } - - else if (nb < ms->topsize) { /* Split top */ - size_t rsize = ms->topsize -= nb; - mchunkptr p = ms->top; - mchunkptr r = ms->top = chunk_plus_offset(p, nb); - r->head = rsize | PINUSE_BIT; - set_size_and_pinuse_of_inuse_chunk(ms, p, nb); - mem = chunk2mem(p); - check_top_chunk(ms, ms->top); - check_malloced_chunk(ms, mem, nb); - goto postaction; - } - - mem = sys_alloc(ms, nb); - - postaction: - POSTACTION(ms); - return mem; - } - - return 0; -} - -void mspace_free(mspace msp, void* mem) { - if (mem != 0) { - mchunkptr p = mem2chunk(mem); -#if FOOTERS - mstate fm = get_mstate_for(p); - (void)msp; /* placate people compiling -Wunused */ -#else /* FOOTERS */ - mstate fm = (mstate)msp; -#endif /* FOOTERS */ - if (!ok_magic(fm)) { - USAGE_ERROR_ACTION(fm, p); - return; - } - if (!PREACTION(fm)) { - check_inuse_chunk(fm, p); - if (RTCHECK(ok_address(fm, p) && ok_inuse(p))) { - size_t psize = chunksize(p); - mchunkptr next = chunk_plus_offset(p, psize); - if (!pinuse(p)) { - size_t prevsize = p->prev_foot; - if (is_mmapped(p)) { - psize += prevsize + MMAP_FOOT_PAD; - if (CALL_MUNMAP((char*)p - prevsize, psize) == 0) - fm->footprint -= psize; - goto postaction; - } - else { - mchunkptr prev = chunk_minus_offset(p, prevsize); - psize += prevsize; - p = prev; - if (RTCHECK(ok_address(fm, prev))) { /* consolidate backward */ - if (p != fm->dv) { - unlink_chunk(fm, p, prevsize); - } - else if ((next->head & INUSE_BITS) == INUSE_BITS) { - fm->dvsize = psize; - set_free_with_pinuse(p, psize, next); - goto postaction; - } - } - else - goto erroraction; - } - } - - if (RTCHECK(ok_next(p, next) && ok_pinuse(next))) { - if (!cinuse(next)) { /* consolidate forward */ - if (next == fm->top) { - size_t tsize = fm->topsize += psize; - fm->top = p; - p->head = tsize | PINUSE_BIT; - if (p == fm->dv) { - fm->dv = 0; - fm->dvsize = 0; - } - if (should_trim(fm, tsize)) - sys_trim(fm, 0); - goto postaction; - } - else if (next == fm->dv) { - size_t dsize = fm->dvsize += psize; - fm->dv = p; - set_size_and_pinuse_of_free_chunk(p, dsize); - goto postaction; - } - else { - size_t nsize = chunksize(next); - psize += nsize; - unlink_chunk(fm, next, nsize); - set_size_and_pinuse_of_free_chunk(p, psize); - if (p == fm->dv) { - fm->dvsize = psize; - goto postaction; - } - } - } - else - set_free_with_pinuse(p, psize, next); - - if (is_small(psize)) { - insert_small_chunk(fm, p, psize); - check_free_chunk(fm, p); - } - else { - tchunkptr tp = (tchunkptr)p; - insert_large_chunk(fm, tp, psize); - check_free_chunk(fm, p); - if (--fm->release_checks == 0) - release_unused_segments(fm); - } - goto postaction; - } - } - erroraction: - USAGE_ERROR_ACTION(fm, p); - postaction: - POSTACTION(fm); - } - } -} - -void* mspace_calloc(mspace msp, size_t n_elements, size_t elem_size) { - void* mem; - size_t req = 0; - mstate ms = (mstate)msp; - if (!ok_magic(ms)) { - USAGE_ERROR_ACTION(ms,ms); - return 0; - } - if (n_elements != 0) { - req = n_elements * elem_size; - if (((n_elements | elem_size) & ~(size_t)0xffff) && - (req / n_elements != elem_size)) - req = MAX_SIZE_T; /* force downstream failure on overflow */ - } - mem = internal_malloc(ms, req); - if (mem != 0 && calloc_must_clear(mem2chunk(mem))) - memset(mem, 0, req); - return mem; -} - -void* mspace_realloc(mspace msp, void* oldmem, size_t bytes) { - void* mem = 0; - if (oldmem == 0) { - mem = mspace_malloc(msp, bytes); - } - else if (bytes >= MAX_REQUEST) { - MALLOC_FAILURE_ACTION; - } -#ifdef REALLOC_ZERO_BYTES_FREES - else if (bytes == 0) { - mspace_free(msp, oldmem); - } -#endif /* REALLOC_ZERO_BYTES_FREES */ - else { - size_t nb = request2size(bytes); - mchunkptr oldp = mem2chunk(oldmem); -#if ! FOOTERS - mstate m = (mstate)msp; -#else /* FOOTERS */ - mstate m = get_mstate_for(oldp); - if (!ok_magic(m)) { - USAGE_ERROR_ACTION(m, oldmem); - return 0; - } -#endif /* FOOTERS */ - if (!PREACTION(m)) { - mchunkptr newp = try_realloc_chunk(m, oldp, nb, 1); - POSTACTION(m); - if (newp != 0) { - check_inuse_chunk(m, newp); - mem = chunk2mem(newp); - } - else { - mem = mspace_malloc(m, bytes); - if (mem != 0) { - size_t oc = chunksize(oldp) - overhead_for(oldp); - memcpy(mem, oldmem, (oc < bytes)? oc : bytes); - mspace_free(m, oldmem); - } - } - } - } - return mem; -} - -void* mspace_realloc_in_place(mspace msp, void* oldmem, size_t bytes) { - void* mem = 0; - if (oldmem != 0) { - if (bytes >= MAX_REQUEST) { - MALLOC_FAILURE_ACTION; - } - else { - size_t nb = request2size(bytes); - mchunkptr oldp = mem2chunk(oldmem); -#if ! FOOTERS - mstate m = (mstate)msp; -#else /* FOOTERS */ - mstate m = get_mstate_for(oldp); - (void)msp; /* placate people compiling -Wunused */ - if (!ok_magic(m)) { - USAGE_ERROR_ACTION(m, oldmem); - return 0; - } -#endif /* FOOTERS */ - if (!PREACTION(m)) { - mchunkptr newp = try_realloc_chunk(m, oldp, nb, 0); - POSTACTION(m); - if (newp == oldp) { - check_inuse_chunk(m, newp); - mem = oldmem; - } - } - } - } - return mem; -} - -void* mspace_memalign(mspace msp, size_t alignment, size_t bytes) { - mstate ms = (mstate)msp; - if (!ok_magic(ms)) { - USAGE_ERROR_ACTION(ms,ms); - return 0; - } - if (alignment <= MALLOC_ALIGNMENT) - return mspace_malloc(msp, bytes); - return internal_memalign(ms, alignment, bytes); -} - -void** mspace_independent_calloc(mspace msp, size_t n_elements, - size_t elem_size, void* chunks[]) { - size_t sz = elem_size; /* serves as 1-element array */ - mstate ms = (mstate)msp; - if (!ok_magic(ms)) { - USAGE_ERROR_ACTION(ms,ms); - return 0; - } - return ialloc(ms, n_elements, &sz, 3, chunks); -} - -void** mspace_independent_comalloc(mspace msp, size_t n_elements, - size_t sizes[], void* chunks[]) { - mstate ms = (mstate)msp; - if (!ok_magic(ms)) { - USAGE_ERROR_ACTION(ms,ms); - return 0; - } - return ialloc(ms, n_elements, sizes, 0, chunks); -} - -size_t mspace_bulk_free(mspace msp, void* array[], size_t nelem) { - return internal_bulk_free((mstate)msp, array, nelem); -} - -#if MALLOC_INSPECT_ALL -void mspace_inspect_all(mspace msp, - void(*handler)(void *start, - void *end, - size_t used_bytes, - void* callback_arg), - void* arg) { - mstate ms = (mstate)msp; - if (ok_magic(ms)) { - if (!PREACTION(ms)) { - internal_inspect_all(ms, handler, arg); - POSTACTION(ms); - } - } - else { - USAGE_ERROR_ACTION(ms,ms); - } -} -#endif /* MALLOC_INSPECT_ALL */ - -int mspace_trim(mspace msp, size_t pad) { - int result = 0; - mstate ms = (mstate)msp; - if (ok_magic(ms)) { - if (!PREACTION(ms)) { - result = sys_trim(ms, pad); - POSTACTION(ms); - } - } - else { - USAGE_ERROR_ACTION(ms,ms); - } - return result; -} - -#if !NO_MALLOC_STATS -void mspace_malloc_stats(mspace msp) { - mstate ms = (mstate)msp; - if (ok_magic(ms)) { - internal_malloc_stats(ms); - } - else { - USAGE_ERROR_ACTION(ms,ms); - } -} -#endif /* NO_MALLOC_STATS */ - -size_t mspace_footprint(mspace msp) { - size_t result = 0; - mstate ms = (mstate)msp; - if (ok_magic(ms)) { - result = ms->footprint; - } - else { - USAGE_ERROR_ACTION(ms,ms); - } - return result; -} - -size_t mspace_max_footprint(mspace msp) { - size_t result = 0; - mstate ms = (mstate)msp; - if (ok_magic(ms)) { - result = ms->max_footprint; - } - else { - USAGE_ERROR_ACTION(ms,ms); - } - return result; -} - -size_t mspace_footprint_limit(mspace msp) { - size_t result = 0; - mstate ms = (mstate)msp; - if (ok_magic(ms)) { - size_t maf = ms->footprint_limit; - result = (maf == 0) ? MAX_SIZE_T : maf; - } - else { - USAGE_ERROR_ACTION(ms,ms); - } - return result; -} - -size_t mspace_set_footprint_limit(mspace msp, size_t bytes) { - size_t result = 0; - mstate ms = (mstate)msp; - if (ok_magic(ms)) { - if (bytes == 0) - result = granularity_align(1); /* Use minimal size */ - if (bytes == MAX_SIZE_T) - result = 0; /* disable */ - else - result = granularity_align(bytes); - ms->footprint_limit = result; - } - else { - USAGE_ERROR_ACTION(ms,ms); - } - return result; -} - -#if !NO_MALLINFO -struct mallinfo mspace_mallinfo(mspace msp) { - mstate ms = (mstate)msp; - if (!ok_magic(ms)) { - USAGE_ERROR_ACTION(ms,ms); - } - return internal_mallinfo(ms); -} -#endif /* NO_MALLINFO */ - -size_t mspace_usable_size(const void* mem) { - if (mem != 0) { - mchunkptr p = mem2chunk(mem); - if (is_inuse(p)) - return chunksize(p) - overhead_for(p); - } - return 0; -} - -int mspace_mallopt(int param_number, int value) { - return change_mparam(param_number, value); -} - -#endif /* MSPACES */ - - -/* -------------------- Alternative MORECORE functions ------------------- */ - -/* - Guidelines for creating a custom version of MORECORE: - - * For best performance, MORECORE should allocate in multiples of pagesize. - * MORECORE may allocate more memory than requested. (Or even less, - but this will usually result in a malloc failure.) - * MORECORE must not allocate memory when given argument zero, but - instead return one past the end address of memory from previous - nonzero call. - * For best performance, consecutive calls to MORECORE with positive - arguments should return increasing addresses, indicating that - space has been contiguously extended. - * Even though consecutive calls to MORECORE need not return contiguous - addresses, it must be OK for malloc'ed chunks to span multiple - regions in those cases where they do happen to be contiguous. - * MORECORE need not handle negative arguments -- it may instead - just return MFAIL when given negative arguments. - Negative arguments are always multiples of pagesize. MORECORE - must not misinterpret negative args as large positive unsigned - args. You can suppress all such calls from even occurring by defining - MORECORE_CANNOT_TRIM, - - As an example alternative MORECORE, here is a custom allocator - kindly contributed for pre-OSX macOS. It uses virtually but not - necessarily physically contiguous non-paged memory (locked in, - present and won't get swapped out). You can use it by uncommenting - this section, adding some #includes, and setting up the appropriate - defines above: - - #define MORECORE osMoreCore - - There is also a shutdown routine that should somehow be called for - cleanup upon program exit. - - #define MAX_POOL_ENTRIES 100 - #define MINIMUM_MORECORE_SIZE (64 * 1024U) - static int next_os_pool; - void *our_os_pools[MAX_POOL_ENTRIES]; - - void *osMoreCore(int size) - { - void *ptr = 0; - static void *sbrk_top = 0; - - if (size > 0) - { - if (size < MINIMUM_MORECORE_SIZE) - size = MINIMUM_MORECORE_SIZE; - if (CurrentExecutionLevel() == kTaskLevel) - ptr = PoolAllocateResident(size + RM_PAGE_SIZE, 0); - if (ptr == 0) - { - return (void *) MFAIL; - } - // save ptrs so they can be freed during cleanup - our_os_pools[next_os_pool] = ptr; - next_os_pool++; - ptr = (void *) ((((size_t) ptr) + RM_PAGE_MASK) & ~RM_PAGE_MASK); - sbrk_top = (char *) ptr + size; - return ptr; - } - else if (size < 0) - { - // we don't currently support shrink behavior - return (void *) MFAIL; - } - else - { - return sbrk_top; - } - } - - // cleanup any allocated memory pools - // called as last thing before shutting down driver - - void osCleanupMem(void) - { - void **ptr; - - for (ptr = our_os_pools; ptr < &our_os_pools[MAX_POOL_ENTRIES]; ptr++) - if (*ptr) - { - PoolDeallocate(*ptr); - *ptr = 0; - } - } - -*/ - - -/* ----------------------------------------------------------------------- -History: - v2.8.6 Wed Aug 29 06:57:58 2012 Doug Lea - * fix bad comparison in dlposix_memalign - * don't reuse adjusted asize in sys_alloc - * add LOCK_AT_FORK -- thanks to Kirill Artamonov for the suggestion - * reduce compiler warnings -- thanks to all who reported/suggested these - - v2.8.5 Sun May 22 10:26:02 2011 Doug Lea (dl at gee) - * Always perform unlink checks unless INSECURE - * Add posix_memalign. - * Improve realloc to expand in more cases; expose realloc_in_place. - Thanks to Peter Buhr for the suggestion. - * Add footprint_limit, inspect_all, bulk_free. Thanks - to Barry Hayes and others for the suggestions. - * Internal refactorings to avoid calls while holding locks - * Use non-reentrant locks by default. Thanks to Roland McGrath - for the suggestion. - * Small fixes to mspace_destroy, reset_on_error. - * Various configuration extensions/changes. Thanks - to all who contributed these. - - V2.8.4a Thu Apr 28 14:39:43 2011 (dl at gee.cs.oswego.edu) - * Update Creative Commons URL - - V2.8.4 Wed May 27 09:56:23 2009 Doug Lea (dl at gee) - * Use zeros instead of prev foot for is_mmapped - * Add mspace_track_large_chunks; thanks to Jean Brouwers - * Fix set_inuse in internal_realloc; thanks to Jean Brouwers - * Fix insufficient sys_alloc padding when using 16byte alignment - * Fix bad error check in mspace_footprint - * Adaptations for ptmalloc; thanks to Wolfram Gloger. - * Reentrant spin locks; thanks to Earl Chew and others - * Win32 improvements; thanks to Niall Douglas and Earl Chew - * Add NO_SEGMENT_TRAVERSAL and MAX_RELEASE_CHECK_RATE options - * Extension hook in malloc_state - * Various small adjustments to reduce warnings on some compilers - * Various configuration extensions/changes for more platforms. Thanks - to all who contributed these. - - V2.8.3 Thu Sep 22 11:16:32 2005 Doug Lea (dl at gee) - * Add max_footprint functions - * Ensure all appropriate literals are size_t - * Fix conditional compilation problem for some #define settings - * Avoid concatenating segments with the one provided - in create_mspace_with_base - * Rename some variables to avoid compiler shadowing warnings - * Use explicit lock initialization. - * Better handling of sbrk interference. - * Simplify and fix segment insertion, trimming and mspace_destroy - * Reinstate REALLOC_ZERO_BYTES_FREES option from 2.7.x - * Thanks especially to Dennis Flanagan for help on these. - - V2.8.2 Sun Jun 12 16:01:10 2005 Doug Lea (dl at gee) - * Fix memalign brace error. - - V2.8.1 Wed Jun 8 16:11:46 2005 Doug Lea (dl at gee) - * Fix improper #endif nesting in C++ - * Add explicit casts needed for C++ - - V2.8.0 Mon May 30 14:09:02 2005 Doug Lea (dl at gee) - * Use trees for large bins - * Support mspaces - * Use segments to unify sbrk-based and mmap-based system allocation, - removing need for emulation on most platforms without sbrk. - * Default safety checks - * Optional footer checks. Thanks to William Robertson for the idea. - * Internal code refactoring - * Incorporate suggestions and platform-specific changes. - Thanks to Dennis Flanagan, Colin Plumb, Niall Douglas, - Aaron Bachmann, Emery Berger, and others. - * Speed up non-fastbin processing enough to remove fastbins. - * Remove useless cfree() to avoid conflicts with other apps. - * Remove internal memcpy, memset. Compilers handle builtins better. - * Remove some options that no one ever used and rename others. - - V2.7.2 Sat Aug 17 09:07:30 2002 Doug Lea (dl at gee) - * Fix malloc_state bitmap array misdeclaration - - V2.7.1 Thu Jul 25 10:58:03 2002 Doug Lea (dl at gee) - * Allow tuning of FIRST_SORTED_BIN_SIZE - * Use PTR_UINT as type for all ptr->int casts. Thanks to John Belmonte. - * Better detection and support for non-contiguousness of MORECORE. - Thanks to Andreas Mueller, Conal Walsh, and Wolfram Gloger - * Bypass most of malloc if no frees. Thanks To Emery Berger. - * Fix freeing of old top non-contiguous chunk im sysmalloc. - * Raised default trim and map thresholds to 256K. - * Fix mmap-related #defines. Thanks to Lubos Lunak. - * Fix copy macros; added LACKS_FCNTL_H. Thanks to Neal Walfield. - * Branch-free bin calculation - * Default trim and mmap thresholds now 256K. - - V2.7.0 Sun Mar 11 14:14:06 2001 Doug Lea (dl at gee) - * Introduce independent_comalloc and independent_calloc. - Thanks to Michael Pachos for motivation and help. - * Make optional .h file available - * Allow > 2GB requests on 32bit systems. - * new WIN32 sbrk, mmap, munmap, lock code from . - Thanks also to Andreas Mueller , - and Anonymous. - * Allow override of MALLOC_ALIGNMENT (Thanks to Ruud Waij for - helping test this.) - * memalign: check alignment arg - * realloc: don't try to shift chunks backwards, since this - leads to more fragmentation in some programs and doesn't - seem to help in any others. - * Collect all cases in malloc requiring system memory into sysmalloc - * Use mmap as backup to sbrk - * Place all internal state in malloc_state - * Introduce fastbins (although similar to 2.5.1) - * Many minor tunings and cosmetic improvements - * Introduce USE_PUBLIC_MALLOC_WRAPPERS, USE_MALLOC_LOCK - * Introduce MALLOC_FAILURE_ACTION, MORECORE_CONTIGUOUS - Thanks to Tony E. Bennett and others. - * Include errno.h to support default failure action. - - V2.6.6 Sun Dec 5 07:42:19 1999 Doug Lea (dl at gee) - * return null for negative arguments - * Added Several WIN32 cleanups from Martin C. Fong - * Add 'LACKS_SYS_PARAM_H' for those systems without 'sys/param.h' - (e.g. WIN32 platforms) - * Cleanup header file inclusion for WIN32 platforms - * Cleanup code to avoid Microsoft Visual C++ compiler complaints - * Add 'USE_DL_PREFIX' to quickly allow co-existence with existing - memory allocation routines - * Set 'malloc_getpagesize' for WIN32 platforms (needs more work) - * Use 'assert' rather than 'ASSERT' in WIN32 code to conform to - usage of 'assert' in non-WIN32 code - * Improve WIN32 'sbrk()' emulation's 'findRegion()' routine to - avoid infinite loop - * Always call 'fREe()' rather than 'free()' - - V2.6.5 Wed Jun 17 15:57:31 1998 Doug Lea (dl at gee) - * Fixed ordering problem with boundary-stamping - - V2.6.3 Sun May 19 08:17:58 1996 Doug Lea (dl at gee) - * Added pvalloc, as recommended by H.J. Liu - * Added 64bit pointer support mainly from Wolfram Gloger - * Added anonymously donated WIN32 sbrk emulation - * Malloc, calloc, getpagesize: add optimizations from Raymond Nijssen - * malloc_extend_top: fix mask error that caused wastage after - foreign sbrks - * Add linux mremap support code from HJ Liu - - V2.6.2 Tue Dec 5 06:52:55 1995 Doug Lea (dl at gee) - * Integrated most documentation with the code. - * Add support for mmap, with help from - Wolfram Gloger (Gloger@lrz.uni-muenchen.de). - * Use last_remainder in more cases. - * Pack bins using idea from colin@nyx10.cs.du.edu - * Use ordered bins instead of best-fit threshhold - * Eliminate block-local decls to simplify tracing and debugging. - * Support another case of realloc via move into top - * Fix error occuring when initial sbrk_base not word-aligned. - * Rely on page size for units instead of SBRK_UNIT to - avoid surprises about sbrk alignment conventions. - * Add mallinfo, mallopt. Thanks to Raymond Nijssen - (raymond@es.ele.tue.nl) for the suggestion. - * Add `pad' argument to malloc_trim and top_pad mallopt parameter. - * More precautions for cases where other routines call sbrk, - courtesy of Wolfram Gloger (Gloger@lrz.uni-muenchen.de). - * Added macros etc., allowing use in linux libc from - H.J. Lu (hjl@gnu.ai.mit.edu) - * Inverted this history list - - V2.6.1 Sat Dec 2 14:10:57 1995 Doug Lea (dl at gee) - * Re-tuned and fixed to behave more nicely with V2.6.0 changes. - * Removed all preallocation code since under current scheme - the work required to undo bad preallocations exceeds - the work saved in good cases for most test programs. - * No longer use return list or unconsolidated bins since - no scheme using them consistently outperforms those that don't - given above changes. - * Use best fit for very large chunks to prevent some worst-cases. - * Added some support for debugging - - V2.6.0 Sat Nov 4 07:05:23 1995 Doug Lea (dl at gee) - * Removed footers when chunks are in use. Thanks to - Paul Wilson (wilson@cs.texas.edu) for the suggestion. - - V2.5.4 Wed Nov 1 07:54:51 1995 Doug Lea (dl at gee) - * Added malloc_trim, with help from Wolfram Gloger - (wmglo@Dent.MED.Uni-Muenchen.DE). - - V2.5.3 Tue Apr 26 10:16:01 1994 Doug Lea (dl at g) - - V2.5.2 Tue Apr 5 16:20:40 1994 Doug Lea (dl at g) - * realloc: try to expand in both directions - * malloc: swap order of clean-bin strategy; - * realloc: only conditionally expand backwards - * Try not to scavenge used bins - * Use bin counts as a guide to preallocation - * Occasionally bin return list chunks in first scan - * Add a few optimizations from colin@nyx10.cs.du.edu - - V2.5.1 Sat Aug 14 15:40:43 1993 Doug Lea (dl at g) - * faster bin computation & slightly different binning - * merged all consolidations to one part of malloc proper - (eliminating old malloc_find_space & malloc_clean_bin) - * Scan 2 returns chunks (not just 1) - * Propagate failure in realloc if malloc returns 0 - * Add stuff to allow compilation on non-ANSI compilers - from kpv@research.att.com - - V2.5 Sat Aug 7 07:41:59 1993 Doug Lea (dl at g.oswego.edu) - * removed potential for odd address access in prev_chunk - * removed dependency on getpagesize.h - * misc cosmetics and a bit more internal documentation - * anticosmetics: mangled names in macros to evade debugger strangeness - * tested on sparc, hp-700, dec-mips, rs6000 - with gcc & native cc (hp, dec only) allowing - Detlefs & Zorn comparison study (in SIGPLAN Notices.) - - Trial version Fri Aug 28 13:14:29 1992 Doug Lea (dl at g.oswego.edu) - * Based loosely on libg++-1.2X malloc. (It retains some of the overall - structure of old version, but most details differ.) - -*/ - -#endif // KONAN_INTERNAL_MALLOC diff --git a/kotlin-native/runtime/src/main/cpp/dtoa/dblparse.cpp b/kotlin-native/runtime/src/main/cpp/dtoa/dblparse.cpp index 22716833c43..8125152231c 100644 --- a/kotlin-native/runtime/src/main/cpp/dtoa/dblparse.cpp +++ b/kotlin-native/runtime/src/main/cpp/dtoa/dblparse.cpp @@ -25,8 +25,6 @@ #include "../Natives.h" #include "../Porting.h" #include "../utf8.h" -#include "../KotlinMath.h" -#include "../ReturnSlot.h" #include "../DoubleConversions.h" #include "../std_support/CStdlib.hpp" #include "../std_support/String.hpp" @@ -293,15 +291,6 @@ KDouble createDouble (const char *s, KInt e) } -#ifdef KONAN_WASM -double konan_pow(double base, double exponent) { - knjs__Math_pow(doubleUpper(base), doubleLower(base), doubleUpper(exponent), doubleLower(exponent)); - return ReturnSlot_getDouble(); -} -#else -#define konan_pow(arg1, arg2) pow(arg1, arg2) -#endif - KDouble createDouble1 (U_64 * f, IDATA length, KInt e) { @@ -324,7 +313,7 @@ createDouble1 (U_64 * f, IDATA length, KInt e) } else if (e >= 0 && e < APPROX_MAX_MAGNITUDE) { - result = toDoubleHighPrecision (f, length) * konan_pow (10.0, (double) e); + result = toDoubleHighPrecision (f, length) * pow (10.0, (double) e); } else if (e >= APPROX_MAX_MAGNITUDE) { @@ -344,14 +333,14 @@ createDouble1 (U_64 * f, IDATA length, KInt e) } else if (e > APPROX_MIN_MAGNITUDE) { - result = toDoubleHighPrecision (f, length) / konan_pow (10.0, (double) -e); + result = toDoubleHighPrecision (f, length) / pow (10.0, (double) -e); } if (e <= APPROX_MIN_MAGNITUDE) { - result = toDoubleHighPrecision (f, length) * konan_pow (10.0, (double) (e + 52)); - result = result * konan_pow (10.0, (double) -52); + result = toDoubleHighPrecision (f, length) * pow (10.0, (double) (e + 52)); + result = result * pow (10.0, (double) -52); } @@ -660,9 +649,12 @@ KDouble Kotlin_native_FloatingPointParser_parseDoubleImpl (KString s, KInt e) const KChar* utf16 = CharArrayAddressOfElementAt(s, 0); std_support::string utf8; utf8.reserve(s->count_); - TRY_CATCH(utf8::utf16to8(utf16, utf16 + s->count_, back_inserter(utf8)), - utf8::unchecked::utf16to8(utf16, utf16 + s->count_, back_inserter(utf8)), - /* Illegal UTF-16 string. */ ThrowNumberFormatException()); + try { + utf8::utf16to8(utf16, utf16 + s->count_, back_inserter(utf8)); + } catch (...) { + /* Illegal UTF-16 string. */ + ThrowNumberFormatException(); + } const char *str = utf8.c_str(); auto dbl = createDouble (str, e); diff --git a/kotlin-native/runtime/src/main/cpp/dtoa/fltparse.cpp b/kotlin-native/runtime/src/main/cpp/dtoa/fltparse.cpp index d3c966374fd..c876ecff8c7 100644 --- a/kotlin-native/runtime/src/main/cpp/dtoa/fltparse.cpp +++ b/kotlin-native/runtime/src/main/cpp/dtoa/fltparse.cpp @@ -548,9 +548,12 @@ Kotlin_native_FloatingPointParser_parseFloatImpl(KString s, KInt e) const KChar* utf16 = CharArrayAddressOfElementAt(s, 0); std_support::string utf8; utf8.reserve(s->count_); - TRY_CATCH(utf8::utf16to8(utf16, utf16 + s->count_, back_inserter(utf8)), - utf8::unchecked::utf16to8(utf16, utf16 + s->count_, back_inserter(utf8)), - /* Illegal UTF-16 string. */ ThrowNumberFormatException()); + try { + utf8::utf16to8(utf16, utf16 + s->count_, back_inserter(utf8)); + } catch (...) { + /* Illegal UTF-16 string. */ + ThrowNumberFormatException(); + } const char *str = utf8.c_str(); auto flt = createFloat(str, e); diff --git a/kotlin-native/runtime/src/main/cpp/math/COPYRIGHT b/kotlin-native/runtime/src/main/cpp/math/COPYRIGHT deleted file mode 100644 index a8a38a56305..00000000000 --- a/kotlin-native/runtime/src/main/cpp/math/COPYRIGHT +++ /dev/null @@ -1,128 +0,0 @@ -musl as a whole is licensed under the following standard MIT license: - ----------------------------------------------------------------------- -Copyright © 2005-2014 Rich Felker, et al. - -Permission is hereby granted, free of charge, to any person obtaining -a copy of this software and associated documentation files (the -"Software"), to deal in the Software without restriction, including -without limitation the rights to use, copy, modify, merge, publish, -distribute, sublicense, and/or sell copies of the Software, and to -permit persons to whom the Software is furnished to do so, subject to -the following conditions: - -The above copyright notice and this permission notice shall be -included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. -IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY -CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, -TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE -SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ----------------------------------------------------------------------- - -Authors/contributors include: - -Anthony G. Basile -Arvid Picciani -Bobby Bingham -Boris Brezillon -Chris Spiegel -Emil Renner Berthing -Hiltjo Posthuma -Isaac Dunham -Jens Gustedt -Jeremy Huntwork -John Spencer -Justin Cormack -Luca Barbato -Luka Perkov -Michael Forney -Nicholas J. Kain -orc -Pascal Cuoq -Pierre Carrier -Rich Felker -Richard Pennington -Solar Designer -Strake -Szabolcs Nagy -Timo Teräs -Valentin Ochs -William Haddon - -Portions of this software are derived from third-party works licensed -under terms compatible with the above MIT license: - -The TRE regular expression implementation (src/regex/reg* and -src/regex/tre*) is Copyright © 2001-2008 Ville Laurikari and licensed -under a 2-clause BSD license (license text in the source files). The -included version has been heavily modified by Rich Felker in 2012, in -the interests of size, simplicity, and namespace cleanliness. - -Much of the math library code (src/math/* and src/complex/*) is -Copyright © 1993,2004 Sun Microsystems or -Copyright © 2003-2011 David Schultz or -Copyright © 2003-2009 Steven G. Kargl or -Copyright © 2003-2009 Bruce D. Evans or -Copyright © 2008 Stephen L. Moshier -and labelled as such in comments in the individual source files. All -have been licensed under extremely permissive terms. - -The ARM memcpy code (src/string/armel/memcpy.s) is Copyright © 2008 -The Android Open Source Project and is licensed under a two-clause BSD -license. It was taken from Bionic libc, used on Android. - -The implementation of DES for crypt (src/misc/crypt_des.c) is -Copyright © 1994 David Burren. It is licensed under a BSD license. - -The implementation of blowfish crypt (src/misc/crypt_blowfish.c) was -originally written by Solar Designer and placed into the public -domain. The code also comes with a fallback permissive license for use -in jurisdictions that may not recognize the public domain. - -The smoothsort implementation (src/stdlib/qsort.c) is Copyright © 2011 -Valentin Ochs and is licensed under an MIT-style license. - -The BSD PRNG implementation (src/prng/random.c) and XSI search API -(src/search/*.c) functions are Copyright © 2011 Szabolcs Nagy and -licensed under following terms: "Permission to use, copy, modify, -and/or distribute this code for any purpose with or without fee is -hereby granted. There is no warranty." - -The x86_64 port was written by Nicholas J. Kain. Several files (crt) -were released into the public domain; others are licensed under the -standard MIT license terms at the top of this file. See individual -files for their copyright status. - -The mips and microblaze ports were originally written by Richard -Pennington for use in the ellcc project. The original code was adapted -by Rich Felker for build system and code conventions during upstream -integration. It is licensed under the standard MIT terms. - -The powerpc port was also originally written by Richard Pennington, -and later supplemented and integrated by John Spencer. It is licensed -under the standard MIT terms. - -All other files which have no copyright comments are original works -produced specifically for use as part of this library, written either -by Rich Felker, the main author of the library, or by one or more -contibutors listed above. Details on authorship of individual files -can be found in the git version control history of the project. The -omission of copyright and license comments in each file is in the -interest of source tree size. - -All public header files (include/* and arch/*/bits/*) should be -treated as Public Domain as they intentionally contain no content -which can be covered by copyright. Some source modules may fall in -this category as well. If you believe that a file is so trivial that -it should be in the Public Domain, please contact the authors and -request an explicit statement releasing it from copyright. - -The following files are trivial, believed not to be copyrightable in -the first place, and hereby explicitly released to the Public Domain: - -All public headers: include/*, arch/*/bits/* -Startup files: crt/* diff --git a/kotlin-native/runtime/src/main/cpp/math/endian.h b/kotlin-native/runtime/src/main/cpp/math/endian.h deleted file mode 100644 index 29b91dfb22a..00000000000 --- a/kotlin-native/runtime/src/main/cpp/math/endian.h +++ /dev/null @@ -1,86 +0,0 @@ -#ifdef KONAN_WASM - -#ifndef _ENDIAN_H -#define _ENDIAN_H - -#include - -#define __LITTLE_ENDIAN 1234 -#define __BIG_ENDIAN 4321 -#define __PDP_ENDIAN 3412 - -#if defined(__GNUC__) && defined(__BYTE_ORDER__) -#define __BYTE_ORDER __BYTE_ORDER__ -#else -#include -#endif - -#if defined(_GNU_SOURCE) || defined(_BSD_SOURCE) - -#define BIG_ENDIAN __BIG_ENDIAN -#define LITTLE_ENDIAN __LITTLE_ENDIAN -#define PDP_ENDIAN __PDP_ENDIAN -#define BYTE_ORDER __BYTE_ORDER - -#include - -static __inline uint16_t __bswap16(uint16_t __x) -{ - return __x<<8 | __x>>8; -} - -static __inline uint32_t __bswap32(uint32_t __x) -{ - return __x>>24 | __x>>8&0xff00 | __x<<8&0xff0000 | __x<<24; -} - -static __inline uint64_t __bswap64(uint64_t __x) -{ - return __bswap32(__x)+0ULL<<32 | __bswap32(__x>>32); -} - -#if __BYTE_ORDER == __LITTLE_ENDIAN -#define htobe16(x) __bswap16(x) -#define be16toh(x) __bswap16(x) -#define betoh16(x) __bswap16(x) -#define htobe32(x) __bswap32(x) -#define be32toh(x) __bswap32(x) -#define betoh32(x) __bswap32(x) -#define htobe64(x) __bswap64(x) -#define be64toh(x) __bswap64(x) -#define betoh64(x) __bswap64(x) -#define htole16(x) (uint16_t)(x) -#define le16toh(x) (uint16_t)(x) -#define letoh16(x) (uint16_t)(x) -#define htole32(x) (uint32_t)(x) -#define le32toh(x) (uint32_t)(x) -#define letoh32(x) (uint32_t)(x) -#define htole64(x) (uint64_t)(x) -#define le64toh(x) (uint64_t)(x) -#define letoh64(x) (uint64_t)(x) -#else -#define htobe16(x) (uint16_t)(x) -#define be16toh(x) (uint16_t)(x) -#define betoh16(x) (uint16_t)(x) -#define htobe32(x) (uint32_t)(x) -#define be32toh(x) (uint32_t)(x) -#define betoh32(x) (uint32_t)(x) -#define htobe64(x) (uint64_t)(x) -#define be64toh(x) (uint64_t)(x) -#define betoh64(x) (uint64_t)(x) -#define htole16(x) __bswap16(x) -#define le16toh(x) __bswap16(x) -#define letoh16(x) __bswap16(x) -#define htole32(x) __bswap32(x) -#define le32toh(x) __bswap32(x) -#define letoh32(x) __bswap32(x) -#define htole64(x) __bswap64(x) -#define le64toh(x) __bswap64(x) -#define letoh64(x) __bswap64(x) -#endif - -#endif - -#endif - -#endif // KONAN_WASM \ No newline at end of file diff --git a/kotlin-native/runtime/src/main/cpp/math/fmod.cpp b/kotlin-native/runtime/src/main/cpp/math/fmod.cpp deleted file mode 100644 index 263f3b2ef59..00000000000 --- a/kotlin-native/runtime/src/main/cpp/math/fmod.cpp +++ /dev/null @@ -1,74 +0,0 @@ -#ifdef KONAN_WASM - -#include -#include -#include "Common.h" - -RUNTIME_USED -double fmod(double x, double y) -{ - union {double f; uint64_t i;} ux = {x}, uy = {y}; - int ex = ux.i>>52 & 0x7ff; - int ey = uy.i>>52 & 0x7ff; - int sx = ux.i>>63; - uint64_t i; - - /* in the followings uxi should be ux.i, but then gcc wrongly adds */ - /* float load/store to inner loops ruining performance and code size */ - uint64_t uxi = ux.i; - - if (uy.i<<1 == 0 || isnan(y) || ex == 0x7ff) - return (x*y)/(x*y); - if (uxi<<1 <= uy.i<<1) { - if (uxi<<1 == uy.i<<1) - return 0*x; - return x; - } - - /* normalize x and y */ - if (!ex) { - for (i = uxi<<12; i>>63 == 0; ex--, i <<= 1); - uxi <<= -ex + 1; - } else { - uxi &= -1ULL >> 12; - uxi |= 1ULL << 52; - } - if (!ey) { - for (i = uy.i<<12; i>>63 == 0; ey--, i <<= 1); - uy.i <<= -ey + 1; - } else { - uy.i &= -1ULL >> 12; - uy.i |= 1ULL << 52; - } - - /* x mod y */ - for (; ex > ey; ex--) { - i = uxi - uy.i; - if (i >> 63 == 0) { - if (i == 0) - return 0*x; - uxi = i; - } - uxi <<= 1; - } - i = uxi - uy.i; - if (i >> 63 == 0) { - if (i == 0) - return 0*x; - uxi = i; - } - for (; uxi>>52 == 0; uxi <<= 1, ex--); - - /* scale result */ - if (ex > 0) { - uxi -= 1ULL << 52; - uxi |= (uint64_t)ex << 52; - } else { - uxi >>= -ex + 1; - } - uxi |= (uint64_t)sx << 63; - ux.i = uxi; - return ux.f; -} - -#endif // KONAN_WASM diff --git a/kotlin-native/runtime/src/main/cpp/math/fmodf.cpp b/kotlin-native/runtime/src/main/cpp/math/fmodf.cpp deleted file mode 100644 index 7619ea83757..00000000000 --- a/kotlin-native/runtime/src/main/cpp/math/fmodf.cpp +++ /dev/null @@ -1,71 +0,0 @@ -#ifdef KONAN_WASM - -#include -#include -#include "Common.h" - -RUNTIME_USED -float fmodf(float x, float y) -{ - union {float f; uint32_t i;} ux = {x}, uy = {y}; - int ex = ux.i>>23 & 0xff; - int ey = uy.i>>23 & 0xff; - uint32_t sx = ux.i & 0x80000000; - uint32_t i; - uint32_t uxi = ux.i; - - if (uy.i<<1 == 0 || isnan(y) || ex == 0xff) - return (x*y)/(x*y); - if (uxi<<1 <= uy.i<<1) { - if (uxi<<1 == uy.i<<1) - return 0*x; - return x; - } - - /* normalize x and y */ - if (!ex) { - for (i = uxi<<9; i>>31 == 0; ex--, i <<= 1); - uxi <<= -ex + 1; - } else { - uxi &= -1U >> 9; - uxi |= 1U << 23; - } - if (!ey) { - for (i = uy.i<<9; i>>31 == 0; ey--, i <<= 1); - uy.i <<= -ey + 1; - } else { - uy.i &= -1U >> 9; - uy.i |= 1U << 23; - } - - /* x mod y */ - for (; ex > ey; ex--) { - i = uxi - uy.i; - if (i >> 31 == 0) { - if (i == 0) - return 0*x; - uxi = i; - } - uxi <<= 1; - } - i = uxi - uy.i; - if (i >> 31 == 0) { - if (i == 0) - return 0*x; - uxi = i; - } - for (; uxi>>23 == 0; uxi <<= 1, ex--); - - /* scale result up */ - if (ex > 0) { - uxi -= 1U << 23; - uxi |= (uint32_t)ex << 23; - } else { - uxi >>= -ex + 1; - } - uxi |= sx; - ux.i = uxi; - return ux.f; -} - -#endif // KONAN_WASM diff --git a/kotlin-native/runtime/src/main/cpp/math/libm.h b/kotlin-native/runtime/src/main/cpp/math/libm.h deleted file mode 100644 index bff6cc88bd6..00000000000 --- a/kotlin-native/runtime/src/main/cpp/math/libm.h +++ /dev/null @@ -1,167 +0,0 @@ -#ifdef KONAN_WASM - -/* origin: FreeBSD /usr/src/lib/msun/src/math_private.h */ -/* - * ==================================================== - * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. - * - * Developed at SunPro, a Sun Microsystems, Inc. business. - * Permission to use, copy, modify, and distribute this - * software is freely granted, provided that this notice - * is preserved. - * ==================================================== - */ - -#ifndef _LIBM_H -#define _LIBM_H - -#include -#include -#include -//#include "endian.h" - -#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024 -#elif LDBL_MANT_DIG == 64 && LDBL_MAX_EXP == 16384 && __BYTE_ORDER == __LITTLE_ENDIAN -union ldshape { - long double f; - struct { - uint64_t m; - uint16_t se; - } i; -}; -#elif LDBL_MANT_DIG == 113 && LDBL_MAX_EXP == 16384 && __BYTE_ORDER == __LITTLE_ENDIAN -union ldshape { - long double f; - struct { - uint64_t lo; - uint32_t mid; - uint16_t top; - uint16_t se; - } i; - struct { - uint64_t lo; - uint64_t hi; - } i2; -}; -#else -#error Unsupported long double representation -#endif - -#ifdef __EMSCRIPTEN__ -/* - * asm.js doesn't have user-accessible floating point exceptions, so there's - * no point in trying to force expression evaluations to produce them. - */ -#define FORCE_EVAL(x) -#else -#define FORCE_EVAL(x) do { \ - if (sizeof(x) == sizeof(float)) { \ - volatile float __x; \ - __x = (x); \ - } else if (sizeof(x) == sizeof(double)) { \ - volatile double __x; \ - __x = (x); \ - } else { \ - volatile long double __x; \ - __x = (x); \ - } \ -} while(0) -#endif - -/* Get two 32 bit ints from a double. */ -#define EXTRACT_WORDS(hi,lo,d) \ -do { \ - union {double f; uint64_t i;} __u; \ - __u.f = (d); \ - (hi) = __u.i >> 32; \ - (lo) = (uint32_t)__u.i; \ -} while (0) - -/* Get the more significant 32 bit int from a double. */ -#define GET_HIGH_WORD(hi,d) \ -do { \ - union {double f; uint64_t i;} __u; \ - __u.f = (d); \ - (hi) = __u.i >> 32; \ -} while (0) - -/* Get the less significant 32 bit int from a double. */ -#define GET_LOW_WORD(lo,d) \ -do { \ - union {double f; uint64_t i;} __u; \ - __u.f = (d); \ - (lo) = (uint32_t)__u.i; \ -} while (0) - -/* Set a double from two 32 bit ints. */ -#define INSERT_WORDS(d,hi,lo) \ -do { \ - union {double f; uint64_t i;} __u; \ - __u.i = ((uint64_t)(hi)<<32) | (uint32_t)(lo); \ - (d) = __u.f; \ -} while (0) - -/* Set the more significant 32 bits of a double from an int. */ -#define SET_HIGH_WORD(d,hi) \ -do { \ - union {double f; uint64_t i;} __u; \ - __u.f = (d); \ - __u.i &= 0xffffffff; \ - __u.i |= (uint64_t)(hi) << 32; \ - (d) = __u.f; \ -} while (0) - -/* Set the less significant 32 bits of a double from an int. */ -#define SET_LOW_WORD(d,lo) \ -do { \ - union {double f; uint64_t i;} __u; \ - __u.f = (d); \ - __u.i &= 0xffffffff00000000ull; \ - __u.i |= (uint32_t)(lo); \ - (d) = __u.f; \ -} while (0) - -/* Get a 32 bit int from a float. */ -#define GET_FLOAT_WORD(w,d) \ -do { \ - union {float f; uint32_t i;} __u; \ - __u.f = (d); \ - (w) = __u.i; \ -} while (0) - -/* Set a float from a 32 bit int. */ -#define SET_FLOAT_WORD(d,w) \ -do { \ - union {float f; uint32_t i;} __u; \ - __u.i = (w); \ - (d) = __u.f; \ -} while (0) - -/* fdlibm kernel functions */ - -int __rem_pio2_large(double*,double*,int,int,int); - -int __rem_pio2(double,double*); -double __sin(double,double,int); -double __cos(double,double); -double __tan(double,double,int); -double __expo2(double); - -int __rem_pio2f(float,double*); -float __sindf(double); -float __cosdf(double); -float __tandf(double,int); -float __expo2f(float); - -int __rem_pio2l(long double, long double *); -long double __sinl(long double, long double, int); -long double __cosl(long double, long double); -long double __tanl(long double, long double, int); - -/* polynomial evaluation */ -long double __polevll(long double, const long double *, int); -long double __p1evll(long double, const long double *, int); - -#endif - -#endif // KONAN_WASM diff --git a/kotlin-native/runtime/src/main/cpp/math/scalbn.cpp b/kotlin-native/runtime/src/main/cpp/math/scalbn.cpp deleted file mode 100644 index 57b5d0eea89..00000000000 --- a/kotlin-native/runtime/src/main/cpp/math/scalbn.cpp +++ /dev/null @@ -1,35 +0,0 @@ -#ifdef KONAN_WASM - -#include -#include - -double scalbn(double x, int n) -{ - union {double f; uint64_t i;} u; - double_t y = x; - - if (n > 1023) { - y *= 0x1p1023; - n -= 1023; - if (n > 1023) { - y *= 0x1p1023; - n -= 1023; - if (n > 1023) - n = 1023; - } - } else if (n < -1022) { - y *= 0x1p-1022; - n += 1022; - if (n < -1022) { - y *= 0x1p-1022; - n += 1022; - if (n < -1022) - n = -1022; - } - } - u.i = (uint64_t)(0x3ff+n)<<52; - x = y * u.f; - return x; -} - -#endif // KONAN_WASM diff --git a/kotlin-native/runtime/src/main/cpp/snprintf/AUTHORS b/kotlin-native/runtime/src/main/cpp/snprintf/AUTHORS deleted file mode 100644 index 88a1b0fef7f..00000000000 --- a/kotlin-native/runtime/src/main/cpp/snprintf/AUTHORS +++ /dev/null @@ -1,9 +0,0 @@ -Patrick Powell -Brandon Long -Thomas Roessler -Michael Elkins -Andrew Tridgell -Russ Allbery -Hrvoje Niksic -Damien Miller -Holger Weiss diff --git a/kotlin-native/runtime/src/main/cpp/snprintf/COPYING b/kotlin-native/runtime/src/main/cpp/snprintf/COPYING deleted file mode 100644 index d84962f2342..00000000000 --- a/kotlin-native/runtime/src/main/cpp/snprintf/COPYING +++ /dev/null @@ -1,3 +0,0 @@ -UNLESS SPECIFIED OTHERWISE IN THE INDIVIDUAL SOURCE FILES INCLUDED WITH -THIS PACKAGE, they may freely be used, modified and/or redistributed for -any purpose. diff --git a/kotlin-native/runtime/src/main/cpp/snprintf/snprintf.cpp b/kotlin-native/runtime/src/main/cpp/snprintf/snprintf.cpp deleted file mode 100644 index 29585359abf..00000000000 --- a/kotlin-native/runtime/src/main/cpp/snprintf/snprintf.cpp +++ /dev/null @@ -1,2116 +0,0 @@ -/* - * Copyright (c) 1995 Patrick Powell. - * - * This code is based on code written by Patrick Powell . - * It may be used for any purpose as long as this notice remains intact on all - * source code distributions. - */ - -/* - * Copyright (c) 2008 Holger Weiss. - * - * This version of the code is maintained by Holger Weiss . - * My changes to the code may freely be used, modified and/or redistributed for - * any purpose. It would be nice if additions and fixes to this file (including - * trivial code cleanups) would be sent back in order to let me include them in - * the version available at . - * However, this is not a requirement for using or redistributing (possibly - * modified) versions of this file, nor is leaving this notice intact mandatory. - */ - -/* - * History - * - * 2008-01-20 Holger Weiss for C99-snprintf 1.1: - * - * Fixed the detection of infinite floating point values on IRIX (and - * possibly other systems) and applied another few minor cleanups. - * - * 2008-01-06 Holger Weiss for C99-snprintf 1.0: - * - * Added a lot of new features, fixed many bugs, and incorporated various - * improvements done by Andrew Tridgell , Russ Allbery - * , Hrvoje Niksic , Damien Miller - * , and others for the Samba, INN, Wget, and OpenSSH - * projects. The additions include: support the "e", "E", "g", "G", and - * "F" conversion specifiers (and use conversion style "f" or "F" for the - * still unsupported "a" and "A" specifiers); support the "hh", "ll", "j", - * "t", and "z" length modifiers; support the "#" flag and the (non-C99) - * "'" flag; use localeconv(3) (if available) to get both the current - * locale's decimal point character and the separator between groups of - * digits; fix the handling of various corner cases of field width and - * precision specifications; fix various floating point conversion bugs; - * handle infinite and NaN floating point values; don't attempt to write to - * the output buffer (which may be NULL) if a size of zero was specified; - * check for integer overflow of the field width, precision, and return - * values and during the floating point conversion; use the OUTCHAR() macro - * instead of a function for better performance; provide asprintf(3) and - * vasprintf(3) functions; add new test cases. The replacement functions - * have been renamed to use an "rpl_" prefix, the function calls in the - * main project (and in this file) must be redefined accordingly for each - * replacement function which is needed (by using Autoconf or other means). - * Various other minor improvements have been applied and the coding style - * was cleaned up for consistency. - * - * 2007-07-23 Holger Weiss for Mutt 1.5.13: - * - * C99 compliant snprintf(3) and vsnprintf(3) functions return the number - * of characters that would have been written to a sufficiently sized - * buffer (excluding the '\0'). The original code simply returned the - * length of the resulting output string, so that's been fixed. - * - * 1998-03-05 Michael Elkins for Mutt 0.90.8: - * - * The original code assumed that both snprintf(3) and vsnprintf(3) were - * missing. Some systems only have snprintf(3) but not vsnprintf(3), so - * the code is now broken down under HAVE_SNPRINTF and HAVE_VSNPRINTF. - * - * 1998-01-27 Thomas Roessler for Mutt 0.89i: - * - * The PGP code was using unsigned hexadecimal formats. Unfortunately, - * unsigned formats simply didn't work. - * - * 1997-10-22 Brandon Long for Mutt 0.87.1: - * - * Ok, added some minimal floating point support, which means this probably - * requires libm on most operating systems. Don't yet support the exponent - * (e,E) and sigfig (g,G). Also, fmtint() was pretty badly broken, it just - * wasn't being exercised in ways which showed it, so that's been fixed. - * Also, formatted the code to Mutt conventions, and removed dead code left - * over from the original. Also, there is now a builtin-test, run with: - * gcc -DTEST_SNPRINTF -o snprintf snprintf.c -lm && ./snprintf - * - * 2996-09-15 Brandon Long for Mutt 0.43: - * - * This was ugly. It is still ugly. I opted out of floating point - * numbers, but the formatter understands just about everything from the - * normal C string format, at least as far as I can tell from the Solaris - * 2.5 printf(3S) man page. - */ - -/* - * ToDo - * - * - Add wide character support. - * - Add support for "%a" and "%A" conversions. - * - Create test routines which predefine the expected results. Our test cases - * usually expose bugs in system implementations rather than in ours :-) - */ - -/* - * Usage - * - * 1) The following preprocessor macros should be defined to 1 if the feature or - * file in question is available on the target system (by using Autoconf or - * other means), though basic functionality should be available as long as - * HAVE_STDARG_H and HAVE_STDLIB_H are defined correctly: - * - * HAVE_VSNPRINTF - * HAVE_SNPRINTF - * HAVE_VASPRINTF - * HAVE_ASPRINTF - * HAVE_STDARG_H - * HAVE_STDDEF_H - * HAVE_STDINT_H - * HAVE_STDLIB_H - * HAVE_FLOAT_H - * HAVE_INTTYPES_H - * HAVE_LOCALE_H - * HAVE_LOCALECONV - * HAVE_LCONV_DECIMAL_POINT - * HAVE_LCONV_THOUSANDS_SEP - * HAVE_LONG_DOUBLE - * HAVE_LONG_LONG_INT - * HAVE_UNSIGNED_LONG_LONG_INT - * HAVE_INTMAX_T - * HAVE_UINTMAX_T - * HAVE_UINTPTR_T - * HAVE_PTRDIFF_T - * HAVE_VA_COPY - * HAVE___VA_COPY - * - * 2) The calls to the functions which should be replaced must be redefined - * throughout the project files (by using Autoconf or other means): - * - * #define vsnprintf rpl_vsnprintf - * #define snprintf rpl_snprintf - * #define vasprintf rpl_vasprintf - * #define asprintf rpl_asprintf - * - * 3) The required replacement functions should be declared in some header file - * included throughout the project files: - * - * #if HAVE_CONFIG_H - * #include - * #endif - * #if HAVE_STDARG_H - * #include - * #if !HAVE_VSNPRINTF - * int rpl_vsnprintf(char *, size_t, const char *, va_list); - * #endif - * #if !HAVE_SNPRINTF - * int rpl_snprintf(char *, size_t, const char *, ...); - * #endif - * #if !HAVE_VASPRINTF - * int rpl_vasprintf(char **, const char *, va_list); - * #endif - * #if !HAVE_ASPRINTF - * int rpl_asprintf(char **, const char *, ...); - * #endif - * #endif - * - * Autoconf macros for handling step 1 and step 2 are available at - * . - */ - -#if KONAN_INTERNAL_SNPRINTF - -/**** Start of Konan-specific c99-snprintf configuration. ****/ - -#define HAVE_FLOAT_H 1 -#define HAVE_STDARG_H 1 -#define HAVE_STDDEF_H 1 -#define HAVE_STDLIB_H 1 -#define HAVE_SNPRINTF 1 -#define HAVE_VASPRINTF 1 -#define HAVE_ASPRINTF 1 -#define HAVE_LONG_LONG_INT 1 -#define HAVE_UNSIGNED_LONG_LONG_INT 1 -#include -#include -extern "C" int rpl_vsnprintf(char *, size_t, const char *, va_list); -#define malloc(size) konan:calloc(1, size) - -/**** End of Konan-specific c99-snprintf configuration. ****/ - -#if HAVE_CONFIG_H -#include -#endif /* HAVE_CONFIG_H */ - -#if TEST_SNPRINTF -#include /* For pow(3), NAN, and INFINITY. */ -#include /* For strcmp(3). */ -#if defined(__NetBSD__) || \ - defined(__FreeBSD__) || \ - defined(__OpenBSD__) || \ - defined(__NeXT__) || \ - defined(__bsd__) -#define OS_BSD 1 -#elif defined(sgi) || defined(__sgi) -#ifndef __c99 -#define __c99 /* Force C99 mode to get included on IRIX 6.5.30. */ -#endif /* !defined(__c99) */ -#define OS_IRIX 1 -#define OS_SYSV 1 -#elif defined(__svr4__) -#define OS_SYSV 1 -#elif defined(__linux__) -#define OS_LINUX 1 -#endif /* defined(__NetBSD__) || defined(__FreeBSD__) || [...] */ -#if HAVE_CONFIG_H /* Undefine definitions possibly done in config.h. */ -#ifdef HAVE_SNPRINTF -#undef HAVE_SNPRINTF -#endif /* defined(HAVE_SNPRINTF) */ -#ifdef HAVE_VSNPRINTF -#undef HAVE_VSNPRINTF -#endif /* defined(HAVE_VSNPRINTF) */ -#ifdef HAVE_ASPRINTF -#undef HAVE_ASPRINTF -#endif /* defined(HAVE_ASPRINTF) */ -#ifdef HAVE_VASPRINTF -#undef HAVE_VASPRINTF -#endif /* defined(HAVE_VASPRINTF) */ -#ifdef snprintf -#undef snprintf -#endif /* defined(snprintf) */ -#ifdef vsnprintf -#undef vsnprintf -#endif /* defined(vsnprintf) */ -#ifdef asprintf -#undef asprintf -#endif /* defined(asprintf) */ -#ifdef vasprintf -#undef vasprintf -#endif /* defined(vasprintf) */ -#else /* By default, we assume a modern system for testing. */ -#ifndef HAVE_STDARG_H -#define HAVE_STDARG_H 1 -#endif /* HAVE_STDARG_H */ -#ifndef HAVE_STDDEF_H -#define HAVE_STDDEF_H 1 -#endif /* HAVE_STDDEF_H */ -#ifndef HAVE_STDINT_H -#define HAVE_STDINT_H 1 -#endif /* HAVE_STDINT_H */ -#ifndef HAVE_STDLIB_H -#define HAVE_STDLIB_H 1 -#endif /* HAVE_STDLIB_H */ -#ifndef HAVE_FLOAT_H -#define HAVE_FLOAT_H 1 -#endif /* HAVE_FLOAT_H */ -#ifndef HAVE_INTTYPES_H -#define HAVE_INTTYPES_H 1 -#endif /* HAVE_INTTYPES_H */ -#ifndef HAVE_LOCALE_H -#define HAVE_LOCALE_H 1 -#endif /* HAVE_LOCALE_H */ -#ifndef HAVE_LOCALECONV -#define HAVE_LOCALECONV 1 -#endif /* !defined(HAVE_LOCALECONV) */ -#ifndef HAVE_LCONV_DECIMAL_POINT -#define HAVE_LCONV_DECIMAL_POINT 1 -#endif /* HAVE_LCONV_DECIMAL_POINT */ -#ifndef HAVE_LCONV_THOUSANDS_SEP -#define HAVE_LCONV_THOUSANDS_SEP 1 -#endif /* HAVE_LCONV_THOUSANDS_SEP */ -#ifndef HAVE_LONG_DOUBLE -#define HAVE_LONG_DOUBLE 1 -#endif /* !defined(HAVE_LONG_DOUBLE) */ -#ifndef HAVE_LONG_LONG_INT -#define HAVE_LONG_LONG_INT 1 -#endif /* !defined(HAVE_LONG_LONG_INT) */ -#ifndef HAVE_UNSIGNED_LONG_LONG_INT -#define HAVE_UNSIGNED_LONG_LONG_INT 1 -#endif /* !defined(HAVE_UNSIGNED_LONG_LONG_INT) */ -#ifndef HAVE_INTMAX_T -#define HAVE_INTMAX_T 1 -#endif /* !defined(HAVE_INTMAX_T) */ -#ifndef HAVE_UINTMAX_T -#define HAVE_UINTMAX_T 1 -#endif /* !defined(HAVE_UINTMAX_T) */ -#ifndef HAVE_UINTPTR_T -#define HAVE_UINTPTR_T 1 -#endif /* !defined(HAVE_UINTPTR_T) */ -#ifndef HAVE_PTRDIFF_T -#define HAVE_PTRDIFF_T 1 -#endif /* !defined(HAVE_PTRDIFF_T) */ -#ifndef HAVE_VA_COPY -#define HAVE_VA_COPY 1 -#endif /* !defined(HAVE_VA_COPY) */ -#ifndef HAVE___VA_COPY -#define HAVE___VA_COPY 1 -#endif /* !defined(HAVE___VA_COPY) */ -#endif /* HAVE_CONFIG_H */ -#define snprintf rpl_snprintf -#define vsnprintf rpl_vsnprintf -#define asprintf rpl_asprintf -#define vasprintf rpl_vasprintf -#endif /* TEST_SNPRINTF */ - -#if !HAVE_SNPRINTF || !HAVE_VSNPRINTF || !HAVE_ASPRINTF || !HAVE_VASPRINTF -#include /* For NULL, size_t, vsnprintf(3), and vasprintf(3). */ -#ifdef VA_START -#undef VA_START -#endif /* defined(VA_START) */ -#ifdef VA_SHIFT -#undef VA_SHIFT -#endif /* defined(VA_SHIFT) */ -#if HAVE_STDARG_H -#include -#define VA_START(ap, last) va_start(ap, last) -#define VA_SHIFT(ap, value, type) /* No-op for ANSI C. */ -#else /* Assume is available. */ -#include -#define VA_START(ap, last) va_start(ap) /* "last" is ignored. */ -#define VA_SHIFT(ap, value, type) value = va_arg(ap, type) -#endif /* HAVE_STDARG_H */ - -#if !HAVE_VASPRINTF -#if HAVE_STDLIB_H -#include /* For malloc(3). */ -#endif /* HAVE_STDLIB_H */ -#ifdef VA_COPY -#undef VA_COPY -#endif /* defined(VA_COPY) */ -#ifdef VA_END_COPY -#undef VA_END_COPY -#endif /* defined(VA_END_COPY) */ -#if HAVE_VA_COPY -#define VA_COPY(dest, src) va_copy(dest, src) -#define VA_END_COPY(ap) va_end(ap) -#elif HAVE___VA_COPY -#define VA_COPY(dest, src) __va_copy(dest, src) -#define VA_END_COPY(ap) va_end(ap) -#else -#define VA_COPY(dest, src) (void)mymemcpy(&dest, &src, sizeof(va_list)) -#define VA_END_COPY(ap) /* No-op. */ -#define NEED_MYMEMCPY 1 -static void *mymemcpy(void *, void *, size_t); -#endif /* HAVE_VA_COPY */ -#endif /* !HAVE_VASPRINTF */ - -#if !HAVE_VSNPRINTF -#include /* For ERANGE and errno. */ -#include /* For *_MAX. */ -#if HAVE_FLOAT_H -#include /* For *DBL_{MIN,MAX}_10_EXP. */ -#endif /* HAVE_FLOAT_H */ -#if HAVE_INTTYPES_H -#include /* For intmax_t (if not defined in ). */ -#endif /* HAVE_INTTYPES_H */ -#if HAVE_LOCALE_H -#include /* For localeconv(3). */ -#endif /* HAVE_LOCALE_H */ -#if HAVE_STDDEF_H -#include /* For ptrdiff_t. */ -#endif /* HAVE_STDDEF_H */ -#if HAVE_STDINT_H -#include /* For intmax_t. */ -#endif /* HAVE_STDINT_H */ - -/* Support for unsigned long long int. We may also need ULLONG_MAX. */ -#ifndef ULONG_MAX /* We may need ULONG_MAX as a fallback. */ -#ifdef UINT_MAX -#define ULONG_MAX UINT_MAX -#else -#define ULONG_MAX INT_MAX -#endif /* defined(UINT_MAX) */ -#endif /* !defined(ULONG_MAX) */ -#ifdef ULLONG -#undef ULLONG -#endif /* defined(ULLONG) */ -#if HAVE_UNSIGNED_LONG_LONG_INT -#define ULLONG unsigned long long int -#ifndef ULLONG_MAX -#define ULLONG_MAX ULONG_MAX -#endif /* !defined(ULLONG_MAX) */ -#else -#define ULLONG unsigned long int -#ifdef ULLONG_MAX -#undef ULLONG_MAX -#endif /* defined(ULLONG_MAX) */ -#define ULLONG_MAX ULONG_MAX -#endif /* HAVE_LONG_LONG_INT */ - -/* Support for uintmax_t. We also need UINTMAX_MAX. */ -#ifdef UINTMAX_T -#undef UINTMAX_T -#endif /* defined(UINTMAX_T) */ -#if HAVE_UINTMAX_T || defined(uintmax_t) -#define UINTMAX_T uintmax_t -#ifndef UINTMAX_MAX -#define UINTMAX_MAX ULLONG_MAX -#endif /* !defined(UINTMAX_MAX) */ -#else -#define UINTMAX_T ULLONG -#ifdef UINTMAX_MAX -#undef UINTMAX_MAX -#endif /* defined(UINTMAX_MAX) */ -#define UINTMAX_MAX ULLONG_MAX -#endif /* HAVE_UINTMAX_T || defined(uintmax_t) */ - -/* Support for long double. */ -#ifndef LDOUBLE -#if HAVE_LONG_DOUBLE -#define LDOUBLE long double -#define LDOUBLE_MIN_10_EXP LDBL_MIN_10_EXP -#define LDOUBLE_MAX_10_EXP LDBL_MAX_10_EXP -#else -#define LDOUBLE double -#define LDOUBLE_MIN_10_EXP DBL_MIN_10_EXP -#define LDOUBLE_MAX_10_EXP DBL_MAX_10_EXP -#endif /* HAVE_LONG_DOUBLE */ -#endif /* !defined(LDOUBLE) */ - -/* Support for long long int. */ -#ifndef LLONG -#if HAVE_LONG_LONG_INT -#define LLONG long long int -#else -#define LLONG long int -#endif /* HAVE_LONG_LONG_INT */ -#endif /* !defined(LLONG) */ - -/* Support for intmax_t. */ -#ifndef INTMAX_T -#if HAVE_INTMAX_T || defined(intmax_t) -#define INTMAX_T intmax_t -#else -#define INTMAX_T LLONG -#endif /* HAVE_INTMAX_T || defined(intmax_t) */ -#endif /* !defined(INTMAX_T) */ - -/* Support for uintptr_t. */ -#ifndef UINTPTR_T -#if HAVE_UINTPTR_T || defined(uintptr_t) -#define UINTPTR_T uintptr_t -#else -#define UINTPTR_T unsigned long int -#endif /* HAVE_UINTPTR_T || defined(uintptr_t) */ -#endif /* !defined(UINTPTR_T) */ - -/* Support for ptrdiff_t. */ -#ifndef PTRDIFF_T -#if HAVE_PTRDIFF_T || defined(ptrdiff_t) -#define PTRDIFF_T ptrdiff_t -#else -#define PTRDIFF_T long int -#endif /* HAVE_PTRDIFF_T || defined(ptrdiff_t) */ -#endif /* !defined(PTRDIFF_T) */ - -/* - * We need an unsigned integer type corresponding to ptrdiff_t (cf. C99: - * 7.19.6.1, 7). However, we'll simply use PTRDIFF_T and convert it to an - * unsigned type if necessary. This should work just fine in practice. - */ -#ifndef UPTRDIFF_T -#define UPTRDIFF_T PTRDIFF_T -#endif /* !defined(UPTRDIFF_T) */ - -/* - * We need a signed integer type corresponding to size_t (cf. C99: 7.19.6.1, 7). - * However, we'll simply use size_t and convert it to a signed type if - * necessary. This should work just fine in practice. - */ -#ifndef SSIZE_T -#define SSIZE_T size_t -#endif /* !defined(SSIZE_T) */ - -/* Either ERANGE or E2BIG should be available everywhere. */ -#ifndef ERANGE -#define ERANGE E2BIG -#endif /* !defined(ERANGE) */ -#ifndef EOVERFLOW -#define EOVERFLOW ERANGE -#endif /* !defined(EOVERFLOW) */ - -/* - * Buffer size to hold the octal string representation of UINT128_MAX without - * nul-termination ("3777777777777777777777777777777777777777777"). - */ -#ifdef MAX_CONVERT_LENGTH -#undef MAX_CONVERT_LENGTH -#endif /* defined(MAX_CONVERT_LENGTH) */ -#define MAX_CONVERT_LENGTH 43 - -/* Format read states. */ -#define PRINT_S_DEFAULT 0 -#define PRINT_S_FLAGS 1 -#define PRINT_S_WIDTH 2 -#define PRINT_S_DOT 3 -#define PRINT_S_PRECISION 4 -#define PRINT_S_MOD 5 -#define PRINT_S_CONV 6 - -/* Format flags. */ -#define PRINT_F_MINUS (1 << 0) -#define PRINT_F_PLUS (1 << 1) -#define PRINT_F_SPACE (1 << 2) -#define PRINT_F_NUM (1 << 3) -#define PRINT_F_ZERO (1 << 4) -#define PRINT_F_QUOTE (1 << 5) -#define PRINT_F_UP (1 << 6) -#define PRINT_F_UNSIGNED (1 << 7) -#define PRINT_F_TYPE_G (1 << 8) -#define PRINT_F_TYPE_E (1 << 9) - -/* Conversion flags. */ -#define PRINT_C_CHAR 1 -#define PRINT_C_SHORT 2 -#define PRINT_C_LONG 3 -#define PRINT_C_LLONG 4 -#define PRINT_C_LDOUBLE 5 -#define PRINT_C_SIZE 6 -#define PRINT_C_PTRDIFF 7 -#define PRINT_C_INTMAX 8 - -#ifndef MAX -#define MAX(x, y) ((x >= y) ? x : y) -#endif /* !defined(MAX) */ -#ifndef CHARTOINT -#define CHARTOINT(ch) (ch - '0') -#endif /* !defined(CHARTOINT) */ -#ifndef ISDIGIT -#define ISDIGIT(ch) ('0' <= (unsigned char)ch && (unsigned char)ch <= '9') -#endif /* !defined(ISDIGIT) */ -#ifndef ISNAN -#define ISNAN(x) (x != x) -#endif /* !defined(ISNAN) */ -#ifndef ISINF -#define ISINF(x) ((x < -1 || x > 1) && x + x == x) -#endif /* !defined(ISINF) */ - -#ifdef OUTCHAR -#undef OUTCHAR -#endif /* defined(OUTCHAR) */ -#define OUTCHAR(str, len, size, ch) \ -do { \ - if (len + 1 < size) \ - str[len] = ch; \ - (len)++; \ -} while (/* CONSTCOND */ 0) - -static void fmtstr(char *, size_t *, size_t, const char *, int, int, int); -static void fmtint(char *, size_t *, size_t, INTMAX_T, int, int, int, int); -static void fmtflt(char *, size_t *, size_t, LDOUBLE, int, int, int, int *); -static void printsep(char *, size_t *, size_t); -static int getnumsep(int); -static int getexponent(LDOUBLE); -static int convert(UINTMAX_T, char *, size_t, int, int); -static UINTMAX_T cast(LDOUBLE); -static UINTMAX_T myround(LDOUBLE); -static LDOUBLE mypow10(int); - -extern int errno; - -int -rpl_vsnprintf(char *str, size_t size, const char *format, va_list args) -{ - LDOUBLE fvalue; - INTMAX_T value; - unsigned char cvalue; - const char *strvalue; - INTMAX_T *intmaxptr; - PTRDIFF_T *ptrdiffptr; - SSIZE_T *sizeptr; - LLONG *llongptr; - long int *longptr; - int *intptr; - short int *shortptr; - signed char *charptr; - size_t len = 0; - int overflow = 0; - int base = 0; - int cflags = 0; - int flags = 0; - int width = 0; - int precision = -1; - int state = PRINT_S_DEFAULT; - char ch = *format++; - - /* - * C99 says: "If `n' is zero, nothing is written, and `s' may be a null - * pointer." (7.19.6.5, 2) We're forgiving and allow a NULL pointer - * even if a size larger than zero was specified. At least NetBSD's - * snprintf(3) does the same, as well as other versions of this file. - * (Though some of these versions will write to a non-NULL buffer even - * if a size of zero was specified, which violates the standard.) - */ - if (str == NULL && size != 0) - size = 0; - - while (ch != '\0') - switch (state) { - case PRINT_S_DEFAULT: - if (ch == '%') - state = PRINT_S_FLAGS; - else - OUTCHAR(str, len, size, ch); - ch = *format++; - break; - case PRINT_S_FLAGS: - switch (ch) { - case '-': - flags |= PRINT_F_MINUS; - ch = *format++; - break; - case '+': - flags |= PRINT_F_PLUS; - ch = *format++; - break; - case ' ': - flags |= PRINT_F_SPACE; - ch = *format++; - break; - case '#': - flags |= PRINT_F_NUM; - ch = *format++; - break; - case '0': - flags |= PRINT_F_ZERO; - ch = *format++; - break; - case '\'': /* SUSv2 flag (not in C99). */ - flags |= PRINT_F_QUOTE; - ch = *format++; - break; - default: - state = PRINT_S_WIDTH; - break; - } - break; - case PRINT_S_WIDTH: - if (ISDIGIT(ch)) { - ch = CHARTOINT(ch); - if (width > (INT_MAX - ch) / 10) { - overflow = 1; - goto out; - } - width = 10 * width + ch; - ch = *format++; - } else if (ch == '*') { - /* - * C99 says: "A negative field width argument is - * taken as a `-' flag followed by a positive - * field width." (7.19.6.1, 5) - */ - if ((width = va_arg(args, int)) < 0) { - flags |= PRINT_F_MINUS; - width = -width; - } - ch = *format++; - state = PRINT_S_DOT; - } else - state = PRINT_S_DOT; - break; - case PRINT_S_DOT: - if (ch == '.') { - state = PRINT_S_PRECISION; - ch = *format++; - } else - state = PRINT_S_MOD; - break; - case PRINT_S_PRECISION: - if (precision == -1) - precision = 0; - if (ISDIGIT(ch)) { - ch = CHARTOINT(ch); - if (precision > (INT_MAX - ch) / 10) { - overflow = 1; - goto out; - } - precision = 10 * precision + ch; - ch = *format++; - } else if (ch == '*') { - /* - * C99 says: "A negative precision argument is - * taken as if the precision were omitted." - * (7.19.6.1, 5) - */ - if ((precision = va_arg(args, int)) < 0) - precision = -1; - ch = *format++; - state = PRINT_S_MOD; - } else - state = PRINT_S_MOD; - break; - case PRINT_S_MOD: - switch (ch) { - case 'h': - ch = *format++; - if (ch == 'h') { /* It's a char. */ - ch = *format++; - cflags = PRINT_C_CHAR; - } else - cflags = PRINT_C_SHORT; - break; - case 'l': - ch = *format++; - if (ch == 'l') { /* It's a long long. */ - ch = *format++; - cflags = PRINT_C_LLONG; - } else - cflags = PRINT_C_LONG; - break; - case 'L': - cflags = PRINT_C_LDOUBLE; - ch = *format++; - break; - case 'j': - cflags = PRINT_C_INTMAX; - ch = *format++; - break; - case 't': - cflags = PRINT_C_PTRDIFF; - ch = *format++; - break; - case 'z': - cflags = PRINT_C_SIZE; - ch = *format++; - break; - } - state = PRINT_S_CONV; - break; - case PRINT_S_CONV: - switch (ch) { - case 'd': - /* FALLTHROUGH */ - case 'i': - switch (cflags) { - case PRINT_C_CHAR: - value = (signed char)va_arg(args, int); - break; - case PRINT_C_SHORT: - value = (short int)va_arg(args, int); - break; - case PRINT_C_LONG: - value = va_arg(args, long int); - break; - case PRINT_C_LLONG: - value = va_arg(args, LLONG); - break; - case PRINT_C_SIZE: - value = va_arg(args, SSIZE_T); - break; - case PRINT_C_INTMAX: - value = va_arg(args, INTMAX_T); - break; - case PRINT_C_PTRDIFF: - value = va_arg(args, PTRDIFF_T); - break; - default: - value = va_arg(args, int); - break; - } - fmtint(str, &len, size, value, 10, width, - precision, flags); - break; - case 'X': - flags |= PRINT_F_UP; - /* FALLTHROUGH */ - case 'x': - base = 16; - /* FALLTHROUGH */ - case 'o': - if (base == 0) - base = 8; - /* FALLTHROUGH */ - case 'u': - if (base == 0) - base = 10; - flags |= PRINT_F_UNSIGNED; - switch (cflags) { - case PRINT_C_CHAR: - value = (unsigned char)va_arg(args, - unsigned int); - break; - case PRINT_C_SHORT: - value = (unsigned short int)va_arg(args, - unsigned int); - break; - case PRINT_C_LONG: - value = va_arg(args, unsigned long int); - break; - case PRINT_C_LLONG: - value = va_arg(args, ULLONG); - break; - case PRINT_C_SIZE: - value = va_arg(args, size_t); - break; - case PRINT_C_INTMAX: - value = va_arg(args, UINTMAX_T); - break; - case PRINT_C_PTRDIFF: - value = va_arg(args, UPTRDIFF_T); - break; - default: - value = va_arg(args, unsigned int); - break; - } - fmtint(str, &len, size, value, base, width, - precision, flags); - break; - case 'A': - /* Not yet supported, we'll use "%F". */ - /* FALLTHROUGH */ - case 'E': - if (ch == 'E') - flags |= PRINT_F_TYPE_E; - /* FALLTHROUGH */ - case 'G': - if (ch == 'G') - flags |= PRINT_F_TYPE_G; - /* FALLTHROUGH */ - case 'F': - flags |= PRINT_F_UP; - /* FALLTHROUGH */ - case 'a': - /* Not yet supported, we'll use "%f". */ - /* FALLTHROUGH */ - case 'e': - if (ch == 'e') - flags |= PRINT_F_TYPE_E; - /* FALLTHROUGH */ - case 'g': - if (ch == 'g') - flags |= PRINT_F_TYPE_G; - /* FALLTHROUGH */ - case 'f': - if (cflags == PRINT_C_LDOUBLE) - fvalue = va_arg(args, LDOUBLE); - else - fvalue = va_arg(args, double); - fmtflt(str, &len, size, fvalue, width, - precision, flags, &overflow); - if (overflow) - goto out; - break; - case 'c': - cvalue = va_arg(args, int); - OUTCHAR(str, len, size, cvalue); - break; - case 's': - strvalue = va_arg(args, char *); - fmtstr(str, &len, size, strvalue, width, - precision, flags); - break; - case 'p': - /* - * C99 says: "The value of the pointer is - * converted to a sequence of printing - * characters, in an implementation-defined - * manner." (C99: 7.19.6.1, 8) - */ - if ((strvalue = (char*)va_arg(args, void *)) == NULL) - /* - * We use the glibc format. BSD prints - * "0x0", SysV "0". - */ - fmtstr(str, &len, size, "(nil)", width, - -1, flags); - else { - /* - * We use the BSD/glibc format. SysV - * omits the "0x" prefix (which we emit - * using the PRINT_F_NUM flag). - */ - flags |= PRINT_F_NUM; - flags |= PRINT_F_UNSIGNED; - fmtint(str, &len, size, - (UINTPTR_T)strvalue, 16, width, - precision, flags); - } - break; - case 'n': - switch (cflags) { - case PRINT_C_CHAR: - charptr = va_arg(args, signed char *); - *charptr = len; - break; - case PRINT_C_SHORT: - shortptr = va_arg(args, short int *); - *shortptr = len; - break; - case PRINT_C_LONG: - longptr = va_arg(args, long int *); - *longptr = len; - break; - case PRINT_C_LLONG: - llongptr = va_arg(args, LLONG *); - *llongptr = len; - break; - case PRINT_C_SIZE: - /* - * C99 says that with the "z" length - * modifier, "a following `n' conversion - * specifier applies to a pointer to a - * signed integer type corresponding to - * size_t argument." (7.19.6.1, 7) - */ - sizeptr = va_arg(args, SSIZE_T *); - *sizeptr = len; - break; - case PRINT_C_INTMAX: - intmaxptr = va_arg(args, INTMAX_T *); - *intmaxptr = len; - break; - case PRINT_C_PTRDIFF: - ptrdiffptr = va_arg(args, PTRDIFF_T *); - *ptrdiffptr = len; - break; - default: - intptr = va_arg(args, int *); - *intptr = len; - break; - } - break; - case '%': /* Print a "%" character verbatim. */ - OUTCHAR(str, len, size, ch); - break; - default: /* Skip other characters. */ - break; - } - ch = *format++; - state = PRINT_S_DEFAULT; - base = cflags = flags = width = 0; - precision = -1; - break; - } -out: - if (len < size) - str[len] = '\0'; - else if (size > 0) - str[size - 1] = '\0'; - - if (overflow || len > INT_MAX) { - errno = EOVERFLOW; - return -1; - } - return (int)len; -} - -static void -fmtstr(char *str, size_t *len, size_t size, const char *value, int width, - int precision, int flags) -{ - int padlen, strln; /* Amount to pad. */ - int noprecision = (precision == -1); - - if (value == NULL) /* We're forgiving. */ - value = "(null)"; - - /* If a precision was specified, don't read the string past it. */ - for (strln = 0; value[strln] != '\0' && - (noprecision || strln < precision); strln++) - continue; - - if ((padlen = width - strln) < 0) - padlen = 0; - if (flags & PRINT_F_MINUS) /* Left justify. */ - padlen = -padlen; - - while (padlen > 0) { /* Leading spaces. */ - OUTCHAR(str, *len, size, ' '); - padlen--; - } - while (*value != '\0' && (noprecision || precision-- > 0)) { - OUTCHAR(str, *len, size, *value); - value++; - } - while (padlen < 0) { /* Trailing spaces. */ - OUTCHAR(str, *len, size, ' '); - padlen++; - } -} - -static void -fmtint(char *str, size_t *len, size_t size, INTMAX_T value, int base, int width, - int precision, int flags) -{ - UINTMAX_T uvalue; - char iconvert[MAX_CONVERT_LENGTH]; - char sign = 0; - char hexprefix = 0; - int spadlen = 0; /* Amount to space pad. */ - int zpadlen = 0; /* Amount to zero pad. */ - int pos; - int separators = (flags & PRINT_F_QUOTE); - int noprecision = (precision == -1); - - if (flags & PRINT_F_UNSIGNED) - uvalue = value; - else { - uvalue = (value >= 0) ? value : -value; - if (value < 0) - sign = '-'; - else if (flags & PRINT_F_PLUS) /* Do a sign. */ - sign = '+'; - else if (flags & PRINT_F_SPACE) - sign = ' '; - } - - pos = convert(uvalue, iconvert, sizeof(iconvert), base, - flags & PRINT_F_UP); - - if (flags & PRINT_F_NUM && uvalue != 0) { - /* - * C99 says: "The result is converted to an `alternative form'. - * For `o' conversion, it increases the precision, if and only - * if necessary, to force the first digit of the result to be a - * zero (if the value and precision are both 0, a single 0 is - * printed). For `x' (or `X') conversion, a nonzero result has - * `0x' (or `0X') prefixed to it." (7.19.6.1, 6) - */ - switch (base) { - case 8: - if (precision <= pos) - precision = pos + 1; - break; - case 16: - hexprefix = (flags & PRINT_F_UP) ? 'X' : 'x'; - break; - } - } - - if (separators) /* Get the number of group separators we'll print. */ - separators = getnumsep(pos); - - zpadlen = precision - pos - separators; - spadlen = width /* Minimum field width. */ - - separators /* Number of separators. */ - - MAX(precision, pos) /* Number of integer digits. */ - - ((sign != 0) ? 1 : 0) /* Will we print a sign? */ - - ((hexprefix != 0) ? 2 : 0); /* Will we print a prefix? */ - - if (zpadlen < 0) - zpadlen = 0; - if (spadlen < 0) - spadlen = 0; - - /* - * C99 says: "If the `0' and `-' flags both appear, the `0' flag is - * ignored. For `d', `i', `o', `u', `x', and `X' conversions, if a - * precision is specified, the `0' flag is ignored." (7.19.6.1, 6) - */ - if (flags & PRINT_F_MINUS) /* Left justify. */ - spadlen = -spadlen; - else if (flags & PRINT_F_ZERO && noprecision) { - zpadlen += spadlen; - spadlen = 0; - } - while (spadlen > 0) { /* Leading spaces. */ - OUTCHAR(str, *len, size, ' '); - spadlen--; - } - if (sign != 0) /* Sign. */ - OUTCHAR(str, *len, size, sign); - if (hexprefix != 0) { /* A "0x" or "0X" prefix. */ - OUTCHAR(str, *len, size, '0'); - OUTCHAR(str, *len, size, hexprefix); - } - while (zpadlen > 0) { /* Leading zeros. */ - OUTCHAR(str, *len, size, '0'); - zpadlen--; - } - while (pos > 0) { /* The actual digits. */ - pos--; - OUTCHAR(str, *len, size, iconvert[pos]); - if (separators > 0 && pos > 0 && pos % 3 == 0) - printsep(str, len, size); - } - while (spadlen < 0) { /* Trailing spaces. */ - OUTCHAR(str, *len, size, ' '); - spadlen++; - } -} - -static void -fmtflt(char *str, size_t *len, size_t size, LDOUBLE fvalue, int width, - int precision, int flags, int *overflow) -{ - LDOUBLE ufvalue; - UINTMAX_T intpart; - UINTMAX_T fracpart; - UINTMAX_T mask; - const char *infnan = NULL; - char iconvert[MAX_CONVERT_LENGTH]; - char fconvert[MAX_CONVERT_LENGTH]; - char econvert[5]; /* "e-300" (without nul-termination). */ - char esign = 0; - char sign = 0; - int leadfraczeros = 0; - int exponent = 0; - int emitpoint = 0; - int omitzeros = 0; - int omitcount = 0; - int padlen = 0; - int epos = 0; - int fpos = 0; - int ipos = 0; - int separators = (flags & PRINT_F_QUOTE); - int estyle = (flags & PRINT_F_TYPE_E); -#if HAVE_LOCALECONV && HAVE_LCONV_DECIMAL_POINT - struct lconv *lc = localeconv(); -#endif /* HAVE_LOCALECONV && HAVE_LCONV_DECIMAL_POINT */ - - /* - * AIX' man page says the default is 0, but C99 and at least Solaris' - * and NetBSD's man pages say the default is 6, and sprintf(3) on AIX - * defaults to 6. - */ - if (precision == -1) - precision = 6; - - if (fvalue < 0.0) - sign = '-'; - else if (flags & PRINT_F_PLUS) /* Do a sign. */ - sign = '+'; - else if (flags & PRINT_F_SPACE) - sign = ' '; - - if (ISNAN(fvalue)) - infnan = (flags & PRINT_F_UP) ? "NAN" : "nan"; - else if (ISINF(fvalue)) - infnan = (flags & PRINT_F_UP) ? "INF" : "inf"; - - if (infnan != NULL) { - if (sign != 0) - iconvert[ipos++] = sign; - while (*infnan != '\0') - iconvert[ipos++] = *infnan++; - fmtstr(str, len, size, iconvert, width, ipos, flags); - return; - } - - /* "%e" (or "%E") or "%g" (or "%G") conversion. */ - if (flags & PRINT_F_TYPE_E || flags & PRINT_F_TYPE_G) { - if (flags & PRINT_F_TYPE_G) { - /* - * If the precision is zero, it is treated as one (cf. - * C99: 7.19.6.1, 8). - */ - if (precision == 0) - precision = 1; - /* - * For "%g" (and "%G") conversions, the precision - * specifies the number of significant digits, which - * includes the digits in the integer part. The - * conversion will or will not be using "e-style" (like - * "%e" or "%E" conversions) depending on the precision - * and on the exponent. However, the exponent can be - * affected by rounding the converted value, so we'll - * leave this decision for later. Until then, we'll - * assume that we're going to do an "e-style" conversion - * (in order to get the exponent calculated). For - * "e-style", the precision must be decremented by one. - */ - precision--; - /* - * For "%g" (and "%G") conversions, trailing zeros are - * removed from the fractional portion of the result - * unless the "#" flag was specified. - */ - if (!(flags & PRINT_F_NUM)) - omitzeros = 1; - } - exponent = getexponent(fvalue); - estyle = 1; - } - -again: - /* - * Sorry, we only support 9, 19, or 38 digits (that is, the number of - * digits of the 32-bit, the 64-bit, or the 128-bit UINTMAX_MAX value - * minus one) past the decimal point due to our conversion method. - */ - switch (sizeof(UINTMAX_T)) { - case 16: - if (precision > 38) - precision = 38; - break; - case 8: - if (precision > 19) - precision = 19; - break; - default: - if (precision > 9) - precision = 9; - break; - } - - ufvalue = (fvalue >= 0.0) ? fvalue : -fvalue; - if (estyle) /* We want exactly one integer digit. */ - ufvalue /= mypow10(exponent); - - if ((intpart = cast(ufvalue)) == UINTMAX_MAX) { - *overflow = 1; - return; - } - - /* - * Factor of ten with the number of digits needed for the fractional - * part. For example, if the precision is 3, the mask will be 1000. - */ - mask = mypow10(precision); - /* - * We "cheat" by converting the fractional part to integer by - * multiplying by a factor of ten. - */ - if ((fracpart = myround(mask * (ufvalue - intpart))) >= mask) { - /* - * For example, ufvalue = 2.99962, intpart = 2, and mask = 1000 - * (because precision = 3). Now, myround(1000 * 0.99962) will - * return 1000. So, the integer part must be incremented by one - * and the fractional part must be set to zero. - */ - intpart++; - fracpart = 0; - if (estyle && intpart == 10) { - /* - * The value was rounded up to ten, but we only want one - * integer digit if using "e-style". So, the integer - * part must be set to one and the exponent must be - * incremented by one. - */ - intpart = 1; - exponent++; - } - } - - /* - * Now that we know the real exponent, we can check whether or not to - * use "e-style" for "%g" (and "%G") conversions. If we don't need - * "e-style", the precision must be adjusted and the integer and - * fractional parts must be recalculated from the original value. - * - * C99 says: "Let P equal the precision if nonzero, 6 if the precision - * is omitted, or 1 if the precision is zero. Then, if a conversion - * with style `E' would have an exponent of X: - * - * - if P > X >= -4, the conversion is with style `f' (or `F') and - * precision P - (X + 1). - * - * - otherwise, the conversion is with style `e' (or `E') and precision - * P - 1." (7.19.6.1, 8) - * - * Note that we had decremented the precision by one. - */ - if (flags & PRINT_F_TYPE_G && estyle && - precision + 1 > exponent && exponent >= -4) { - precision -= exponent; - estyle = 0; - goto again; - } - - if (estyle) { - if (exponent < 0) { - exponent = -exponent; - esign = '-'; - } else - esign = '+'; - - /* - * Convert the exponent. The sizeof(econvert) is 5. So, the - * econvert buffer can hold e.g. "e+999" and "e-999". We don't - * support an exponent which contains more than three digits. - * Therefore, the following stores are safe. - */ - epos = convert(exponent, econvert, 3, 10, 0); - /* - * C99 says: "The exponent always contains at least two digits, - * and only as many more digits as necessary to represent the - * exponent." (7.19.6.1, 8) - */ - if (epos == 1) - econvert[epos++] = '0'; - econvert[epos++] = esign; - econvert[epos++] = (flags & PRINT_F_UP) ? 'E' : 'e'; - } - - /* Convert the integer part and the fractional part. */ - ipos = convert(intpart, iconvert, sizeof(iconvert), 10, 0); - if (fracpart != 0) /* convert() would return 1 if fracpart == 0. */ - fpos = convert(fracpart, fconvert, sizeof(fconvert), 10, 0); - - leadfraczeros = precision - fpos; - - if (omitzeros) { - if (fpos > 0) /* Omit trailing fractional part zeros. */ - while (omitcount < fpos && fconvert[omitcount] == '0') - omitcount++; - else { /* The fractional part is zero, omit it completely. */ - omitcount = precision; - leadfraczeros = 0; - } - precision -= omitcount; - } - - /* - * Print a decimal point if either the fractional part is non-zero - * and/or the "#" flag was specified. - */ - if (precision > 0 || flags & PRINT_F_NUM) - emitpoint = 1; - if (separators) /* Get the number of group separators we'll print. */ - separators = getnumsep(ipos); - - padlen = width /* Minimum field width. */ - - ipos /* Number of integer digits. */ - - epos /* Number of exponent characters. */ - - precision /* Number of fractional digits. */ - - separators /* Number of group separators. */ - - (emitpoint ? 1 : 0) /* Will we print a decimal point? */ - - ((sign != 0) ? 1 : 0); /* Will we print a sign character? */ - - if (padlen < 0) - padlen = 0; - - /* - * C99 says: "If the `0' and `-' flags both appear, the `0' flag is - * ignored." (7.19.6.1, 6) - */ - if (flags & PRINT_F_MINUS) /* Left justifty. */ - padlen = -padlen; - else if (flags & PRINT_F_ZERO && padlen > 0) { - if (sign != 0) { /* Sign. */ - OUTCHAR(str, *len, size, sign); - sign = 0; - } - while (padlen > 0) { /* Leading zeros. */ - OUTCHAR(str, *len, size, '0'); - padlen--; - } - } - while (padlen > 0) { /* Leading spaces. */ - OUTCHAR(str, *len, size, ' '); - padlen--; - } - if (sign != 0) /* Sign. */ - OUTCHAR(str, *len, size, sign); - while (ipos > 0) { /* Integer part. */ - ipos--; - OUTCHAR(str, *len, size, iconvert[ipos]); - if (separators > 0 && ipos > 0 && ipos % 3 == 0) - printsep(str, len, size); - } - if (emitpoint) { /* Decimal point. */ -#if HAVE_LOCALECONV && HAVE_LCONV_DECIMAL_POINT - if (lc->decimal_point != NULL && *lc->decimal_point != '\0') - OUTCHAR(str, *len, size, *lc->decimal_point); - else /* We'll always print some decimal point character. */ -#endif /* HAVE_LOCALECONV && HAVE_LCONV_DECIMAL_POINT */ - OUTCHAR(str, *len, size, '.'); - } - while (leadfraczeros > 0) { /* Leading fractional part zeros. */ - OUTCHAR(str, *len, size, '0'); - leadfraczeros--; - } - while (fpos > omitcount) { /* The remaining fractional part. */ - fpos--; - OUTCHAR(str, *len, size, fconvert[fpos]); - } - while (epos > 0) { /* Exponent. */ - epos--; - OUTCHAR(str, *len, size, econvert[epos]); - } - while (padlen < 0) { /* Trailing spaces. */ - OUTCHAR(str, *len, size, ' '); - padlen++; - } -} - -static void -printsep(char *str, size_t *len, size_t size) -{ -#if HAVE_LOCALECONV && HAVE_LCONV_THOUSANDS_SEP - struct lconv *lc = localeconv(); - int i; - - if (lc->thousands_sep != NULL) - for (i = 0; lc->thousands_sep[i] != '\0'; i++) - OUTCHAR(str, *len, size, lc->thousands_sep[i]); - else -#endif /* HAVE_LOCALECONV && HAVE_LCONV_THOUSANDS_SEP */ - OUTCHAR(str, *len, size, ','); -} - -static int -getnumsep(int digits) -{ - int separators = (digits - ((digits % 3 == 0) ? 1 : 0)) / 3; -#if HAVE_LOCALECONV && HAVE_LCONV_THOUSANDS_SEP - int strln; - struct lconv *lc = localeconv(); - - /* We support an arbitrary separator length (including zero). */ - if (lc->thousands_sep != NULL) { - for (strln = 0; lc->thousands_sep[strln] != '\0'; strln++) - continue; - separators *= strln; - } -#endif /* HAVE_LOCALECONV && HAVE_LCONV_THOUSANDS_SEP */ - return separators; -} - -static int -getexponent(LDOUBLE value) -{ - LDOUBLE tmp = (value >= 0.0) ? value : -value; - int exponent = 0; - - /* - * We check for LDOUBLE_MAX_10_EXP >= exponent >= LDOUBLE_MIN_10_EXP in - * order to work around possible endless loops which could happen (at - * least) in the second loop (at least) if we're called with an infinite - * value. However, we checked for infinity before calling this function - * using our ISINF() macro, so this might be somewhat paranoid. - */ - while (tmp < 1.0 && tmp > 0.0 && --exponent >= LDOUBLE_MIN_10_EXP) - tmp *= 10; - while (tmp >= 10.0 && ++exponent <= LDOUBLE_MAX_10_EXP) - tmp /= 10; - - return exponent; -} - -static int -convert(UINTMAX_T value, char *buf, size_t size, int base, int caps) -{ - const char *digits = caps ? "0123456789ABCDEF" : "0123456789abcdef"; - size_t pos = 0; - - /* We return an unterminated buffer with the digits in reverse order. */ - do { - buf[pos++] = digits[value % base]; - value /= base; - } while (value != 0 && pos < size); - - return (int)pos; -} - -static UINTMAX_T -cast(LDOUBLE value) -{ - UINTMAX_T result; - - /* - * We check for ">=" and not for ">" because if UINTMAX_MAX cannot be - * represented exactly as an LDOUBLE value (but is less than LDBL_MAX), - * it may be increased to the nearest higher representable value for the - * comparison (cf. C99: 6.3.1.4, 2). It might then equal the LDOUBLE - * value although converting the latter to UINTMAX_T would overflow. - */ - if (value >= static_cast(UINTMAX_MAX)) - return UINTMAX_MAX; - - result = value; - /* - * At least on NetBSD/sparc64 3.0.2 and 4.99.30, casting long double to - * an integer type converts e.g. 1.9 to 2 instead of 1 (which violates - * the standard). Sigh. - */ - return (result <= value) ? result : result - 1; -} - -static UINTMAX_T -myround(LDOUBLE value) -{ - UINTMAX_T intpart = cast(value); - - return ((value -= intpart) < 0.5) ? intpart : intpart + 1; -} - -static LDOUBLE -mypow10(int exponent) -{ - LDOUBLE result = 1; - - while (exponent > 0) { - result *= 10; - exponent--; - } - while (exponent < 0) { - result /= 10; - exponent++; - } - return result; -} -#endif /* !HAVE_VSNPRINTF */ - -#if !HAVE_VASPRINTF -#if NEED_MYMEMCPY -void * -mymemcpy(void *dst, void *src, size_t len) -{ - const char *from = (char*)src; - char *to = (char*)dst; - - /* No need for optimization, we use this only to replace va_copy(3). */ - while (len-- > 0) - *to++ = *from++; - return dst; -} -#endif /* NEED_MYMEMCPY */ - -int -rpl_vasprintf(char **ret, const char *format, va_list ap) -{ - size_t size; - int len; - va_list aq; - - VA_COPY(aq, ap); - len = vsnprintf(NULL, 0, format, aq); - VA_END_COPY(aq); - if (len < 0 || (*ret = (char*)malloc(size = len + 1)) == NULL) - return -1; - return vsnprintf(*ret, size, format, ap); -} -#endif /* !HAVE_VASPRINTF */ - -#if !HAVE_SNPRINTF -#if HAVE_STDARG_H -int -rpl_snprintf(char *str, size_t size, const char *format, ...) -#else -int -rpl_snprintf(va_alist) va_dcl -#endif /* HAVE_STDARG_H */ -{ -#if !HAVE_STDARG_H - char *str; - size_t size; - char *format; -#endif /* HAVE_STDARG_H */ - va_list ap; - int len; - - VA_START(ap, format); - VA_SHIFT(ap, str, char *); - VA_SHIFT(ap, size, size_t); - VA_SHIFT(ap, format, const char *); - len = vsnprintf(str, size, format, ap); - va_end(ap); - return len; -} -#endif /* !HAVE_SNPRINTF */ - -#if !HAVE_ASPRINTF -#if HAVE_STDARG_H -int -rpl_asprintf(char **ret, const char *format, ...) -#else -int -rpl_asprintf(va_alist) va_dcl -#endif /* HAVE_STDARG_H */ -{ -#if !HAVE_STDARG_H - char **ret; - char *format; -#endif /* HAVE_STDARG_H */ - va_list ap; - int len; - - VA_START(ap, format); - VA_SHIFT(ap, ret, char **); - VA_SHIFT(ap, format, const char *); - len = vasprintf(ret, format, ap); - va_end(ap); - return len; -} -#endif /* !HAVE_ASPRINTF */ -#else /* Dummy declaration to avoid empty translation unit warnings. */ -int main(int argc, char **argv); -#endif /* !HAVE_SNPRINTF || !HAVE_VSNPRINTF || !HAVE_ASPRINTF || [...] */ - -#if TEST_SNPRINTF -int -main(void) -{ - const char *float_fmt[] = { - /* "%E" and "%e" formats. */ -#if HAVE_LONG_LONG_INT && !OS_BSD && !OS_IRIX - "%.16e", - "%22.16e", - "%022.16e", - "%-22.16e", - "%#+'022.16e", -#endif /* HAVE_LONG_LONG_INT && !OS_BSD && !OS_IRIX */ - "foo|%#+0123.9E|bar", - "%-123.9e", - "%123.9e", - "%+23.9e", - "%+05.8e", - "%-05.8e", - "%05.8e", - "%+5.8e", - "%-5.8e", - "% 5.8e", - "%5.8e", - "%+4.9e", -#if !OS_LINUX /* glibc sometimes gets these wrong. */ - "%+#010.0e", - "%#10.1e", - "%10.5e", - "% 10.5e", - "%5.0e", - "%5.e", - "%#5.0e", - "%#5.e", - "%3.2e", - "%3.1e", - "%-1.5e", - "%1.5e", - "%01.3e", - "%1.e", - "%.1e", - "%#.0e", - "%+.0e", - "% .0e", - "%.0e", - "%#.e", - "%+.e", - "% .e", - "%.e", - "%4e", - "%e", - "%E", -#endif /* !OS_LINUX */ - /* "%F" and "%f" formats. */ -#if !OS_BSD && !OS_IRIX - "% '022f", - "%+'022f", - "%-'22f", - "%'22f", -#if HAVE_LONG_LONG_INT - "%.16f", - "%22.16f", - "%022.16f", - "%-22.16f", - "%#+'022.16f", -#endif /* HAVE_LONG_LONG_INT */ -#endif /* !OS_BSD && !OS_IRIX */ - "foo|%#+0123.9F|bar", - "%-123.9f", - "%123.9f", - "%+23.9f", - "%+#010.0f", - "%#10.1f", - "%10.5f", - "% 10.5f", - "%+05.8f", - "%-05.8f", - "%05.8f", - "%+5.8f", - "%-5.8f", - "% 5.8f", - "%5.8f", - "%5.0f", - "%5.f", - "%#5.0f", - "%#5.f", - "%+4.9f", - "%3.2f", - "%3.1f", - "%-1.5f", - "%1.5f", - "%01.3f", - "%1.f", - "%.1f", - "%#.0f", - "%+.0f", - "% .0f", - "%.0f", - "%#.f", - "%+.f", - "% .f", - "%.f", - "%4f", - "%f", - "%F", - /* "%G" and "%g" formats. */ -#if !OS_BSD && !OS_IRIX && !OS_LINUX - "% '022g", - "%+'022g", - "%-'22g", - "%'22g", -#if HAVE_LONG_LONG_INT - "%.16g", - "%22.16g", - "%022.16g", - "%-22.16g", - "%#+'022.16g", -#endif /* HAVE_LONG_LONG_INT */ -#endif /* !OS_BSD && !OS_IRIX && !OS_LINUX */ - "foo|%#+0123.9G|bar", - "%-123.9g", - "%123.9g", - "%+23.9g", - "%+05.8g", - "%-05.8g", - "%05.8g", - "%+5.8g", - "%-5.8g", - "% 5.8g", - "%5.8g", - "%+4.9g", -#if !OS_LINUX /* glibc sometimes gets these wrong. */ - "%+#010.0g", - "%#10.1g", - "%10.5g", - "% 10.5g", - "%5.0g", - "%5.g", - "%#5.0g", - "%#5.g", - "%3.2g", - "%3.1g", - "%-1.5g", - "%1.5g", - "%01.3g", - "%1.g", - "%.1g", - "%#.0g", - "%+.0g", - "% .0g", - "%.0g", - "%#.g", - "%+.g", - "% .g", - "%.g", - "%4g", - "%g", - "%G", -#endif /* !OS_LINUX */ - NULL - }; - double float_val[] = { - -4.136, - -134.52, - -5.04030201, - -3410.01234, - -999999.999999, - -913450.29876, - -913450.2, - -91345.2, - -9134.2, - -913.2, - -91.2, - -9.2, - -9.9, - 4.136, - 134.52, - 5.04030201, - 3410.01234, - 999999.999999, - 913450.29876, - 913450.2, - 91345.2, - 9134.2, - 913.2, - 91.2, - 9.2, - 9.9, - 9.96, - 9.996, - 9.9996, - 9.99996, - 9.999996, - 9.9999996, - 9.99999996, - 0.99999996, - 0.99999999, - 0.09999999, - 0.00999999, - 0.00099999, - 0.00009999, - 0.00000999, - 0.00000099, - 0.00000009, - 0.00000001, - 0.0000001, - 0.000001, - 0.00001, - 0.0001, - 0.001, - 0.01, - 0.1, - 1.0, - 1.5, - -1.5, - -1.0, - -0.1, -#if !OS_BSD /* BSD sometimes gets these wrong. */ -#ifdef INFINITY - INFINITY, - -INFINITY, -#endif /* defined(INFINITY) */ -#ifdef NAN - NAN, -#endif /* defined(NAN) */ -#endif /* !OS_BSD */ - 0 - }; - const char *long_fmt[] = { - "foo|%0123ld|bar", -#if !OS_IRIX - "% '0123ld", - "%+'0123ld", - "%-'123ld", - "%'123ld", -#endif /* !OS_IRiX */ - "%123.9ld", - "% 123.9ld", - "%+123.9ld", - "%-123.9ld", - "%0123ld", - "% 0123ld", - "%+0123ld", - "%-0123ld", - "%10.5ld", - "% 10.5ld", - "%+10.5ld", - "%-10.5ld", - "%010ld", - "% 010ld", - "%+010ld", - "%-010ld", - "%4.2ld", - "% 4.2ld", - "%+4.2ld", - "%-4.2ld", - "%04ld", - "% 04ld", - "%+04ld", - "%-04ld", - "%5.5ld", - "%+22.33ld", - "%01.3ld", - "%1.5ld", - "%-1.5ld", - "%44ld", - "%4ld", - "%4.0ld", - "%4.ld", - "%.44ld", - "%.4ld", - "%.0ld", - "%.ld", - "%ld", - NULL - }; - long int long_val[] = { -#ifdef LONG_MAX - LONG_MAX, -#endif /* LONG_MAX */ -#ifdef LONG_MIN - LONG_MIN, -#endif /* LONG_MIN */ - -91340, - 91340, - 341, - 134, - 0203, - -1, - 1, - 0 - }; - const char *ulong_fmt[] = { - /* "%u" formats. */ - "foo|%0123lu|bar", -#if !OS_IRIX - "% '0123lu", - "%+'0123lu", - "%-'123lu", - "%'123lu", -#endif /* !OS_IRiX */ - "%123.9lu", - "% 123.9lu", - "%+123.9lu", - "%-123.9lu", - "%0123lu", - "% 0123lu", - "%+0123lu", - "%-0123lu", - "%5.5lu", - "%+22.33lu", - "%01.3lu", - "%1.5lu", - "%-1.5lu", - "%44lu", - "%lu", - /* "%o" formats. */ - "foo|%#0123lo|bar", - "%#123.9lo", - "%# 123.9lo", - "%#+123.9lo", - "%#-123.9lo", - "%#0123lo", - "%# 0123lo", - "%#+0123lo", - "%#-0123lo", - "%#5.5lo", - "%#+22.33lo", - "%#01.3lo", - "%#1.5lo", - "%#-1.5lo", - "%#44lo", - "%#lo", - "%123.9lo", - "% 123.9lo", - "%+123.9lo", - "%-123.9lo", - "%0123lo", - "% 0123lo", - "%+0123lo", - "%-0123lo", - "%5.5lo", - "%+22.33lo", - "%01.3lo", - "%1.5lo", - "%-1.5lo", - "%44lo", - "%lo", - /* "%X" and "%x" formats. */ - "foo|%#0123lX|bar", - "%#123.9lx", - "%# 123.9lx", - "%#+123.9lx", - "%#-123.9lx", - "%#0123lx", - "%# 0123lx", - "%#+0123lx", - "%#-0123lx", - "%#5.5lx", - "%#+22.33lx", - "%#01.3lx", - "%#1.5lx", - "%#-1.5lx", - "%#44lx", - "%#lx", - "%#lX", - "%123.9lx", - "% 123.9lx", - "%+123.9lx", - "%-123.9lx", - "%0123lx", - "% 0123lx", - "%+0123lx", - "%-0123lx", - "%5.5lx", - "%+22.33lx", - "%01.3lx", - "%1.5lx", - "%-1.5lx", - "%44lx", - "%lx", - "%lX", - NULL - }; - unsigned long int ulong_val[] = { -#ifdef ULONG_MAX - ULONG_MAX, -#endif /* ULONG_MAX */ - 91340, - 341, - 134, - 0203, - 1, - 0 - }; - const char *llong_fmt[] = { - "foo|%0123lld|bar", - "%123.9lld", - "% 123.9lld", - "%+123.9lld", - "%-123.9lld", - "%0123lld", - "% 0123lld", - "%+0123lld", - "%-0123lld", - "%5.5lld", - "%+22.33lld", - "%01.3lld", - "%1.5lld", - "%-1.5lld", - "%44lld", - "%lld", - NULL - }; - LLONG llong_val[] = { -#ifdef LLONG_MAX - LLONG_MAX, -#endif /* LLONG_MAX */ -#ifdef LLONG_MIN - LLONG_MIN, -#endif /* LLONG_MIN */ - -91340, - 91340, - 341, - 134, - 0203, - -1, - 1, - 0 - }; - const char *string_fmt[] = { - "foo|%10.10s|bar", - "%-10.10s", - "%10.10s", - "%10.5s", - "%5.10s", - "%10.1s", - "%1.10s", - "%10.0s", - "%0.10s", - "%-42.5s", - "%2.s", - "%.10s", - "%.1s", - "%.0s", - "%.s", - "%4s", - "%s", - NULL - }; - const char *string_val[] = { - "Hello", - "Hello, world!", - "Sound check: One, two, three.", - "This string is a little longer than the other strings.", - "1", - "", - NULL - }; -#if !OS_SYSV /* SysV uses a different format than we do. */ - const char *pointer_fmt[] = { - "foo|%p|bar", - "%42p", - "%p", - NULL - }; - const char *pointer_val[] = { - *pointer_fmt, - *string_fmt, - *string_val, - NULL - }; -#endif /* !OS_SYSV */ - char buf1[1024], buf2[1024]; - double value, digits = 9.123456789012345678901234567890123456789; - int i, j, r1, r2, failed = 0, num = 0; - -/* - * Use -DTEST_NILS in order to also test the conversion of nil values. Might - * segfault on systems which don't support converting a NULL pointer with "%s" - * and lets some test cases fail against BSD and glibc due to bugs in their - * implementations. - */ -#ifndef TEST_NILS -#define TEST_NILS 0 -#elif TEST_NILS -#undef TEST_NILS -#define TEST_NILS 1 -#endif /* !defined(TEST_NILS) */ -#ifdef TEST -#undef TEST -#endif /* defined(TEST) */ -#define TEST(fmt, val) \ -do { \ - for (i = 0; fmt[i] != NULL; i++) \ - for (j = 0; j == 0 || val[j - TEST_NILS] != 0; j++) { \ - r1 = sprintf(buf1, fmt[i], val[j]); \ - r2 = snprintf(buf2, sizeof(buf2), fmt[i], val[j]); \ - if (strcmp(buf1, buf2) != 0 || r1 != r2) { \ - (void)printf("Results don't match, " \ - "format string: %s\n" \ - "\t sprintf(3): [%s] (%d)\n" \ - "\tsnprintf(3): [%s] (%d)\n", \ - fmt[i], buf1, r1, buf2, r2); \ - failed++; \ - } \ - num++; \ - } \ -} while (/* CONSTCOND */ 0) - -#if HAVE_LOCALE_H - (void)setlocale(LC_ALL, ""); -#endif /* HAVE_LOCALE_H */ - - (void)puts("Testing our snprintf(3) against your system's sprintf(3)."); - TEST(float_fmt, float_val); - TEST(long_fmt, long_val); - TEST(ulong_fmt, ulong_val); - TEST(llong_fmt, llong_val); - TEST(string_fmt, string_val); -#if !OS_SYSV /* SysV uses a different format than we do. */ - TEST(pointer_fmt, pointer_val); -#endif /* !OS_SYSV */ - (void)printf("Result: %d out of %d tests failed.\n", failed, num); - - (void)fputs("Checking how many digits we support: ", stdout); - for (i = 0; i < 100; i++) { - value = pow(10, i) * digits; - (void)sprintf(buf1, "%.1f", value); - (void)snprintf(buf2, sizeof(buf2), "%.1f", value); - if (strcmp(buf1, buf2) != 0) { - (void)printf("apparently %d.\n", i); - break; - } - } - return (failed == 0) ? 0 : 1; -} -#endif /* TEST_SNPRINTF */ - -#endif // KONAN_INTERNAL_SNPRINTF -/* vim: set joinspaces noexpandtab textwidth=80 cinoptions=(4,u0: */ diff --git a/kotlin-native/runtime/src/main/cpp/std_support/CStdlib.cpp b/kotlin-native/runtime/src/main/cpp/std_support/CStdlib.cpp index 2a61b628ea5..f69514407e0 100644 --- a/kotlin-native/runtime/src/main/cpp/std_support/CStdlib.cpp +++ b/kotlin-native/runtime/src/main/cpp/std_support/CStdlib.cpp @@ -7,6 +7,7 @@ #include #include +#include #include #include "Alignment.hpp" @@ -14,123 +15,29 @@ using namespace kotlin; -#if KONAN_INTERNAL_DLMALLOC -extern "C" void* dlmalloc(size_t); -extern "C" void* dlcalloc(size_t, size_t); -extern "C" void* dlrealloc(void*, size_t); -extern "C" void* dlmemalign(size_t, size_t); -extern "C" void dlfree(void*); - -#define malloc_impl dlmalloc -#define aligned_malloc_impl dlmemalign -#define calloc_impl dlcalloc -#define realloc_impl dlrealloc -#define free_impl dlfree -#define aligned_free_impl dlfree -#else -#include - -#define malloc_impl std::malloc -#define aligned_malloc_impl(alignment, size) ::_mm_malloc(size, alignment) -#define calloc_impl std::calloc -#define realloc_impl std::realloc -#define free_impl std::free -#define aligned_free_impl ::_mm_free -#endif - void* std_support::malloc(std::size_t size) noexcept { - return malloc_impl(size); + return std::malloc(size); } void* std_support::aligned_malloc(std::size_t alignment, std::size_t size) noexcept { // Enforcing alignment requirements of std::aligned_alloc. RuntimeAssert(IsValidAlignment(alignment), "Invalid alignment %zu", alignment); RuntimeAssert(IsAligned(size, alignment), "Size %zu must be aligned to %zu", size, alignment); - return aligned_malloc_impl(alignment, size); + return ::_mm_malloc(size, alignment); } void* std_support::calloc(std::size_t num, std::size_t size) noexcept { - return calloc_impl(num, size); + return std::calloc(num, size); } void* std_support::realloc(void* ptr, std::size_t size) noexcept { - return realloc_impl(ptr, size); + return std::realloc(ptr, size); } void std_support::free(void* ptr) noexcept { - return free_impl(ptr); + return std::free(ptr); } void std_support::aligned_free(void* ptr) noexcept { - return aligned_free_impl(ptr); + return ::_mm_free(ptr); } - -namespace konan { - -#if KONAN_INTERNAL_DLMALLOC -// This function is being called when memory allocator needs more RAM. - -#if KONAN_WASM - -namespace { - -constexpr uint32_t MFAIL = ~(uint32_t)0; -constexpr uint32_t WASM_PAGESIZE_EXPONENT = 16; -constexpr uint32_t WASM_PAGESIZE = 1u << WASM_PAGESIZE_EXPONENT; -constexpr uint32_t WASM_PAGEMASK = WASM_PAGESIZE - 1; - -uint32_t pageAlign(int32_t value) { - return (value + WASM_PAGEMASK) & ~(WASM_PAGEMASK); -} - -uint32_t inBytes(uint32_t pageCount) { - return pageCount << WASM_PAGESIZE_EXPONENT; -} - -uint32_t inPages(uint32_t value) { - return value >> WASM_PAGESIZE_EXPONENT; -} - -extern "C" void Konan_notify_memory_grow(); - -uint32_t memorySize() { - return __builtin_wasm_memory_size(0); -} - -int32_t growMemory(uint32_t delta) { - int32_t oldLength = __builtin_wasm_memory_grow(0, delta); - Konan_notify_memory_grow(); - return oldLength; -} - -} // namespace - -void* moreCore(int32_t delta) { - uint32_t top = inBytes(memorySize()); - if (delta > 0) { - if (growMemory(inPages(pageAlign(delta))) == 0) { - return (void*)MFAIL; - } - } else if (delta < 0) { - return (void*)MFAIL; - } - return (void*)top; -} - -// dlmalloc() wants to know the page size. -long getpagesize() { - return WASM_PAGESIZE; -} - -#else -void* moreCore(int size) { - return sbrk(size); -} - -long getpagesize() { - return sysconf(_SC_PAGESIZE); -} -#endif -#endif - -} // namespace konan diff --git a/kotlin-native/runtime/src/main/cpp/std_support/Memory.hpp b/kotlin-native/runtime/src/main/cpp/std_support/Memory.hpp index f93f098d4be..85a95c862b1 100644 --- a/kotlin-native/runtime/src/main/cpp/std_support/Memory.hpp +++ b/kotlin-native/runtime/src/main/cpp/std_support/Memory.hpp @@ -57,10 +57,6 @@ T* allocator_new(const Allocator& allocator, Args&&... args) { auto a = TAllocator(allocator); T* ptr = TAllocatorTraits::allocate(a, 1); -#if KONAN_NO_EXCEPTIONS - TAllocatorTraits::construct(a, ptr, std::forward(args)...); - return ptr; -#else try { TAllocatorTraits::construct(a, ptr, std::forward(args)...); return ptr; @@ -68,7 +64,6 @@ T* allocator_new(const Allocator& allocator, Args&&... args) { TAllocatorTraits::deallocate(a, ptr, 1); throw; } -#endif } template diff --git a/kotlin-native/runtime/src/main/cpp/std_support/Optional.hpp b/kotlin-native/runtime/src/main/cpp/std_support/Optional.hpp deleted file mode 100644 index be6e38a0794..00000000000 --- a/kotlin-native/runtime/src/main/cpp/std_support/Optional.hpp +++ /dev/null @@ -1,20 +0,0 @@ -/* - * Copyright 2010-2022 JetBrains s.r.o. and Kotlin Programming Language contributors. - * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. - */ - -#pragma once - -#if __has_include() -#include -#elif __has_include() -// TODO: Remove when wasm32 is gone. -#include -namespace std { -template -using optional = std::experimental::optional; -inline constexpr auto nullopt = std::experimental::nullopt; -} // namespace std -#else -#error "No " -#endif diff --git a/kotlin-native/runtime/src/main/cpp/std_support/README.md b/kotlin-native/runtime/src/main/cpp/std_support/README.md index 1de7b8fca0e..47babf6d681 100644 --- a/kotlin-native/runtime/src/main/cpp/std_support/README.md +++ b/kotlin-native/runtime/src/main/cpp/std_support/README.md @@ -25,4 +25,3 @@ Adjustments: `std_support::kdelete` as a replacement for operator `delete` for objects created with custom `new`. * `Deque.hpp`, `ForwardList.hpp`, `List.hpp`, `Map.hpp`, `Set.hpp`, `String.hpp`, `UnorderedMap.hpp`, `UnorderedSet.hpp`, `Vector.hpp` - standard containers and `std_support::string` that default to using `std_support::allocator`. -* `Optional.hpp` - wrapper choosing correct way to include on different platforms. \ No newline at end of file diff --git a/kotlin-native/runtime/src/main/cpp/utf8.h b/kotlin-native/runtime/src/main/cpp/utf8.h index 8c7a1dc694c..050cf9f4122 100644 --- a/kotlin-native/runtime/src/main/cpp/utf8.h +++ b/kotlin-native/runtime/src/main/cpp/utf8.h @@ -31,8 +31,6 @@ DEALINGS IN THE SOFTWARE. #include "utf8/unchecked.h" #include "utf8/with_replacement.h" -#if !KONAN_NO_EXCEPTIONS #include "utf8/checked.h" -#endif #endif // header guard diff --git a/kotlin-native/runtime/src/mm/cpp/CallsChecker.cpp b/kotlin-native/runtime/src/mm/cpp/CallsChecker.cpp index 98086477d1b..6c70ba0d176 100644 --- a/kotlin-native/runtime/src/mm/cpp/CallsChecker.cpp +++ b/kotlin-native/runtime/src/mm/cpp/CallsChecker.cpp @@ -5,7 +5,6 @@ #include "CallsChecker.hpp" -#ifndef KONAN_NO_EXTERNAL_CALLS_CHECKER #include #include @@ -373,8 +372,3 @@ extern "C" RUNTIME_NOTHROW RUNTIME_NODEBUG void Kotlin_mm_checkStateAtExternalFu CallsCheckerIgnoreGuard::CallsCheckerIgnoreGuard() noexcept { ++ignoreGuardsCount; } CallsCheckerIgnoreGuard::~CallsCheckerIgnoreGuard() { --ignoreGuardsCount; } - -#else -kotlin::CallsCheckerIgnoreGuard::CallsCheckerIgnoreGuard() noexcept {} -kotlin::CallsCheckerIgnoreGuard::~CallsCheckerIgnoreGuard() {} -#endif // KONAN_NO_EXTERNAL_CALLS_CHECKER diff --git a/kotlin-native/runtime/src/mm/cpp/ExceptionObjHolder.cpp b/kotlin-native/runtime/src/mm/cpp/ExceptionObjHolder.cpp index 027470f2692..312dbf9c0e0 100644 --- a/kotlin-native/runtime/src/mm/cpp/ExceptionObjHolder.cpp +++ b/kotlin-native/runtime/src/mm/cpp/ExceptionObjHolder.cpp @@ -13,7 +13,6 @@ using namespace kotlin; namespace { -#if !KONAN_NO_EXCEPTIONS class ExceptionObjHolderImpl : public ExceptionObjHolder, private Pinned { public: explicit ExceptionObjHolderImpl(ObjHeader* obj) noexcept : stableRef_(mm::StableRef::create(obj)) {} @@ -25,11 +24,9 @@ public: private: mm::StableRef stableRef_; }; -#endif } // namespace -#if !KONAN_NO_EXCEPTIONS // static RUNTIME_NORETURN void ExceptionObjHolder::Throw(ObjHeader* exception) { throw ExceptionObjHolderImpl(exception); @@ -38,4 +35,3 @@ RUNTIME_NORETURN void ExceptionObjHolder::Throw(ObjHeader* exception) { ObjHeader* ExceptionObjHolder::GetExceptionObject() noexcept { return static_cast(this)->obj(); } -#endif diff --git a/native/utils/src/org/jetbrains/kotlin/konan/target/ClangArgs.kt b/native/utils/src/org/jetbrains/kotlin/konan/target/ClangArgs.kt index 84fd1f6060a..42dd318bfd6 100644 --- a/native/utils/src/org/jetbrains/kotlin/konan/target/ClangArgs.kt +++ b/native/utils/src/org/jetbrains/kotlin/konan/target/ClangArgs.kt @@ -43,8 +43,6 @@ sealed class ClangArgs( "WINDOWS".takeIf { target.family == Family.MINGW }, "MACOSX".takeIf { target.family == Family.OSX }, - "NO_THREADS".takeUnless { target.supportsThreads() }, - "NO_EXCEPTIONS".takeUnless { target.supportsExceptions() }, "NO_MEMMEM".takeUnless { target.suportsMemMem() }, "NO_64BIT_ATOMIC".takeUnless { target.supports64BitAtomics() }, "NO_UNALIGNED_ACCESS".takeUnless { target.supportsUnalignedAccess() }, @@ -55,7 +53,6 @@ sealed class ClangArgs( "HAS_UIKIT_FRAMEWORK".takeIf { target.hasUIKitFramework() }, "REPORT_BACKTRACE_TO_IOS_CRASH_LOG".takeIf { target.supportsIosCrashLog() }, "NEED_SMALL_BINARY".takeIf { target.needSmallBinary() }, - "TARGET_HAS_ADDRESS_DEPENDENCY".takeIf { target.hasAddressDependencyInMemoryModel() }, "SUPPORTS_GRAND_CENTRAL_DISPATCH".takeIf { target.supportsGrandCentralDispatch }, ).map { "KONAN_$it=1" } val otherOptions = listOfNotNull( @@ -71,8 +68,7 @@ sealed class ClangArgs( // so just undefine it. "NS_FORMAT_ARGUMENT(A)=".takeIf { target.family.isAppleFamily }, ) - val customOptions = target.customArgsForKonanSources() - return (konanOptions + otherOptions + customOptions).map { "-D$it" } + return (konanOptions + otherOptions).map { "-D$it" } } private val binDir = when (HostManager.host) { diff --git a/native/utils/src/org/jetbrains/kotlin/konan/target/KonanTargetExtenstions.kt b/native/utils/src/org/jetbrains/kotlin/konan/target/KonanTargetExtenstions.kt index 6a31013d607..a7be1169174 100644 --- a/native/utils/src/org/jetbrains/kotlin/konan/target/KonanTargetExtenstions.kt +++ b/native/utils/src/org/jetbrains/kotlin/konan/target/KonanTargetExtenstions.kt @@ -177,26 +177,3 @@ val KonanTarget.supportsGrandCentralDispatch Family.WATCHOS, Family.IOS, Family.TVOS, Family.OSX -> true else -> false } - -// TODO: this is bad function. It should be replaced by capabilities functions like above -// but two affected targets are too strange, so we postpone it -fun KonanTarget.customArgsForKonanSources() = when (this) { - KonanTarget.WASM32 -> listOf( - "KONAN_NO_FFI=1", - "KONAN_INTERNAL_DLMALLOC=1", - "KONAN_INTERNAL_SNPRINTF=1", - "KONAN_INTERNAL_NOW=1", - "KONAN_NO_CTORS_SECTION=1", - "KONAN_NO_BACKTRACE=1", - "KONAN_NO_EXTERNAL_CALLS_CHECKER=1", - ) - is KonanTarget.ZEPHYR -> listOf( - "KONAN_NO_FFI=1", - "KONAN_NO_MATH=1", - "KONAN_INTERNAL_SNPRINTF=1", - "KONAN_INTERNAL_NOW=1", - "KONAN_NO_CTORS_SECTION=1", - "KONAN_NO_BACKTRACE=1" - ) - else -> emptyList() -} \ No newline at end of file