bmalloc-7603.1.30.0.34

This commit is contained in:
Andrew Hyatt 2017-08-12 10:26:17 -07:00
parent f1047d896b
commit b2e63a5448
58 changed files with 12156 additions and 0 deletions

35
CMakeLists.txt Normal file
View File

@ -0,0 +1,35 @@
set_property(DIRECTORY . PROPERTY FOLDER "bmalloc")
set(bmalloc_INCLUDE_DIRECTORIES
"${BMALLOC_DIR}"
)
set(bmalloc_SOURCES
bmalloc/Allocator.cpp
bmalloc/Cache.cpp
bmalloc/Deallocator.cpp
bmalloc/Environment.cpp
bmalloc/Heap.cpp
bmalloc/LargeMap.cpp
bmalloc/Logging.cpp
bmalloc/ObjectType.cpp
bmalloc/StaticMutex.cpp
bmalloc/VMHeap.cpp
bmalloc/mbmalloc.cpp
)
if (CMAKE_SYSTEM_NAME MATCHES "Darwin")
list(APPEND bmalloc_SOURCES
bmalloc/Zone.cpp
)
endif ()
set(bmalloc_LIBRARIES
${CMAKE_DL_LIBS}
)
WEBKIT_WRAP_SOURCELIST(${bmalloc_SOURCES})
include_directories(${bmalloc_INCLUDE_DIRECTORIES})
add_library(bmalloc STATIC ${bmalloc_SOURCES})
target_link_libraries(bmalloc ${bmalloc_LIBRARIES})
set_target_properties(bmalloc PROPERTIES COMPILE_DEFINITIONS "BUILDING_bmalloc")

6129
ChangeLog Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,115 @@
// Copyright (C) 2009, 2010, 2011, 2013 Apple Inc. All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions
// are met:
// 1. Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// 2. Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
// OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "../../../../Internal/Configurations/HaveInternalSDK.xcconfig"
USE_INTERNAL_SDK = $(USE_INTERNAL_SDK_$(CONFIGURATION));
USE_INTERNAL_SDK_Production = YES;
USE_INTERNAL_SDK_Debug = $(HAVE_INTERNAL_SDK);
USE_INTERNAL_SDK_Release = $(HAVE_INTERNAL_SDK);
CLANG_CXX_LANGUAGE_STANDARD = gnu++14;
CLANG_CXX_LIBRARY = libc++;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_CXX0X_EXTENSIONS = NO;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INFINITE_RECURSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_SUSPICIOUS_MOVE = YES;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
DEBUG_INFORMATION_FORMAT = dwarf-with-dsym;
GCC_C_LANGUAGE_STANDARD = gnu99;
GCC_DEBUGGING_SYMBOLS = default;
GCC_DYNAMIC_NO_PIC = NO;
GCC_ENABLE_CPP_EXCEPTIONS = NO;
GCC_ENABLE_CPP_RTTI = NO;
GCC_ENABLE_OBJC_EXCEPTIONS = YES;
GCC_ENABLE_SYMBOL_SEPARATION = NO;
GCC_FAST_OBJC_DISPATCH = YES;
GCC_GENERATE_DEBUGGING_SYMBOLS = YES;
GCC_INLINES_ARE_PRIVATE_EXTERN = YES;
GCC_NO_COMMON_BLOCKS = YES;
GCC_OBJC_CALL_CXX_CDTORS = YES;
GCC_PRECOMPILE_PREFIX_HEADER = YES;
ENABLE_STRICT_OBJC_MSGSEND = YES;
GCC_PREPROCESSOR_DEFINITIONS = $(DEBUG_DEFINES) $(inherited);
GCC_STRICT_ALIASING = YES;
GCC_THREADSAFE_STATICS = NO;
GCC_TREAT_WARNINGS_AS_ERRORS = YES;
GCC_VERSION = com.apple.compilers.llvm.clang.1_0;
// FIXME: <http://webkit.org/b/107093> WTF should build with -Wshorten-64-to-32
GCC_WARN_64_TO_32_BIT_CONVERSION = $(GCC_WARN_64_TO_32_BIT_CONVERSION_$(CURRENT_ARCH));
GCC_WARN_64_TO_32_BIT_CONVERSION_ = YES;
GCC_WARN_64_TO_32_BIT_CONVERSION_armv7 = YES;
GCC_WARN_64_TO_32_BIT_CONVERSION_armv7k = YES;
GCC_WARN_64_TO_32_BIT_CONVERSION_armv7s = YES;
GCC_WARN_64_TO_32_BIT_CONVERSION_arm64 = NO;
GCC_WARN_64_TO_32_BIT_CONVERSION_i386 = YES;
GCC_WARN_64_TO_32_BIT_CONVERSION_x86_64 = NO;
GCC_WARN_ABOUT_DEPRECATED_FUNCTIONS = NO;
GCC_WARN_ABOUT_MISSING_NEWLINE = YES;
GCC_WARN_ABOUT_MISSING_PROTOTYPES = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES;
GCC_WARN_NON_VIRTUAL_DESTRUCTOR = YES;
GCC_WARN_SIGN_COMPARE = YES;
GCC_WARN_UNDECLARED_SELECTOR = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
PREBINDING = NO;
WARNING_CFLAGS = -Wall -Wextra -Wcast-qual -Wchar-subscripts -Wextra-tokens -Wformat=2 -Winit-self -Wmissing-format-attribute -Wmissing-noreturn -Wpacked -Wpointer-arith -Wredundant-decls -Wundef -Wwrite-strings -Wexit-time-destructors -Wglobal-constructors -Wtautological-compare -Wimplicit-fallthrough;
TARGET_MAC_OS_X_VERSION_MAJOR = $(TARGET_MAC_OS_X_VERSION_MAJOR$(MACOSX_DEPLOYMENT_TARGET:suffix:identifier));
TARGET_MAC_OS_X_VERSION_MAJOR_10 = 101000;
TARGET_MAC_OS_X_VERSION_MAJOR_11 = 101100;
TARGET_MAC_OS_X_VERSION_MAJOR_12 = 101200;
TARGET_MAC_OS_X_VERSION_MAJOR_13 = 101300;
SUPPORTED_PLATFORMS = iphoneos iphonesimulator macosx appletvos appletvsimulator watchos watchsimulator;
// DEBUG_DEFINES, GCC_OPTIMIZATION_LEVEL, STRIP_INSTALLED_PRODUCT and DEAD_CODE_STRIPPING vary between the debug and normal variants.
// We set up the values for each variant here, and have the Debug configuration in the Xcode project use the _debug variant.
DEBUG_DEFINES_debug = ;
DEBUG_DEFINES_normal = NDEBUG;
DEBUG_DEFINES = $(DEBUG_DEFINES_$(CURRENT_VARIANT));
GCC_OPTIMIZATION_LEVEL = $(GCC_OPTIMIZATION_LEVEL_$(CURRENT_VARIANT));
GCC_OPTIMIZATION_LEVEL_normal = 3;
GCC_OPTIMIZATION_LEVEL_debug = 0;
STRIP_INSTALLED_PRODUCT = $(STRIP_INSTALLED_PRODUCT_$(CURRENT_VARIANT));
STRIP_INSTALLED_PRODUCT_normal = YES;
STRIP_INSTALLED_PRODUCT_debug = NO;
DEAD_CODE_STRIPPING_debug = NO;
DEAD_CODE_STRIPPING_normal = YES;
DEAD_CODE_STRIPPING = $(DEAD_CODE_STRIPPING_$(CURRENT_VARIANT));
SDKROOT = macosx.internal;
OTHER_CFLAGS = $(ASAN_OTHER_CFLAGS);
OTHER_CPLUSPLUSFLAGS = $(ASAN_OTHER_CPLUSPLUSFLAGS);
OTHER_LDFLAGS = $(ASAN_OTHER_LDFLAGS);

View File

@ -0,0 +1,42 @@
// Copyright (C) 2009, 2010, 2013 Apple Inc. All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions
// are met:
// 1. Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// 2. Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
// OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "Base.xcconfig"
ARCHS = $(ARCHS_STANDARD_32_64_BIT);
ONLY_ACTIVE_ARCH = YES;
TARGET_MAC_OS_X_VERSION_MAJOR = $(MAC_OS_X_VERSION_MAJOR);
MACOSX_DEPLOYMENT_TARGET = $(MACOSX_DEPLOYMENT_TARGET_$(PLATFORM_NAME)_$(TARGET_MAC_OS_X_VERSION_MAJOR));
MACOSX_DEPLOYMENT_TARGET_macosx_101000 = 10.10;
MACOSX_DEPLOYMENT_TARGET_macosx_101100 = 10.11;
MACOSX_DEPLOYMENT_TARGET_macosx_101200 = 10.12;
MACOSX_DEPLOYMENT_TARGET_macosx_101300 = 10.13;
GCC_WARN_ABOUT_DEPRECATED_FUNCTIONS = YES;
DEBUG_INFORMATION_FORMAT = dwarf;
SDKROOT = $(SDKROOT_$(USE_INTERNAL_SDK));
SDKROOT_ = macosx;
SDKROOT_YES = macosx.internal;

View File

@ -0,0 +1,30 @@
// Copyright (C) 2014 Apple Inc. All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions
// are met:
// 1. Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// 2. Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
// OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
EXECUTABLE_PREFIX = lib;
INSTALL_PATH = /usr/local/lib;
PRIVATE_HEADERS_FOLDER_PATH = /usr/local/include/bmalloc;
PRODUCT_NAME = bmalloc;
GCC_SYMBOLS_PRIVATE_EXTERN = YES;
STRIP_INSTALLED_PRODUCT = NO;

View File

@ -0,0 +1,28 @@
// Copyright (C) 2014 Apple Inc. All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions
// are met:
// 1. Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// 2. Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
// OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
EXECUTABLE_PREFIX = lib;
INSTALL_PATH = /usr/local/lib;
PRODUCT_NAME = mbmalloc;
GCC_SYMBOLS_PRIVATE_EXTERN = YES;

1
Makefile Normal file
View File

@ -0,0 +1 @@
include ../Makefile.shared

View File

@ -0,0 +1,546 @@
// !$*UTF8*$!
{
archiveVersion = 1;
classes = {
};
objectVersion = 46;
objects = {
/* Begin PBXBuildFile section */
1400274918F89C1300115C97 /* Heap.h in Headers */ = {isa = PBXBuildFile; fileRef = 14DA320C18875B09007269E0 /* Heap.h */; settings = {ATTRIBUTES = (Private, ); }; };
1400274A18F89C2300115C97 /* VMHeap.h in Headers */ = {isa = PBXBuildFile; fileRef = 144F7BFC18BFC517003537F3 /* VMHeap.h */; settings = {ATTRIBUTES = (Private, ); }; };
140FA00319CE429C00FFD3C8 /* BumpRange.h in Headers */ = {isa = PBXBuildFile; fileRef = 140FA00219CE429C00FFD3C8 /* BumpRange.h */; settings = {ATTRIBUTES = (Private, ); }; };
140FA00519CE4B6800FFD3C8 /* LineMetadata.h in Headers */ = {isa = PBXBuildFile; fileRef = 140FA00419CE4B6800FFD3C8 /* LineMetadata.h */; settings = {ATTRIBUTES = (Private, ); }; };
141D9B001C8E51C0000ABBA0 /* List.h in Headers */ = {isa = PBXBuildFile; fileRef = 141D9AFF1C8E51C0000ABBA0 /* List.h */; settings = {ATTRIBUTES = (Private, ); }; };
143CB81C19022BC900B16A45 /* StaticMutex.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 143CB81A19022BC900B16A45 /* StaticMutex.cpp */; };
143CB81D19022BC900B16A45 /* StaticMutex.h in Headers */ = {isa = PBXBuildFile; fileRef = 143CB81B19022BC900B16A45 /* StaticMutex.h */; settings = {ATTRIBUTES = (Private, ); }; };
1440AFCB1A95261100837FAA /* Zone.h in Headers */ = {isa = PBXBuildFile; fileRef = 1440AFCA1A95261100837FAA /* Zone.h */; settings = {ATTRIBUTES = (Private, ); }; };
1440AFCD1A9527AF00837FAA /* Zone.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1440AFCC1A9527AF00837FAA /* Zone.cpp */; };
1448C30018F3754600502839 /* mbmalloc.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1448C2FF18F3754300502839 /* mbmalloc.cpp */; };
1448C30118F3754C00502839 /* bmalloc.h in Headers */ = {isa = PBXBuildFile; fileRef = 1448C2FE18F3754300502839 /* bmalloc.h */; settings = {ATTRIBUTES = (Private, ); }; };
144BE11F1CA346520099C8C0 /* Object.h in Headers */ = {isa = PBXBuildFile; fileRef = 144BE11E1CA346520099C8C0 /* Object.h */; settings = {ATTRIBUTES = (Private, ); }; };
144C07F41C7B70260051BB6A /* LargeMap.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 144C07F21C7B70260051BB6A /* LargeMap.cpp */; };
144C07F51C7B70260051BB6A /* LargeMap.h in Headers */ = {isa = PBXBuildFile; fileRef = 144C07F31C7B70260051BB6A /* LargeMap.h */; settings = {ATTRIBUTES = (Private, ); }; };
147DC6E31CA5B70B00724E8D /* Chunk.h in Headers */ = {isa = PBXBuildFile; fileRef = 147DC6E21CA5B70B00724E8D /* Chunk.h */; settings = {ATTRIBUTES = (Private, ); }; };
14895D911A3A319C0006235D /* Environment.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 14895D8F1A3A319C0006235D /* Environment.cpp */; };
14895D921A3A319C0006235D /* Environment.h in Headers */ = {isa = PBXBuildFile; fileRef = 14895D901A3A319C0006235D /* Environment.h */; settings = {ATTRIBUTES = (Private, ); }; };
148EFAE81D6B953B008E721E /* ScopeExit.h in Headers */ = {isa = PBXBuildFile; fileRef = 148EFAE61D6B953B008E721E /* ScopeExit.h */; };
14C8992B1CC485E70027A057 /* Map.h in Headers */ = {isa = PBXBuildFile; fileRef = 14C8992A1CC485E70027A057 /* Map.h */; settings = {ATTRIBUTES = (Private, ); }; };
14C8992D1CC578330027A057 /* LargeRange.h in Headers */ = {isa = PBXBuildFile; fileRef = 14C8992C1CC578330027A057 /* LargeRange.h */; settings = {ATTRIBUTES = (Private, ); }; };
14C919C918FCC59F0028DB43 /* BPlatform.h in Headers */ = {isa = PBXBuildFile; fileRef = 14C919C818FCC59F0028DB43 /* BPlatform.h */; settings = {ATTRIBUTES = (Private, ); }; };
14CC394C18EA8858004AFE34 /* libbmalloc.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 14F271BE18EA3963008C152F /* libbmalloc.a */; };
14DD789018F48CEB00950702 /* Sizes.h in Headers */ = {isa = PBXBuildFile; fileRef = 145F6874179DF84100D65598 /* Sizes.h */; settings = {ATTRIBUTES = (Private, ); }; };
14DD789318F48D0F00950702 /* ObjectType.h in Headers */ = {isa = PBXBuildFile; fileRef = 1485656018A43DBA00ED6942 /* ObjectType.h */; settings = {ATTRIBUTES = (Private, ); }; };
14DD789818F48D4A00950702 /* Allocator.h in Headers */ = {isa = PBXBuildFile; fileRef = 145F6856179DC8CA00D65598 /* Allocator.h */; settings = {ATTRIBUTES = (Private, ); }; };
14DD789918F48D4A00950702 /* Cache.h in Headers */ = {isa = PBXBuildFile; fileRef = 144469E517A46BFE00F9EA1D /* Cache.h */; settings = {ATTRIBUTES = (Private, ); }; };
14DD789A18F48D4A00950702 /* Deallocator.h in Headers */ = {isa = PBXBuildFile; fileRef = 145F685A179DC90200D65598 /* Deallocator.h */; settings = {ATTRIBUTES = (Private, ); }; };
14DD789C18F48D4A00950702 /* BumpAllocator.h in Headers */ = {isa = PBXBuildFile; fileRef = 1413E462189DE1CD00546D68 /* BumpAllocator.h */; settings = {ATTRIBUTES = (Private, ); }; };
14DD78BC18F48D6B00950702 /* SmallLine.h in Headers */ = {isa = PBXBuildFile; fileRef = 1452478618BC757C00F80098 /* SmallLine.h */; settings = {ATTRIBUTES = (Private, ); }; };
14DD78BD18F48D6B00950702 /* SmallPage.h in Headers */ = {isa = PBXBuildFile; fileRef = 143E29ED18CAE90500FE8A0F /* SmallPage.h */; settings = {ATTRIBUTES = (Private, ); }; };
14DD78C518F48D7500950702 /* Algorithm.h in Headers */ = {isa = PBXBuildFile; fileRef = 1421A87718EE462A00B4DD68 /* Algorithm.h */; settings = {ATTRIBUTES = (Private, ); }; };
14DD78C618F48D7500950702 /* AsyncTask.h in Headers */ = {isa = PBXBuildFile; fileRef = 1417F65218BA88A00076FA3F /* AsyncTask.h */; settings = {ATTRIBUTES = (Private, ); }; };
14DD78C718F48D7500950702 /* BAssert.h in Headers */ = {isa = PBXBuildFile; fileRef = 1413E468189EEDE400546D68 /* BAssert.h */; settings = {ATTRIBUTES = (Private, ); }; };
14DD78C818F48D7500950702 /* FixedVector.h in Headers */ = {isa = PBXBuildFile; fileRef = 14D9DB4517F2447100EAAB79 /* FixedVector.h */; settings = {ATTRIBUTES = (Private, ); }; };
14DD78C918F48D7500950702 /* Inline.h in Headers */ = {isa = PBXBuildFile; fileRef = 1413E460189DCE1E00546D68 /* Inline.h */; settings = {ATTRIBUTES = (Private, ); }; };
14DD78CA18F48D7500950702 /* Mutex.h in Headers */ = {isa = PBXBuildFile; fileRef = 144DCED617A649D90093B2F2 /* Mutex.h */; settings = {ATTRIBUTES = (Private, ); }; };
14DD78CB18F48D7500950702 /* PerProcess.h in Headers */ = {isa = PBXBuildFile; fileRef = 14446A0717A61FA400F9EA1D /* PerProcess.h */; settings = {ATTRIBUTES = (Private, ); }; };
14DD78CC18F48D7500950702 /* PerThread.h in Headers */ = {isa = PBXBuildFile; fileRef = 144469FD17A61F1F00F9EA1D /* PerThread.h */; settings = {ATTRIBUTES = (Private, ); }; };
14DD78CD18F48D7500950702 /* Range.h in Headers */ = {isa = PBXBuildFile; fileRef = 145F6878179E3A4400D65598 /* Range.h */; settings = {ATTRIBUTES = (Private, ); }; };
14DD78CE18F48D7500950702 /* Syscall.h in Headers */ = {isa = PBXBuildFile; fileRef = 1417F64F18B7280C0076FA3F /* Syscall.h */; settings = {ATTRIBUTES = (Private, ); }; };
14DD78CF18F48D7500950702 /* Vector.h in Headers */ = {isa = PBXBuildFile; fileRef = 1479E21217A1A255006D4E9D /* Vector.h */; settings = {ATTRIBUTES = (Private, ); }; };
14DD78D018F48D7500950702 /* VMAllocate.h in Headers */ = {isa = PBXBuildFile; fileRef = 1479E21417A1A63E006D4E9D /* VMAllocate.h */; settings = {ATTRIBUTES = (Private, ); }; };
14F271C318EA3978008C152F /* Allocator.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 145F6855179DC8CA00D65598 /* Allocator.cpp */; };
14F271C418EA397B008C152F /* Cache.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 144469E417A46BFE00F9EA1D /* Cache.cpp */; };
14F271C518EA397E008C152F /* Deallocator.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 145F6859179DC90200D65598 /* Deallocator.cpp */; };
14F271C718EA3990008C152F /* Heap.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 14DA320E18875D9F007269E0 /* Heap.cpp */; };
14F271C818EA3990008C152F /* ObjectType.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 14105E8318E14374003A106E /* ObjectType.cpp */; };
14F271C918EA3990008C152F /* VMHeap.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 144F7BFB18BFC517003537F3 /* VMHeap.cpp */; };
4426E2801C838EE0008EB042 /* Logging.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4426E27E1C838EE0008EB042 /* Logging.cpp */; };
4426E2811C838EE0008EB042 /* Logging.h in Headers */ = {isa = PBXBuildFile; fileRef = 4426E27F1C838EE0008EB042 /* Logging.h */; settings = {ATTRIBUTES = (Private, ); }; };
4426E2831C839547008EB042 /* BSoftLinking.h in Headers */ = {isa = PBXBuildFile; fileRef = 4426E2821C839547008EB042 /* BSoftLinking.h */; };
/* End PBXBuildFile section */
/* Begin PBXContainerItemProxy section */
14CC394D18EA8861004AFE34 /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = 145F6837179DC45F00D65598 /* Project object */;
proxyType = 1;
remoteGlobalIDString = 14F271BD18EA3963008C152F;
remoteInfo = bmalloc;
};
/* End PBXContainerItemProxy section */
/* Begin PBXFileReference section */
140FA00219CE429C00FFD3C8 /* BumpRange.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = BumpRange.h; path = bmalloc/BumpRange.h; sourceTree = "<group>"; };
140FA00419CE4B6800FFD3C8 /* LineMetadata.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = LineMetadata.h; path = bmalloc/LineMetadata.h; sourceTree = "<group>"; };
14105E8318E14374003A106E /* ObjectType.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = ObjectType.cpp; path = bmalloc/ObjectType.cpp; sourceTree = "<group>"; };
1413E460189DCE1E00546D68 /* Inline.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Inline.h; path = bmalloc/Inline.h; sourceTree = "<group>"; };
1413E462189DE1CD00546D68 /* BumpAllocator.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; lineEnding = 0; name = BumpAllocator.h; path = bmalloc/BumpAllocator.h; sourceTree = "<group>"; };
1413E468189EEDE400546D68 /* BAssert.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = BAssert.h; path = bmalloc/BAssert.h; sourceTree = "<group>"; };
1417F64F18B7280C0076FA3F /* Syscall.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Syscall.h; path = bmalloc/Syscall.h; sourceTree = "<group>"; };
1417F65218BA88A00076FA3F /* AsyncTask.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = AsyncTask.h; path = bmalloc/AsyncTask.h; sourceTree = "<group>"; };
141D9AFF1C8E51C0000ABBA0 /* List.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = List.h; path = bmalloc/List.h; sourceTree = "<group>"; };
1421A87718EE462A00B4DD68 /* Algorithm.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = Algorithm.h; path = bmalloc/Algorithm.h; sourceTree = "<group>"; };
143CB81A19022BC900B16A45 /* StaticMutex.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = StaticMutex.cpp; path = bmalloc/StaticMutex.cpp; sourceTree = "<group>"; };
143CB81B19022BC900B16A45 /* StaticMutex.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = StaticMutex.h; path = bmalloc/StaticMutex.h; sourceTree = "<group>"; };
143E29ED18CAE90500FE8A0F /* SmallPage.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SmallPage.h; path = bmalloc/SmallPage.h; sourceTree = "<group>"; };
1440AFCA1A95261100837FAA /* Zone.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Zone.h; path = bmalloc/Zone.h; sourceTree = "<group>"; };
1440AFCC1A9527AF00837FAA /* Zone.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = Zone.cpp; path = bmalloc/Zone.cpp; sourceTree = "<group>"; };
144469E417A46BFE00F9EA1D /* Cache.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; lineEnding = 0; name = Cache.cpp; path = bmalloc/Cache.cpp; sourceTree = "<group>"; xcLanguageSpecificationIdentifier = xcode.lang.cpp; };
144469E517A46BFE00F9EA1D /* Cache.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; lineEnding = 0; name = Cache.h; path = bmalloc/Cache.h; sourceTree = "<group>"; xcLanguageSpecificationIdentifier = xcode.lang.objcpp; };
144469FD17A61F1F00F9EA1D /* PerThread.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; lineEnding = 0; name = PerThread.h; path = bmalloc/PerThread.h; sourceTree = "<group>"; xcLanguageSpecificationIdentifier = xcode.lang.objcpp; };
14446A0717A61FA400F9EA1D /* PerProcess.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = PerProcess.h; path = bmalloc/PerProcess.h; sourceTree = "<group>"; };
1448C2FE18F3754300502839 /* bmalloc.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = bmalloc.h; path = bmalloc/bmalloc.h; sourceTree = "<group>"; };
1448C2FF18F3754300502839 /* mbmalloc.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = mbmalloc.cpp; path = bmalloc/mbmalloc.cpp; sourceTree = "<group>"; };
144BE11E1CA346520099C8C0 /* Object.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Object.h; path = bmalloc/Object.h; sourceTree = "<group>"; };
144C07F21C7B70260051BB6A /* LargeMap.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = LargeMap.cpp; path = bmalloc/LargeMap.cpp; sourceTree = "<group>"; };
144C07F31C7B70260051BB6A /* LargeMap.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = LargeMap.h; path = bmalloc/LargeMap.h; sourceTree = "<group>"; };
144DCED617A649D90093B2F2 /* Mutex.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Mutex.h; path = bmalloc/Mutex.h; sourceTree = "<group>"; };
144F7BFB18BFC517003537F3 /* VMHeap.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = VMHeap.cpp; path = bmalloc/VMHeap.cpp; sourceTree = "<group>"; };
144F7BFC18BFC517003537F3 /* VMHeap.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = VMHeap.h; path = bmalloc/VMHeap.h; sourceTree = "<group>"; };
1452478618BC757C00F80098 /* SmallLine.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SmallLine.h; path = bmalloc/SmallLine.h; sourceTree = "<group>"; };
145F6855179DC8CA00D65598 /* Allocator.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; lineEnding = 0; name = Allocator.cpp; path = bmalloc/Allocator.cpp; sourceTree = "<group>"; xcLanguageSpecificationIdentifier = xcode.lang.cpp; };
145F6856179DC8CA00D65598 /* Allocator.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; lineEnding = 0; name = Allocator.h; path = bmalloc/Allocator.h; sourceTree = "<group>"; xcLanguageSpecificationIdentifier = xcode.lang.objcpp; };
145F6859179DC90200D65598 /* Deallocator.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; lineEnding = 0; name = Deallocator.cpp; path = bmalloc/Deallocator.cpp; sourceTree = "<group>"; xcLanguageSpecificationIdentifier = xcode.lang.cpp; };
145F685A179DC90200D65598 /* Deallocator.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; lineEnding = 0; name = Deallocator.h; path = bmalloc/Deallocator.h; sourceTree = "<group>"; xcLanguageSpecificationIdentifier = xcode.lang.objcpp; };
145F6874179DF84100D65598 /* Sizes.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Sizes.h; path = bmalloc/Sizes.h; sourceTree = "<group>"; };
145F6878179E3A4400D65598 /* Range.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; lineEnding = 0; name = Range.h; path = bmalloc/Range.h; sourceTree = "<group>"; xcLanguageSpecificationIdentifier = xcode.lang.objcpp; };
1479E21217A1A255006D4E9D /* Vector.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; lineEnding = 0; name = Vector.h; path = bmalloc/Vector.h; sourceTree = "<group>"; xcLanguageSpecificationIdentifier = xcode.lang.objcpp; };
1479E21417A1A63E006D4E9D /* VMAllocate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; lineEnding = 0; name = VMAllocate.h; path = bmalloc/VMAllocate.h; sourceTree = "<group>"; xcLanguageSpecificationIdentifier = xcode.lang.objcpp; };
147DC6E21CA5B70B00724E8D /* Chunk.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Chunk.h; path = bmalloc/Chunk.h; sourceTree = "<group>"; };
1485656018A43DBA00ED6942 /* ObjectType.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ObjectType.h; path = bmalloc/ObjectType.h; sourceTree = "<group>"; };
14895D8F1A3A319C0006235D /* Environment.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = Environment.cpp; path = bmalloc/Environment.cpp; sourceTree = "<group>"; };
14895D901A3A319C0006235D /* Environment.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Environment.h; path = bmalloc/Environment.h; sourceTree = "<group>"; };
148EFAE61D6B953B008E721E /* ScopeExit.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ScopeExit.h; path = bmalloc/ScopeExit.h; sourceTree = "<group>"; };
14B650C518F39F4800751968 /* Base.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Base.xcconfig; sourceTree = "<group>"; };
14B650C618F39F4800751968 /* bmalloc.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = bmalloc.xcconfig; sourceTree = "<group>"; };
14B650C718F39F4800751968 /* DebugRelease.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = DebugRelease.xcconfig; sourceTree = "<group>"; };
14B650C918F3A04200751968 /* mbmalloc.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = mbmalloc.xcconfig; sourceTree = "<group>"; };
14C8992A1CC485E70027A057 /* Map.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Map.h; path = bmalloc/Map.h; sourceTree = "<group>"; };
14C8992C1CC578330027A057 /* LargeRange.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = LargeRange.h; path = bmalloc/LargeRange.h; sourceTree = "<group>"; };
14C919C818FCC59F0028DB43 /* BPlatform.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = BPlatform.h; path = bmalloc/BPlatform.h; sourceTree = "<group>"; };
14CC394418EA8743004AFE34 /* libmbmalloc.dylib */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.dylib"; includeInIndex = 0; path = libmbmalloc.dylib; sourceTree = BUILT_PRODUCTS_DIR; };
14D9DB4517F2447100EAAB79 /* FixedVector.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; lineEnding = 0; name = FixedVector.h; path = bmalloc/FixedVector.h; sourceTree = "<group>"; xcLanguageSpecificationIdentifier = xcode.lang.objcpp; };
14DA320C18875B09007269E0 /* Heap.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Heap.h; path = bmalloc/Heap.h; sourceTree = "<group>"; };
14DA320E18875D9F007269E0 /* Heap.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = Heap.cpp; path = bmalloc/Heap.cpp; sourceTree = "<group>"; };
14F271BE18EA3963008C152F /* libbmalloc.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libbmalloc.a; sourceTree = BUILT_PRODUCTS_DIR; };
4426E27E1C838EE0008EB042 /* Logging.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = Logging.cpp; path = bmalloc/Logging.cpp; sourceTree = "<group>"; };
4426E27F1C838EE0008EB042 /* Logging.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Logging.h; path = bmalloc/Logging.h; sourceTree = "<group>"; };
4426E2821C839547008EB042 /* BSoftLinking.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = BSoftLinking.h; path = bmalloc/darwin/BSoftLinking.h; sourceTree = "<group>"; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
14CC394118EA8743004AFE34 /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
14CC394C18EA8858004AFE34 /* libbmalloc.a in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
14F271BB18EA3963008C152F /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXFrameworksBuildPhase section */
/* Begin PBXGroup section */
1448C2FD18F3752B00502839 /* api */ = {
isa = PBXGroup;
children = (
1448C2FE18F3754300502839 /* bmalloc.h */,
1448C2FF18F3754300502839 /* mbmalloc.cpp */,
);
name = api;
sourceTree = "<group>";
};
145F6836179DC45F00D65598 = {
isa = PBXGroup;
children = (
1448C2FD18F3752B00502839 /* api */,
14D9DB4D17F2865C00EAAB79 /* cache */,
14B650C418F39F4800751968 /* Configurations */,
14D9DB4E17F2866E00EAAB79 /* heap */,
147AAA9C18CE6010002201E4 /* heap: large */,
147AAA9A18CE5FD3002201E4 /* heap: small */,
145F6840179DC45F00D65598 /* Products */,
14D9DB4F17F2868900EAAB79 /* stdlib */,
);
sourceTree = "<group>";
};
145F6840179DC45F00D65598 /* Products */ = {
isa = PBXGroup;
children = (
14F271BE18EA3963008C152F /* libbmalloc.a */,
14CC394418EA8743004AFE34 /* libmbmalloc.dylib */,
);
name = Products;
sourceTree = "<group>";
};
147AAA9A18CE5FD3002201E4 /* heap: small */ = {
isa = PBXGroup;
children = (
1452478618BC757C00F80098 /* SmallLine.h */,
143E29ED18CAE90500FE8A0F /* SmallPage.h */,
);
name = "heap: small";
sourceTree = "<group>";
};
147AAA9C18CE6010002201E4 /* heap: large */ = {
isa = PBXGroup;
children = (
144C07F21C7B70260051BB6A /* LargeMap.cpp */,
144C07F31C7B70260051BB6A /* LargeMap.h */,
14C8992C1CC578330027A057 /* LargeRange.h */,
);
name = "heap: large";
sourceTree = "<group>";
};
14B650C418F39F4800751968 /* Configurations */ = {
isa = PBXGroup;
children = (
14B650C518F39F4800751968 /* Base.xcconfig */,
14B650C618F39F4800751968 /* bmalloc.xcconfig */,
14B650C718F39F4800751968 /* DebugRelease.xcconfig */,
14B650C918F3A04200751968 /* mbmalloc.xcconfig */,
);
path = Configurations;
sourceTree = "<group>";
};
14D9DB4D17F2865C00EAAB79 /* cache */ = {
isa = PBXGroup;
children = (
145F6855179DC8CA00D65598 /* Allocator.cpp */,
145F6856179DC8CA00D65598 /* Allocator.h */,
1413E462189DE1CD00546D68 /* BumpAllocator.h */,
144469E417A46BFE00F9EA1D /* Cache.cpp */,
144469E517A46BFE00F9EA1D /* Cache.h */,
145F6859179DC90200D65598 /* Deallocator.cpp */,
145F685A179DC90200D65598 /* Deallocator.h */,
);
name = cache;
sourceTree = "<group>";
};
14D9DB4E17F2866E00EAAB79 /* heap */ = {
isa = PBXGroup;
children = (
140FA00219CE429C00FFD3C8 /* BumpRange.h */,
147DC6E21CA5B70B00724E8D /* Chunk.h */,
14895D8F1A3A319C0006235D /* Environment.cpp */,
14895D901A3A319C0006235D /* Environment.h */,
14DA320E18875D9F007269E0 /* Heap.cpp */,
14DA320C18875B09007269E0 /* Heap.h */,
140FA00419CE4B6800FFD3C8 /* LineMetadata.h */,
144BE11E1CA346520099C8C0 /* Object.h */,
14105E8318E14374003A106E /* ObjectType.cpp */,
1485656018A43DBA00ED6942 /* ObjectType.h */,
145F6874179DF84100D65598 /* Sizes.h */,
144F7BFB18BFC517003537F3 /* VMHeap.cpp */,
144F7BFC18BFC517003537F3 /* VMHeap.h */,
1440AFCC1A9527AF00837FAA /* Zone.cpp */,
1440AFCA1A95261100837FAA /* Zone.h */,
);
name = heap;
sourceTree = "<group>";
};
14D9DB4F17F2868900EAAB79 /* stdlib */ = {
isa = PBXGroup;
children = (
4408F2961C9896C40012EC64 /* darwin */,
1421A87718EE462A00B4DD68 /* Algorithm.h */,
1417F65218BA88A00076FA3F /* AsyncTask.h */,
1413E468189EEDE400546D68 /* BAssert.h */,
14C919C818FCC59F0028DB43 /* BPlatform.h */,
14D9DB4517F2447100EAAB79 /* FixedVector.h */,
1413E460189DCE1E00546D68 /* Inline.h */,
141D9AFF1C8E51C0000ABBA0 /* List.h */,
4426E27E1C838EE0008EB042 /* Logging.cpp */,
4426E27F1C838EE0008EB042 /* Logging.h */,
14C8992A1CC485E70027A057 /* Map.h */,
144DCED617A649D90093B2F2 /* Mutex.h */,
14446A0717A61FA400F9EA1D /* PerProcess.h */,
144469FD17A61F1F00F9EA1D /* PerThread.h */,
145F6878179E3A4400D65598 /* Range.h */,
148EFAE61D6B953B008E721E /* ScopeExit.h */,
143CB81A19022BC900B16A45 /* StaticMutex.cpp */,
143CB81B19022BC900B16A45 /* StaticMutex.h */,
1417F64F18B7280C0076FA3F /* Syscall.h */,
1479E21217A1A255006D4E9D /* Vector.h */,
1479E21417A1A63E006D4E9D /* VMAllocate.h */,
);
name = stdlib;
sourceTree = "<group>";
};
4408F2961C9896C40012EC64 /* darwin */ = {
isa = PBXGroup;
children = (
4426E2821C839547008EB042 /* BSoftLinking.h */,
);
name = darwin;
sourceTree = "<group>";
};
/* End PBXGroup section */
/* Begin PBXHeadersBuildPhase section */
14CC394218EA8743004AFE34 /* Headers */ = {
isa = PBXHeadersBuildPhase;
buildActionMask = 2147483647;
files = (
);
runOnlyForDeploymentPostprocessing = 0;
};
14F271BC18EA3963008C152F /* Headers */ = {
isa = PBXHeadersBuildPhase;
buildActionMask = 2147483647;
files = (
14DD78C518F48D7500950702 /* Algorithm.h in Headers */,
14DD789818F48D4A00950702 /* Allocator.h in Headers */,
14DD78C618F48D7500950702 /* AsyncTask.h in Headers */,
14DD78C718F48D7500950702 /* BAssert.h in Headers */,
1448C30118F3754C00502839 /* bmalloc.h in Headers */,
14C919C918FCC59F0028DB43 /* BPlatform.h in Headers */,
4426E2831C839547008EB042 /* BSoftLinking.h in Headers */,
14DD789C18F48D4A00950702 /* BumpAllocator.h in Headers */,
140FA00319CE429C00FFD3C8 /* BumpRange.h in Headers */,
14DD789918F48D4A00950702 /* Cache.h in Headers */,
147DC6E31CA5B70B00724E8D /* Chunk.h in Headers */,
14DD789A18F48D4A00950702 /* Deallocator.h in Headers */,
14895D921A3A319C0006235D /* Environment.h in Headers */,
14DD78C818F48D7500950702 /* FixedVector.h in Headers */,
1400274918F89C1300115C97 /* Heap.h in Headers */,
14DD78C918F48D7500950702 /* Inline.h in Headers */,
144C07F51C7B70260051BB6A /* LargeMap.h in Headers */,
14C8992D1CC578330027A057 /* LargeRange.h in Headers */,
140FA00519CE4B6800FFD3C8 /* LineMetadata.h in Headers */,
141D9B001C8E51C0000ABBA0 /* List.h in Headers */,
4426E2811C838EE0008EB042 /* Logging.h in Headers */,
14C8992B1CC485E70027A057 /* Map.h in Headers */,
14DD78CA18F48D7500950702 /* Mutex.h in Headers */,
144BE11F1CA346520099C8C0 /* Object.h in Headers */,
14DD789318F48D0F00950702 /* ObjectType.h in Headers */,
14DD78CB18F48D7500950702 /* PerProcess.h in Headers */,
14DD78CC18F48D7500950702 /* PerThread.h in Headers */,
14DD78CD18F48D7500950702 /* Range.h in Headers */,
148EFAE81D6B953B008E721E /* ScopeExit.h in Headers */,
14DD789018F48CEB00950702 /* Sizes.h in Headers */,
14DD78BC18F48D6B00950702 /* SmallLine.h in Headers */,
14DD78BD18F48D6B00950702 /* SmallPage.h in Headers */,
143CB81D19022BC900B16A45 /* StaticMutex.h in Headers */,
14DD78CE18F48D7500950702 /* Syscall.h in Headers */,
14DD78CF18F48D7500950702 /* Vector.h in Headers */,
14DD78D018F48D7500950702 /* VMAllocate.h in Headers */,
1400274A18F89C2300115C97 /* VMHeap.h in Headers */,
1440AFCB1A95261100837FAA /* Zone.h in Headers */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXHeadersBuildPhase section */
/* Begin PBXNativeTarget section */
14CC394318EA8743004AFE34 /* mbmalloc */ = {
isa = PBXNativeTarget;
buildConfigurationList = 14CC394518EA8743004AFE34 /* Build configuration list for PBXNativeTarget "mbmalloc" */;
buildPhases = (
14CC394018EA8743004AFE34 /* Sources */,
14CC394118EA8743004AFE34 /* Frameworks */,
14CC394218EA8743004AFE34 /* Headers */,
);
buildRules = (
);
dependencies = (
14CC394E18EA8861004AFE34 /* PBXTargetDependency */,
);
name = mbmalloc;
productName = mbmalloc;
productReference = 14CC394418EA8743004AFE34 /* libmbmalloc.dylib */;
productType = "com.apple.product-type.library.dynamic";
};
14F271BD18EA3963008C152F /* bmalloc */ = {
isa = PBXNativeTarget;
buildConfigurationList = 14F271BF18EA3963008C152F /* Build configuration list for PBXNativeTarget "bmalloc" */;
buildPhases = (
14F271BA18EA3963008C152F /* Sources */,
14F271BB18EA3963008C152F /* Frameworks */,
14F271BC18EA3963008C152F /* Headers */,
);
buildRules = (
);
dependencies = (
);
name = bmalloc;
productName = bmalloc;
productReference = 14F271BE18EA3963008C152F /* libbmalloc.a */;
productType = "com.apple.product-type.library.static";
};
/* End PBXNativeTarget section */
/* Begin PBXProject section */
145F6837179DC45F00D65598 /* Project object */ = {
isa = PBXProject;
attributes = {
LastSwiftUpdateCheck = 0700;
LastUpgradeCheck = 0700;
};
buildConfigurationList = 145F683A179DC45F00D65598 /* Build configuration list for PBXProject "bmalloc" */;
compatibilityVersion = "Xcode 3.2";
developmentRegion = English;
hasScannedForEncodings = 0;
knownRegions = (
en,
);
mainGroup = 145F6836179DC45F00D65598;
productRefGroup = 145F6840179DC45F00D65598 /* Products */;
projectDirPath = "";
projectRoot = "";
targets = (
14F271BD18EA3963008C152F /* bmalloc */,
14CC394318EA8743004AFE34 /* mbmalloc */,
);
};
/* End PBXProject section */
/* Begin PBXSourcesBuildPhase section */
14CC394018EA8743004AFE34 /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
1448C30018F3754600502839 /* mbmalloc.cpp in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
14F271BA18EA3963008C152F /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
14F271C318EA3978008C152F /* Allocator.cpp in Sources */,
14F271C418EA397B008C152F /* Cache.cpp in Sources */,
14F271C518EA397E008C152F /* Deallocator.cpp in Sources */,
14895D911A3A319C0006235D /* Environment.cpp in Sources */,
14F271C718EA3990008C152F /* Heap.cpp in Sources */,
144C07F41C7B70260051BB6A /* LargeMap.cpp in Sources */,
4426E2801C838EE0008EB042 /* Logging.cpp in Sources */,
14F271C818EA3990008C152F /* ObjectType.cpp in Sources */,
143CB81C19022BC900B16A45 /* StaticMutex.cpp in Sources */,
14F271C918EA3990008C152F /* VMHeap.cpp in Sources */,
1440AFCD1A9527AF00837FAA /* Zone.cpp in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXSourcesBuildPhase section */
/* Begin PBXTargetDependency section */
14CC394E18EA8861004AFE34 /* PBXTargetDependency */ = {
isa = PBXTargetDependency;
target = 14F271BD18EA3963008C152F /* bmalloc */;
targetProxy = 14CC394D18EA8861004AFE34 /* PBXContainerItemProxy */;
};
/* End PBXTargetDependency section */
/* Begin XCBuildConfiguration section */
14202F0F18F37C15006C37DB /* Production */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = 14B650C518F39F4800751968 /* Base.xcconfig */;
buildSettings = {
};
name = Production;
};
14202F1018F37C15006C37DB /* Production */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = 14B650C618F39F4800751968 /* bmalloc.xcconfig */;
buildSettings = {
};
name = Production;
};
14202F1118F37C15006C37DB /* Production */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = 14B650C918F3A04200751968 /* mbmalloc.xcconfig */;
buildSettings = {
};
name = Production;
};
145F684A179DC45F00D65598 /* Debug */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = 14B650C718F39F4800751968 /* DebugRelease.xcconfig */;
buildSettings = {
DEAD_CODE_STRIPPING = "$(DEAD_CODE_STRIPPING_debug)";
DEBUG_DEFINES = "$(DEBUG_DEFINES_debug)";
GCC_OPTIMIZATION_LEVEL = "$(GCC_OPTIMIZATION_LEVEL_debug)";
STRIP_INSTALLED_PRODUCT = "$(STRIP_INSTALLED_PRODUCT_debug)";
};
name = Debug;
};
145F684B179DC45F00D65598 /* Release */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = 14B650C718F39F4800751968 /* DebugRelease.xcconfig */;
buildSettings = {
};
name = Release;
};
14CC394618EA8743004AFE34 /* Debug */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = 14B650C918F3A04200751968 /* mbmalloc.xcconfig */;
buildSettings = {
};
name = Debug;
};
14CC394718EA8743004AFE34 /* Release */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = 14B650C918F3A04200751968 /* mbmalloc.xcconfig */;
buildSettings = {
};
name = Release;
};
14F271C018EA3963008C152F /* Debug */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = 14B650C618F39F4800751968 /* bmalloc.xcconfig */;
buildSettings = {
};
name = Debug;
};
14F271C118EA3963008C152F /* Release */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = 14B650C618F39F4800751968 /* bmalloc.xcconfig */;
buildSettings = {
};
name = Release;
};
/* End XCBuildConfiguration section */
/* Begin XCConfigurationList section */
145F683A179DC45F00D65598 /* Build configuration list for PBXProject "bmalloc" */ = {
isa = XCConfigurationList;
buildConfigurations = (
145F684A179DC45F00D65598 /* Debug */,
145F684B179DC45F00D65598 /* Release */,
14202F0F18F37C15006C37DB /* Production */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Production;
};
14CC394518EA8743004AFE34 /* Build configuration list for PBXNativeTarget "mbmalloc" */ = {
isa = XCConfigurationList;
buildConfigurations = (
14CC394618EA8743004AFE34 /* Debug */,
14CC394718EA8743004AFE34 /* Release */,
14202F1118F37C15006C37DB /* Production */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Production;
};
14F271BF18EA3963008C152F /* Build configuration list for PBXNativeTarget "bmalloc" */ = {
isa = XCConfigurationList;
buildConfigurations = (
14F271C018EA3963008C152F /* Debug */,
14F271C118EA3963008C152F /* Release */,
14202F1018F37C15006C37DB /* Production */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Production;
};
/* End XCConfigurationList section */
};
rootObject = 145F6837179DC45F00D65598 /* Project object */;
}

128
bmalloc/Algorithm.h Normal file
View File

@ -0,0 +1,128 @@
/*
* Copyright (C) 2014 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef Algorithm_h
#define Algorithm_h
#include "Algorithm.h"
#include "BAssert.h"
#include <algorithm>
#include <cstdint>
#include <cstddef>
#include <limits>
#include <type_traits>
#include <chrono>
namespace bmalloc {
// Versions of min and max that are compatible with compile-time constants.
template<typename T> inline constexpr T max(T a, T b)
{
return a > b ? a : b;
}
template<typename T> inline constexpr T min(T a, T b)
{
return a < b ? a : b;
}
template<typename T> inline constexpr T mask(T value, uintptr_t mask)
{
return reinterpret_cast<T>(reinterpret_cast<uintptr_t>(value) & mask);
}
template<typename T> inline constexpr bool test(T value, uintptr_t mask)
{
return !!(reinterpret_cast<uintptr_t>(value) & mask);
}
inline constexpr bool isPowerOfTwo(size_t size)
{
return size && !(size & (size - 1));
}
template<typename T> inline T roundUpToMultipleOf(size_t divisor, T x)
{
BASSERT(isPowerOfTwo(divisor));
return reinterpret_cast<T>((reinterpret_cast<uintptr_t>(x) + (divisor - 1)) & ~(divisor - 1));
}
template<size_t divisor, typename T> inline constexpr T roundUpToMultipleOf(T x)
{
static_assert(isPowerOfTwo(divisor), "'divisor' must be a power of two.");
return roundUpToMultipleOf(divisor, x);
}
template<typename T> inline T roundDownToMultipleOf(size_t divisor, T x)
{
BASSERT(isPowerOfTwo(divisor));
return reinterpret_cast<T>(mask(reinterpret_cast<uintptr_t>(x), ~(divisor - 1ul)));
}
template<size_t divisor, typename T> inline constexpr T roundDownToMultipleOf(T x)
{
static_assert(isPowerOfTwo(divisor), "'divisor' must be a power of two.");
return roundDownToMultipleOf(divisor, x);
}
template<typename T> inline void divideRoundingUp(T numerator, T denominator, T& quotient, T& remainder)
{
// We expect the compiler to emit a single divide instruction to extract both the quotient and the remainder.
quotient = numerator / denominator;
remainder = numerator % denominator;
if (remainder)
quotient += 1;
}
template<typename T> inline T divideRoundingUp(T numerator, T denominator)
{
return (numerator + denominator - 1) / denominator;
}
template<typename T> inline T roundUpToMultipleOfNonPowerOfTwo(size_t divisor, T x)
{
return divideRoundingUp(x, divisor) * divisor;
}
// Version of sizeof that returns 0 for empty classes.
template<typename T> inline constexpr size_t sizeOf()
{
return std::is_empty<T>::value ? 0 : sizeof(T);
}
template<typename T> inline constexpr size_t bitCount()
{
return sizeof(T) * 8;
}
inline constexpr unsigned long log2(unsigned long value)
{
return bitCount<unsigned long>() - 1 - __builtin_clzl(value);
}
} // namespace bmalloc
#endif // Algorithm_h

216
bmalloc/Allocator.cpp Normal file
View File

@ -0,0 +1,216 @@
/*
* Copyright (C) 2014-2016 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "Allocator.h"
#include "BAssert.h"
#include "Chunk.h"
#include "Deallocator.h"
#include "Heap.h"
#include "PerProcess.h"
#include "Sizes.h"
#include <algorithm>
#include <cstdlib>
using namespace std;
namespace bmalloc {
Allocator::Allocator(Heap* heap, Deallocator& deallocator)
: m_isBmallocEnabled(heap->environment().isBmallocEnabled())
, m_deallocator(deallocator)
{
for (size_t sizeClass = 0; sizeClass < sizeClassCount; ++sizeClass)
m_bumpAllocators[sizeClass].init(objectSize(sizeClass));
}
Allocator::~Allocator()
{
scavenge();
}
void* Allocator::tryAllocate(size_t size)
{
if (!m_isBmallocEnabled)
return malloc(size);
if (size <= smallMax)
return allocate(size);
std::lock_guard<StaticMutex> lock(PerProcess<Heap>::mutex());
return PerProcess<Heap>::getFastCase()->tryAllocateLarge(lock, alignment, size);
}
void* Allocator::allocate(size_t alignment, size_t size)
{
bool crashOnFailure = true;
return allocateImpl(alignment, size, crashOnFailure);
}
void* Allocator::tryAllocate(size_t alignment, size_t size)
{
bool crashOnFailure = false;
return allocateImpl(alignment, size, crashOnFailure);
}
void* Allocator::allocateImpl(size_t alignment, size_t size, bool crashOnFailure)
{
BASSERT(isPowerOfTwo(alignment));
if (!m_isBmallocEnabled) {
void* result = nullptr;
if (posix_memalign(&result, alignment, size)) {
if (crashOnFailure)
BCRASH();
return nullptr;
}
return result;
}
if (!size)
size = alignment;
if (size <= smallMax && alignment <= smallMax)
return allocate(roundUpToMultipleOf(alignment, size));
std::lock_guard<StaticMutex> lock(PerProcess<Heap>::mutex());
Heap* heap = PerProcess<Heap>::getFastCase();
if (crashOnFailure)
return heap->allocateLarge(lock, alignment, size);
return heap->tryAllocateLarge(lock, alignment, size);
}
void* Allocator::reallocate(void* object, size_t newSize)
{
if (!m_isBmallocEnabled) {
void* result = realloc(object, newSize);
if (!result)
BCRASH();
return result;
}
size_t oldSize = 0;
switch (objectType(object)) {
case ObjectType::Small: {
BASSERT(objectType(nullptr) == ObjectType::Small);
if (!object)
break;
size_t sizeClass = Object(object).page()->sizeClass();
oldSize = objectSize(sizeClass);
break;
}
case ObjectType::Large: {
std::lock_guard<StaticMutex> lock(PerProcess<Heap>::mutex());
oldSize = PerProcess<Heap>::getFastCase()->largeSize(lock, object);
if (newSize < oldSize && newSize > smallMax) {
PerProcess<Heap>::getFastCase()->shrinkLarge(lock, Range(object, oldSize), newSize);
return object;
}
break;
}
}
void* result = allocate(newSize);
size_t copySize = std::min(oldSize, newSize);
memcpy(result, object, copySize);
m_deallocator.deallocate(object);
return result;
}
void Allocator::scavenge()
{
for (size_t sizeClass = 0; sizeClass < sizeClassCount; ++sizeClass) {
BumpAllocator& allocator = m_bumpAllocators[sizeClass];
BumpRangeCache& bumpRangeCache = m_bumpRangeCaches[sizeClass];
while (allocator.canAllocate())
m_deallocator.deallocate(allocator.allocate());
while (bumpRangeCache.size()) {
allocator.refill(bumpRangeCache.pop());
while (allocator.canAllocate())
m_deallocator.deallocate(allocator.allocate());
}
allocator.clear();
}
}
NO_INLINE void Allocator::refillAllocatorSlowCase(BumpAllocator& allocator, size_t sizeClass)
{
BumpRangeCache& bumpRangeCache = m_bumpRangeCaches[sizeClass];
std::lock_guard<StaticMutex> lock(PerProcess<Heap>::mutex());
m_deallocator.processObjectLog(lock);
PerProcess<Heap>::getFastCase()->allocateSmallBumpRanges(lock, sizeClass, allocator, bumpRangeCache);
}
INLINE void Allocator::refillAllocator(BumpAllocator& allocator, size_t sizeClass)
{
BumpRangeCache& bumpRangeCache = m_bumpRangeCaches[sizeClass];
if (!bumpRangeCache.size())
return refillAllocatorSlowCase(allocator, sizeClass);
return allocator.refill(bumpRangeCache.pop());
}
NO_INLINE void* Allocator::allocateLarge(size_t size)
{
std::lock_guard<StaticMutex> lock(PerProcess<Heap>::mutex());
return PerProcess<Heap>::getFastCase()->allocateLarge(lock, alignment, size);
}
NO_INLINE void* Allocator::allocateLogSizeClass(size_t size)
{
size_t sizeClass = bmalloc::sizeClass(size);
BumpAllocator& allocator = m_bumpAllocators[sizeClass];
if (!allocator.canAllocate())
refillAllocator(allocator, sizeClass);
return allocator.allocate();
}
void* Allocator::allocateSlowCase(size_t size)
{
if (!m_isBmallocEnabled) {
void* result = malloc(size);
if (!result)
BCRASH();
return result;
}
if (size <= maskSizeClassMax) {
size_t sizeClass = bmalloc::maskSizeClass(size);
BumpAllocator& allocator = m_bumpAllocators[sizeClass];
refillAllocator(allocator, sizeClass);
return allocator.allocate();
}
if (size <= smallMax)
return allocateLogSizeClass(size);
return allocateLarge(size);
}
} // namespace bmalloc

94
bmalloc/Allocator.h Normal file
View File

@ -0,0 +1,94 @@
/*
* Copyright (C) 2014, 2016 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef Allocator_h
#define Allocator_h
#include "BumpAllocator.h"
#include <array>
namespace bmalloc {
class Deallocator;
class Heap;
// Per-cache object allocator.
class Allocator {
public:
Allocator(Heap*, Deallocator&);
~Allocator();
void* tryAllocate(size_t);
void* allocate(size_t);
void* tryAllocate(size_t alignment, size_t);
void* allocate(size_t alignment, size_t);
void* reallocate(void*, size_t);
void scavenge();
private:
void* allocateImpl(size_t alignment, size_t, bool crashOnFailure);
bool allocateFastCase(size_t, void*&);
void* allocateSlowCase(size_t);
void* allocateLogSizeClass(size_t);
void* allocateLarge(size_t);
void refillAllocator(BumpAllocator&, size_t sizeClass);
void refillAllocatorSlowCase(BumpAllocator&, size_t sizeClass);
std::array<BumpAllocator, sizeClassCount> m_bumpAllocators;
std::array<BumpRangeCache, sizeClassCount> m_bumpRangeCaches;
bool m_isBmallocEnabled;
Deallocator& m_deallocator;
};
inline bool Allocator::allocateFastCase(size_t size, void*& object)
{
if (size > maskSizeClassMax)
return false;
BumpAllocator& allocator = m_bumpAllocators[maskSizeClass(size)];
if (!allocator.canAllocate())
return false;
object = allocator.allocate();
return true;
}
inline void* Allocator::allocate(size_t size)
{
void* object;
if (!allocateFastCase(size, object))
return allocateSlowCase(size);
return object;
}
} // namespace bmalloc
#endif // Allocator_h

137
bmalloc/AsyncTask.h Normal file
View File

@ -0,0 +1,137 @@
/*
* Copyright (C) 2014, 2015 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef AsyncTask_h
#define AsyncTask_h
#include "BAssert.h"
#include "Inline.h"
#include "Mutex.h"
#include <atomic>
#include <condition_variable>
#include <thread>
namespace bmalloc {
template<typename Object, typename Function>
class AsyncTask {
public:
AsyncTask(Object&, const Function&);
~AsyncTask();
void run();
private:
enum State { Sleeping, Running, RunRequested };
void runSlowCase();
static void threadEntryPoint(AsyncTask*);
void threadRunLoop();
std::atomic<State> m_state;
Mutex m_conditionMutex;
std::condition_variable_any m_condition;
std::thread m_thread;
Object& m_object;
Function m_function;
};
template<typename Object, typename Function>
AsyncTask<Object, Function>::AsyncTask(Object& object, const Function& function)
: m_state(Running)
, m_condition()
, m_thread(std::thread(&AsyncTask::threadEntryPoint, this))
, m_object(object)
, m_function(function)
{
}
template<typename Object, typename Function>
AsyncTask<Object, Function>::~AsyncTask()
{
// We'd like to mark our destructor deleted but C++ won't allow it because
// we are an automatic member of Heap.
RELEASE_BASSERT(0);
}
template<typename Object, typename Function>
inline void AsyncTask<Object, Function>::run()
{
if (m_state == RunRequested)
return;
runSlowCase();
}
template<typename Object, typename Function>
NO_INLINE void AsyncTask<Object, Function>::runSlowCase()
{
State oldState = m_state.exchange(RunRequested);
if (oldState == RunRequested || oldState == Running)
return;
BASSERT(oldState == Sleeping);
std::lock_guard<Mutex> lock(m_conditionMutex);
m_condition.notify_all();
}
template<typename Object, typename Function>
void AsyncTask<Object, Function>::threadEntryPoint(AsyncTask* asyncTask)
{
#if BOS(DARWIN)
pthread_set_qos_class_self_np(QOS_CLASS_USER_INTERACTIVE, 0);
#endif
asyncTask->threadRunLoop();
}
template<typename Object, typename Function>
void AsyncTask<Object, Function>::threadRunLoop()
{
// This loop ratchets downward from most active to least active state. While
// we ratchet downward, any other thread may reset our state.
// We require any state change while we are sleeping to signal to our
// condition variable and wake us up.
while (1) {
State expectedState = RunRequested;
if (m_state.compare_exchange_weak(expectedState, Running))
(m_object.*m_function)();
expectedState = Running;
if (m_state.compare_exchange_weak(expectedState, Sleeping)) {
std::unique_lock<Mutex> lock(m_conditionMutex);
m_condition.wait(lock, [&]() { return m_state != Sleeping; });
}
}
}
} // namespace bmalloc
#endif // AsyncTask_h

109
bmalloc/BAssert.h Normal file
View File

@ -0,0 +1,109 @@
/*
* Copyright (C) 2014-2016 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#pragma once
#include "BPlatform.h"
#include "Logging.h"
#if BUSE(OS_LOG)
#include <os/log.h>
#endif
#if defined(NDEBUG) && BOS(DARWIN)
#if BCPU(X86_64) || BCPU(X86)
#define BBreakpointTrap() __asm__ volatile ("int3")
#elif BCPU(ARM_THUMB2)
#define BBreakpointTrap() __asm__ volatile ("bkpt #0")
#elif BCPU(ARM64)
#define BBreakpointTrap() __asm__ volatile ("brk #0")
#else
#error "Unsupported CPU".
#endif
// Crash with a SIGTRAP i.e EXC_BREAKPOINT.
// We are not using __builtin_trap because it is only guaranteed to abort, but not necessarily
// trigger a SIGTRAP. Instead, we use inline asm to ensure that we trigger the SIGTRAP.
#define BCRASH() do { \
BBreakpointTrap(); \
__builtin_unreachable(); \
} while (false)
#else // not defined(NDEBUG) && BOS(DARWIN)
#define BCRASH() do { \
*(int*)0xbbadbeef = 0; \
} while (0);
#endif // defined(NDEBUG) && BOS(DARWIN)
#define BASSERT_IMPL(x) do { \
if (!(x)) \
BCRASH(); \
} while (0);
#define RELEASE_BASSERT(x) BASSERT_IMPL(x)
#if BUSE(OS_LOG)
#define BMALLOC_LOGGING_PREFIX "bmalloc: "
#define BLOG_ERROR(format, ...) os_log_error(OS_LOG_DEFAULT, BMALLOC_LOGGING_PREFIX format, __VA_ARGS__)
#else
#define BLOG_ERROR(format, ...) bmalloc::reportAssertionFailureWithMessage(__FILE__, __LINE__, __PRETTY_FUNCTION__, format, __VA_ARGS__)
#endif
#if defined(NDEBUG)
#define RELEASE_BASSERT_WITH_MESSAGE(x, format, ...) BASSERT_IMPL(x)
#else
#define RELEASE_BASSERT_WITH_MESSAGE(x, format, ...) do { \
if (!(x)) { \
BLOG_ERROR("ASSERTION FAILED: " #x " :: " format, ##__VA_ARGS__); \
BCRASH(); \
} \
} while (0);
#endif
#define UNUSED(x) ((void)x)
// ===== Release build =====
#if defined(NDEBUG)
#define BASSERT(x)
#define IF_DEBUG(x)
#endif // defined(NDEBUG)
// ===== Debug build =====
#if !defined(NDEBUG)
#define BASSERT(x) BASSERT_IMPL(x)
#define IF_DEBUG(x) (x)
#endif // !defined(NDEBUG)

196
bmalloc/BPlatform.h Normal file
View File

@ -0,0 +1,196 @@
/*
* Copyright (C) 2014 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#pragma once
#ifdef __APPLE__
#include <Availability.h>
#include <AvailabilityMacros.h>
#include <TargetConditionals.h>
#endif
#define BPLATFORM(PLATFORM) (defined BPLATFORM_##PLATFORM && BPLATFORM_##PLATFORM)
#define BOS(OS) (defined BOS_##OS && BOS_##OS)
#ifdef __APPLE__
#define BOS_DARWIN 1
#endif
#ifdef __unix
#define BOS_UNIX 1
#endif
#if BOS(DARWIN) && ((defined(TARGET_OS_EMBEDDED) && TARGET_OS_EMBEDDED) \
|| (defined(TARGET_OS_IPHONE) && TARGET_OS_IPHONE) \
|| (defined(TARGET_IPHONE_SIMULATOR) && TARGET_IPHONE_SIMULATOR))
#define BPLATFORM_IOS 1
#elif BOS(DARWIN) && defined(TARGET_OS_MAC) && TARGET_OS_MAC
#define BPLATFORM_MAC 1
#endif
/* ==== Policy decision macros: these define policy choices for a particular port. ==== */
/* BUSE() - use a particular third-party library or optional OS service */
#define BUSE(FEATURE) (defined BUSE_##FEATURE && BUSE_##FEATURE)
/* ==== Platform adaptation macros: these describe properties of the target environment. ==== */
/* BCPU() - the target CPU architecture */
#define BCPU(_FEATURE) (defined BCPU_##_FEATURE && BCPU_##_FEATURE)
/* BCPU(X86) - i386 / x86 32-bit */
#if defined(__i386__) \
|| defined(i386) \
|| defined(_M_IX86) \
|| defined(_X86_) \
|| defined(__THW_INTEL)
#define BCPU_X86 1
#endif
/* BCPU(X86_64) - AMD64 / Intel64 / x86_64 64-bit */
#if defined(__x86_64__) \
|| defined(_M_X64)
#define BCPU_X86_64 1
#endif
/* BCPU(ARM64) - Apple */
#if (defined(__arm64__) && defined(__APPLE__)) || defined(__aarch64__)
#define BCPU_ARM64 1
#endif
/* BCPU(ARM) - ARM, any version*/
#define BARM_ARCH_AT_LEAST(N) (BCPU(ARM) && BARM_ARCH_VERSION >= N)
#if defined(arm) \
|| defined(__arm__) \
|| defined(ARM) \
|| defined(_ARM_)
#define BCPU_ARM 1
/* Set BARM_ARCH_VERSION */
#if defined(__ARM_ARCH_4__) \
|| defined(__ARM_ARCH_4T__) \
|| defined(__MARM_ARMV4__)
#define BARM_ARCH_VERSION 4
#elif defined(__ARM_ARCH_5__) \
|| defined(__ARM_ARCH_5T__) \
|| defined(__MARM_ARMV5__)
#define BARM_ARCH_VERSION 5
#elif defined(__ARM_ARCH_5E__) \
|| defined(__ARM_ARCH_5TE__) \
|| defined(__ARM_ARCH_5TEJ__)
#define BARM_ARCH_VERSION 5
#elif defined(__ARM_ARCH_6__) \
|| defined(__ARM_ARCH_6J__) \
|| defined(__ARM_ARCH_6K__) \
|| defined(__ARM_ARCH_6Z__) \
|| defined(__ARM_ARCH_6ZK__) \
|| defined(__ARM_ARCH_6T2__) \
|| defined(__ARMV6__)
#define BARM_ARCH_VERSION 6
#elif defined(__ARM_ARCH_7A__) \
|| defined(__ARM_ARCH_7K__) \
|| defined(__ARM_ARCH_7R__) \
|| defined(__ARM_ARCH_7S__)
#define BARM_ARCH_VERSION 7
#elif defined(__ARM_ARCH_8__)
#define BARM_ARCH_VERSION 8
/* MSVC sets _M_ARM */
#elif defined(_M_ARM)
#define BARM_ARCH_VERSION _M_ARM
/* RVCT sets _TARGET_ARCH_ARM */
#elif defined(__TARGET_ARCH_ARM)
#define BARM_ARCH_VERSION __TARGET_ARCH_ARM
#else
#define WTF_ARM_ARCH_VERSION 0
#endif
/* Set BTHUMB_ARCH_VERSION */
#if defined(__ARM_ARCH_4T__)
#define BTHUMB_ARCH_VERSION 1
#elif defined(__ARM_ARCH_5T__) \
|| defined(__ARM_ARCH_5TE__) \
|| defined(__ARM_ARCH_5TEJ__)
#define BTHUMB_ARCH_VERSION 2
#elif defined(__ARM_ARCH_6J__) \
|| defined(__ARM_ARCH_6K__) \
|| defined(__ARM_ARCH_6Z__) \
|| defined(__ARM_ARCH_6ZK__) \
|| defined(__ARM_ARCH_6M__)
#define BTHUMB_ARCH_VERSION 3
#elif defined(__ARM_ARCH_6T2__) \
|| defined(__ARM_ARCH_7__) \
|| defined(__ARM_ARCH_7A__) \
|| defined(__ARM_ARCH_7K__) \
|| defined(__ARM_ARCH_7M__) \
|| defined(__ARM_ARCH_7R__) \
|| defined(__ARM_ARCH_7S__)
#define BTHUMB_ARCH_VERSION 4
/* RVCT sets __TARGET_ARCH_THUMB */
#elif defined(__TARGET_ARCH_THUMB)
#define BTHUMB_ARCH_VERSION __TARGET_ARCH_THUMB
#else
#define BTHUMB_ARCH_VERSION 0
#endif
/* BCPU(ARM_TRADITIONAL) - Thumb2 is not available, only traditional ARM (v4 or greater) */
/* BCPU(ARM_THUMB2) - Thumb2 instruction set is available */
/* Only one of these will be defined. */
#if !defined(BCPU_ARM_TRADITIONAL) && !defined(BCPU_ARM_THUMB2)
# if defined(thumb2) || defined(__thumb2__) \
|| ((defined(__thumb) || defined(__thumb__)) && BTHUMB_ARCH_VERSION == 4)
# define BCPU_ARM_TRADITIONAL 0
# define BCPU_ARM_THUMB2 1
# elif BARM_ARCH_AT_LEAST(4)
# define BCPU_ARM_TRADITIONAL 1
# define BCPU_ARM_THUMB2 0
# else
# error "Not supported ARM architecture"
# endif
#elif BCPU(ARM_TRADITIONAL) && BCPU(ARM_THUMB2) /* Sanity Check */
# error "Cannot use both of BCPU_ARM_TRADITIONAL and BCPU_ARM_THUMB2 platforms"
#endif /* !defined(BCPU_ARM_TRADITIONAL) && !defined(BCPU_ARM_THUMB2) */
#endif /* ARM */
#define BATTRIBUTE_PRINTF(formatStringArgument, extraArguments) __attribute__((__format__(printf, formatStringArgument, extraArguments)))
#if (BPLATFORM(MAC) && __MAC_OS_X_VERSION_MIN_REQUIRED >= 101200) || (BPLATFORM(IOS) && __IPHONE_OS_VERSION_MIN_REQUIRED >= 100000)
#define BUSE_OS_LOG 1
#endif

98
bmalloc/BumpAllocator.h Normal file
View File

@ -0,0 +1,98 @@
/*
* Copyright (C) 2014 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef BumpAllocator_h
#define BumpAllocator_h
#include "BAssert.h"
#include "BumpRange.h"
#include "ObjectType.h"
namespace bmalloc {
// Helper object for allocating small objects.
class BumpAllocator {
public:
BumpAllocator();
void init(size_t);
size_t size() { return m_size; }
bool isNull() { return !m_ptr; }
void clear();
bool canAllocate() { return !!m_remaining; }
void* allocate();
void refill(const BumpRange&);
private:
char* m_ptr;
unsigned m_size;
unsigned m_remaining;
};
inline BumpAllocator::BumpAllocator()
: m_ptr()
, m_size()
, m_remaining()
{
}
inline void BumpAllocator::init(size_t size)
{
m_ptr = nullptr;
m_size = size;
m_remaining = 0;
}
inline void* BumpAllocator::allocate()
{
BASSERT(m_remaining);
--m_remaining;
char* result = m_ptr;
m_ptr += m_size;
return result;
}
inline void BumpAllocator::refill(const BumpRange& bumpRange)
{
BASSERT(!canAllocate());
m_ptr = bumpRange.begin;
m_remaining = bumpRange.objectCount;
BASSERT(canAllocate());
}
inline void BumpAllocator::clear()
{
m_ptr = nullptr;
m_remaining = 0;
}
} // namespace bmalloc
#endif // BumpAllocator_h

44
bmalloc/BumpRange.h Normal file
View File

@ -0,0 +1,44 @@
/*
* Copyright (C) 2014 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef BumpRange_h
#define BumpRange_h
#include "FixedVector.h"
#include "Range.h"
#include "Sizes.h"
namespace bmalloc {
struct BumpRange {
char* begin;
unsigned short objectCount;
};
typedef FixedVector<BumpRange, bumpRangeCacheCapacity> BumpRangeCache;
} // namespace bmalloc
#endif // BumpRange_h

84
bmalloc/Cache.cpp Normal file
View File

@ -0,0 +1,84 @@
/*
* Copyright (C) 2014, 2015 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "Cache.h"
#include "Heap.h"
#include "Inline.h"
#include "PerProcess.h"
namespace bmalloc {
void* Cache::operator new(size_t size)
{
return vmAllocate(vmSize(size));
}
void Cache::operator delete(void* p, size_t size)
{
vmDeallocate(p, vmSize(size));
}
void Cache::scavenge()
{
Cache* cache = PerThread<Cache>::getFastCase();
if (!cache)
return;
cache->allocator().scavenge();
cache->deallocator().scavenge();
}
Cache::Cache()
: m_deallocator(PerProcess<Heap>::get())
, m_allocator(PerProcess<Heap>::get(), m_deallocator)
{
}
NO_INLINE void* Cache::tryAllocateSlowCaseNullCache(size_t size)
{
return PerThread<Cache>::getSlowCase()->allocator().tryAllocate(size);
}
NO_INLINE void* Cache::allocateSlowCaseNullCache(size_t size)
{
return PerThread<Cache>::getSlowCase()->allocator().allocate(size);
}
NO_INLINE void* Cache::allocateSlowCaseNullCache(size_t alignment, size_t size)
{
return PerThread<Cache>::getSlowCase()->allocator().allocate(alignment, size);
}
NO_INLINE void Cache::deallocateSlowCaseNullCache(void* object)
{
PerThread<Cache>::getSlowCase()->deallocator().deallocate(object);
}
NO_INLINE void* Cache::reallocateSlowCaseNullCache(void* object, size_t newSize)
{
return PerThread<Cache>::getSlowCase()->allocator().reallocate(object, newSize);
}
} // namespace bmalloc

117
bmalloc/Cache.h Normal file
View File

@ -0,0 +1,117 @@
/*
* Copyright (C) 2014, 2016 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef Cache_h
#define Cache_h
#include "Allocator.h"
#include "Deallocator.h"
#include "PerThread.h"
namespace bmalloc {
// Per-thread allocation / deallocation cache, backed by a per-process Heap.
class Cache {
public:
void* operator new(size_t);
void operator delete(void*, size_t);
static void* tryAllocate(size_t);
static void* allocate(size_t);
static void* tryAllocate(size_t alignment, size_t);
static void* allocate(size_t alignment, size_t);
static void deallocate(void*);
static void* reallocate(void*, size_t);
static void scavenge();
Cache();
Allocator& allocator() { return m_allocator; }
Deallocator& deallocator() { return m_deallocator; }
private:
static void* tryAllocateSlowCaseNullCache(size_t);
static void* allocateSlowCaseNullCache(size_t);
static void* allocateSlowCaseNullCache(size_t alignment, size_t);
static void deallocateSlowCaseNullCache(void*);
static void* reallocateSlowCaseNullCache(void*, size_t);
Deallocator m_deallocator;
Allocator m_allocator;
};
inline void* Cache::tryAllocate(size_t size)
{
Cache* cache = PerThread<Cache>::getFastCase();
if (!cache)
return tryAllocateSlowCaseNullCache(size);
return cache->allocator().tryAllocate(size);
}
inline void* Cache::allocate(size_t size)
{
Cache* cache = PerThread<Cache>::getFastCase();
if (!cache)
return allocateSlowCaseNullCache(size);
return cache->allocator().allocate(size);
}
inline void* Cache::tryAllocate(size_t alignment, size_t size)
{
Cache* cache = PerThread<Cache>::getFastCase();
if (!cache)
return allocateSlowCaseNullCache(alignment, size);
return cache->allocator().tryAllocate(alignment, size);
}
inline void* Cache::allocate(size_t alignment, size_t size)
{
Cache* cache = PerThread<Cache>::getFastCase();
if (!cache)
return allocateSlowCaseNullCache(alignment, size);
return cache->allocator().allocate(alignment, size);
}
inline void Cache::deallocate(void* object)
{
Cache* cache = PerThread<Cache>::getFastCase();
if (!cache)
return deallocateSlowCaseNullCache(object);
return cache->deallocator().deallocate(object);
}
inline void* Cache::reallocate(void* object, size_t newSize)
{
Cache* cache = PerThread<Cache>::getFastCase();
if (!cache)
return reallocateSlowCaseNullCache(object, newSize);
return cache->allocator().reallocate(object, newSize);
}
} // namespace bmalloc
#endif // Cache_h

153
bmalloc/Chunk.h Normal file
View File

@ -0,0 +1,153 @@
/*
* Copyright (C) 2014 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef Chunk_h
#define Chunk_h
#include "Object.h"
#include "Sizes.h"
#include "SmallLine.h"
#include "SmallPage.h"
#include "VMAllocate.h"
#include <array>
namespace bmalloc {
class Chunk {
public:
static Chunk* get(void*);
Chunk(std::lock_guard<StaticMutex>&);
size_t offset(void*);
char* address(size_t offset);
SmallPage* page(size_t offset);
SmallLine* line(size_t offset);
char* bytes() { return reinterpret_cast<char*>(this); }
SmallLine* lines() { return &m_lines[0]; }
SmallPage* pages() { return &m_pages[0]; }
private:
std::array<SmallLine, chunkSize / smallLineSize> m_lines;
std::array<SmallPage, chunkSize / smallPageSize> m_pages;
};
struct ChunkHash {
static unsigned hash(Chunk* key)
{
return static_cast<unsigned>(
reinterpret_cast<uintptr_t>(key) / chunkSize);
}
};
inline Chunk::Chunk(std::lock_guard<StaticMutex>&)
{
}
inline Chunk* Chunk::get(void* address)
{
return static_cast<Chunk*>(mask(address, chunkMask));
}
inline size_t Chunk::offset(void* address)
{
BASSERT(address >= this);
BASSERT(address < bytes() + chunkSize);
return static_cast<char*>(address) - bytes();
}
inline char* Chunk::address(size_t offset)
{
return bytes() + offset;
}
inline SmallPage* Chunk::page(size_t offset)
{
size_t pageNumber = offset / smallPageSize;
SmallPage* page = &m_pages[pageNumber];
return page - page->slide();
}
inline SmallLine* Chunk::line(size_t offset)
{
size_t lineNumber = offset / smallLineSize;
return &m_lines[lineNumber];
}
inline char* SmallLine::begin()
{
Chunk* chunk = Chunk::get(this);
size_t lineNumber = this - chunk->lines();
size_t offset = lineNumber * smallLineSize;
return &reinterpret_cast<char*>(chunk)[offset];
}
inline char* SmallLine::end()
{
return begin() + smallLineSize;
}
inline SmallLine* SmallPage::begin()
{
BASSERT(!m_slide);
Chunk* chunk = Chunk::get(this);
size_t pageNumber = this - chunk->pages();
size_t lineNumber = pageNumber * smallPageLineCount;
return &chunk->lines()[lineNumber];
}
inline Object::Object(void* object)
: m_chunk(Chunk::get(object))
, m_offset(m_chunk->offset(object))
{
}
inline Object::Object(Chunk* chunk, void* object)
: m_chunk(chunk)
, m_offset(m_chunk->offset(object))
{
BASSERT(chunk == Chunk::get(object));
}
inline char* Object::address()
{
return m_chunk->address(m_offset);
}
inline SmallLine* Object::line()
{
return m_chunk->line(m_offset);
}
inline SmallPage* Object::page()
{
return m_chunk->page(m_offset);
}
}; // namespace bmalloc
#endif // Chunk

100
bmalloc/Deallocator.cpp Normal file
View File

@ -0,0 +1,100 @@
/*
* Copyright (C) 2014 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "BAssert.h"
#include "Chunk.h"
#include "Deallocator.h"
#include "Heap.h"
#include "Inline.h"
#include "Object.h"
#include "PerProcess.h"
#include <algorithm>
#include <cstdlib>
#include <sys/mman.h>
using namespace std;
namespace bmalloc {
Deallocator::Deallocator(Heap* heap)
: m_isBmallocEnabled(heap->environment().isBmallocEnabled())
{
if (!m_isBmallocEnabled) {
// Fill the object log in order to disable the fast path.
while (m_objectLog.size() != m_objectLog.capacity())
m_objectLog.push(nullptr);
}
}
Deallocator::~Deallocator()
{
scavenge();
}
void Deallocator::scavenge()
{
if (m_isBmallocEnabled)
processObjectLog();
}
void Deallocator::processObjectLog(std::lock_guard<StaticMutex>& lock)
{
Heap* heap = PerProcess<Heap>::getFastCase();
for (Object object : m_objectLog)
heap->derefSmallLine(lock, object);
m_objectLog.clear();
}
void Deallocator::processObjectLog()
{
std::lock_guard<StaticMutex> lock(PerProcess<Heap>::mutex());
processObjectLog(lock);
}
void Deallocator::deallocateSlowCase(void* object)
{
if (!m_isBmallocEnabled) {
free(object);
return;
}
if (!object)
return;
std::lock_guard<StaticMutex> lock(PerProcess<Heap>::mutex());
if (PerProcess<Heap>::getFastCase()->isLarge(lock, object)) {
PerProcess<Heap>::getFastCase()->deallocateLarge(lock, object);
return;
}
if (m_objectLog.size() == m_objectLog.capacity())
processObjectLog(lock);
m_objectLog.push(object);
}
} // namespace bmalloc

79
bmalloc/Deallocator.h Normal file
View File

@ -0,0 +1,79 @@
/*
* Copyright (C) 2014 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef Deallocator_h
#define Deallocator_h
#include "FixedVector.h"
#include <mutex>
namespace bmalloc {
class Heap;
class StaticMutex;
// Per-cache object deallocator.
class Deallocator {
public:
Deallocator(Heap*);
~Deallocator();
void deallocate(void*);
void scavenge();
void processObjectLog();
void processObjectLog(std::lock_guard<StaticMutex>&);
private:
bool deallocateFastCase(void*);
void deallocateSlowCase(void*);
FixedVector<void*, deallocatorLogCapacity> m_objectLog;
bool m_isBmallocEnabled;
};
inline bool Deallocator::deallocateFastCase(void* object)
{
BASSERT(mightBeLarge(nullptr));
if (mightBeLarge(object))
return false;
if (m_objectLog.size() == m_objectLog.capacity())
return false;
m_objectLog.push(object);
return true;
}
inline void Deallocator::deallocate(void* object)
{
if (!deallocateFastCase(object))
deallocateSlowCase(object);
}
} // namespace bmalloc
#endif // Deallocator_h

126
bmalloc/Environment.cpp Normal file
View File

@ -0,0 +1,126 @@
/*
* Copyright (C) 2014 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "BPlatform.h"
#include "Environment.h"
#include <cstdlib>
#include <cstring>
#if BOS(DARWIN)
#include <mach-o/dyld.h>
#elif BOS(UNIX)
#include <dlfcn.h>
#endif
namespace bmalloc {
static bool isMallocEnvironmentVariableSet()
{
const char* list[] = {
"Malloc",
"MallocLogFile",
"MallocGuardEdges",
"MallocDoNotProtectPrelude",
"MallocDoNotProtectPostlude",
"MallocStackLogging",
"MallocStackLoggingNoCompact",
"MallocStackLoggingDirectory",
"MallocScribble",
"MallocCheckHeapStart",
"MallocCheckHeapEach",
"MallocCheckHeapSleep",
"MallocCheckHeapAbort",
"MallocErrorAbort",
"MallocCorruptionAbort",
"MallocHelp"
};
size_t size = sizeof(list) / sizeof(const char*);
for (size_t i = 0; i < size; ++i) {
if (getenv(list[i]))
return true;
}
return false;
}
static bool isLibgmallocEnabled()
{
char* variable = getenv("DYLD_INSERT_LIBRARIES");
if (!variable)
return false;
if (!strstr(variable, "libgmalloc"))
return false;
return true;
}
static bool isSanitizerEnabled()
{
#if BOS(DARWIN)
static const char sanitizerPrefix[] = "/libclang_rt.";
static const char asanName[] = "asan_";
static const char tsanName[] = "tsan_";
uint32_t imageCount = _dyld_image_count();
for (uint32_t i = 0; i < imageCount; ++i) {
const char* imageName = _dyld_get_image_name(i);
if (!imageName)
continue;
if (const char* s = strstr(imageName, sanitizerPrefix)) {
const char* sanitizerName = s + sizeof(sanitizerPrefix) - 1;
if (!strncmp(sanitizerName, asanName, sizeof(asanName) - 1))
return true;
if (!strncmp(sanitizerName, tsanName, sizeof(tsanName) - 1))
return true;
}
}
return false;
#elif BOS(UNIX)
void* handle = dlopen(nullptr, RTLD_NOW);
if (!handle)
return false;
bool result = !!dlsym(handle, "__asan_init") || !!dlsym(handle, "__tsan_init");
dlclose(handle);
return result;
#else
return false;
#endif
}
Environment::Environment()
: m_isBmallocEnabled(computeIsBmallocEnabled())
{
}
bool Environment::computeIsBmallocEnabled()
{
if (isMallocEnvironmentVariableSet())
return false;
if (isLibgmallocEnabled())
return false;
if (isSanitizerEnabled())
return false;
return true;
}
} // namespace bmalloc

45
bmalloc/Environment.h Normal file
View File

@ -0,0 +1,45 @@
/*
* Copyright (C) 2014 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef Environment_h
#define Environment_h
namespace bmalloc {
class Environment {
public:
Environment();
bool isBmallocEnabled() { return m_isBmallocEnabled; }
private:
bool computeIsBmallocEnabled();
bool m_isBmallocEnabled;
};
} // namespace bmalloc
#endif // Environment_h

119
bmalloc/FixedVector.h Normal file
View File

@ -0,0 +1,119 @@
/*
* Copyright (C) 2014 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef FixedVector_h
#define FixedVector_h
#include "BAssert.h"
#include <array>
#include <cstddef>
#include <type_traits>
namespace bmalloc {
// A replacement for std::vector that uses a fixed-sized inline backing store.
template<typename T, size_t Capacity>
class FixedVector {
static_assert(std::is_trivially_destructible<T>::value, "FixedVector must have a trivial destructor.");
public:
FixedVector(const FixedVector&) = delete;
FixedVector& operator=(const FixedVector&) = delete;
FixedVector();
const T* begin() const { return &m_buffer[0]; }
const T* end() const { return begin() + size(); }
size_t size() const { return m_size; }
size_t capacity() const { return Capacity; }
T& operator[](size_t);
void push(const T&);
void push(const T*, const T*);
T pop();
void shrink(T*);
void shrink(size_t);
void clear() { shrink(static_cast<size_t>(0)); }
bool isEmpty() { return !m_size; }
private:
size_t m_size;
std::array<T, Capacity> m_buffer;
};
template<typename T, size_t Capacity>
inline FixedVector<T, Capacity>::FixedVector()
: m_size(0)
{
}
template<typename T, size_t Capacity>
inline T& FixedVector<T, Capacity>::operator[](size_t i)
{
BASSERT(i < m_size);
return m_buffer[i];
}
template<typename T, size_t Capacity>
inline void FixedVector<T, Capacity>::push(const T& value)
{
BASSERT(m_size < Capacity);
m_buffer[m_size++] = value;
}
template<typename T, size_t Capacity>
inline void FixedVector<T, Capacity>::push(const T* begin, const T* end)
{
for (const T* it = begin; it != end; ++it)
push(*it);
}
template<typename T, size_t Capacity>
inline T FixedVector<T, Capacity>::pop()
{
BASSERT(m_size);
return m_buffer[--m_size];
}
template<typename T, size_t Capacity>
inline void FixedVector<T, Capacity>::shrink(size_t size)
{
BASSERT(size <= m_size);
m_size = size;
}
template<typename T, size_t Capacity>
inline void FixedVector<T, Capacity>::shrink(T* end)
{
shrink(end - begin());
}
} // namespace bmalloc
#endif // FixedVector_h

415
bmalloc/Heap.cpp Normal file
View File

@ -0,0 +1,415 @@
/*
* Copyright (C) 2014-2016 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "Heap.h"
#include "BumpAllocator.h"
#include "Chunk.h"
#include "PerProcess.h"
#include "SmallLine.h"
#include "SmallPage.h"
#include <thread>
namespace bmalloc {
Heap::Heap(std::lock_guard<StaticMutex>&)
: m_vmPageSizePhysical(vmPageSizePhysical())
, m_isAllocatingPages(false)
, m_scavenger(*this, &Heap::concurrentScavenge)
{
RELEASE_BASSERT(vmPageSizePhysical() >= smallPageSize);
RELEASE_BASSERT(vmPageSize() >= vmPageSizePhysical());
initializeLineMetadata();
initializePageMetadata();
}
void Heap::initializeLineMetadata()
{
size_t sizeClassCount = bmalloc::sizeClass(smallLineSize);
size_t smallLineCount = m_vmPageSizePhysical / smallLineSize;
m_smallLineMetadata.grow(sizeClassCount * smallLineCount);
for (size_t sizeClass = 0; sizeClass < sizeClassCount; ++sizeClass) {
size_t size = objectSize(sizeClass);
LineMetadata* pageMetadata = &m_smallLineMetadata[sizeClass * smallLineCount];
size_t object = 0;
size_t line = 0;
while (object < m_vmPageSizePhysical) {
line = object / smallLineSize;
size_t leftover = object % smallLineSize;
size_t objectCount;
size_t remainder;
divideRoundingUp(smallLineSize - leftover, size, objectCount, remainder);
pageMetadata[line] = { static_cast<unsigned char>(leftover), static_cast<unsigned char>(objectCount) };
object += objectCount * size;
}
// Don't allow the last object in a page to escape the page.
if (object > m_vmPageSizePhysical) {
BASSERT(pageMetadata[line].objectCount);
--pageMetadata[line].objectCount;
}
}
}
void Heap::initializePageMetadata()
{
auto computePageSize = [&](size_t sizeClass) {
size_t size = objectSize(sizeClass);
if (sizeClass < bmalloc::sizeClass(smallLineSize))
return m_vmPageSizePhysical;
for (size_t pageSize = m_vmPageSizePhysical;
pageSize < pageSizeMax;
pageSize += m_vmPageSizePhysical) {
RELEASE_BASSERT(pageSize <= chunkSize / 2);
size_t waste = pageSize % size;
if (waste <= pageSize / pageSizeWasteFactor)
return pageSize;
}
return pageSizeMax;
};
for (size_t i = 0; i < sizeClassCount; ++i)
m_pageClasses[i] = (computePageSize(i) - 1) / smallPageSize;
}
void Heap::concurrentScavenge()
{
std::unique_lock<StaticMutex> lock(PerProcess<Heap>::mutex());
#if BOS(DARWIN)
if (auto requestedQOSClass = PerProcess<Heap>::getFastCase()->takeRequestedScavengerThreadQOSClass())
pthread_set_qos_class_self_np(requestedQOSClass, 0);
#endif
scavenge(lock, scavengeSleepDuration);
}
void Heap::scavenge(std::unique_lock<StaticMutex>& lock, std::chrono::milliseconds sleepDuration)
{
waitUntilFalse(lock, sleepDuration, m_isAllocatingPages);
scavengeSmallPages(lock, sleepDuration);
scavengeLargeObjects(lock, sleepDuration);
sleep(lock, sleepDuration);
}
void Heap::scavengeSmallPages(std::unique_lock<StaticMutex>& lock, std::chrono::milliseconds sleepDuration)
{
for (auto& smallPages : m_smallPages) {
while (!smallPages.isEmpty()) {
SmallPage* page = smallPages.pop();
size_t pageClass = m_pageClasses[page->sizeClass()];
m_vmHeap.deallocateSmallPage(lock, pageClass, page);
waitUntilFalse(lock, sleepDuration, m_isAllocatingPages);
}
}
}
void Heap::scavengeLargeObjects(std::unique_lock<StaticMutex>& lock, std::chrono::milliseconds sleepDuration)
{
auto& ranges = m_largeFree.ranges();
for (size_t i = ranges.size(); i-- > 0; i = std::min(i, ranges.size())) {
auto range = ranges.pop(i);
lock.unlock();
vmDeallocatePhysicalPagesSloppy(range.begin(), range.size());
lock.lock();
range.setPhysicalSize(0);
ranges.push(range);
waitUntilFalse(lock, sleepDuration, m_isAllocatingPages);
}
}
SmallPage* Heap::allocateSmallPage(std::lock_guard<StaticMutex>& lock, size_t sizeClass)
{
if (!m_smallPagesWithFreeLines[sizeClass].isEmpty())
return m_smallPagesWithFreeLines[sizeClass].popFront();
SmallPage* page = [&]() {
size_t pageClass = m_pageClasses[sizeClass];
if (!m_smallPages[pageClass].isEmpty())
return m_smallPages[pageClass].pop();
m_isAllocatingPages = true;
SmallPage* page = m_vmHeap.allocateSmallPage(lock, pageClass);
m_objectTypes.set(Chunk::get(page), ObjectType::Small);
return page;
}();
page->setSizeClass(sizeClass);
return page;
}
void Heap::deallocateSmallLine(std::lock_guard<StaticMutex>& lock, Object object)
{
BASSERT(!object.line()->refCount(lock));
SmallPage* page = object.page();
page->deref(lock);
if (!page->hasFreeLines(lock)) {
page->setHasFreeLines(lock, true);
m_smallPagesWithFreeLines[page->sizeClass()].push(page);
}
if (page->refCount(lock))
return;
size_t sizeClass = page->sizeClass();
size_t pageClass = m_pageClasses[sizeClass];
m_smallPagesWithFreeLines[sizeClass].remove(page);
m_smallPages[pageClass].push(page);
m_scavenger.run();
}
void Heap::allocateSmallBumpRangesByMetadata(
std::lock_guard<StaticMutex>& lock, size_t sizeClass,
BumpAllocator& allocator, BumpRangeCache& rangeCache)
{
SmallPage* page = allocateSmallPage(lock, sizeClass);
SmallLine* lines = page->begin();
BASSERT(page->hasFreeLines(lock));
size_t smallLineCount = m_vmPageSizePhysical / smallLineSize;
LineMetadata* pageMetadata = &m_smallLineMetadata[sizeClass * smallLineCount];
auto findSmallBumpRange = [&](size_t& lineNumber) {
for ( ; lineNumber < smallLineCount; ++lineNumber) {
if (!lines[lineNumber].refCount(lock)) {
if (pageMetadata[lineNumber].objectCount)
return true;
}
}
return false;
};
auto allocateSmallBumpRange = [&](size_t& lineNumber) -> BumpRange {
char* begin = lines[lineNumber].begin() + pageMetadata[lineNumber].startOffset;
unsigned short objectCount = 0;
for ( ; lineNumber < smallLineCount; ++lineNumber) {
if (lines[lineNumber].refCount(lock))
break;
if (!pageMetadata[lineNumber].objectCount)
continue;
objectCount += pageMetadata[lineNumber].objectCount;
lines[lineNumber].ref(lock, pageMetadata[lineNumber].objectCount);
page->ref(lock);
}
return { begin, objectCount };
};
size_t lineNumber = 0;
for (;;) {
if (!findSmallBumpRange(lineNumber)) {
page->setHasFreeLines(lock, false);
BASSERT(allocator.canAllocate());
return;
}
// In a fragmented page, some free ranges might not fit in the cache.
if (rangeCache.size() == rangeCache.capacity()) {
m_smallPagesWithFreeLines[sizeClass].push(page);
BASSERT(allocator.canAllocate());
return;
}
BumpRange bumpRange = allocateSmallBumpRange(lineNumber);
if (allocator.canAllocate())
rangeCache.push(bumpRange);
else
allocator.refill(bumpRange);
}
}
void Heap::allocateSmallBumpRangesByObject(
std::lock_guard<StaticMutex>& lock, size_t sizeClass,
BumpAllocator& allocator, BumpRangeCache& rangeCache)
{
size_t size = allocator.size();
SmallPage* page = allocateSmallPage(lock, sizeClass);
BASSERT(page->hasFreeLines(lock));
auto findSmallBumpRange = [&](Object& it, Object& end) {
for ( ; it + size <= end; it = it + size) {
if (!it.line()->refCount(lock))
return true;
}
return false;
};
auto allocateSmallBumpRange = [&](Object& it, Object& end) -> BumpRange {
char* begin = it.address();
unsigned short objectCount = 0;
for ( ; it + size <= end; it = it + size) {
if (it.line()->refCount(lock))
break;
++objectCount;
it.line()->ref(lock);
it.page()->ref(lock);
}
return { begin, objectCount };
};
Object it(page->begin()->begin());
Object end(it + pageSize(m_pageClasses[sizeClass]));
for (;;) {
if (!findSmallBumpRange(it, end)) {
page->setHasFreeLines(lock, false);
BASSERT(allocator.canAllocate());
return;
}
// In a fragmented page, some free ranges might not fit in the cache.
if (rangeCache.size() == rangeCache.capacity()) {
m_smallPagesWithFreeLines[sizeClass].push(page);
BASSERT(allocator.canAllocate());
return;
}
BumpRange bumpRange = allocateSmallBumpRange(it, end);
if (allocator.canAllocate())
rangeCache.push(bumpRange);
else
allocator.refill(bumpRange);
}
}
LargeRange Heap::splitAndAllocate(LargeRange& range, size_t alignment, size_t size)
{
LargeRange prev;
LargeRange next;
size_t alignmentMask = alignment - 1;
if (test(range.begin(), alignmentMask)) {
size_t prefixSize = roundUpToMultipleOf(alignment, range.begin()) - range.begin();
std::pair<LargeRange, LargeRange> pair = range.split(prefixSize);
prev = pair.first;
range = pair.second;
}
if (range.size() - size > size / pageSizeWasteFactor) {
std::pair<LargeRange, LargeRange> pair = range.split(size);
range = pair.first;
next = pair.second;
}
if (range.physicalSize() < range.size()) {
m_isAllocatingPages = true;
vmAllocatePhysicalPagesSloppy(range.begin() + range.physicalSize(), range.size() - range.physicalSize());
range.setPhysicalSize(range.size());
}
if (prev)
m_largeFree.add(prev);
if (next)
m_largeFree.add(next);
m_objectTypes.set(Chunk::get(range.begin()), ObjectType::Large);
m_largeAllocated.set(range.begin(), range.size());
return range;
}
void* Heap::tryAllocateLarge(std::lock_guard<StaticMutex>& lock, size_t alignment, size_t size)
{
BASSERT(isPowerOfTwo(alignment));
size_t roundedSize = size ? roundUpToMultipleOf(largeAlignment, size) : largeAlignment;
if (roundedSize < size) // Check for overflow
return nullptr;
size = roundedSize;
size_t roundedAlignment = roundUpToMultipleOf<largeAlignment>(alignment);
if (roundedAlignment < alignment) // Check for overflow
return nullptr;
alignment = roundedAlignment;
LargeRange range = m_largeFree.remove(alignment, size);
if (!range) {
range = m_vmHeap.tryAllocateLargeChunk(lock, alignment, size);
if (!range)
return nullptr;
m_largeFree.add(range);
range = m_largeFree.remove(alignment, size);
}
return splitAndAllocate(range, alignment, size).begin();
}
void* Heap::allocateLarge(std::lock_guard<StaticMutex>& lock, size_t alignment, size_t size)
{
void* result = tryAllocateLarge(lock, alignment, size);
RELEASE_BASSERT(result);
return result;
}
bool Heap::isLarge(std::lock_guard<StaticMutex>&, void* object)
{
return m_objectTypes.get(Object(object).chunk()) == ObjectType::Large;
}
size_t Heap::largeSize(std::lock_guard<StaticMutex>&, void* object)
{
return m_largeAllocated.get(object);
}
void Heap::shrinkLarge(std::lock_guard<StaticMutex>&, const Range& object, size_t newSize)
{
BASSERT(object.size() > newSize);
size_t size = m_largeAllocated.remove(object.begin());
LargeRange range = LargeRange(object, size);
splitAndAllocate(range, alignment, newSize);
m_scavenger.run();
}
void Heap::deallocateLarge(std::lock_guard<StaticMutex>&, void* object)
{
size_t size = m_largeAllocated.remove(object);
m_largeFree.add(LargeRange(object, size, size));
m_scavenger.run();
}
} // namespace bmalloc

150
bmalloc/Heap.h Normal file
View File

@ -0,0 +1,150 @@
/*
* Copyright (C) 2014-2016 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef Heap_h
#define Heap_h
#include "AsyncTask.h"
#include "BumpRange.h"
#include "Environment.h"
#include "LargeMap.h"
#include "LineMetadata.h"
#include "List.h"
#include "Map.h"
#include "Mutex.h"
#include "Object.h"
#include "SmallLine.h"
#include "SmallPage.h"
#include "VMHeap.h"
#include "Vector.h"
#include <array>
#include <mutex>
namespace bmalloc {
class BeginTag;
class BumpAllocator;
class EndTag;
class Heap {
public:
Heap(std::lock_guard<StaticMutex>&);
Environment& environment() { return m_environment; }
void allocateSmallBumpRanges(std::lock_guard<StaticMutex>&, size_t sizeClass, BumpAllocator&, BumpRangeCache&);
void derefSmallLine(std::lock_guard<StaticMutex>&, Object);
void* allocateLarge(std::lock_guard<StaticMutex>&, size_t alignment, size_t);
void* tryAllocateLarge(std::lock_guard<StaticMutex>&, size_t alignment, size_t);
void deallocateLarge(std::lock_guard<StaticMutex>&, void*);
bool isLarge(std::lock_guard<StaticMutex>&, void*);
size_t largeSize(std::lock_guard<StaticMutex>&, void*);
void shrinkLarge(std::lock_guard<StaticMutex>&, const Range&, size_t);
void scavenge(std::unique_lock<StaticMutex>&, std::chrono::milliseconds sleepDuration);
#if BOS(DARWIN)
qos_class_t takeRequestedScavengerThreadQOSClass() { return std::exchange(m_requestedScavengerThreadQOSClass, QOS_CLASS_UNSPECIFIED); }
void setScavengerThreadQOSClass(qos_class_t overrideClass) { m_requestedScavengerThreadQOSClass = overrideClass; }
#endif
private:
struct LargeObjectHash {
static unsigned hash(void* key)
{
return static_cast<unsigned>(
reinterpret_cast<uintptr_t>(key) / smallMax);
}
};
~Heap() = delete;
void initializeLineMetadata();
void initializePageMetadata();
void allocateSmallBumpRangesByMetadata(std::lock_guard<StaticMutex>&,
size_t sizeClass, BumpAllocator&, BumpRangeCache&);
void allocateSmallBumpRangesByObject(std::lock_guard<StaticMutex>&,
size_t sizeClass, BumpAllocator&, BumpRangeCache&);
SmallPage* allocateSmallPage(std::lock_guard<StaticMutex>&, size_t sizeClass);
void deallocateSmallLine(std::lock_guard<StaticMutex>&, Object);
void mergeLarge(BeginTag*&, EndTag*&, Range&);
void mergeLargeLeft(EndTag*&, BeginTag*&, Range&, bool& inVMHeap);
void mergeLargeRight(EndTag*&, BeginTag*&, Range&, bool& inVMHeap);
LargeRange splitAndAllocate(LargeRange&, size_t alignment, size_t);
void concurrentScavenge();
void scavengeSmallPages(std::unique_lock<StaticMutex>&, std::chrono::milliseconds);
void scavengeLargeObjects(std::unique_lock<StaticMutex>&, std::chrono::milliseconds);
size_t m_vmPageSizePhysical;
Vector<LineMetadata> m_smallLineMetadata;
std::array<size_t, sizeClassCount> m_pageClasses;
std::array<List<SmallPage>, sizeClassCount> m_smallPagesWithFreeLines;
std::array<List<SmallPage>, pageClassCount> m_smallPages;
Map<void*, size_t, LargeObjectHash> m_largeAllocated;
LargeMap m_largeFree;
Map<Chunk*, ObjectType, ChunkHash> m_objectTypes;
bool m_isAllocatingPages;
AsyncTask<Heap, decltype(&Heap::concurrentScavenge)> m_scavenger;
Environment m_environment;
VMHeap m_vmHeap;
#if BOS(DARWIN)
qos_class_t m_requestedScavengerThreadQOSClass { QOS_CLASS_UNSPECIFIED };
#endif
};
inline void Heap::allocateSmallBumpRanges(
std::lock_guard<StaticMutex>& lock, size_t sizeClass,
BumpAllocator& allocator, BumpRangeCache& rangeCache)
{
if (sizeClass < bmalloc::sizeClass(smallLineSize))
return allocateSmallBumpRangesByMetadata(lock, sizeClass, allocator, rangeCache);
return allocateSmallBumpRangesByObject(lock, sizeClass, allocator, rangeCache);
}
inline void Heap::derefSmallLine(std::lock_guard<StaticMutex>& lock, Object object)
{
if (!object.line()->deref(lock))
return;
deallocateSmallLine(lock, object);
}
} // namespace bmalloc
#endif // Heap_h

33
bmalloc/Inline.h Normal file
View File

@ -0,0 +1,33 @@
/*
* Copyright (C) 2014 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef Inline_h
#define Inline_h
#define INLINE __attribute__((always_inline)) inline
#define NO_INLINE __attribute__((noinline))
#endif // Inline_h

79
bmalloc/LargeMap.cpp Normal file
View File

@ -0,0 +1,79 @@
/*
* Copyright (C) 2016 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "LargeMap.h"
#include <utility>
namespace bmalloc {
LargeRange LargeMap::remove(size_t alignment, size_t size)
{
size_t alignmentMask = alignment - 1;
LargeRange* candidate = m_free.end();
for (LargeRange* it = m_free.begin(); it != m_free.end(); ++it) {
if (it->size() < size)
continue;
if (candidate != m_free.end() && candidate->begin() < it->begin())
continue;
if (test(it->begin(), alignmentMask)) {
char* aligned = roundUpToMultipleOf(alignment, it->begin());
if (aligned < it->begin()) // Check for overflow.
continue;
char* alignedEnd = aligned + size;
if (alignedEnd < aligned) // Check for overflow.
continue;
if (alignedEnd > it->end())
continue;
}
candidate = it;
}
if (candidate == m_free.end())
return LargeRange();
return m_free.pop(candidate);
}
void LargeMap::add(const LargeRange& range)
{
LargeRange merged = range;
for (size_t i = 0; i < m_free.size(); ++i) {
if (!canMerge(merged, m_free[i]))
continue;
merged = merge(merged, m_free.pop(i--));
}
m_free.push(merged);
}
} // namespace bmalloc

47
bmalloc/LargeMap.h Normal file
View File

@ -0,0 +1,47 @@
/*
* Copyright (C) 2016 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef LargeMap_h
#define LargeMap_h
#include "LargeRange.h"
#include "Vector.h"
#include <algorithm>
namespace bmalloc {
class LargeMap {
public:
void add(const LargeRange&);
LargeRange remove(size_t alignment, size_t);
Vector<LargeRange>& ranges() { return m_free; }
private:
Vector<LargeRange> m_free;
};
} // namespace bmalloc
#endif // LargeMap_h

110
bmalloc/LargeRange.h Normal file
View File

@ -0,0 +1,110 @@
/*
* Copyright (C) 2016 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef LargeRange_h
#define LargeRange_h
#include "BAssert.h"
#include "Range.h"
namespace bmalloc {
class LargeRange : public Range {
public:
LargeRange()
: Range()
, m_physicalSize(0)
{
}
LargeRange(const Range& other, size_t physicalSize)
: Range(other)
, m_physicalSize(physicalSize)
{
}
LargeRange(void* begin, size_t size, size_t physicalSize)
: Range(begin, size)
, m_physicalSize(physicalSize)
{
}
size_t physicalSize() const { return m_physicalSize; }
void setPhysicalSize(size_t physicalSize) { m_physicalSize = physicalSize; }
std::pair<LargeRange, LargeRange> split(size_t) const;
bool operator<(const void* other) const { return begin() < other; }
bool operator<(const LargeRange& other) const { return begin() < other.begin(); }
private:
size_t m_physicalSize;
};
inline bool canMerge(const LargeRange& a, const LargeRange& b)
{
if (a.end() == b.begin())
return true;
if (b.end() == a.begin())
return true;
return false;
}
inline LargeRange merge(const LargeRange& a, const LargeRange& b)
{
const LargeRange& left = std::min(a, b);
if (left.size() == left.physicalSize()) {
return LargeRange(
left.begin(),
a.size() + b.size(),
a.physicalSize() + b.physicalSize());
}
return LargeRange(
left.begin(),
a.size() + b.size(),
left.physicalSize());
}
inline std::pair<LargeRange, LargeRange> LargeRange::split(size_t size) const
{
BASSERT(size <= this->size());
if (size <= physicalSize()) {
LargeRange left(begin(), size, size);
LargeRange right(left.end(), this->size() - size, physicalSize() - size);
return std::make_pair(left, right);
}
LargeRange left(begin(), size, physicalSize());
LargeRange right(left.end(), this->size() - size, 0);
return std::make_pair(left, right);
}
} // namespace bmalloc
#endif // LargeRange_h

46
bmalloc/LineMetadata.h Normal file
View File

@ -0,0 +1,46 @@
/*
* Copyright (C) 2014 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef LineMetadata_h
#define LineMetadata_h
namespace bmalloc {
struct LineMetadata {
unsigned char startOffset;
unsigned char objectCount;
};
static_assert(
smallLineSize - alignment <= std::numeric_limits<unsigned char>::max(),
"maximum object offset must fit in LineMetadata::startOffset");
static_assert(
smallLineSize / alignment <= std::numeric_limits<unsigned char>::max(),
"maximum object count must fit in LineMetadata::objectCount");
} // namespace bmalloc
#endif // LineMetadata_h

102
bmalloc/List.h Normal file
View File

@ -0,0 +1,102 @@
/*
* Copyright (C) 2016 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef List_h
#define List_h
namespace bmalloc {
template<typename T>
struct ListNode {
ListNode()
: prev(this)
, next(this)
{
}
ListNode<T>* prev;
ListNode<T>* next;
};
template<typename T>
class List {
static_assert(std::is_trivially_destructible<T>::value, "List must have a trivial destructor.");
public:
bool isEmpty() { return m_root.next == &m_root; }
T* head() { return static_cast<T*>(m_root.next); }
T* tail() { return static_cast<T*>(m_root.prev); }
void push(T* node)
{
ListNode<T>* it = tail();
insertAfter(it, node);
}
T* pop()
{
ListNode<T>* result = tail();
remove(result);
return static_cast<T*>(result);
}
T* popFront()
{
ListNode<T>* result = head();
remove(result);
return static_cast<T*>(result);
}
void insertAfter(ListNode<T>* it, ListNode<T>* node)
{
ListNode<T>* prev = it;
ListNode<T>* next = it->next;
node->next = next;
next->prev = node;
node->prev = prev;
prev->next = node;
}
void remove(ListNode<T>* node)
{
ListNode<T>* next = node->next;
ListNode<T>* prev = node->prev;
next->prev = prev;
prev->next = next;
node->prev = node;
node->next = node;
}
private:
ListNode<T> m_root;
};
} // namespace bmalloc
#endif // List_h

65
bmalloc/Logging.cpp Normal file
View File

@ -0,0 +1,65 @@
/*
* Copyright (C) 2016 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "Logging.h"
#include "BPlatform.h"
#if !BUSE(OS_LOG)
#include <stdarg.h>
#include <stdio.h>
#endif
#if BPLATFORM(IOS)
#include <mach/exception_types.h>
#include <objc/objc.h>
#include <unistd.h>
#include "BSoftLinking.h"
BSOFT_LINK_PRIVATE_FRAMEWORK(CrashReporterSupport);
BSOFT_LINK_FUNCTION(CrashReporterSupport, SimulateCrash, BOOL, (pid_t pid, mach_exception_data_type_t exceptionCode, id description), (pid, exceptionCode, description));
#endif
namespace bmalloc {
void logVMFailure()
{
#if BPLATFORM(IOS)
const mach_exception_data_type_t kExceptionCode = 0xc105ca11;
SimulateCrash(getpid(), kExceptionCode, nullptr);
#endif
}
#if !BUSE(OS_LOG)
void reportAssertionFailureWithMessage(const char* file, int line, const char* function, const char* format, ...)
{
va_list args;
va_start(args, format);
vfprintf(stderr, format, args);
va_end(args);
fprintf(stderr, "%s(%d) : %s\n", file, line, function);
}
#endif
} // namespace bmalloc

38
bmalloc/Logging.h Normal file
View File

@ -0,0 +1,38 @@
/*
* Copyright (C) 2016 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#pragma once
#include "BPlatform.h"
namespace bmalloc {
void logVMFailure();
#if !BUSE(OS_LOG)
void reportAssertionFailureWithMessage(const char* file, int line, const char* function, const char* format, ...) BATTRIBUTE_PRINTF(4, 5);
#endif
} // namespace bmalloc

134
bmalloc/Map.h Normal file
View File

@ -0,0 +1,134 @@
/*
* Copyright (C) 2016 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef Map_h
#define Map_h
#include "Inline.h"
#include "Sizes.h"
#include "Vector.h"
namespace bmalloc {
class SmallPage;
template<typename Key, typename Value, typename Hash> class Map {
static_assert(std::is_trivially_destructible<Key>::value, "Map must have a trivial destructor.");
static_assert(std::is_trivially_destructible<Value>::value, "Map must have a trivial destructor.");
public:
struct Bucket {
Key key;
Value value;
};
size_t size() { return m_keyCount; }
size_t capacity() { return m_table.size(); }
// key must be in the map.
Value& get(const Key& key)
{
auto& bucket = find(key, [&](const Bucket& bucket) { return bucket.key == key; });
return bucket.value;
}
void set(const Key& key, const Value& value)
{
if (shouldGrow())
rehash();
auto& bucket = find(key, [&](const Bucket& bucket) { return !bucket.key || bucket.key == key; });
if (!bucket.key) {
bucket.key = key;
++m_keyCount;
}
bucket.value = value;
}
// key must be in the map.
Value remove(const Key& key)
{
if (shouldShrink())
rehash();
auto& bucket = find(key, [&](const Bucket& bucket) { return bucket.key == key; });
Value value = bucket.value;
bucket.key = Key();
--m_keyCount;
return value;
}
private:
static const unsigned minCapacity = 16;
static const unsigned maxLoad = 2;
static const unsigned rehashLoad = 4;
static const unsigned minLoad = 8;
bool shouldGrow() { return m_keyCount * maxLoad >= capacity(); }
bool shouldShrink() { return m_keyCount * minLoad <= capacity() && capacity() > minCapacity; }
void rehash();
template<typename Predicate>
Bucket& find(const Key& key, const Predicate& predicate)
{
for (unsigned h = Hash::hash(key); ; ++h) {
unsigned i = h & m_tableMask;
Bucket& bucket = m_table[i];
if (predicate(bucket))
return bucket;
}
}
unsigned m_keyCount;
unsigned m_tableMask;
Vector<Bucket> m_table;
};
template<typename Key, typename Value, typename Hash>
void Map<Key, Value, Hash>::rehash()
{
auto oldTable = std::move(m_table);
size_t newCapacity = std::max(minCapacity, m_keyCount * rehashLoad);
m_table.resize(newCapacity);
m_keyCount = 0;
m_tableMask = newCapacity - 1;
for (auto& bucket : oldTable) {
if (!bucket.key)
continue;
BASSERT(!shouldGrow());
set(bucket.key, bucket.value);
}
}
template<typename Key, typename Value, typename Hash> const unsigned Map<Key, Value, Hash>::minCapacity;
} // namespace bmalloc
#endif // Map_h

48
bmalloc/Mutex.h Normal file
View File

@ -0,0 +1,48 @@
/*
* Copyright (C) 2014 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef Mutex_h
#define Mutex_h
#include "StaticMutex.h"
// A fast replacement for std::mutex, for use in standard storage.
namespace bmalloc {
class Mutex : public StaticMutex {
public:
Mutex();
};
inline Mutex::Mutex()
{
// StaticMutex requires explicit initialization when used in non-static storage.
init();
}
} // namespace bmalloc
#endif // Mutex_h

81
bmalloc/Object.h Normal file
View File

@ -0,0 +1,81 @@
/*
* Copyright (C) 2016 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef Object_h
#define Object_h
#include <cstddef>
namespace bmalloc {
class Chunk;
class SmallLine;
class SmallPage;
class Object {
public:
Object(void*);
Object(Chunk*, void*);
Object(Chunk* chunk, size_t offset)
: m_chunk(chunk)
, m_offset(offset)
{
}
Chunk* chunk() { return m_chunk; }
size_t offset() { return m_offset; }
char* address();
SmallLine* line();
SmallPage* page();
Object operator+(size_t);
Object operator-(size_t);
bool operator<=(const Object&);
private:
Chunk* m_chunk;
size_t m_offset;
};
inline Object Object::operator+(size_t offset)
{
return Object(m_chunk, m_offset + offset);
}
inline Object Object::operator-(size_t offset)
{
return Object(m_chunk, m_offset - offset);
}
inline bool Object::operator<=(const Object& other)
{
BASSERT(m_chunk == other.m_chunk);
return m_offset <= other.m_offset;
}
}; // namespace bmalloc
#endif // Object_h

49
bmalloc/ObjectType.cpp Normal file
View File

@ -0,0 +1,49 @@
/*
* Copyright (C) 2014 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "ObjectType.h"
#include "Chunk.h"
#include "Heap.h"
#include "Object.h"
#include "PerProcess.h"
namespace bmalloc {
ObjectType objectType(void* object)
{
if (mightBeLarge(object)) {
if (!object)
return ObjectType::Small;
std::lock_guard<StaticMutex> lock(PerProcess<Heap>::mutex());
if (PerProcess<Heap>::getFastCase()->isLarge(lock, object))
return ObjectType::Large;
}
return ObjectType::Small;
}
} // namespace bmalloc

45
bmalloc/ObjectType.h Normal file
View File

@ -0,0 +1,45 @@
/*
* Copyright (C) 2014 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef ObjectType_h
#define ObjectType_h
#include "BAssert.h"
#include "Sizes.h"
namespace bmalloc {
enum class ObjectType : unsigned char { Small, Large };
ObjectType objectType(void*);
inline bool mightBeLarge(void* object)
{
return !test(object, largeAlignmentMask);
}
} // namespace bmalloc
#endif // ObjectType_h

110
bmalloc/PerProcess.h Normal file
View File

@ -0,0 +1,110 @@
/*
* Copyright (C) 2014 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef PerProcess_h
#define PerProcess_h
#include "Inline.h"
#include "Sizes.h"
#include "StaticMutex.h"
#include <mutex>
namespace bmalloc {
// Usage:
// Object* object = PerProcess<Object>::get();
// x = object->field->field;
//
// Object will be instantiated only once, even in the face of concurrency.
//
// NOTE: If you observe global side-effects of the Object constructor, be
// sure to lock the Object mutex. For example:
//
// Object() : m_field(...) { globalFlag = true }
//
// Object* object = PerProcess<Object>::get();
// x = object->m_field; // OK
// if (gobalFlag) { ... } // Undefined behavior.
//
// std::lock_guard<StaticMutex> lock(PerProcess<Object>::mutex());
// Object* object = PerProcess<Object>::get(lock);
// if (gobalFlag) { ... } // OK.
template<typename T>
class PerProcess {
public:
static T* get();
static T* getFastCase();
static StaticMutex& mutex() { return s_mutex; }
private:
static T* getSlowCase();
static std::atomic<T*> s_object;
static StaticMutex s_mutex;
typedef typename std::aligned_storage<sizeof(T), std::alignment_of<T>::value>::type Memory;
static Memory s_memory;
};
template<typename T>
INLINE T* PerProcess<T>::getFastCase()
{
return s_object.load(std::memory_order_consume);
}
template<typename T>
INLINE T* PerProcess<T>::get()
{
T* object = getFastCase();
if (!object)
return getSlowCase();
return object;
}
template<typename T>
NO_INLINE T* PerProcess<T>::getSlowCase()
{
std::lock_guard<StaticMutex> lock(s_mutex);
if (!s_object.load(std::memory_order_consume)) {
T* t = new (&s_memory) T(lock);
s_object.store(t, std::memory_order_release);
}
return s_object.load(std::memory_order_consume);
}
template<typename T>
std::atomic<T*> PerProcess<T>::s_object;
template<typename T>
StaticMutex PerProcess<T>::s_mutex;
template<typename T>
typename PerProcess<T>::Memory PerProcess<T>::s_memory;
} // namespace bmalloc
#endif // PerProcess_h

148
bmalloc/PerThread.h Normal file
View File

@ -0,0 +1,148 @@
/*
* Copyright (C) 2014 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef PerThread_h
#define PerThread_h
#include "BPlatform.h"
#include "Inline.h"
#include <mutex>
#include <pthread.h>
#if defined(__has_include)
#if __has_include(<System/pthread_machdep.h>)
#include <System/pthread_machdep.h>
#define HAVE_PTHREAD_MACHDEP_H 1
#else
#define HAVE_PTHREAD_MACHDEP_H 0
#endif
#else
#define HAVE_PTHREAD_MACHDEP_H 0
#endif
namespace bmalloc {
// Usage:
// Object* object = PerThread<Object>::get();
template<typename T>
class PerThread {
public:
static T* get();
static T* getFastCase();
static T* getSlowCase();
private:
static void destructor(void*);
};
#if HAVE_PTHREAD_MACHDEP_H
class Cache;
template<typename T> struct PerThreadStorage;
// For now, we only support PerThread<Cache>. We can expand to other types by
// using more keys.
template<> struct PerThreadStorage<Cache> {
static const pthread_key_t key = __PTK_FRAMEWORK_JAVASCRIPTCORE_KEY0;
static void* get()
{
return _pthread_getspecific_direct(key);
}
static void init(void* object, void (*destructor)(void*))
{
_pthread_setspecific_direct(key, object);
pthread_key_init_np(key, destructor);
}
};
#else
template<typename T> struct PerThreadStorage {
static bool s_didInitialize;
static pthread_key_t s_key;
static std::once_flag s_onceFlag;
static void* get()
{
if (!s_didInitialize)
return nullptr;
return pthread_getspecific(s_key);
}
static void init(void* object, void (*destructor)(void*))
{
std::call_once(s_onceFlag, [destructor]() {
int error = pthread_key_create(&s_key, destructor);
if (error)
BCRASH();
s_didInitialize = true;
});
pthread_setspecific(s_key, object);
}
};
template<typename T> bool PerThreadStorage<T>::s_didInitialize;
template<typename T> pthread_key_t PerThreadStorage<T>::s_key;
template<typename T> std::once_flag PerThreadStorage<T>::s_onceFlag;
#endif
template<typename T>
INLINE T* PerThread<T>::getFastCase()
{
return static_cast<T*>(PerThreadStorage<T>::get());
}
template<typename T>
inline T* PerThread<T>::get()
{
T* t = getFastCase();
if (!t)
return getSlowCase();
return t;
}
template<typename T>
void PerThread<T>::destructor(void* p)
{
T* t = static_cast<T*>(p);
delete t;
}
template<typename T>
T* PerThread<T>::getSlowCase()
{
BASSERT(!getFastCase());
T* t = new T;
PerThreadStorage<T>::init(t, destructor);
return t;
}
} // namespace bmalloc
#endif // PerThread_h

73
bmalloc/Range.h Normal file
View File

@ -0,0 +1,73 @@
/*
* Copyright (C) 2014 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef Range_h
#define Range_h
#include <algorithm>
#include <cstddef>
namespace bmalloc {
class Range {
public:
Range()
: m_begin(0)
, m_size(0)
{
}
Range(void* start, size_t size)
: m_begin(static_cast<char*>(start))
, m_size(size)
{
}
char* begin() const { return m_begin; }
char* end() const { return m_begin + m_size; }
size_t size() const { return m_size; }
bool operator!() const { return !m_size; }
explicit operator bool() const { return !!*this; }
bool operator<(const Range& other) const { return m_begin < other.m_begin; }
private:
char* m_begin;
size_t m_size;
};
inline bool canMerge(const Range& a, const Range& b)
{
return a.begin() == b.end() || a.end() == b.begin();
}
inline Range merge(const Range& a, const Range& b)
{
return Range(std::min(a.begin(), b.begin()), a.size() + b.size());
}
} // namespace bmalloc
#endif // Range_h

54
bmalloc/ScopeExit.h Normal file
View File

@ -0,0 +1,54 @@
/*
* Copyright (C) 2016 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <type_traits>
#include <utility>
namespace bmalloc {
template<typename ExitFunction>
class ScopeExit {
public:
explicit ScopeExit(ExitFunction&& exitFunction)
: m_exitFunction(exitFunction)
{
}
~ScopeExit()
{
m_exitFunction();
}
private:
ExitFunction m_exitFunction;
};
template<typename ExitFunction>
ScopeExit<ExitFunction> makeScopeExit(ExitFunction&& exitFunction)
{
return ScopeExit<ExitFunction>(std::forward<ExitFunction>(exitFunction));
}
} // namespace bmalloc

130
bmalloc/Sizes.h Normal file
View File

@ -0,0 +1,130 @@
/*
* Copyright (C) 2014 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef Sizes_h
#define Sizes_h
#include "Algorithm.h"
#include "BPlatform.h"
#include <algorithm>
#include <cstdint>
#include <cstddef>
#include <limits>
#include <type_traits>
#include <chrono>
namespace bmalloc {
// Repository for malloc sizing constants and calculations.
namespace Sizes {
static const size_t kB = 1024;
static const size_t MB = kB * kB;
static const size_t alignment = 8;
static const size_t alignmentMask = alignment - 1ul;
static const size_t chunkSize = 2 * MB;
static const size_t chunkMask = ~(chunkSize - 1ul);
static const size_t smallLineSize = 256;
static const size_t smallPageSize = 4 * kB;
static const size_t smallPageLineCount = smallPageSize / smallLineSize;
static const size_t maskSizeClassMax = 512;
static const size_t smallMax = 32 * kB;
static const size_t pageSizeMax = smallMax * 2;
static const size_t pageClassCount = pageSizeMax / smallPageSize;
static const size_t pageSizeWasteFactor = 8;
static const size_t logWasteFactor = 8;
static const size_t largeAlignment = smallMax / pageSizeWasteFactor;
static const size_t largeAlignmentMask = largeAlignment - 1;
static const size_t deallocatorLogCapacity = 256;
static const size_t bumpRangeCacheCapacity = 3;
static const std::chrono::milliseconds scavengeSleepDuration = std::chrono::milliseconds(512);
static const size_t maskSizeClassCount = maskSizeClassMax / alignment;
inline constexpr size_t maskSizeClass(size_t size)
{
// We mask to accommodate zero.
return mask((size - 1) / alignment, maskSizeClassCount - 1);
}
inline size_t maskObjectSize(size_t maskSizeClass)
{
return (maskSizeClass + 1) * alignment;
}
static const size_t logAlignmentMin = maskSizeClassMax / logWasteFactor;
static const size_t logSizeClassCount = (log2(smallMax) - log2(maskSizeClassMax)) * logWasteFactor;
inline size_t logSizeClass(size_t size)
{
size_t base = log2(size - 1) - log2(maskSizeClassMax);
size_t offset = (size - 1 - (maskSizeClassMax << base));
return base * logWasteFactor + offset / (logAlignmentMin << base);
}
inline size_t logObjectSize(size_t logSizeClass)
{
size_t base = logSizeClass / logWasteFactor;
size_t offset = logSizeClass % logWasteFactor;
return (maskSizeClassMax << base) + (offset + 1) * (logAlignmentMin << base);
}
static const size_t sizeClassCount = maskSizeClassCount + logSizeClassCount;
inline size_t sizeClass(size_t size)
{
if (size <= maskSizeClassMax)
return maskSizeClass(size);
return maskSizeClassCount + logSizeClass(size);
}
inline size_t objectSize(size_t sizeClass)
{
if (sizeClass < maskSizeClassCount)
return maskObjectSize(sizeClass);
return logObjectSize(sizeClass - maskSizeClassCount);
}
inline size_t pageSize(size_t pageClass)
{
return (pageClass + 1) * smallPageSize;
}
}
using namespace Sizes;
} // namespace bmalloc
#endif // Sizes_h

69
bmalloc/SmallLine.h Normal file
View File

@ -0,0 +1,69 @@
/*
* Copyright (C) 2014-2016 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef SmallLine_h
#define SmallLine_h
#include "BAssert.h"
#include "Mutex.h"
#include "ObjectType.h"
#include <mutex>
namespace bmalloc {
class SmallLine {
public:
void ref(std::lock_guard<StaticMutex>&, unsigned char = 1);
bool deref(std::lock_guard<StaticMutex>&);
unsigned refCount(std::lock_guard<StaticMutex>&) { return m_refCount; }
char* begin();
char* end();
private:
unsigned char m_refCount;
static_assert(
smallLineSize / alignment <= std::numeric_limits<decltype(m_refCount)>::max(),
"maximum object count must fit in SmallLine::m_refCount");
};
inline void SmallLine::ref(std::lock_guard<StaticMutex>&, unsigned char refCount)
{
BASSERT(!m_refCount);
m_refCount = refCount;
}
inline bool SmallLine::deref(std::lock_guard<StaticMutex>&)
{
BASSERT(m_refCount);
--m_refCount;
return !m_refCount;
}
} // namespace bmalloc
#endif // SmallLine_h

87
bmalloc/SmallPage.h Normal file
View File

@ -0,0 +1,87 @@
/*
* Copyright (C) 2014-2016 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef SmallPage_h
#define SmallPage_h
#include "BAssert.h"
#include "List.h"
#include "Mutex.h"
#include "VMAllocate.h"
#include <mutex>
namespace bmalloc {
class SmallPage : public ListNode<SmallPage> {
public:
SmallPage()
: m_hasFreeLines(true)
{
}
void ref(std::lock_guard<StaticMutex>&);
bool deref(std::lock_guard<StaticMutex>&);
unsigned refCount(std::lock_guard<StaticMutex>&) { return m_refCount; }
size_t sizeClass() { return m_sizeClass; }
void setSizeClass(size_t sizeClass) { m_sizeClass = sizeClass; }
bool hasFreeLines(std::lock_guard<StaticMutex>&) const { return m_hasFreeLines; }
void setHasFreeLines(std::lock_guard<StaticMutex>&, bool hasFreeLines) { m_hasFreeLines = hasFreeLines; }
SmallLine* begin();
unsigned char slide() const { return m_slide; }
void setSlide(unsigned char slide) { m_slide = slide; }
private:
unsigned char m_hasFreeLines: 1;
unsigned char m_refCount: 7;
unsigned char m_sizeClass;
unsigned char m_slide;
static_assert(
sizeClassCount <= std::numeric_limits<decltype(m_sizeClass)>::max(),
"Largest size class must fit in SmallPage metadata");
};
inline void SmallPage::ref(std::lock_guard<StaticMutex>&)
{
BASSERT(!m_slide);
++m_refCount;
BASSERT(m_refCount);
}
inline bool SmallPage::deref(std::lock_guard<StaticMutex>&)
{
BASSERT(!m_slide);
BASSERT(m_refCount);
--m_refCount;
return !m_refCount;
}
} // namespace bmalloc
#endif // SmallPage_h

53
bmalloc/StaticMutex.cpp Normal file
View File

@ -0,0 +1,53 @@
/*
* Copyright (C) 2014 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "ScopeExit.h"
#include "StaticMutex.h"
#include <thread>
namespace bmalloc {
void StaticMutex::lockSlowCase()
{
// The longest critical section in bmalloc is much shorter than the
// time it takes to make a system call to yield to the OS scheduler.
// So, we try again a lot before we yield.
static const size_t aLot = 256;
if (!m_isSpinning.test_and_set()) {
auto clear = makeScopeExit([&] { m_isSpinning.clear(); });
for (size_t i = 0; i < aLot; ++i) {
if (try_lock())
return;
}
}
// Avoid spinning pathologically.
while (!try_lock())
std::this_thread::yield();
}
} // namespace bmalloc

103
bmalloc/StaticMutex.h Normal file
View File

@ -0,0 +1,103 @@
/*
* Copyright (C) 2014 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef StaticMutex_h
#define StaticMutex_h
#include "BAssert.h"
#include <atomic>
#include <mutex>
#include <thread>
// A fast replacement for std::mutex, for use in static storage.
// Use StaticMutex in static storage, where global constructors and exit-time
// destructors are prohibited, but all memory is zero-initialized automatically.
namespace bmalloc {
class StaticMutex {
protected:
// Subclasses that support non-static storage must use explicit initialization.
void init();
public:
void lock();
bool try_lock();
void unlock();
private:
void lockSlowCase();
std::atomic_flag m_flag;
std::atomic_flag m_isSpinning;
};
static inline void sleep(
std::unique_lock<StaticMutex>& lock, std::chrono::milliseconds duration)
{
if (duration == std::chrono::milliseconds(0))
return;
lock.unlock();
std::this_thread::sleep_for(duration);
lock.lock();
}
static inline void waitUntilFalse(
std::unique_lock<StaticMutex>& lock, std::chrono::milliseconds sleepDuration,
bool& condition)
{
while (condition) {
condition = false;
sleep(lock, sleepDuration);
}
}
inline void StaticMutex::init()
{
m_flag.clear();
m_isSpinning.clear();
}
inline bool StaticMutex::try_lock()
{
return !m_flag.test_and_set(std::memory_order_acquire);
}
inline void StaticMutex::lock()
{
if (!try_lock())
lockSlowCase();
}
inline void StaticMutex::unlock()
{
m_flag.clear(std::memory_order_release);
}
} // namespace bmalloc
#endif // StaticMutex_h

35
bmalloc/Syscall.h Normal file
View File

@ -0,0 +1,35 @@
/*
* Copyright (C) 2014, 2015 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef Syscall_h
#define Syscall_h
#include <errno.h>
#define SYSCALL(x) do { \
while ((x) == -1 && errno == EAGAIN) { } \
} while (0);
#endif // Syscall_h

230
bmalloc/VMAllocate.h Normal file
View File

@ -0,0 +1,230 @@
/*
* Copyright (C) 2014-2016 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef VMAllocate_h
#define VMAllocate_h
#include "BAssert.h"
#include "Logging.h"
#include "Range.h"
#include "Sizes.h"
#include "Syscall.h"
#include <algorithm>
#include <sys/mman.h>
#include <unistd.h>
#if BOS(DARWIN)
#include <mach/vm_page_size.h>
#include <mach/vm_statistics.h>
#endif
namespace bmalloc {
#if BOS(DARWIN)
#define BMALLOC_VM_TAG VM_MAKE_TAG(VM_MEMORY_TCMALLOC)
#else
#define BMALLOC_VM_TAG -1
#endif
inline size_t vmPageSize()
{
static size_t cached;
if (!cached)
cached = sysconf(_SC_PAGESIZE);
return cached;
}
inline size_t vmPageShift()
{
static size_t cached;
if (!cached)
cached = log2(vmPageSize());
return cached;
}
inline size_t vmSize(size_t size)
{
return roundUpToMultipleOf(vmPageSize(), size);
}
inline void vmValidate(size_t vmSize)
{
UNUSED(vmSize);
BASSERT(vmSize);
BASSERT(vmSize == roundUpToMultipleOf(vmPageSize(), vmSize));
}
inline void vmValidate(void* p, size_t vmSize)
{
vmValidate(vmSize);
UNUSED(p);
BASSERT(p);
BASSERT(p == mask(p, ~(vmPageSize() - 1)));
}
inline size_t vmPageSizePhysical()
{
#if (BPLATFORM(IOS) && __IPHONE_OS_VERSION_MIN_REQUIRED >= 100000)
return vm_kernel_page_size;
#else
static size_t cached;
if (!cached)
cached = sysconf(_SC_PAGESIZE);
return cached;
#endif
}
inline void vmValidatePhysical(size_t vmSize)
{
UNUSED(vmSize);
BASSERT(vmSize);
BASSERT(vmSize == roundUpToMultipleOf(vmPageSizePhysical(), vmSize));
}
inline void vmValidatePhysical(void* p, size_t vmSize)
{
vmValidatePhysical(vmSize);
UNUSED(p);
BASSERT(p);
BASSERT(p == mask(p, ~(vmPageSizePhysical() - 1)));
}
inline void* tryVMAllocate(size_t vmSize)
{
vmValidate(vmSize);
void* result = mmap(0, vmSize, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON, BMALLOC_VM_TAG, 0);
if (result == MAP_FAILED) {
logVMFailure();
return nullptr;
}
return result;
}
inline void* vmAllocate(size_t vmSize)
{
void* result = tryVMAllocate(vmSize);
RELEASE_BASSERT(result);
return result;
}
inline void vmDeallocate(void* p, size_t vmSize)
{
vmValidate(p, vmSize);
munmap(p, vmSize);
}
inline void vmRevokePermissions(void* p, size_t vmSize)
{
vmValidate(p, vmSize);
mprotect(p, vmSize, PROT_NONE);
}
// Allocates vmSize bytes at a specified power-of-two alignment.
// Use this function to create maskable memory regions.
inline void* tryVMAllocate(size_t vmAlignment, size_t vmSize)
{
vmValidate(vmSize);
vmValidate(vmAlignment);
size_t mappedSize = vmAlignment + vmSize;
if (mappedSize < vmAlignment || mappedSize < vmSize) // Check for overflow
return nullptr;
char* mapped = static_cast<char*>(tryVMAllocate(mappedSize));
if (!mapped)
return nullptr;
char* mappedEnd = mapped + mappedSize;
char* aligned = roundUpToMultipleOf(vmAlignment, mapped);
char* alignedEnd = aligned + vmSize;
RELEASE_BASSERT(alignedEnd <= mappedEnd);
if (size_t leftExtra = aligned - mapped)
vmDeallocate(mapped, leftExtra);
if (size_t rightExtra = mappedEnd - alignedEnd)
vmDeallocate(alignedEnd, rightExtra);
return aligned;
}
inline void* vmAllocate(size_t vmAlignment, size_t vmSize)
{
void* result = tryVMAllocate(vmAlignment, vmSize);
RELEASE_BASSERT(result);
return result;
}
inline void vmDeallocatePhysicalPages(void* p, size_t vmSize)
{
vmValidatePhysical(p, vmSize);
#if BOS(DARWIN)
SYSCALL(madvise(p, vmSize, MADV_FREE_REUSABLE));
#else
SYSCALL(madvise(p, vmSize, MADV_DONTNEED));
#endif
}
inline void vmAllocatePhysicalPages(void* p, size_t vmSize)
{
vmValidatePhysical(p, vmSize);
#if BOS(DARWIN)
SYSCALL(madvise(p, vmSize, MADV_FREE_REUSE));
#else
SYSCALL(madvise(p, vmSize, MADV_NORMAL));
#endif
}
// Trims requests that are un-page-aligned.
inline void vmDeallocatePhysicalPagesSloppy(void* p, size_t size)
{
char* begin = roundUpToMultipleOf(vmPageSizePhysical(), static_cast<char*>(p));
char* end = roundDownToMultipleOf(vmPageSizePhysical(), static_cast<char*>(p) + size);
if (begin >= end)
return;
vmDeallocatePhysicalPages(begin, end - begin);
}
// Expands requests that are un-page-aligned.
inline void vmAllocatePhysicalPagesSloppy(void* p, size_t size)
{
char* begin = roundDownToMultipleOf(vmPageSizePhysical(), static_cast<char*>(p));
char* end = roundUpToMultipleOf(vmPageSizePhysical(), static_cast<char*>(p) + size);
if (begin >= end)
return;
vmAllocatePhysicalPages(begin, end - begin);
}
} // namespace bmalloc
#endif // VMAllocate_h

101
bmalloc/VMHeap.cpp Normal file
View File

@ -0,0 +1,101 @@
/*
* Copyright (C) 2014, 2015 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "PerProcess.h"
#include "VMHeap.h"
#include <thread>
namespace bmalloc {
LargeRange VMHeap::tryAllocateLargeChunk(std::lock_guard<StaticMutex>&, size_t alignment, size_t size)
{
// We allocate VM in aligned multiples to increase the chances that
// the OS will provide contiguous ranges that we can merge.
size_t roundedAlignment = roundUpToMultipleOf<chunkSize>(alignment);
if (roundedAlignment < alignment) // Check for overflow
return LargeRange();
alignment = roundedAlignment;
size_t roundedSize = roundUpToMultipleOf<chunkSize>(size);
if (roundedSize < size) // Check for overflow
return LargeRange();
size = roundedSize;
void* memory = tryVMAllocate(alignment, size);
if (!memory)
return LargeRange();
Chunk* chunk = static_cast<Chunk*>(memory);
#if BOS(DARWIN)
m_zone.addRange(Range(chunk->bytes(), size));
#endif
return LargeRange(chunk->bytes(), size, 0);
}
void VMHeap::allocateSmallChunk(std::lock_guard<StaticMutex>& lock, size_t pageClass)
{
size_t pageSize = bmalloc::pageSize(pageClass);
size_t smallPageCount = pageSize / smallPageSize;
void* memory = vmAllocate(chunkSize, chunkSize);
Chunk* chunk = static_cast<Chunk*>(memory);
// We align to our page size in order to honor OS APIs and in order to
// guarantee that we can service aligned allocation requests at equal
// and smaller powers of two.
size_t vmPageSize = roundUpToMultipleOf(bmalloc::vmPageSize(), pageSize);
size_t metadataSize = roundUpToMultipleOfNonPowerOfTwo(vmPageSize, sizeof(Chunk));
Object begin(chunk, metadataSize);
Object end(chunk, chunkSize);
// Establish guard pages before writing to Chunk memory to work around
// an edge case in the Darwin VM system (<rdar://problem/25910098>).
vmRevokePermissions(begin.address(), vmPageSize);
vmRevokePermissions(end.address() - vmPageSize, vmPageSize);
begin = begin + vmPageSize;
end = end - vmPageSize;
BASSERT(begin <= end && end.offset() - begin.offset() >= pageSize);
new (chunk) Chunk(lock);
#if BOS(DARWIN)
m_zone.addRange(Range(begin.address(), end.address() - begin.address()));
#endif
for (Object it = begin; it + pageSize <= end; it = it + pageSize) {
SmallPage* page = it.page();
for (size_t i = 0; i < smallPageCount; ++i)
page[i].setSlide(i);
m_smallPages[pageClass].push(page);
}
}
} // namespace bmalloc

82
bmalloc/VMHeap.h Normal file
View File

@ -0,0 +1,82 @@
/*
* Copyright (C) 2014-2016 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef VMHeap_h
#define VMHeap_h
#include "Chunk.h"
#include "FixedVector.h"
#include "LargeRange.h"
#include "Map.h"
#include "Vector.h"
#if BOS(DARWIN)
#include "Zone.h"
#endif
namespace bmalloc {
class BeginTag;
class EndTag;
class Heap;
class VMHeap {
public:
SmallPage* allocateSmallPage(std::lock_guard<StaticMutex>&, size_t);
void deallocateSmallPage(std::unique_lock<StaticMutex>&, size_t, SmallPage*);
LargeRange tryAllocateLargeChunk(std::lock_guard<StaticMutex>&, size_t alignment, size_t);
private:
void allocateSmallChunk(std::lock_guard<StaticMutex>&, size_t);
std::array<List<SmallPage>, pageClassCount> m_smallPages;
#if BOS(DARWIN)
Zone m_zone;
#endif
};
inline SmallPage* VMHeap::allocateSmallPage(std::lock_guard<StaticMutex>& lock, size_t pageClass)
{
if (m_smallPages[pageClass].isEmpty())
allocateSmallChunk(lock, pageClass);
SmallPage* page = m_smallPages[pageClass].pop();
vmAllocatePhysicalPagesSloppy(page->begin()->begin(), pageSize(pageClass));
return page;
}
inline void VMHeap::deallocateSmallPage(std::unique_lock<StaticMutex>& lock, size_t pageClass, SmallPage* page)
{
lock.unlock();
vmDeallocatePhysicalPagesSloppy(page->begin()->begin(), pageSize(pageClass));
lock.lock();
m_smallPages[pageClass].push(page);
}
} // namespace bmalloc
#endif // VMHeap_h

237
bmalloc/Vector.h Normal file
View File

@ -0,0 +1,237 @@
/*
* Copyright (C) 2014 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef Vector_h
#define Vector_h
#include "Inline.h"
#include "VMAllocate.h"
#include <cstddef>
#include <cstring>
namespace bmalloc {
// A replacement for std::vector that allocates using vmAllocate instead of
// malloc, shrinks automatically, and supports "popping" from the middle.
template<typename T>
class Vector {
static_assert(std::is_trivially_destructible<T>::value, "Vector must have a trivial destructor.");
public:
typedef T* iterator;
typedef const T* const_iterator;
Vector();
Vector(Vector&&);
~Vector();
iterator begin() { return m_buffer; }
iterator end() { return m_buffer + m_size; }
size_t size() { return m_size; }
size_t capacity() { return m_capacity; }
T& operator[](size_t);
T& last() { return m_buffer[m_size - 1]; }
void push(const T&);
T pop();
T pop(size_t);
T pop(const_iterator it) { return pop(it - begin()); }
void insert(iterator, const T&);
T remove(iterator);
void grow(size_t);
void shrink(size_t);
void resize(size_t);
void shrinkToFit();
private:
static const size_t growFactor = 2;
static const size_t shrinkFactor = 4;
static size_t initialCapacity() { return vmPageSize() / sizeof(T); }
void growCapacity();
void shrinkCapacity();
void reallocateBuffer(size_t);
T* m_buffer;
size_t m_size;
size_t m_capacity;
};
template<typename T>
inline Vector<T>::Vector()
: m_buffer(nullptr)
, m_size(0)
, m_capacity(0)
{
}
template<typename T>
inline Vector<T>::Vector(Vector&& other)
: m_buffer(other.m_buffer)
, m_size(other.m_size)
, m_capacity(other.m_capacity)
{
other.m_buffer = nullptr;
other.m_size = 0;
other.m_capacity = 0;
}
template<typename T>
Vector<T>::~Vector()
{
if (m_buffer)
vmDeallocate(m_buffer, vmSize(m_capacity * sizeof(T)));
}
template<typename T>
inline T& Vector<T>::operator[](size_t i)
{
BASSERT(i < m_size);
return m_buffer[i];
}
template<typename T>
INLINE void Vector<T>::push(const T& value)
{
if (m_size == m_capacity)
growCapacity();
m_buffer[m_size++] = value;
}
template<typename T>
inline T Vector<T>::pop()
{
BASSERT(m_size);
T value = m_buffer[m_size - 1];
shrink(m_size - 1);
return value;
}
template<typename T>
inline T Vector<T>::pop(size_t i)
{
BASSERT(i < m_size);
std::swap(m_buffer[i], last());
return pop();
}
template<typename T>
void Vector<T>::insert(iterator it, const T& value)
{
size_t index = it - begin();
size_t moveCount = end() - it;
grow(m_size + 1);
std::memmove(&m_buffer[index + 1], &m_buffer[index], moveCount * sizeof(T));
m_buffer[index] = value;
}
template<typename T>
T Vector<T>::remove(iterator it)
{
size_t index = it - begin();
size_t moveCount = end() - it - 1;
T result = *it;
std::memmove(&m_buffer[index], &m_buffer[index + 1], moveCount * sizeof(T));
shrink(m_size - 1);
return result;
}
template<typename T>
inline void Vector<T>::grow(size_t size)
{
BASSERT(size >= m_size);
while (m_size < size)
push(T());
}
template<typename T>
inline void Vector<T>::shrink(size_t size)
{
BASSERT(size <= m_size);
m_size = size;
if (m_size < m_capacity / shrinkFactor && m_capacity > initialCapacity())
shrinkCapacity();
}
template<typename T>
inline void Vector<T>::resize(size_t size)
{
if (size <= m_size)
shrink(size);
else
grow(size);
}
template<typename T>
void Vector<T>::reallocateBuffer(size_t newCapacity)
{
RELEASE_BASSERT(newCapacity < std::numeric_limits<size_t>::max() / sizeof(T));
size_t vmSize = bmalloc::vmSize(newCapacity * sizeof(T));
T* newBuffer = vmSize ? static_cast<T*>(vmAllocate(vmSize)) : nullptr;
if (m_buffer) {
std::memcpy(newBuffer, m_buffer, m_size * sizeof(T));
vmDeallocate(m_buffer, bmalloc::vmSize(m_capacity * sizeof(T)));
}
m_buffer = newBuffer;
m_capacity = vmSize / sizeof(T);
}
template<typename T>
NO_INLINE void Vector<T>::shrinkCapacity()
{
size_t newCapacity = max(initialCapacity(), m_capacity / shrinkFactor);
reallocateBuffer(newCapacity);
}
template<typename T>
NO_INLINE void Vector<T>::growCapacity()
{
size_t newCapacity = max(initialCapacity(), m_size * growFactor);
reallocateBuffer(newCapacity);
}
template<typename T>
void Vector<T>::shrinkToFit()
{
if (m_size < m_capacity)
reallocateBuffer(m_size);
}
} // namespace bmalloc
#endif // Vector_h

132
bmalloc/Zone.cpp Normal file
View File

@ -0,0 +1,132 @@
/*
* Copyright (C) 2014, 2015 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "Sizes.h"
#include "Zone.h"
namespace bmalloc {
template<typename T> static void remoteRead(task_t task, memory_reader_t reader, vm_address_t remotePointer, T& result)
{
void* tmp = nullptr;
kern_return_t error = reader(task, remotePointer, sizeof(T), &tmp);
// This read sometimes fails for unknown reasons (<rdar://problem/14093757>).
// Avoid a crash by skipping the memcpy when this happens.
if (error || !tmp) {
fprintf(stderr, "bmalloc: error reading remote process: 0x%x\n", error);
return;
}
memcpy(&result, tmp, sizeof(T));
}
// These function pointers are invoked unconditionally on all zones by various
// system tools. We don't support any of these features, but we provide
// just enough functionality not to crash.
static size_t good_size(malloc_zone_t*, size_t size)
{
return size;
}
static boolean_t check(malloc_zone_t*)
{
return true;
}
static void print(malloc_zone_t*, boolean_t)
{
}
static void log(malloc_zone_t*, void*)
{
}
static void force_lock(malloc_zone_t*)
{
}
static void force_unlock(malloc_zone_t*)
{
}
static void statistics(malloc_zone_t*, malloc_statistics_t* statistics)
{
memset(statistics, 0, sizeof(malloc_statistics_t));
}
static size_t zoneSize(malloc_zone_t*, const void*)
{
// Our zone is not public API, so no pointer can belong to us.
return 0;
}
// This function runs inside the leaks process.
static kern_return_t enumerator(task_t task, void* context, unsigned type_mask, vm_address_t zone_address, memory_reader_t reader, vm_range_recorder_t recorder)
{
Zone remoteZone(task, reader, zone_address);
for (auto& range : remoteZone.ranges()) {
vm_range_t vmRange = { reinterpret_cast<vm_address_t>(range.begin()), range.size() };
if ((type_mask & MALLOC_PTR_REGION_RANGE_TYPE))
(*recorder)(task, context, MALLOC_PTR_REGION_RANGE_TYPE, &vmRange, 1);
if ((type_mask & MALLOC_PTR_IN_USE_RANGE_TYPE))
(*recorder)(task, context, MALLOC_PTR_IN_USE_RANGE_TYPE, &vmRange, 1);
}
return 0;
}
// The memory analysis API requires the contents of this struct to be a static
// constant in the program binary. The leaks process will load this struct
// out of the program binary (and not out of the running process).
static const malloc_introspection_t zoneIntrospect = {
.enumerator = bmalloc::enumerator,
.good_size = bmalloc::good_size,
.check = bmalloc::check,
.print = bmalloc::print,
.log = bmalloc::log,
.force_lock = bmalloc::force_lock,
.force_unlock = bmalloc::force_unlock,
.statistics = bmalloc::statistics
};
Zone::Zone()
{
malloc_zone_t::size = &bmalloc::zoneSize;
malloc_zone_t::zone_name = "WebKit Malloc";
malloc_zone_t::introspect = const_cast<malloc_introspection_t*>(&bmalloc::zoneIntrospect);
malloc_zone_t::version = 4;
malloc_zone_register(this);
}
Zone::Zone(task_t task, memory_reader_t reader, vm_address_t remotePointer)
{
remoteRead(task, reader, remotePointer, *this);
}
} // namespace bmalloc

73
bmalloc/Zone.h Normal file
View File

@ -0,0 +1,73 @@
/*
* Copyright (C) 2014, 2015 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef Zone_h
#define Zone_h
#include "FixedVector.h"
#include "Range.h"
#include <malloc/malloc.h>
namespace bmalloc {
class Chunk;
class Zone : public malloc_zone_t {
public:
// Enough capacity to track a 64GB heap, so probably enough for anything.
static const size_t capacity = 2048;
Zone();
Zone(task_t, memory_reader_t, vm_address_t);
void addRange(Range);
FixedVector<Range, capacity>& ranges() { return m_ranges; }
private:
// This vector has two purposes:
// (1) It stores the list of Chunks so that we can enumerate
// each Chunk and request that it be scanned if reachable.
// (2) It roots a pointer to each Chunk in a global non-malloc
// VM region, making each Chunk appear reachable, and therefore
// ensuring that the leaks tool will scan it. (The leaks tool
// conservatively scans all writeable VM regions that are not malloc
// regions, and then scans malloc regions using the introspection API.)
// This prevents the leaks tool from reporting false positive leaks for
// objects pointed to from bmalloc memory -- though it also prevents the
// leaks tool from finding any leaks in bmalloc memory.
FixedVector<Range, capacity> m_ranges;
};
inline void Zone::addRange(Range range)
{
if (m_ranges.size() == m_ranges.capacity())
return;
m_ranges.push(range);
}
} // namespace bmalloc
#endif // Zone_h

97
bmalloc/bmalloc.h Normal file
View File

@ -0,0 +1,97 @@
/*
* Copyright (C) 2014-2016 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "Cache.h"
#include "Heap.h"
#include "PerProcess.h"
#include "StaticMutex.h"
namespace bmalloc {
namespace api {
// Returns null on failure.
inline void* tryMalloc(size_t size)
{
return Cache::tryAllocate(size);
}
// Crashes on failure.
inline void* malloc(size_t size)
{
return Cache::allocate(size);
}
// Returns null on failure.
inline void* tryMemalign(size_t alignment, size_t size)
{
return Cache::tryAllocate(alignment, size);
}
// Crashes on failure.
inline void* memalign(size_t alignment, size_t size)
{
return Cache::allocate(alignment, size);
}
// Crashes on failure.
inline void* realloc(void* object, size_t newSize)
{
return Cache::reallocate(object, newSize);
}
inline void free(void* object)
{
Cache::deallocate(object);
}
inline void scavengeThisThread()
{
Cache::scavenge();
}
inline void scavenge()
{
scavengeThisThread();
std::unique_lock<StaticMutex> lock(PerProcess<Heap>::mutex());
PerProcess<Heap>::get()->scavenge(lock, std::chrono::milliseconds(0));
}
inline bool isEnabled()
{
std::unique_lock<StaticMutex> lock(PerProcess<Heap>::mutex());
return PerProcess<Heap>::getFastCase()->environment().isBmallocEnabled();
}
#if BOS(DARWIN)
inline void setScavengerThreadQOSClass(qos_class_t overrideClass)
{
std::unique_lock<StaticMutex> lock(PerProcess<Heap>::mutex());
PerProcess<Heap>::getFastCase()->setScavengerThreadQOSClass(overrideClass);
}
#endif
} // namespace api
} // namespace bmalloc

View File

@ -0,0 +1,66 @@
/*
* Copyright (C) 2007, 2008, 2011-2016 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef BSoftLinking_h
#define BSoftLinking_h
#include "BAssert.h"
#include <dlfcn.h>
#include <mutex>
#define BSOFT_LINK_PRIVATE_FRAMEWORK(framework) \
static void* framework##Library() \
{ \
static void* frameworkLibrary; \
static std::once_flag once; \
std::call_once(once, [] { \
frameworkLibrary = dlopen("/System/Library/PrivateFrameworks/" #framework ".framework/" #framework, RTLD_NOW); \
RELEASE_BASSERT_WITH_MESSAGE(frameworkLibrary, "%s", dlerror()); \
}); \
return frameworkLibrary; \
}
#define BSOFT_LINK_FUNCTION(framework, functionName, resultType, parameterDeclarations, parameterNames) \
extern "C" { \
resultType functionName parameterDeclarations; \
} \
static resultType init##functionName parameterDeclarations; \
static resultType (*softLink##functionName) parameterDeclarations = init##functionName; \
\
static resultType init##functionName parameterDeclarations \
{ \
static std::once_flag once; \
std::call_once(once, [] { \
softLink##functionName = (resultType (*) parameterDeclarations) dlsym(framework##Library(), #functionName); \
RELEASE_BASSERT_WITH_MESSAGE(softLink##functionName, "%s", dlerror()); \
}); \
return softLink##functionName parameterNames; \
} \
\
inline resultType functionName parameterDeclarations \
{ \
return softLink##functionName parameterNames; \
}
#endif // BSoftLinking_h

63
bmalloc/mbmalloc.cpp Normal file
View File

@ -0,0 +1,63 @@
/*
* Copyright (C) 2014 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "bmalloc.h"
#define EXPORT __attribute__((visibility("default")))
extern "C" {
EXPORT void* mbmalloc(size_t);
EXPORT void* mbmemalign(size_t, size_t);
EXPORT void mbfree(void*, size_t);
EXPORT void* mbrealloc(void*, size_t, size_t);
EXPORT void mbscavenge();
void* mbmalloc(size_t size)
{
return bmalloc::api::malloc(size);
}
void* mbmemalign(size_t alignment, size_t size)
{
return bmalloc::api::memalign(alignment, size);
}
void mbfree(void* p, size_t)
{
bmalloc::api::free(p);
}
void* mbrealloc(void* p, size_t, size_t size)
{
return bmalloc::api::realloc(p, size);
}
void mbscavenge()
{
bmalloc::api::scavenge();
}
} // extern "C"