android-platform-art (10.0.0+r36-4) unstable; urgency=medium
authorRoger Shimizu <rosh@debian.org>
Fri, 21 Jan 2022 15:26:23 +0000 (15:26 +0000)
committerRoger Shimizu <rosh@debian.org>
Fri, 21 Jan 2022 15:26:23 +0000 (15:26 +0000)
  * Team upload.
  * debian/patches:
    - Add patch to fix ftbfs for c++17 (Closes: #983964).

[dgit import unpatched android-platform-art 10.0.0+r36-4]

52 files changed:
1  2 
debian/.gitlab-ci.yml
debian/android-libart.docs
debian/android-libart.install
debian/changelog
debian/clean
debian/control
debian/copyright
debian/detect-arch.mk
debian/dexdump.docs
debian/dexdump.install
debian/dexdump.links
debian/dexdump.lintian-overrides
debian/dexdump.manpages
debian/dexdump.mk
debian/dexlist.docs
debian/dexlist.install
debian/dexlist.lintian-overrides
debian/dexlist.mk
debian/dlmalloc/README.source
debian/dlmalloc/malloc.c
debian/dlmalloc/malloc.h
debian/dmtracedump.docs
debian/dmtracedump.install
debian/dmtracedump.links
debian/dmtracedump.manpages
debian/dmtracedump.mk
debian/libart.mk
debian/libdexfile_external.mk
debian/libdexfile_support.mk
debian/libsigchain.mk
debian/patches/Fix-ftbfs-for-c-17.patch
debian/patches/adapt-asm-output-of-clang-that-no-is-placed-before-data.patch
debian/patches/arm-asm-instruction.patch
debian/patches/atomic-exception-specification.patch
debian/patches/fix-build-on-non-x86.patch
debian/patches/fix-mterp-assembly-to-use-uxtw-instead-of-lsl-where-needed.patch
debian/patches/image-space-dereference.patch
debian/patches/method-reference-std-ns.patch
debian/patches/missing-system-includes.patch
debian/patches/python3-gen_mterp.patch
debian/patches/series
debian/patches/stats-incomplete-def.patch
debian/patches/storage-mode-concat.patch
debian/patches/ucontext.patch
debian/patches/use-android-dlmalloc.patch
debian/patches/workaround-cacheflush-on-arm.patch
debian/rules
debian/source/format
debian/tests/control
debian/tests/dexdump-dexlist
debian/upstream/metadata
debian/watch

index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..6d0a7fc7e853e0d1033f88ebeffd93741e17aa2b
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,16 @@@
++pages:
++  image: registry.salsa.debian.org/salsa-ci-team/ci-image-git-buildpackage
++  stage: deploy
++  except:
++    - tags
++    - pristine-tar
++    - upstream
++  artifacts:
++    paths:
++      - public
++    expire_in: 1 day
++  script:
++    - gitlab-ci-add-pages-repo android-tools-team/android-platform-libnativehelper
++    - gitlab-ci-add-pages-repo android-tools-team/android-platform-system-core
++    - gitlab-ci-git-buildpackage-all
++    - gitlab-ci-aptly
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..132d13f0ed71837b3e82c50541af7c4ae5f4dede
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,1 @@@
++NOTICE
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..b2a07761f551ccb8c19d0d4289b232545137d496
new file mode 100755 (executable)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,8 @@@
++#!/usr/bin/dh-exec
++
++libdexfile/external/include/art_api/dex_file_support.h   /usr/include/android/art_api
++libdexfile/external/include/art_api/dex_file_external.h  /usr/include/android/art_api
++debian/out/libart.so*        usr/lib/${DEB_HOST_MULTIARCH}/android
++debian/out/libdexfile_external.so*  usr/lib/${DEB_HOST_MULTIARCH}/android
++debian/out/libdexfile_support.so*   usr/lib/${DEB_HOST_MULTIARCH}/android
++debian/out/libsigchain.so*          usr/lib/${DEB_HOST_MULTIARCH}/android
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..ee7a324bf2a925be3132c2d7dcb660b64aa21a13
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,160 @@@
++android-platform-art (10.0.0+r36-4) unstable; urgency=medium
++
++  * Team upload.
++  * debian/patches:
++    - Add patch to fix ftbfs for c++17 (Closes: #983964).
++
++ -- Roger Shimizu <rosh@debian.org>  Sat, 22 Jan 2022 00:26:23 +0900
++
++android-platform-art (10.0.0+r36-3) unstable; urgency=medium
++
++  * Team upload.
++
++  [ Roger Shimizu ]
++  * debian/*.mk:
++    - Remove runtime library path: debian/out, which is only needed
++      after building.
++    - Remove LDFLAGS=-nodefaultlibs for library.
++  * debian/rules:
++    - Add LD_LIBRARY_PATH=debian/out for help2man calling.
++
++  [ Hans-Christoph Steiner ]
++  * mv man page gen to dh_auto_build and respect arches
++
++ -- Hans-Christoph Steiner <hans@eds.org>  Thu, 07 Jan 2021 13:08:42 +0100
++
++android-platform-art (10.0.0+r36-2) unstable; urgency=medium
++
++  * Team upload.
++  * debian/*.mk:
++    - Add necessary linking libraries to fix ftbfs issue.
++
++ -- Roger Shimizu <rosh@debian.org>  Wed, 06 Jan 2021 19:29:23 +0900
++
++android-platform-art (10.0.0+r36-1) unstable; urgency=medium
++
++  * Team upload.
++  * Revert "remove stage1 components"
++  * debian/tests:
++    - Add "Depends" to each test command.
++  * debian/control:
++    - Remove building package dexlist/dexdump for armel.
++    - Fix package description.
++  * debian/*.mk:
++    - Remove unnecessary linking dependencies.
++    - Add "-nodefaultlibs" to LDFLAGS.
++  * lintian-overrides:
++    - Rename binary-or-shlib-defines-rpath to custom-library-search-path
++
++ -- Roger Shimizu <rosh@debian.org>  Wed, 06 Jan 2021 00:31:36 +0900
++
++android-platform-art (10.0.0+r36-1~stage1.5) unstable; urgency=medium
++
++  * Team upload.
++  * debian/patches:
++    - Backport patch from upstream to fix mterp asm build on arm64.
++      (Closes: #963058)
++
++ -- Roger Shimizu <rosh@debian.org>  Mon, 04 Jan 2021 16:03:34 +0900
++
++android-platform-art (10.0.0+r36-1~stage1.4) unstable; urgency=medium
++
++  * Team upload.
++  * debian/*.mk:
++    - "mkdir debian/out" command move to debian/rules.
++  * debian/patches:
++    - Add patches to fix ftbfs on armhf/arm64.
++
++ -- Roger Shimizu <rosh@debian.org>  Mon, 04 Jan 2021 01:24:17 +0900
++
++android-platform-art (10.0.0+r36-1~stage1.3) unstable; urgency=medium
++
++  * debian/control:
++    - Bump B-D android-platform-system-core.
++  * debian/patches:
++    - Add patch to workaround cacheflush on arm.
++  * debian/control:
++    - Remove valgrind from B-D.
++  * debian/*.mk:
++    - Remove duplicated "-fPIC" and "-I/usr/include/android"
++
++ -- Roger Shimizu <rosh@debian.org>  Sat, 02 Jan 2021 01:30:12 +0900
++
++android-platform-art (10.0.0+r36-1~stage1.2) unstable; urgency=low
++
++  * Team upload.
++  * d/rules: Exclude building libdexfile_support.so from "any"
++    architecture.
++
++ -- Roger Shimizu <rosh@debian.org>  Fri, 01 Jan 2021 01:21:41 +0900
++
++android-platform-art (10.0.0+r36-1~stage1.1) unstable; urgency=low
++
++  * Team upload.
++
++  [ Hans-Christoph Steiner ]
++  * add missing art_api headers and .cc files
++  * build libdexfile_external and libdexfile_support separately
++
++  [ Roger Shimizu ]
++  * Fix ftbfs issues on mips*
++  * Use patch from android-platform-system-core to fix non-x86 systems
++
++ -- Hans-Christoph Steiner <hans@eds.org>  Wed, 30 Dec 2020 23:15:12 +0100
++
++android-platform-art (10.0.0+r36-1~stage1) unstable; urgency=low
++
++  * Team upload.
++
++  [ Debian Janitor ]
++  * Use correct machine-readable copyright file URI.
++  * Bump debhelper from old 11 to 12.
++  * Set debhelper-compat version in Build-Depends.
++
++  [ Hans-Christoph Steiner ]
++  * New upstream release (Closes: #963058)
++
++ -- Hans-Christoph Steiner <hans@eds.org>  Tue, 13 Oct 2020 17:10:14 +0200
++
++android-platform-art (8.1.0+r23-4) unstable; urgency=medium
++
++  * Team upload.
++  * debian/watch:
++    - Remove the unsupported "rename" option.
++    - Update rule to get new upstream version.
++  * debian/control:
++    - Add Rules-Requires-Root: no
++    - Add help2man to B-D.
++  * debian/rules:
++    - Add more security hardening.
++    - Use help2man to generate manpages for dexdump, and dmtracedump.
++
++ -- Roger Shimizu <rosh@debian.org>  Sun, 10 May 2020 18:42:38 +0900
++
++android-platform-art (8.1.0+r23-3) unstable; urgency=medium
++
++  * Put all LDFLAGS that link libraries at the end of the command line. This
++    fixes FTBFS on Ubuntu because `--as-needed` is used by default.
++    (Closes: #916250) Thanks to Logan Rosen.
++  * ucontext.patch: Fix a type mismatch causing FTBFS on armhf
++  * Use GCC to compile assembly code on armhf as Clang does not support the
++    `ADRL` instruction. See <https://bugs.llvm.org/show_bug.cgi?id=24350>.
++
++ -- Kai-Chung Yan <seamlik@debian.org>  Thu, 13 Dec 2018 17:11:09 +0800
++
++android-platform-art (8.1.0+r23-2) unstable; urgency=medium
++
++  * Use my DD account in Uploaders
++  * Disable libart and its users on MIPS as ART only supports MIPSr6 while
++    Debian is by default MIPSr2
++  * Fix FTBFS on i386
++  * Use Clang only for libart and its users while GCC for the rest. This allows
++    `dmtracedump` to be released on all architectures.
++
++ -- Kai-Chung Yan <seamlik@debian.org>  Thu, 06 Dec 2018 03:40:05 +0800
++
++android-platform-art (8.1.0+r23-1) unstable; urgency=low
++
++  * Initial release (Closes: #913785)
++
++ -- Kai-Chung Yan <seamlikok@gmail.com>  Tue, 30 Oct 2018 15:33:48 +0800
diff --cc debian/clean
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..92a7cdc2a355146982dbb4182ebfde2169e6b061
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,1 @@@
++debian/out/
diff --cc debian/control
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..0561a66c87867d5ecf567ada0f8ffd26919ea42e
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,76 @@@
++Source: android-platform-art
++Section: devel
++Priority: optional
++Maintainer: Android Tools Maintainers <android-tools-devel@lists.alioth.debian.org>
++Uploaders: Kai-Chung Yan <seamlik@debian.org>
++Build-Depends:
++ android-libbacktrace-dev (>= 1:10.0.0+r36-3~~) [amd64 i386 armel armhf arm64],
++ android-libbase-dev (>= 1:10.0.0+r36-3~~) [amd64 i386 armel armhf arm64],
++ android-libcutils-dev (>= 1:10.0.0+r36-3~~) [amd64 i386 armel armhf arm64],
++ android-libnativebridge-dev (>= 1:10.0.0+r36-3~~) [amd64 i386 armel armhf arm64],
++ android-libnativeloader-dev (>= 1:10.0.0+r36-3~~) [amd64 i386 armel armhf arm64],
++ android-libutils-dev (>= 1:10.0.0+r36-3~~) [amd64 i386 armel armhf arm64],
++ android-libziparchive-dev (>= 1:10.0.0+r36-3~~) [amd64 i386 armel armhf arm64],
++ clang [amd64 i386 armel armhf arm64],
++ debhelper-compat (= 12),
++ dh-exec,
++ help2man,
++ libicu-dev [amd64 i386 armel armhf arm64],
++ liblz4-dev [amd64 i386 armel armhf arm64],
++ python3 [amd64 i386 armel armhf arm64],
++ zlib1g-dev [amd64 i386 armel armhf arm64]
++Standards-Version: 4.5.0
++Rules-Requires-Root: no
++Homepage: https://android.googlesource.com/platform/art
++Vcs-Git: https://salsa.debian.org/android-tools-team/android-platform-art.git
++Vcs-Browser: https://salsa.debian.org/android-tools-team/android-platform-art
++
++Package: dexdump
++Architecture: amd64 i386 armhf arm64
++Multi-Arch: foreign
++Build-Profiles: <!stage1>
++Depends: ${misc:Depends}, ${shlibs:Depends}
++Description: Displays information about Android DEX files
++ The `dexdump` tool is intended to mimic `objdump`. When possible, use
++ similar command-line arguments.
++ .
++ This is a re-implementation of the original `dexdump` utility that was
++ based on Dalvik functions in `libdex` into a new `dexdump` that is now
++ based on ART functions in `libart` instead. The output is very similar
++ to the original for correct DEX files. Error messages may differ,
++ however. Also, ODEX files are no longer supported.
++
++Package: dmtracedump
++Architecture: any
++Multi-Arch: foreign
++Depends: graphviz, ${shlibs:Depends}, ${misc:Depends}
++Description: Generates graphical call-stack diagrams from Android trace logs
++ `dmtracedump` generates the call stack data as a tree diagram, where
++ each node represents a method call. It shows call flow (from parent
++ node to child nodes) using arrows.
++
++Package: android-libart
++Architecture: amd64 i386 armhf arm64
++Depends: ${shlibs:Depends}, ${misc:Depends}
++Description: Android Runtime
++ Android Runtime (ART) is the managed runtime used by applications and
++ some system services on Android. ART and its predecessor Dalvik were
++ originally created specifically for the Android project. ART as the
++ runtime executes the Dalvik Executable format and DEX bytecode
++ specification.
++ .
++ This package provides `libart` and `libsigchain`.
++ .
++ This library is only used by Android SDK and uses a customized RPATH.
++
++Package: dexlist
++Architecture: amd64 i386 armhf arm64
++Multi-Arch: foreign
++Build-Profiles: <!stage1>
++Depends: ${misc:Depends}, ${shlibs:Depends}
++Description: Lists all methods in all concrete classes in Android DEX files
++ This is a re-implementation of the original `dexlist` utility that was
++ based on Dalvik functions in `libdex` into a new `dexlist` that is now
++ based on ART functions in `libart` instead. The output is very similar
++ to the original for correct DEX files. Error messages may differ,
++ however. Also, ODEX files are no longer supported.
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..c0276a953a43e6bc425625ab7ec0ca4a7590000e
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,51 @@@
++Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/
++Upstream-Name: Android Runtime
++Source: https://android.googlesource.com/platform/art
++
++Files: *
++Copyright: 2005-2018, The Android Open Source Project
++License: Apache-2.0
++
++Files: debian/*
++Copyright: 2018, Kai-Chung Yan (殷啟聰)
++License: Apache-2.0
++
++Files: debian/dlmalloc/*
++Copyright: N/A
++License: public-domain
++
++License: Apache-2.0
++ Licensed under the Apache License, Version 2.0 (the "License");
++ you may not use this file except in compliance with the License.
++ .
++ Unless required by applicable law or agreed to in writing, software
++ distributed under the License is distributed on an "AS IS" BASIS,
++ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
++ See the License for the specific language governing permissions and
++ limitations under the License.
++ .
++ On Debian systems, the full text of the Apache License, Version 2.0
++ can be found in the file `/usr/share/common-licenses/Apache-2.0'.
++
++License: public-domain
++ The person who associated a work with this deed has dedicated the work to the
++ public domain by waiving all of his or her rights to the work worldwide under
++ copyright law, including all related and neighboring rights, to the extent
++ allowed by law.
++ .
++ You can copy, modify, distribute and perform the work, even for commercial
++ purposes, all without asking permission.
++ .
++ In no way are the patent or trademark rights of any person affected by CC0, nor
++ are the rights that other persons may have in the work or in how the work is
++ used, such as publicity or privacy rights.
++ .
++ Unless expressly stated otherwise, the person who associated a work with this
++ deed makes no warranties about the work, and disclaims liability for all uses
++ of the work, to the fullest extent permitted by applicable law.
++ .
++ When using or citing the work, you should not imply endorsement by the author
++ or the affirmer.
++ .
++ The full text of this license is can be found at
++ <https://creativecommons.org/publicdomain/zero/1.0>.
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..25c68a46a8d503791af04e7add27aa5f63aa8988
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,26 @@@
++# More info see: /usr/share/dpkg/cputable
++
++ifeq ($(DEB_HOST_ARCH), amd64)
++  CPU = x86_64
++endif
++ifeq ($(DEB_HOST_ARCH), i386)
++  CPU = x86
++endif
++ifeq ($(DEB_HOST_ARCH), armel)
++  CPU = arm
++endif
++ifeq ($(DEB_HOST_ARCH), armhf)
++  CPU = arm
++endif
++ifeq ($(DEB_HOST_ARCH), arm64)
++  CPU = arm64
++endif
++ifeq ($(DEB_HOST_ARCH), mips)
++  CPU = mips
++endif
++ifeq ($(DEB_HOST_ARCH), mipsel)
++  CPU = mips
++endif
++ifeq ($(DEB_HOST_ARCH), mips64el)
++  CPU = mips64
++endif
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..132d13f0ed71837b3e82c50541af7c4ae5f4dede
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,1 @@@
++NOTICE
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..a9738847c4df6b46df9820d8a19688178113e139
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,1 @@@
++debian/out/dexdump           usr/lib/android-sdk/build-tools/debian
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..67eccc8c8fa45dfd0036947c11dc19ec05959e9c
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,2 @@@
++usr/lib/android-sdk/build-tools/debian/dexdump   usr/bin/dexdump
++usr/lib/android-sdk/build-tools/debian/dexdump   usr/bin/dexdump2
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..a8109fc3f1be713c1691c21d86e778c416f4ee4f
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,4 @@@
++# Executables and libraries of Android SDK uses private libraries located in
++# /usr/lib/${DEB_HOST_MULTIARCH}/android
++
++custom-library-search-path
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..020c7c8acbbbb309574eeffe4360c3db9850e254
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,1 @@@
++debian/out/dexdump.1
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..fe8dac0fed8504e8306999b8be44b3d27ef8c5ea
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,30 @@@
++NAME = dexdump
++SOURCES = dexdump_cfg.cc dexdump_main.cc dexdump.cc
++SOURCES := $(foreach source, $(SOURCES), dexdump/$(source))
++
++CPPFLAGS += \
++  -Ilibartbase \
++  -Idexdump \
++  -Ilibdexfile \
++  -Iruntime \
++  -I/usr/include/android/nativehelper \
++
++CXXFLAGS += -std=gnu++17
++
++# libsigchain defines wrapper functions around sigaction() family. In order to
++# override the ones provided by libc, libsignal must appear in the shared
++# object dependency tree before libc in the breadth-first order.
++LDFLAGS += -nodefaultlibs \
++  -L/usr/lib/$(DEB_HOST_MULTIARCH)/android \
++  -Ldebian/out \
++  -Wl,-rpath=/usr/lib/$(DEB_HOST_MULTIARCH)/android
++LIBRARIES_FLAGS += \
++  -lsigchain \
++  -lc \
++  -lstdc++ \
++  -lgcc_s \
++  -lart \
++  -lbase \
++
++debian/out/$(NAME): $(SOURCES)
++      $(CXX) $^ -o $@ $(CXXFLAGS) $(CPPFLAGS) $(LDFLAGS) $(LIBRARIES_FLAGS)
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..132d13f0ed71837b3e82c50541af7c4ae5f4dede
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,1 @@@
++NOTICE
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..3387d7e3b5adfa24e4e9f7c6173590177fe713fa
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,1 @@@
++debian/out/dexlist   usr/bin
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..a8109fc3f1be713c1691c21d86e778c416f4ee4f
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,4 @@@
++# Executables and libraries of Android SDK uses private libraries located in
++# /usr/lib/${DEB_HOST_MULTIARCH}/android
++
++custom-library-search-path
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..042804d0cec5b3be4bfa9b6eb339f567f90639bd
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,26 @@@
++NAME = dexlist
++SOURCES = dexlist.cc
++SOURCES := $(foreach source, $(SOURCES), dexlist/$(source))
++CPPFLAGS += \
++  -Ilibartbase \
++  -Ilibdexfile \
++  -Iruntime \
++  -I/usr/include/android/nativehelper \
++
++CXXFLAGS += -std=gnu++17
++
++# See the comment in `dexdump.mk`
++LDFLAGS += -nodefaultlibs \
++  -L/usr/lib/$(DEB_HOST_MULTIARCH)/android \
++  -Ldebian/out \
++  -Wl,-rpath=/usr/lib/$(DEB_HOST_MULTIARCH)/android
++LIBRARIES_FLAGS += \
++  -lbase \
++  -lsigchain \
++  -lc \
++  -lstdc++ \
++  -lgcc_s \
++  -lart \
++
++debian/out/$(NAME): $(SOURCES)
++      $(CXX) $^ -o $@ $(CXXFLAGS) $(CPPFLAGS) $(LDFLAGS) $(LIBRARIES_FLAGS)
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..148f0b546a00e0368c812162ecea8e191a6b226c
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,4 @@@
++The code is pulled from
++[here](https://android.googlesource.com/platform/external/dlmalloc).
++It seems to be used only at 2 places in AOSP and never receive any update, so
++I decided not to go through the trouble of the NEW queue.
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..a61c0da9cda725e1b990a74b4e28750985fa7acb
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,6323 @@@
++/*
++  This is a version (aka dlmalloc) of malloc/free/realloc written by
++  Doug Lea and released to the public domain, as explained at
++  http://creativecommons.org/publicdomain/zero/1.0/ Send questions,
++  comments, complaints, performance data, etc to dl@cs.oswego.edu
++
++* Version 2.8.6 Wed Aug 29 06:57:58 2012  Doug Lea
++   Note: There may be an updated version of this malloc obtainable at
++           ftp://gee.cs.oswego.edu/pub/misc/malloc.c
++         Check before installing!
++
++* Quickstart
++
++  This library is all in one file to simplify the most common usage:
++  ftp it, compile it (-O3), and link it into another program. All of
++  the compile-time options default to reasonable values for use on
++  most platforms.  You might later want to step through various
++  compile-time and dynamic tuning options.
++
++  For convenience, an include file for code using this malloc is at:
++     ftp://gee.cs.oswego.edu/pub/misc/malloc-2.8.6.h
++  You don't really need this .h file unless you call functions not
++  defined in your system include files.  The .h file contains only the
++  excerpts from this file needed for using this malloc on ANSI C/C++
++  systems, so long as you haven't changed compile-time options about
++  naming and tuning parameters.  If you do, then you can create your
++  own malloc.h that does include all settings by cutting at the point
++  indicated below. Note that you may already by default be using a C
++  library containing a malloc that is based on some version of this
++  malloc (for example in linux). You might still want to use the one
++  in this file to customize settings or to avoid overheads associated
++  with library versions.
++
++* Vital statistics:
++
++  Supported pointer/size_t representation:       4 or 8 bytes
++       size_t MUST be an unsigned type of the same width as
++       pointers. (If you are using an ancient system that declares
++       size_t as a signed type, or need it to be a different width
++       than pointers, you can use a previous release of this malloc
++       (e.g. 2.7.2) supporting these.)
++
++  Alignment:                                     8 bytes (minimum)
++       This suffices for nearly all current machines and C compilers.
++       However, you can define MALLOC_ALIGNMENT to be wider than this
++       if necessary (up to 128bytes), at the expense of using more space.
++
++  Minimum overhead per allocated chunk:   4 or  8 bytes (if 4byte sizes)
++                                          8 or 16 bytes (if 8byte sizes)
++       Each malloced chunk has a hidden word of overhead holding size
++       and status information, and additional cross-check word
++       if FOOTERS is defined.
++
++  Minimum allocated size: 4-byte ptrs:  16 bytes    (including overhead)
++                          8-byte ptrs:  32 bytes    (including overhead)
++
++       Even a request for zero bytes (i.e., malloc(0)) returns a
++       pointer to something of the minimum allocatable size.
++       The maximum overhead wastage (i.e., number of extra bytes
++       allocated than were requested in malloc) is less than or equal
++       to the minimum size, except for requests >= mmap_threshold that
++       are serviced via mmap(), where the worst case wastage is about
++       32 bytes plus the remainder from a system page (the minimal
++       mmap unit); typically 4096 or 8192 bytes.
++
++  Security: static-safe; optionally more or less
++       The "security" of malloc refers to the ability of malicious
++       code to accentuate the effects of errors (for example, freeing
++       space that is not currently malloc'ed or overwriting past the
++       ends of chunks) in code that calls malloc.  This malloc
++       guarantees not to modify any memory locations below the base of
++       heap, i.e., static variables, even in the presence of usage
++       errors.  The routines additionally detect most improper frees
++       and reallocs.  All this holds as long as the static bookkeeping
++       for malloc itself is not corrupted by some other means.  This
++       is only one aspect of security -- these checks do not, and
++       cannot, detect all possible programming errors.
++
++       If FOOTERS is defined nonzero, then each allocated chunk
++       carries an additional check word to verify that it was malloced
++       from its space.  These check words are the same within each
++       execution of a program using malloc, but differ across
++       executions, so externally crafted fake chunks cannot be
++       freed. This improves security by rejecting frees/reallocs that
++       could corrupt heap memory, in addition to the checks preventing
++       writes to statics that are always on.  This may further improve
++       security at the expense of time and space overhead.  (Note that
++       FOOTERS may also be worth using with MSPACES.)
++
++       By default detected errors cause the program to abort (calling
++       "abort()"). You can override this to instead proceed past
++       errors by defining PROCEED_ON_ERROR.  In this case, a bad free
++       has no effect, and a malloc that encounters a bad address
++       caused by user overwrites will ignore the bad address by
++       dropping pointers and indices to all known memory. This may
++       be appropriate for programs that should continue if at all
++       possible in the face of programming errors, although they may
++       run out of memory because dropped memory is never reclaimed.
++
++       If you don't like either of these options, you can define
++       CORRUPTION_ERROR_ACTION and USAGE_ERROR_ACTION to do anything
++       else. And if if you are sure that your program using malloc has
++       no errors or vulnerabilities, you can define INSECURE to 1,
++       which might (or might not) provide a small performance improvement.
++
++       It is also possible to limit the maximum total allocatable
++       space, using malloc_set_footprint_limit. This is not
++       designed as a security feature in itself (calls to set limits
++       are not screened or privileged), but may be useful as one
++       aspect of a secure implementation.
++
++  Thread-safety: NOT thread-safe unless USE_LOCKS defined non-zero
++       When USE_LOCKS is defined, each public call to malloc, free,
++       etc is surrounded with a lock. By default, this uses a plain
++       pthread mutex, win32 critical section, or a spin-lock if if
++       available for the platform and not disabled by setting
++       USE_SPIN_LOCKS=0.  However, if USE_RECURSIVE_LOCKS is defined,
++       recursive versions are used instead (which are not required for
++       base functionality but may be needed in layered extensions).
++       Using a global lock is not especially fast, and can be a major
++       bottleneck.  It is designed only to provide minimal protection
++       in concurrent environments, and to provide a basis for
++       extensions.  If you are using malloc in a concurrent program,
++       consider instead using nedmalloc
++       (http://www.nedprod.com/programs/portable/nedmalloc/) or
++       ptmalloc (See http://www.malloc.de), which are derived from
++       versions of this malloc.
++
++  System requirements: Any combination of MORECORE and/or MMAP/MUNMAP
++       This malloc can use unix sbrk or any emulation (invoked using
++       the CALL_MORECORE macro) and/or mmap/munmap or any emulation
++       (invoked using CALL_MMAP/CALL_MUNMAP) to get and release system
++       memory.  On most unix systems, it tends to work best if both
++       MORECORE and MMAP are enabled.  On Win32, it uses emulations
++       based on VirtualAlloc. It also uses common C library functions
++       like memset.
++
++  Compliance: I believe it is compliant with the Single Unix Specification
++       (See http://www.unix.org). Also SVID/XPG, ANSI C, and probably
++       others as well.
++
++* Overview of algorithms
++
++  This is not the fastest, most space-conserving, most portable, or
++  most tunable malloc ever written. However it is among the fastest
++  while also being among the most space-conserving, portable and
++  tunable.  Consistent balance across these factors results in a good
++  general-purpose allocator for malloc-intensive programs.
++
++  In most ways, this malloc is a best-fit allocator. Generally, it
++  chooses the best-fitting existing chunk for a request, with ties
++  broken in approximately least-recently-used order. (This strategy
++  normally maintains low fragmentation.) However, for requests less
++  than 256bytes, it deviates from best-fit when there is not an
++  exactly fitting available chunk by preferring to use space adjacent
++  to that used for the previous small request, as well as by breaking
++  ties in approximately most-recently-used order. (These enhance
++  locality of series of small allocations.)  And for very large requests
++  (>= 256Kb by default), it relies on system memory mapping
++  facilities, if supported.  (This helps avoid carrying around and
++  possibly fragmenting memory used only for large chunks.)
++
++  All operations (except malloc_stats and mallinfo) have execution
++  times that are bounded by a constant factor of the number of bits in
++  a size_t, not counting any clearing in calloc or copying in realloc,
++  or actions surrounding MORECORE and MMAP that have times
++  proportional to the number of non-contiguous regions returned by
++  system allocation routines, which is often just 1. In real-time
++  applications, you can optionally suppress segment traversals using
++  NO_SEGMENT_TRAVERSAL, which assures bounded execution even when
++  system allocators return non-contiguous spaces, at the typical
++  expense of carrying around more memory and increased fragmentation.
++
++  The implementation is not very modular and seriously overuses
++  macros. Perhaps someday all C compilers will do as good a job
++  inlining modular code as can now be done by brute-force expansion,
++  but now, enough of them seem not to.
++
++  Some compilers issue a lot of warnings about code that is
++  dead/unreachable only on some platforms, and also about intentional
++  uses of negation on unsigned types. All known cases of each can be
++  ignored.
++
++  For a longer but out of date high-level description, see
++     http://gee.cs.oswego.edu/dl/html/malloc.html
++
++* MSPACES
++  If MSPACES is defined, then in addition to malloc, free, etc.,
++  this file also defines mspace_malloc, mspace_free, etc. These
++  are versions of malloc routines that take an "mspace" argument
++  obtained using create_mspace, to control all internal bookkeeping.
++  If ONLY_MSPACES is defined, only these versions are compiled.
++  So if you would like to use this allocator for only some allocations,
++  and your system malloc for others, you can compile with
++  ONLY_MSPACES and then do something like...
++    static mspace mymspace = create_mspace(0,0); // for example
++    #define mymalloc(bytes)  mspace_malloc(mymspace, bytes)
++
++  (Note: If you only need one instance of an mspace, you can instead
++  use "USE_DL_PREFIX" to relabel the global malloc.)
++
++  You can similarly create thread-local allocators by storing
++  mspaces as thread-locals. For example:
++    static __thread mspace tlms = 0;
++    void*  tlmalloc(size_t bytes) {
++      if (tlms == 0) tlms = create_mspace(0, 0);
++      return mspace_malloc(tlms, bytes);
++    }
++    void  tlfree(void* mem) { mspace_free(tlms, mem); }
++
++  Unless FOOTERS is defined, each mspace is completely independent.
++  You cannot allocate from one and free to another (although
++  conformance is only weakly checked, so usage errors are not always
++  caught). If FOOTERS is defined, then each chunk carries around a tag
++  indicating its originating mspace, and frees are directed to their
++  originating spaces. Normally, this requires use of locks.
++
++ -------------------------  Compile-time options ---------------------------
++
++Be careful in setting #define values for numerical constants of type
++size_t. On some systems, literal values are not automatically extended
++to size_t precision unless they are explicitly casted. You can also
++use the symbolic values MAX_SIZE_T, SIZE_T_ONE, etc below.
++
++WIN32                    default: defined if _WIN32 defined
++  Defining WIN32 sets up defaults for MS environment and compilers.
++  Otherwise defaults are for unix. Beware that there seem to be some
++  cases where this malloc might not be a pure drop-in replacement for
++  Win32 malloc: Random-looking failures from Win32 GDI API's (eg;
++  SetDIBits()) may be due to bugs in some video driver implementations
++  when pixel buffers are malloc()ed, and the region spans more than
++  one VirtualAlloc()ed region. Because dlmalloc uses a small (64Kb)
++  default granularity, pixel buffers may straddle virtual allocation
++  regions more often than when using the Microsoft allocator.  You can
++  avoid this by using VirtualAlloc() and VirtualFree() for all pixel
++  buffers rather than using malloc().  If this is not possible,
++  recompile this malloc with a larger DEFAULT_GRANULARITY. Note:
++  in cases where MSC and gcc (cygwin) are known to differ on WIN32,
++  conditions use _MSC_VER to distinguish them.
++
++DLMALLOC_EXPORT       default: extern
++  Defines how public APIs are declared. If you want to export via a
++  Windows DLL, you might define this as
++    #define DLMALLOC_EXPORT extern  __declspec(dllexport)
++  If you want a POSIX ELF shared object, you might use
++    #define DLMALLOC_EXPORT extern __attribute__((visibility("default")))
++
++MALLOC_ALIGNMENT         default: (size_t)(2 * sizeof(void *))
++  Controls the minimum alignment for malloc'ed chunks.  It must be a
++  power of two and at least 8, even on machines for which smaller
++  alignments would suffice. It may be defined as larger than this
++  though. Note however that code and data structures are optimized for
++  the case of 8-byte alignment.
++
++MSPACES                  default: 0 (false)
++  If true, compile in support for independent allocation spaces.
++  This is only supported if HAVE_MMAP is true.
++
++ONLY_MSPACES             default: 0 (false)
++  If true, only compile in mspace versions, not regular versions.
++
++USE_LOCKS                default: 0 (false)
++  Causes each call to each public routine to be surrounded with
++  pthread or WIN32 mutex lock/unlock. (If set true, this can be
++  overridden on a per-mspace basis for mspace versions.) If set to a
++  non-zero value other than 1, locks are used, but their
++  implementation is left out, so lock functions must be supplied manually,
++  as described below.
++
++USE_SPIN_LOCKS           default: 1 iff USE_LOCKS and spin locks available
++  If true, uses custom spin locks for locking. This is currently
++  supported only gcc >= 4.1, older gccs on x86 platforms, and recent
++  MS compilers.  Otherwise, posix locks or win32 critical sections are
++  used.
++
++USE_RECURSIVE_LOCKS      default: not defined
++  If defined nonzero, uses recursive (aka reentrant) locks, otherwise
++  uses plain mutexes. This is not required for malloc proper, but may
++  be needed for layered allocators such as nedmalloc.
++
++LOCK_AT_FORK            default: not defined
++  If defined nonzero, performs pthread_atfork upon initialization
++  to initialize child lock while holding parent lock. The implementation
++  assumes that pthread locks (not custom locks) are being used. In other
++  cases, you may need to customize the implementation.
++
++FOOTERS                  default: 0
++  If true, provide extra checking and dispatching by placing
++  information in the footers of allocated chunks. This adds
++  space and time overhead.
++
++INSECURE                 default: 0
++  If true, omit checks for usage errors and heap space overwrites.
++
++USE_DL_PREFIX            default: NOT defined
++  Causes compiler to prefix all public routines with the string 'dl'.
++  This can be useful when you only want to use this malloc in one part
++  of a program, using your regular system malloc elsewhere.
++
++MALLOC_INSPECT_ALL       default: NOT defined
++  If defined, compiles malloc_inspect_all and mspace_inspect_all, that
++  perform traversal of all heap space.  Unless access to these
++  functions is otherwise restricted, you probably do not want to
++  include them in secure implementations.
++
++ABORT                    default: defined as abort()
++  Defines how to abort on failed checks.  On most systems, a failed
++  check cannot die with an "assert" or even print an informative
++  message, because the underlying print routines in turn call malloc,
++  which will fail again.  Generally, the best policy is to simply call
++  abort(). It's not very useful to do more than this because many
++  errors due to overwriting will show up as address faults (null, odd
++  addresses etc) rather than malloc-triggered checks, so will also
++  abort.  Also, most compilers know that abort() does not return, so
++  can better optimize code conditionally calling it.
++
++PROCEED_ON_ERROR           default: defined as 0 (false)
++  Controls whether detected bad addresses cause them to bypassed
++  rather than aborting. If set, detected bad arguments to free and
++  realloc are ignored. And all bookkeeping information is zeroed out
++  upon a detected overwrite of freed heap space, thus losing the
++  ability to ever return it from malloc again, but enabling the
++  application to proceed. If PROCEED_ON_ERROR is defined, the
++  static variable malloc_corruption_error_count is compiled in
++  and can be examined to see if errors have occurred. This option
++  generates slower code than the default abort policy.
++
++DEBUG                    default: NOT defined
++  The DEBUG setting is mainly intended for people trying to modify
++  this code or diagnose problems when porting to new platforms.
++  However, it may also be able to better isolate user errors than just
++  using runtime checks.  The assertions in the check routines spell
++  out in more detail the assumptions and invariants underlying the
++  algorithms.  The checking is fairly extensive, and will slow down
++  execution noticeably. Calling malloc_stats or mallinfo with DEBUG
++  set will attempt to check every non-mmapped allocated and free chunk
++  in the course of computing the summaries.
++
++ABORT_ON_ASSERT_FAILURE   default: defined as 1 (true)
++  Debugging assertion failures can be nearly impossible if your
++  version of the assert macro causes malloc to be called, which will
++  lead to a cascade of further failures, blowing the runtime stack.
++  ABORT_ON_ASSERT_FAILURE cause assertions failures to call abort(),
++  which will usually make debugging easier.
++
++MALLOC_FAILURE_ACTION     default: sets errno to ENOMEM, or no-op on win32
++  The action to take before "return 0" when malloc fails to be able to
++  return memory because there is none available.
++
++HAVE_MORECORE             default: 1 (true) unless win32 or ONLY_MSPACES
++  True if this system supports sbrk or an emulation of it.
++
++MORECORE                  default: sbrk
++  The name of the sbrk-style system routine to call to obtain more
++  memory.  See below for guidance on writing custom MORECORE
++  functions. The type of the argument to sbrk/MORECORE varies across
++  systems.  It cannot be size_t, because it supports negative
++  arguments, so it is normally the signed type of the same width as
++  size_t (sometimes declared as "intptr_t").  It doesn't much matter
++  though. Internally, we only call it with arguments less than half
++  the max value of a size_t, which should work across all reasonable
++  possibilities, although sometimes generating compiler warnings.
++
++MORECORE_CONTIGUOUS       default: 1 (true) if HAVE_MORECORE
++  If true, take advantage of fact that consecutive calls to MORECORE
++  with positive arguments always return contiguous increasing
++  addresses.  This is true of unix sbrk. It does not hurt too much to
++  set it true anyway, since malloc copes with non-contiguities.
++  Setting it false when definitely non-contiguous saves time
++  and possibly wasted space it would take to discover this though.
++
++MORECORE_CANNOT_TRIM      default: NOT defined
++  True if MORECORE cannot release space back to the system when given
++  negative arguments. This is generally necessary only if you are
++  using a hand-crafted MORECORE function that cannot handle negative
++  arguments.
++
++NO_SEGMENT_TRAVERSAL       default: 0
++  If non-zero, suppresses traversals of memory segments
++  returned by either MORECORE or CALL_MMAP. This disables
++  merging of segments that are contiguous, and selectively
++  releasing them to the OS if unused, but bounds execution times.
++
++HAVE_MMAP                 default: 1 (true)
++  True if this system supports mmap or an emulation of it.  If so, and
++  HAVE_MORECORE is not true, MMAP is used for all system
++  allocation. If set and HAVE_MORECORE is true as well, MMAP is
++  primarily used to directly allocate very large blocks. It is also
++  used as a backup strategy in cases where MORECORE fails to provide
++  space from system. Note: A single call to MUNMAP is assumed to be
++  able to unmap memory that may have be allocated using multiple calls
++  to MMAP, so long as they are adjacent.
++
++HAVE_MREMAP               default: 1 on linux, else 0
++  If true realloc() uses mremap() to re-allocate large blocks and
++  extend or shrink allocation spaces.
++
++MMAP_CLEARS               default: 1 except on WINCE.
++  True if mmap clears memory so calloc doesn't need to. This is true
++  for standard unix mmap using /dev/zero and on WIN32 except for WINCE.
++
++USE_BUILTIN_FFS            default: 0 (i.e., not used)
++  Causes malloc to use the builtin ffs() function to compute indices.
++  Some compilers may recognize and intrinsify ffs to be faster than the
++  supplied C version. Also, the case of x86 using gcc is special-cased
++  to an asm instruction, so is already as fast as it can be, and so
++  this setting has no effect. Similarly for Win32 under recent MS compilers.
++  (On most x86s, the asm version is only slightly faster than the C version.)
++
++malloc_getpagesize         default: derive from system includes, or 4096.
++  The system page size. To the extent possible, this malloc manages
++  memory from the system in page-size units.  This may be (and
++  usually is) a function rather than a constant. This is ignored
++  if WIN32, where page size is determined using getSystemInfo during
++  initialization.
++
++USE_DEV_RANDOM             default: 0 (i.e., not used)
++  Causes malloc to use /dev/random to initialize secure magic seed for
++  stamping footers. Otherwise, the current time is used.
++
++NO_MALLINFO                default: 0
++  If defined, don't compile "mallinfo". This can be a simple way
++  of dealing with mismatches between system declarations and
++  those in this file.
++
++MALLINFO_FIELD_TYPE        default: size_t
++  The type of the fields in the mallinfo struct. This was originally
++  defined as "int" in SVID etc, but is more usefully defined as
++  size_t. The value is used only if  HAVE_USR_INCLUDE_MALLOC_H is not set
++
++NO_MALLOC_STATS            default: 0
++  If defined, don't compile "malloc_stats". This avoids calls to
++  fprintf and bringing in stdio dependencies you might not want.
++
++REALLOC_ZERO_BYTES_FREES    default: not defined
++  This should be set if a call to realloc with zero bytes should
++  be the same as a call to free. Some people think it should. Otherwise,
++  since this malloc returns a unique pointer for malloc(0), so does
++  realloc(p, 0).
++
++LACKS_UNISTD_H, LACKS_FCNTL_H, LACKS_SYS_PARAM_H, LACKS_SYS_MMAN_H
++LACKS_STRINGS_H, LACKS_STRING_H, LACKS_SYS_TYPES_H,  LACKS_ERRNO_H
++LACKS_STDLIB_H LACKS_SCHED_H LACKS_TIME_H  default: NOT defined unless on WIN32
++  Define these if your system does not have these header files.
++  You might need to manually insert some of the declarations they provide.
++
++DEFAULT_GRANULARITY        default: page size if MORECORE_CONTIGUOUS,
++                                system_info.dwAllocationGranularity in WIN32,
++                                otherwise 64K.
++      Also settable using mallopt(M_GRANULARITY, x)
++  The unit for allocating and deallocating memory from the system.  On
++  most systems with contiguous MORECORE, there is no reason to
++  make this more than a page. However, systems with MMAP tend to
++  either require or encourage larger granularities.  You can increase
++  this value to prevent system allocation functions to be called so
++  often, especially if they are slow.  The value must be at least one
++  page and must be a power of two.  Setting to 0 causes initialization
++  to either page size or win32 region size.  (Note: In previous
++  versions of malloc, the equivalent of this option was called
++  "TOP_PAD")
++
++DEFAULT_TRIM_THRESHOLD    default: 2MB
++      Also settable using mallopt(M_TRIM_THRESHOLD, x)
++  The maximum amount of unused top-most memory to keep before
++  releasing via malloc_trim in free().  Automatic trimming is mainly
++  useful in long-lived programs using contiguous MORECORE.  Because
++  trimming via sbrk can be slow on some systems, and can sometimes be
++  wasteful (in cases where programs immediately afterward allocate
++  more large chunks) the value should be high enough so that your
++  overall system performance would improve by releasing this much
++  memory.  As a rough guide, you might set to a value close to the
++  average size of a process (program) running on your system.
++  Releasing this much memory would allow such a process to run in
++  memory.  Generally, it is worth tuning trim thresholds when a
++  program undergoes phases where several large chunks are allocated
++  and released in ways that can reuse each other's storage, perhaps
++  mixed with phases where there are no such chunks at all. The trim
++  value must be greater than page size to have any useful effect.  To
++  disable trimming completely, you can set to MAX_SIZE_T. Note that the trick
++  some people use of mallocing a huge space and then freeing it at
++  program startup, in an attempt to reserve system memory, doesn't
++  have the intended effect under automatic trimming, since that memory
++  will immediately be returned to the system.
++
++DEFAULT_MMAP_THRESHOLD       default: 256K
++      Also settable using mallopt(M_MMAP_THRESHOLD, x)
++  The request size threshold for using MMAP to directly service a
++  request. Requests of at least this size that cannot be allocated
++  using already-existing space will be serviced via mmap.  (If enough
++  normal freed space already exists it is used instead.)  Using mmap
++  segregates relatively large chunks of memory so that they can be
++  individually obtained and released from the host system. A request
++  serviced through mmap is never reused by any other request (at least
++  not directly; the system may just so happen to remap successive
++  requests to the same locations).  Segregating space in this way has
++  the benefits that: Mmapped space can always be individually released
++  back to the system, which helps keep the system level memory demands
++  of a long-lived program low.  Also, mapped memory doesn't become
++  `locked' between other chunks, as can happen with normally allocated
++  chunks, which means that even trimming via malloc_trim would not
++  release them.  However, it has the disadvantage that the space
++  cannot be reclaimed, consolidated, and then used to service later
++  requests, as happens with normal chunks.  The advantages of mmap
++  nearly always outweigh disadvantages for "large" chunks, but the
++  value of "large" may vary across systems.  The default is an
++  empirically derived value that works well in most systems. You can
++  disable mmap by setting to MAX_SIZE_T.
++
++MAX_RELEASE_CHECK_RATE   default: 4095 unless not HAVE_MMAP
++  The number of consolidated frees between checks to release
++  unused segments when freeing. When using non-contiguous segments,
++  especially with multiple mspaces, checking only for topmost space
++  doesn't always suffice to trigger trimming. To compensate for this,
++  free() will, with a period of MAX_RELEASE_CHECK_RATE (or the
++  current number of segments, if greater) try to release unused
++  segments to the OS when freeing chunks that result in
++  consolidation. The best value for this parameter is a compromise
++  between slowing down frees with relatively costly checks that
++  rarely trigger versus holding on to unused memory. To effectively
++  disable, set to MAX_SIZE_T. This may lead to a very slight speed
++  improvement at the expense of carrying around more memory.
++*/
++
++/* Version identifier to allow people to support multiple versions */
++#ifndef DLMALLOC_VERSION
++#define DLMALLOC_VERSION 20806
++#endif /* DLMALLOC_VERSION */
++
++#ifndef DLMALLOC_EXPORT
++#define DLMALLOC_EXPORT extern
++#endif
++
++#ifndef WIN32
++#ifdef _WIN32
++#define WIN32 1
++#endif  /* _WIN32 */
++#ifdef _WIN32_WCE
++#define LACKS_FCNTL_H
++#define WIN32 1
++#endif /* _WIN32_WCE */
++#endif  /* WIN32 */
++#ifdef WIN32
++#define WIN32_LEAN_AND_MEAN
++#include <windows.h>
++#include <tchar.h>
++#define HAVE_MMAP 1
++#define HAVE_MORECORE 0
++#define LACKS_UNISTD_H
++#define LACKS_SYS_PARAM_H
++#define LACKS_SYS_MMAN_H
++#define LACKS_STRING_H
++#define LACKS_STRINGS_H
++#define LACKS_SYS_TYPES_H
++#define LACKS_ERRNO_H
++#define LACKS_SCHED_H
++#ifndef MALLOC_FAILURE_ACTION
++#define MALLOC_FAILURE_ACTION
++#endif /* MALLOC_FAILURE_ACTION */
++#ifndef MMAP_CLEARS
++#ifdef _WIN32_WCE /* WINCE reportedly does not clear */
++#define MMAP_CLEARS 0
++#else
++#define MMAP_CLEARS 1
++#endif /* _WIN32_WCE */
++#endif /*MMAP_CLEARS */
++#endif  /* WIN32 */
++
++#if defined(DARWIN) || defined(_DARWIN)
++/* Mac OSX docs advise not to use sbrk; it seems better to use mmap */
++#ifndef HAVE_MORECORE
++#define HAVE_MORECORE 0
++#define HAVE_MMAP 1
++/* OSX allocators provide 16 byte alignment */
++#ifndef MALLOC_ALIGNMENT
++#define MALLOC_ALIGNMENT ((size_t)16U)
++#endif
++#endif  /* HAVE_MORECORE */
++#endif  /* DARWIN */
++
++#ifndef LACKS_SYS_TYPES_H
++#include <sys/types.h>  /* For size_t */
++#endif  /* LACKS_SYS_TYPES_H */
++
++/* The maximum possible size_t value has all bits set */
++#define MAX_SIZE_T           (~(size_t)0)
++
++#ifndef USE_LOCKS /* ensure true if spin or recursive locks set */
++#define USE_LOCKS  ((defined(USE_SPIN_LOCKS) && USE_SPIN_LOCKS != 0) || \
++                    (defined(USE_RECURSIVE_LOCKS) && USE_RECURSIVE_LOCKS != 0))
++#endif /* USE_LOCKS */
++
++#if USE_LOCKS /* Spin locks for gcc >= 4.1, older gcc on x86, MSC >= 1310 */
++#if ((defined(__GNUC__) &&                                              \
++      ((__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 1)) ||      \
++       defined(__i386__) || defined(__x86_64__))) ||                    \
++     (defined(_MSC_VER) && _MSC_VER>=1310))
++#ifndef USE_SPIN_LOCKS
++#define USE_SPIN_LOCKS 1
++#endif /* USE_SPIN_LOCKS */
++#elif USE_SPIN_LOCKS
++#error "USE_SPIN_LOCKS defined without implementation"
++#endif /* ... locks available... */
++#elif !defined(USE_SPIN_LOCKS)
++#define USE_SPIN_LOCKS 0
++#endif /* USE_LOCKS */
++
++#ifndef ONLY_MSPACES
++#define ONLY_MSPACES 0
++#endif  /* ONLY_MSPACES */
++#ifndef MSPACES
++#if ONLY_MSPACES
++#define MSPACES 1
++#else   /* ONLY_MSPACES */
++#define MSPACES 0
++#endif  /* ONLY_MSPACES */
++#endif  /* MSPACES */
++#ifndef MALLOC_ALIGNMENT
++#define MALLOC_ALIGNMENT ((size_t)(2 * sizeof(void *)))
++#endif  /* MALLOC_ALIGNMENT */
++#ifndef FOOTERS
++#define FOOTERS 0
++#endif  /* FOOTERS */
++#ifndef ABORT
++#define ABORT  abort()
++#endif  /* ABORT */
++#ifndef ABORT_ON_ASSERT_FAILURE
++#define ABORT_ON_ASSERT_FAILURE 1
++#endif  /* ABORT_ON_ASSERT_FAILURE */
++#ifndef PROCEED_ON_ERROR
++#define PROCEED_ON_ERROR 0
++#endif  /* PROCEED_ON_ERROR */
++
++#ifndef INSECURE
++#define INSECURE 0
++#endif  /* INSECURE */
++#ifndef MALLOC_INSPECT_ALL
++#define MALLOC_INSPECT_ALL 0
++#endif  /* MALLOC_INSPECT_ALL */
++#ifndef HAVE_MMAP
++#define HAVE_MMAP 1
++#endif  /* HAVE_MMAP */
++#ifndef MMAP_CLEARS
++#define MMAP_CLEARS 1
++#endif  /* MMAP_CLEARS */
++#ifndef HAVE_MREMAP
++#ifdef linux
++#define HAVE_MREMAP 1
++#define _GNU_SOURCE /* Turns on mremap() definition */
++#else   /* linux */
++#define HAVE_MREMAP 0
++#endif  /* linux */
++#endif  /* HAVE_MREMAP */
++#ifndef MALLOC_FAILURE_ACTION
++#define MALLOC_FAILURE_ACTION  errno = ENOMEM;
++#endif  /* MALLOC_FAILURE_ACTION */
++#ifndef HAVE_MORECORE
++#if ONLY_MSPACES
++#define HAVE_MORECORE 0
++#else   /* ONLY_MSPACES */
++#define HAVE_MORECORE 1
++#endif  /* ONLY_MSPACES */
++#endif  /* HAVE_MORECORE */
++#if !HAVE_MORECORE
++#define MORECORE_CONTIGUOUS 0
++#else   /* !HAVE_MORECORE */
++#define MORECORE_DEFAULT sbrk
++#ifndef MORECORE_CONTIGUOUS
++#define MORECORE_CONTIGUOUS 1
++#endif  /* MORECORE_CONTIGUOUS */
++#endif  /* HAVE_MORECORE */
++#ifndef DEFAULT_GRANULARITY
++#if (MORECORE_CONTIGUOUS || defined(WIN32))
++#define DEFAULT_GRANULARITY (0)  /* 0 means to compute in init_mparams */
++#else   /* MORECORE_CONTIGUOUS */
++#define DEFAULT_GRANULARITY ((size_t)64U * (size_t)1024U)
++#endif  /* MORECORE_CONTIGUOUS */
++#endif  /* DEFAULT_GRANULARITY */
++#ifndef DEFAULT_TRIM_THRESHOLD
++#ifndef MORECORE_CANNOT_TRIM
++#define DEFAULT_TRIM_THRESHOLD ((size_t)2U * (size_t)1024U * (size_t)1024U)
++#else   /* MORECORE_CANNOT_TRIM */
++#define DEFAULT_TRIM_THRESHOLD MAX_SIZE_T
++#endif  /* MORECORE_CANNOT_TRIM */
++#endif  /* DEFAULT_TRIM_THRESHOLD */
++#ifndef DEFAULT_MMAP_THRESHOLD
++#if HAVE_MMAP
++#define DEFAULT_MMAP_THRESHOLD ((size_t)256U * (size_t)1024U)
++#else   /* HAVE_MMAP */
++#define DEFAULT_MMAP_THRESHOLD MAX_SIZE_T
++#endif  /* HAVE_MMAP */
++#endif  /* DEFAULT_MMAP_THRESHOLD */
++#ifndef MAX_RELEASE_CHECK_RATE
++#if HAVE_MMAP
++#define MAX_RELEASE_CHECK_RATE 4095
++#else
++#define MAX_RELEASE_CHECK_RATE MAX_SIZE_T
++#endif /* HAVE_MMAP */
++#endif /* MAX_RELEASE_CHECK_RATE */
++#ifndef USE_BUILTIN_FFS
++#define USE_BUILTIN_FFS 0
++#endif  /* USE_BUILTIN_FFS */
++#ifndef USE_DEV_RANDOM
++#define USE_DEV_RANDOM 0
++#endif  /* USE_DEV_RANDOM */
++#ifndef NO_MALLINFO
++#define NO_MALLINFO 0
++#endif  /* NO_MALLINFO */
++#ifndef MALLINFO_FIELD_TYPE
++#define MALLINFO_FIELD_TYPE size_t
++#endif  /* MALLINFO_FIELD_TYPE */
++#ifndef NO_MALLOC_STATS
++#define NO_MALLOC_STATS 0
++#endif  /* NO_MALLOC_STATS */
++#ifndef NO_SEGMENT_TRAVERSAL
++#define NO_SEGMENT_TRAVERSAL 0
++#endif /* NO_SEGMENT_TRAVERSAL */
++
++/*
++  mallopt tuning options.  SVID/XPG defines four standard parameter
++  numbers for mallopt, normally defined in malloc.h.  None of these
++  are used in this malloc, so setting them has no effect. But this
++  malloc does support the following options.
++*/
++
++#define M_TRIM_THRESHOLD     (-1)
++#define M_GRANULARITY        (-2)
++#define M_MMAP_THRESHOLD     (-3)
++
++/* ------------------------ Mallinfo declarations ------------------------ */
++
++#if !NO_MALLINFO
++/*
++  This version of malloc supports the standard SVID/XPG mallinfo
++  routine that returns a struct containing usage properties and
++  statistics. It should work on any system that has a
++  /usr/include/malloc.h defining struct mallinfo.  The main
++  declaration needed is the mallinfo struct that is returned (by-copy)
++  by mallinfo().  The malloinfo struct contains a bunch of fields that
++  are not even meaningful in this version of malloc.  These fields are
++  are instead filled by mallinfo() with other numbers that might be of
++  interest.
++
++  HAVE_USR_INCLUDE_MALLOC_H should be set if you have a
++  /usr/include/malloc.h file that includes a declaration of struct
++  mallinfo.  If so, it is included; else a compliant version is
++  declared below.  These must be precisely the same for mallinfo() to
++  work.  The original SVID version of this struct, defined on most
++  systems with mallinfo, declares all fields as ints. But some others
++  define as unsigned long. If your system defines the fields using a
++  type of different width than listed here, you MUST #include your
++  system version and #define HAVE_USR_INCLUDE_MALLOC_H.
++*/
++
++/* #define HAVE_USR_INCLUDE_MALLOC_H */
++
++#ifdef HAVE_USR_INCLUDE_MALLOC_H
++#include "/usr/include/malloc.h"
++#else /* HAVE_USR_INCLUDE_MALLOC_H */
++#ifndef STRUCT_MALLINFO_DECLARED
++/* HP-UX (and others?) redefines mallinfo unless _STRUCT_MALLINFO is defined */
++#define _STRUCT_MALLINFO
++#define STRUCT_MALLINFO_DECLARED 1
++struct mallinfo {
++  MALLINFO_FIELD_TYPE arena;    /* non-mmapped space allocated from system */
++  MALLINFO_FIELD_TYPE ordblks;  /* number of free chunks */
++  MALLINFO_FIELD_TYPE smblks;   /* always 0 */
++  MALLINFO_FIELD_TYPE hblks;    /* always 0 */
++  MALLINFO_FIELD_TYPE hblkhd;   /* space in mmapped regions */
++  MALLINFO_FIELD_TYPE usmblks;  /* maximum total allocated space */
++  MALLINFO_FIELD_TYPE fsmblks;  /* always 0 */
++  MALLINFO_FIELD_TYPE uordblks; /* total allocated space */
++  MALLINFO_FIELD_TYPE fordblks; /* total free space */
++  MALLINFO_FIELD_TYPE keepcost; /* releasable (via malloc_trim) space */
++};
++#endif /* STRUCT_MALLINFO_DECLARED */
++#endif /* HAVE_USR_INCLUDE_MALLOC_H */
++#endif /* NO_MALLINFO */
++
++/*
++  Try to persuade compilers to inline. The most critical functions for
++  inlining are defined as macros, so these aren't used for them.
++*/
++
++#ifndef FORCEINLINE
++  #if defined(__GNUC__)
++#define FORCEINLINE __inline __attribute__ ((always_inline))
++  #elif defined(_MSC_VER)
++    #define FORCEINLINE __forceinline
++  #endif
++#endif
++#ifndef NOINLINE
++  #if defined(__GNUC__)
++    #define NOINLINE __attribute__ ((noinline))
++  #elif defined(_MSC_VER)
++    #define NOINLINE __declspec(noinline)
++  #else
++    #define NOINLINE
++  #endif
++#endif
++
++#ifdef __cplusplus
++extern "C" {
++#ifndef FORCEINLINE
++ #define FORCEINLINE inline
++#endif
++#endif /* __cplusplus */
++#ifndef FORCEINLINE
++ #define FORCEINLINE
++#endif
++
++#if !ONLY_MSPACES
++
++/* ------------------- Declarations of public routines ------------------- */
++
++#ifndef USE_DL_PREFIX
++#define dlcalloc               calloc
++#define dlfree                 free
++#define dlmalloc               malloc
++#define dlmemalign             memalign
++#define dlposix_memalign       posix_memalign
++#define dlrealloc              realloc
++#define dlrealloc_in_place     realloc_in_place
++#define dlvalloc               valloc
++#define dlpvalloc              pvalloc
++#define dlmallinfo             mallinfo
++#define dlmallopt              mallopt
++#define dlmalloc_trim          malloc_trim
++#define dlmalloc_stats         malloc_stats
++#define dlmalloc_usable_size   malloc_usable_size
++#define dlmalloc_footprint     malloc_footprint
++#define dlmalloc_max_footprint malloc_max_footprint
++#define dlmalloc_footprint_limit malloc_footprint_limit
++#define dlmalloc_set_footprint_limit malloc_set_footprint_limit
++#define dlmalloc_inspect_all   malloc_inspect_all
++#define dlindependent_calloc   independent_calloc
++#define dlindependent_comalloc independent_comalloc
++#define dlbulk_free            bulk_free
++#endif /* USE_DL_PREFIX */
++
++/*
++  malloc(size_t n)
++  Returns a pointer to a newly allocated chunk of at least n bytes, or
++  null if no space is available, in which case errno is set to ENOMEM
++  on ANSI C systems.
++
++  If n is zero, malloc returns a minimum-sized chunk. (The minimum
++  size is 16 bytes on most 32bit systems, and 32 bytes on 64bit
++  systems.)  Note that size_t is an unsigned type, so calls with
++  arguments that would be negative if signed are interpreted as
++  requests for huge amounts of space, which will often fail. The
++  maximum supported value of n differs across systems, but is in all
++  cases less than the maximum representable value of a size_t.
++*/
++DLMALLOC_EXPORT void* dlmalloc(size_t);
++
++/*
++  free(void* p)
++  Releases the chunk of memory pointed to by p, that had been previously
++  allocated using malloc or a related routine such as realloc.
++  It has no effect if p is null. If p was not malloced or already
++  freed, free(p) will by default cause the current program to abort.
++*/
++DLMALLOC_EXPORT void  dlfree(void*);
++
++/*
++  calloc(size_t n_elements, size_t element_size);
++  Returns a pointer to n_elements * element_size bytes, with all locations
++  set to zero.
++*/
++DLMALLOC_EXPORT void* dlcalloc(size_t, size_t);
++
++/*
++  realloc(void* p, size_t n)
++  Returns a pointer to a chunk of size n that contains the same data
++  as does chunk p up to the minimum of (n, p's size) bytes, or null
++  if no space is available.
++
++  The returned pointer may or may not be the same as p. The algorithm
++  prefers extending p in most cases when possible, otherwise it
++  employs the equivalent of a malloc-copy-free sequence.
++
++  If p is null, realloc is equivalent to malloc.
++
++  If space is not available, realloc returns null, errno is set (if on
++  ANSI) and p is NOT freed.
++
++  if n is for fewer bytes than already held by p, the newly unused
++  space is lopped off and freed if possible.  realloc with a size
++  argument of zero (re)allocates a minimum-sized chunk.
++
++  The old unix realloc convention of allowing the last-free'd chunk
++  to be used as an argument to realloc is not supported.
++*/
++DLMALLOC_EXPORT void* dlrealloc(void*, size_t);
++
++/*
++  realloc_in_place(void* p, size_t n)
++  Resizes the space allocated for p to size n, only if this can be
++  done without moving p (i.e., only if there is adjacent space
++  available if n is greater than p's current allocated size, or n is
++  less than or equal to p's size). This may be used instead of plain
++  realloc if an alternative allocation strategy is needed upon failure
++  to expand space; for example, reallocation of a buffer that must be
++  memory-aligned or cleared. You can use realloc_in_place to trigger
++  these alternatives only when needed.
++
++  Returns p if successful; otherwise null.
++*/
++DLMALLOC_EXPORT void* dlrealloc_in_place(void*, size_t);
++
++/*
++  memalign(size_t alignment, size_t n);
++  Returns a pointer to a newly allocated chunk of n bytes, aligned
++  in accord with the alignment argument.
++
++  The alignment argument should be a power of two. If the argument is
++  not a power of two, the nearest greater power is used.
++  8-byte alignment is guaranteed by normal malloc calls, so don't
++  bother calling memalign with an argument of 8 or less.
++
++  Overreliance on memalign is a sure way to fragment space.
++*/
++DLMALLOC_EXPORT void* dlmemalign(size_t, size_t);
++
++/*
++  int posix_memalign(void** pp, size_t alignment, size_t n);
++  Allocates a chunk of n bytes, aligned in accord with the alignment
++  argument. Differs from memalign only in that it (1) assigns the
++  allocated memory to *pp rather than returning it, (2) fails and
++  returns EINVAL if the alignment is not a power of two (3) fails and
++  returns ENOMEM if memory cannot be allocated.
++*/
++DLMALLOC_EXPORT int dlposix_memalign(void**, size_t, size_t);
++
++/*
++  valloc(size_t n);
++  Equivalent to memalign(pagesize, n), where pagesize is the page
++  size of the system. If the pagesize is unknown, 4096 is used.
++*/
++DLMALLOC_EXPORT void* dlvalloc(size_t);
++
++/*
++  mallopt(int parameter_number, int parameter_value)
++  Sets tunable parameters The format is to provide a
++  (parameter-number, parameter-value) pair.  mallopt then sets the
++  corresponding parameter to the argument value if it can (i.e., so
++  long as the value is meaningful), and returns 1 if successful else
++  0.  To workaround the fact that mallopt is specified to use int,
++  not size_t parameters, the value -1 is specially treated as the
++  maximum unsigned size_t value.
++
++  SVID/XPG/ANSI defines four standard param numbers for mallopt,
++  normally defined in malloc.h.  None of these are use in this malloc,
++  so setting them has no effect. But this malloc also supports other
++  options in mallopt. See below for details.  Briefly, supported
++  parameters are as follows (listed defaults are for "typical"
++  configurations).
++
++  Symbol            param #  default    allowed param values
++  M_TRIM_THRESHOLD     -1   2*1024*1024   any   (-1 disables)
++  M_GRANULARITY        -2     page size   any power of 2 >= page size
++  M_MMAP_THRESHOLD     -3      256*1024   any   (or 0 if no MMAP support)
++*/
++DLMALLOC_EXPORT int dlmallopt(int, int);
++
++/*
++  malloc_footprint();
++  Returns the number of bytes obtained from the system.  The total
++  number of bytes allocated by malloc, realloc etc., is less than this
++  value. Unlike mallinfo, this function returns only a precomputed
++  result, so can be called frequently to monitor memory consumption.
++  Even if locks are otherwise defined, this function does not use them,
++  so results might not be up to date.
++*/
++DLMALLOC_EXPORT size_t dlmalloc_footprint(void);
++
++/*
++  malloc_max_footprint();
++  Returns the maximum number of bytes obtained from the system. This
++  value will be greater than current footprint if deallocated space
++  has been reclaimed by the system. The peak number of bytes allocated
++  by malloc, realloc etc., is less than this value. Unlike mallinfo,
++  this function returns only a precomputed result, so can be called
++  frequently to monitor memory consumption.  Even if locks are
++  otherwise defined, this function does not use them, so results might
++  not be up to date.
++*/
++DLMALLOC_EXPORT size_t dlmalloc_max_footprint(void);
++
++/*
++  malloc_footprint_limit();
++  Returns the number of bytes that the heap is allowed to obtain from
++  the system, returning the last value returned by
++  malloc_set_footprint_limit, or the maximum size_t value if
++  never set. The returned value reflects a permission. There is no
++  guarantee that this number of bytes can actually be obtained from
++  the system.
++*/
++DLMALLOC_EXPORT size_t dlmalloc_footprint_limit();
++
++/*
++  malloc_set_footprint_limit();
++  Sets the maximum number of bytes to obtain from the system, causing
++  failure returns from malloc and related functions upon attempts to
++  exceed this value. The argument value may be subject to page
++  rounding to an enforceable limit; this actual value is returned.
++  Using an argument of the maximum possible size_t effectively
++  disables checks. If the argument is less than or equal to the
++  current malloc_footprint, then all future allocations that require
++  additional system memory will fail. However, invocation cannot
++  retroactively deallocate existing used memory.
++*/
++DLMALLOC_EXPORT size_t dlmalloc_set_footprint_limit(size_t bytes);
++
++#if MALLOC_INSPECT_ALL
++/*
++  malloc_inspect_all(void(*handler)(void *start,
++                                    void *end,
++                                    size_t used_bytes,
++                                    void* callback_arg),
++                      void* arg);
++  Traverses the heap and calls the given handler for each managed
++  region, skipping all bytes that are (or may be) used for bookkeeping
++  purposes.  Traversal does not include include chunks that have been
++  directly memory mapped. Each reported region begins at the start
++  address, and continues up to but not including the end address.  The
++  first used_bytes of the region contain allocated data. If
++  used_bytes is zero, the region is unallocated. The handler is
++  invoked with the given callback argument. If locks are defined, they
++  are held during the entire traversal. It is a bad idea to invoke
++  other malloc functions from within the handler.
++
++  For example, to count the number of in-use chunks with size greater
++  than 1000, you could write:
++  static int count = 0;
++  void count_chunks(void* start, void* end, size_t used, void* arg) {
++    if (used >= 1000) ++count;
++  }
++  then:
++    malloc_inspect_all(count_chunks, NULL);
++
++  malloc_inspect_all is compiled only if MALLOC_INSPECT_ALL is defined.
++*/
++DLMALLOC_EXPORT void dlmalloc_inspect_all(void(*handler)(void*, void *, size_t, void*),
++                           void* arg);
++
++#endif /* MALLOC_INSPECT_ALL */
++
++#if !NO_MALLINFO
++/*
++  mallinfo()
++  Returns (by copy) a struct containing various summary statistics:
++
++  arena:     current total non-mmapped bytes allocated from system
++  ordblks:   the number of free chunks
++  smblks:    always zero.
++  hblks:     current number of mmapped regions
++  hblkhd:    total bytes held in mmapped regions
++  usmblks:   the maximum total allocated space. This will be greater
++                than current total if trimming has occurred.
++  fsmblks:   always zero
++  uordblks:  current total allocated space (normal or mmapped)
++  fordblks:  total free space
++  keepcost:  the maximum number of bytes that could ideally be released
++               back to system via malloc_trim. ("ideally" means that
++               it ignores page restrictions etc.)
++
++  Because these fields are ints, but internal bookkeeping may
++  be kept as longs, the reported values may wrap around zero and
++  thus be inaccurate.
++*/
++DLMALLOC_EXPORT struct mallinfo dlmallinfo(void);
++#endif /* NO_MALLINFO */
++
++/*
++  independent_calloc(size_t n_elements, size_t element_size, void* chunks[]);
++
++  independent_calloc is similar to calloc, but instead of returning a
++  single cleared space, it returns an array of pointers to n_elements
++  independent elements that can hold contents of size elem_size, each
++  of which starts out cleared, and can be independently freed,
++  realloc'ed etc. The elements are guaranteed to be adjacently
++  allocated (this is not guaranteed to occur with multiple callocs or
++  mallocs), which may also improve cache locality in some
++  applications.
++
++  The "chunks" argument is optional (i.e., may be null, which is
++  probably the most typical usage). If it is null, the returned array
++  is itself dynamically allocated and should also be freed when it is
++  no longer needed. Otherwise, the chunks array must be of at least
++  n_elements in length. It is filled in with the pointers to the
++  chunks.
++
++  In either case, independent_calloc returns this pointer array, or
++  null if the allocation failed.  If n_elements is zero and "chunks"
++  is null, it returns a chunk representing an array with zero elements
++  (which should be freed if not wanted).
++
++  Each element must be freed when it is no longer needed. This can be
++  done all at once using bulk_free.
++
++  independent_calloc simplifies and speeds up implementations of many
++  kinds of pools.  It may also be useful when constructing large data
++  structures that initially have a fixed number of fixed-sized nodes,
++  but the number is not known at compile time, and some of the nodes
++  may later need to be freed. For example:
++
++  struct Node { int item; struct Node* next; };
++
++  struct Node* build_list() {
++    struct Node** pool;
++    int n = read_number_of_nodes_needed();
++    if (n <= 0) return 0;
++    pool = (struct Node**)(independent_calloc(n, sizeof(struct Node), 0);
++    if (pool == 0) die();
++    // organize into a linked list...
++    struct Node* first = pool[0];
++    for (i = 0; i < n-1; ++i)
++      pool[i]->next = pool[i+1];
++    free(pool);     // Can now free the array (or not, if it is needed later)
++    return first;
++  }
++*/
++DLMALLOC_EXPORT void** dlindependent_calloc(size_t, size_t, void**);
++
++/*
++  independent_comalloc(size_t n_elements, size_t sizes[], void* chunks[]);
++
++  independent_comalloc allocates, all at once, a set of n_elements
++  chunks with sizes indicated in the "sizes" array.    It returns
++  an array of pointers to these elements, each of which can be
++  independently freed, realloc'ed etc. The elements are guaranteed to
++  be adjacently allocated (this is not guaranteed to occur with
++  multiple callocs or mallocs), which may also improve cache locality
++  in some applications.
++
++  The "chunks" argument is optional (i.e., may be null). If it is null
++  the returned array is itself dynamically allocated and should also
++  be freed when it is no longer needed. Otherwise, the chunks array
++  must be of at least n_elements in length. It is filled in with the
++  pointers to the chunks.
++
++  In either case, independent_comalloc returns this pointer array, or
++  null if the allocation failed.  If n_elements is zero and chunks is
++  null, it returns a chunk representing an array with zero elements
++  (which should be freed if not wanted).
++
++  Each element must be freed when it is no longer needed. This can be
++  done all at once using bulk_free.
++
++  independent_comallac differs from independent_calloc in that each
++  element may have a different size, and also that it does not
++  automatically clear elements.
++
++  independent_comalloc can be used to speed up allocation in cases
++  where several structs or objects must always be allocated at the
++  same time.  For example:
++
++  struct Head { ... }
++  struct Foot { ... }
++
++  void send_message(char* msg) {
++    int msglen = strlen(msg);
++    size_t sizes[3] = { sizeof(struct Head), msglen, sizeof(struct Foot) };
++    void* chunks[3];
++    if (independent_comalloc(3, sizes, chunks) == 0)
++      die();
++    struct Head* head = (struct Head*)(chunks[0]);
++    char*        body = (char*)(chunks[1]);
++    struct Foot* foot = (struct Foot*)(chunks[2]);
++    // ...
++  }
++
++  In general though, independent_comalloc is worth using only for
++  larger values of n_elements. For small values, you probably won't
++  detect enough difference from series of malloc calls to bother.
++
++  Overuse of independent_comalloc can increase overall memory usage,
++  since it cannot reuse existing noncontiguous small chunks that
++  might be available for some of the elements.
++*/
++DLMALLOC_EXPORT void** dlindependent_comalloc(size_t, size_t*, void**);
++
++/*
++  bulk_free(void* array[], size_t n_elements)
++  Frees and clears (sets to null) each non-null pointer in the given
++  array.  This is likely to be faster than freeing them one-by-one.
++  If footers are used, pointers that have been allocated in different
++  mspaces are not freed or cleared, and the count of all such pointers
++  is returned.  For large arrays of pointers with poor locality, it
++  may be worthwhile to sort this array before calling bulk_free.
++*/
++DLMALLOC_EXPORT size_t  dlbulk_free(void**, size_t n_elements);
++
++/*
++  pvalloc(size_t n);
++  Equivalent to valloc(minimum-page-that-holds(n)), that is,
++  round up n to nearest pagesize.
++ */
++DLMALLOC_EXPORT void*  dlpvalloc(size_t);
++
++/*
++  malloc_trim(size_t pad);
++
++  If possible, gives memory back to the system (via negative arguments
++  to sbrk) if there is unused memory at the `high' end of the malloc
++  pool or in unused MMAP segments. You can call this after freeing
++  large blocks of memory to potentially reduce the system-level memory
++  requirements of a program. However, it cannot guarantee to reduce
++  memory. Under some allocation patterns, some large free blocks of
++  memory will be locked between two used chunks, so they cannot be
++  given back to the system.
++
++  The `pad' argument to malloc_trim represents the amount of free
++  trailing space to leave untrimmed. If this argument is zero, only
++  the minimum amount of memory to maintain internal data structures
++  will be left. Non-zero arguments can be supplied to maintain enough
++  trailing space to service future expected allocations without having
++  to re-obtain memory from the system.
++
++  Malloc_trim returns 1 if it actually released any memory, else 0.
++*/
++DLMALLOC_EXPORT int  dlmalloc_trim(size_t);
++
++/*
++  malloc_stats();
++  Prints on stderr the amount of space obtained from the system (both
++  via sbrk and mmap), the maximum amount (which may be more than
++  current if malloc_trim and/or munmap got called), and the current
++  number of bytes allocated via malloc (or realloc, etc) but not yet
++  freed. Note that this is the number of bytes allocated, not the
++  number requested. It will be larger than the number requested
++  because of alignment and bookkeeping overhead. Because it includes
++  alignment wastage as being in use, this figure may be greater than
++  zero even when no user-level chunks are allocated.
++
++  The reported current and maximum system memory can be inaccurate if
++  a program makes other calls to system memory allocation functions
++  (normally sbrk) outside of malloc.
++
++  malloc_stats prints only the most commonly interesting statistics.
++  More information can be obtained by calling mallinfo.
++*/
++DLMALLOC_EXPORT void  dlmalloc_stats(void);
++
++/*
++  malloc_usable_size(void* p);
++
++  Returns the number of bytes you can actually use in
++  an allocated chunk, which may be more than you requested (although
++  often not) due to alignment and minimum size constraints.
++  You can use this many bytes without worrying about
++  overwriting other allocated objects. This is not a particularly great
++  programming practice. malloc_usable_size can be more useful in
++  debugging and assertions, for example:
++
++  p = malloc(n);
++  assert(malloc_usable_size(p) >= 256);
++*/
++/* BEGIN android-changed: added const */
++size_t dlmalloc_usable_size(const void*);
++/* END android-change */
++
++#endif /* ONLY_MSPACES */
++
++#if MSPACES
++
++/*
++  mspace is an opaque type representing an independent
++  region of space that supports mspace_malloc, etc.
++*/
++typedef void* mspace;
++
++/*
++  create_mspace creates and returns a new independent space with the
++  given initial capacity, or, if 0, the default granularity size.  It
++  returns null if there is no system memory available to create the
++  space.  If argument locked is non-zero, the space uses a separate
++  lock to control access. The capacity of the space will grow
++  dynamically as needed to service mspace_malloc requests.  You can
++  control the sizes of incremental increases of this space by
++  compiling with a different DEFAULT_GRANULARITY or dynamically
++  setting with mallopt(M_GRANULARITY, value).
++*/
++DLMALLOC_EXPORT mspace create_mspace(size_t capacity, int locked);
++
++/*
++  destroy_mspace destroys the given space, and attempts to return all
++  of its memory back to the system, returning the total number of
++  bytes freed. After destruction, the results of access to all memory
++  used by the space become undefined.
++*/
++DLMALLOC_EXPORT size_t destroy_mspace(mspace msp);
++
++/*
++  create_mspace_with_base uses the memory supplied as the initial base
++  of a new mspace. Part (less than 128*sizeof(size_t) bytes) of this
++  space is used for bookkeeping, so the capacity must be at least this
++  large. (Otherwise 0 is returned.) When this initial space is
++  exhausted, additional memory will be obtained from the system.
++  Destroying this space will deallocate all additionally allocated
++  space (if possible) but not the initial base.
++*/
++DLMALLOC_EXPORT mspace create_mspace_with_base(void* base, size_t capacity, int locked);
++
++/*
++  mspace_track_large_chunks controls whether requests for large chunks
++  are allocated in their own untracked mmapped regions, separate from
++  others in this mspace. By default large chunks are not tracked,
++  which reduces fragmentation. However, such chunks are not
++  necessarily released to the system upon destroy_mspace.  Enabling
++  tracking by setting to true may increase fragmentation, but avoids
++  leakage when relying on destroy_mspace to release all memory
++  allocated using this space.  The function returns the previous
++  setting.
++*/
++DLMALLOC_EXPORT int mspace_track_large_chunks(mspace msp, int enable);
++
++
++/*
++  mspace_malloc behaves as malloc, but operates within
++  the given space.
++*/
++DLMALLOC_EXPORT void* mspace_malloc(mspace msp, size_t bytes);
++
++/*
++  mspace_free behaves as free, but operates within
++  the given space.
++
++  If compiled with FOOTERS==1, mspace_free is not actually needed.
++  free may be called instead of mspace_free because freed chunks from
++  any space are handled by their originating spaces.
++*/
++DLMALLOC_EXPORT void mspace_free(mspace msp, void* mem);
++
++/*
++  mspace_realloc behaves as realloc, but operates within
++  the given space.
++
++  If compiled with FOOTERS==1, mspace_realloc is not actually
++  needed.  realloc may be called instead of mspace_realloc because
++  realloced chunks from any space are handled by their originating
++  spaces.
++*/
++DLMALLOC_EXPORT void* mspace_realloc(mspace msp, void* mem, size_t newsize);
++
++/*
++  mspace_calloc behaves as calloc, but operates within
++  the given space.
++*/
++DLMALLOC_EXPORT void* mspace_calloc(mspace msp, size_t n_elements, size_t elem_size);
++
++/*
++  mspace_memalign behaves as memalign, but operates within
++  the given space.
++*/
++DLMALLOC_EXPORT void* mspace_memalign(mspace msp, size_t alignment, size_t bytes);
++
++/*
++  mspace_independent_calloc behaves as independent_calloc, but
++  operates within the given space.
++*/
++DLMALLOC_EXPORT void** mspace_independent_calloc(mspace msp, size_t n_elements,
++                                 size_t elem_size, void* chunks[]);
++
++/*
++  mspace_independent_comalloc behaves as independent_comalloc, but
++  operates within the given space.
++*/
++DLMALLOC_EXPORT void** mspace_independent_comalloc(mspace msp, size_t n_elements,
++                                   size_t sizes[], void* chunks[]);
++
++/*
++  mspace_footprint() returns the number of bytes obtained from the
++  system for this space.
++*/
++DLMALLOC_EXPORT size_t mspace_footprint(mspace msp);
++
++/*
++  mspace_max_footprint() returns the peak number of bytes obtained from the
++  system for this space.
++*/
++DLMALLOC_EXPORT size_t mspace_max_footprint(mspace msp);
++
++
++#if !NO_MALLINFO
++/*
++  mspace_mallinfo behaves as mallinfo, but reports properties of
++  the given space.
++*/
++DLMALLOC_EXPORT struct mallinfo mspace_mallinfo(mspace msp);
++#endif /* NO_MALLINFO */
++
++/*
++  malloc_usable_size(void* p) behaves the same as malloc_usable_size;
++*/
++DLMALLOC_EXPORT size_t mspace_usable_size(const void* mem);
++
++/*
++  mspace_malloc_stats behaves as malloc_stats, but reports
++  properties of the given space.
++*/
++DLMALLOC_EXPORT void mspace_malloc_stats(mspace msp);
++
++/*
++  mspace_trim behaves as malloc_trim, but
++  operates within the given space.
++*/
++DLMALLOC_EXPORT int mspace_trim(mspace msp, size_t pad);
++
++/*
++  An alias for mallopt.
++*/
++DLMALLOC_EXPORT int mspace_mallopt(int, int);
++
++#endif /* MSPACES */
++
++#ifdef __cplusplus
++}  /* end of extern "C" */
++#endif /* __cplusplus */
++
++/*
++  ========================================================================
++  To make a fully customizable malloc.h header file, cut everything
++  above this line, put into file malloc.h, edit to suit, and #include it
++  on the next line, as well as in programs that use this malloc.
++  ========================================================================
++*/
++
++/* #include "malloc.h" */
++
++/*------------------------------ internal #includes ---------------------- */
++
++#ifdef _MSC_VER
++#pragma warning( disable : 4146 ) /* no "unsigned" warnings */
++#endif /* _MSC_VER */
++#if !NO_MALLOC_STATS
++#include <stdio.h>       /* for printing in malloc_stats */
++#endif /* NO_MALLOC_STATS */
++#ifndef LACKS_ERRNO_H
++#include <errno.h>       /* for MALLOC_FAILURE_ACTION */
++#endif /* LACKS_ERRNO_H */
++#ifdef DEBUG
++#if ABORT_ON_ASSERT_FAILURE
++#undef assert
++#define assert(x) if(!(x)) ABORT
++#else /* ABORT_ON_ASSERT_FAILURE */
++#include <assert.h>
++#endif /* ABORT_ON_ASSERT_FAILURE */
++#else  /* DEBUG */
++#ifndef assert
++#define assert(x)
++#endif
++#define DEBUG 0
++#endif /* DEBUG */
++#if !defined(WIN32) && !defined(LACKS_TIME_H)
++#include <time.h>        /* for magic initialization */
++#endif /* WIN32 */
++#ifndef LACKS_STDLIB_H
++#include <stdlib.h>      /* for abort() */
++#endif /* LACKS_STDLIB_H */
++#ifndef LACKS_STRING_H
++#include <string.h>      /* for memset etc */
++#endif  /* LACKS_STRING_H */
++#if USE_BUILTIN_FFS
++#ifndef LACKS_STRINGS_H
++#include <strings.h>     /* for ffs */
++#endif /* LACKS_STRINGS_H */
++#endif /* USE_BUILTIN_FFS */
++#if HAVE_MMAP
++#ifndef LACKS_SYS_MMAN_H
++/* On some versions of linux, mremap decl in mman.h needs __USE_GNU set */
++#if (defined(linux) && !defined(__USE_GNU))
++#define __USE_GNU 1
++#include <sys/mman.h>    /* for mmap */
++#undef __USE_GNU
++#else
++#include <sys/mman.h>    /* for mmap */
++#endif /* linux */
++#endif /* LACKS_SYS_MMAN_H */
++#ifndef LACKS_FCNTL_H
++#include <fcntl.h>
++#endif /* LACKS_FCNTL_H */
++#endif /* HAVE_MMAP */
++#ifndef LACKS_UNISTD_H
++#include <unistd.h>     /* for sbrk, sysconf */
++#else /* LACKS_UNISTD_H */
++#if !defined(__FreeBSD__) && !defined(__OpenBSD__) && !defined(__NetBSD__)
++extern void*     sbrk(ptrdiff_t);
++#endif /* FreeBSD etc */
++#endif /* LACKS_UNISTD_H */
++
++/* Declarations for locking */
++#if USE_LOCKS
++#ifndef WIN32
++#if defined (__SVR4) && defined (__sun)  /* solaris */
++#include <thread.h>
++#elif !defined(LACKS_SCHED_H)
++#include <sched.h>
++#endif /* solaris or LACKS_SCHED_H */
++#if (defined(USE_RECURSIVE_LOCKS) && USE_RECURSIVE_LOCKS != 0) || !USE_SPIN_LOCKS
++#include <pthread.h>
++#endif /* USE_RECURSIVE_LOCKS ... */
++#elif defined(_MSC_VER)
++#ifndef _M_AMD64
++/* These are already defined on AMD64 builds */
++#ifdef __cplusplus
++extern "C" {
++#endif /* __cplusplus */
++LONG __cdecl _InterlockedCompareExchange(LONG volatile *Dest, LONG Exchange, LONG Comp);
++LONG __cdecl _InterlockedExchange(LONG volatile *Target, LONG Value);
++#ifdef __cplusplus
++}
++#endif /* __cplusplus */
++#endif /* _M_AMD64 */
++#pragma intrinsic (_InterlockedCompareExchange)
++#pragma intrinsic (_InterlockedExchange)
++#define interlockedcompareexchange _InterlockedCompareExchange
++#define interlockedexchange _InterlockedExchange
++#elif defined(WIN32) && defined(__GNUC__)
++#define interlockedcompareexchange(a, b, c) __sync_val_compare_and_swap(a, c, b)
++#define interlockedexchange __sync_lock_test_and_set
++#endif /* Win32 */
++#else /* USE_LOCKS */
++#endif /* USE_LOCKS */
++
++#ifndef LOCK_AT_FORK
++#define LOCK_AT_FORK 0
++#endif
++
++/* Declarations for bit scanning on win32 */
++#if defined(_MSC_VER) && _MSC_VER>=1300
++#ifndef BitScanForward /* Try to avoid pulling in WinNT.h */
++#ifdef __cplusplus
++extern "C" {
++#endif /* __cplusplus */
++unsigned char _BitScanForward(unsigned long *index, unsigned long mask);
++unsigned char _BitScanReverse(unsigned long *index, unsigned long mask);
++#ifdef __cplusplus
++}
++#endif /* __cplusplus */
++
++#define BitScanForward _BitScanForward
++#define BitScanReverse _BitScanReverse
++#pragma intrinsic(_BitScanForward)
++#pragma intrinsic(_BitScanReverse)
++#endif /* BitScanForward */
++#endif /* defined(_MSC_VER) && _MSC_VER>=1300 */
++
++#ifndef WIN32
++#ifndef malloc_getpagesize
++#  ifdef _SC_PAGESIZE         /* some SVR4 systems omit an underscore */
++#    ifndef _SC_PAGE_SIZE
++#      define _SC_PAGE_SIZE _SC_PAGESIZE
++#    endif
++#  endif
++#  ifdef _SC_PAGE_SIZE
++#    define malloc_getpagesize sysconf(_SC_PAGE_SIZE)
++#  else
++#    if defined(BSD) || defined(DGUX) || defined(HAVE_GETPAGESIZE)
++       extern size_t getpagesize();
++#      define malloc_getpagesize getpagesize()
++#    else
++#      ifdef WIN32 /* use supplied emulation of getpagesize */
++#        define malloc_getpagesize getpagesize()
++#      else
++#        ifndef LACKS_SYS_PARAM_H
++#          include <sys/param.h>
++#        endif
++#        ifdef EXEC_PAGESIZE
++#          define malloc_getpagesize EXEC_PAGESIZE
++#        else
++#          ifdef NBPG
++#            ifndef CLSIZE
++#              define malloc_getpagesize NBPG
++#            else
++#              define malloc_getpagesize (NBPG * CLSIZE)
++#            endif
++#          else
++#            ifdef NBPC
++#              define malloc_getpagesize NBPC
++#            else
++#              ifdef PAGESIZE
++#                define malloc_getpagesize PAGESIZE
++#              else /* just guess */
++#                define malloc_getpagesize ((size_t)4096U)
++#              endif
++#            endif
++#          endif
++#        endif
++#      endif
++#    endif
++#  endif
++#endif
++#endif
++
++/* ------------------- size_t and alignment properties -------------------- */
++
++/* The byte and bit size of a size_t */
++#define SIZE_T_SIZE         (sizeof(size_t))
++#define SIZE_T_BITSIZE      (sizeof(size_t) << 3)
++
++/* Some constants coerced to size_t */
++/* Annoying but necessary to avoid errors on some platforms */
++#define SIZE_T_ZERO         ((size_t)0)
++#define SIZE_T_ONE          ((size_t)1)
++#define SIZE_T_TWO          ((size_t)2)
++#define SIZE_T_FOUR         ((size_t)4)
++#define TWO_SIZE_T_SIZES    (SIZE_T_SIZE<<1)
++#define FOUR_SIZE_T_SIZES   (SIZE_T_SIZE<<2)
++#define SIX_SIZE_T_SIZES    (FOUR_SIZE_T_SIZES+TWO_SIZE_T_SIZES)
++#define HALF_MAX_SIZE_T     (MAX_SIZE_T / 2U)
++
++/* The bit mask value corresponding to MALLOC_ALIGNMENT */
++#define CHUNK_ALIGN_MASK    (MALLOC_ALIGNMENT - SIZE_T_ONE)
++
++/* True if address a has acceptable alignment */
++#define is_aligned(A)       (((size_t)((A)) & (CHUNK_ALIGN_MASK)) == 0)
++
++/* the number of bytes to offset an address to align it */
++#define align_offset(A)\
++ ((((size_t)(A) & CHUNK_ALIGN_MASK) == 0)? 0 :\
++  ((MALLOC_ALIGNMENT - ((size_t)(A) & CHUNK_ALIGN_MASK)) & CHUNK_ALIGN_MASK))
++
++/* -------------------------- MMAP preliminaries ------------------------- */
++
++/*
++   If HAVE_MORECORE or HAVE_MMAP are false, we just define calls and
++   checks to fail so compiler optimizer can delete code rather than
++   using so many "#if"s.
++*/
++
++
++/* MORECORE and MMAP must return MFAIL on failure */
++#define MFAIL                ((void*)(MAX_SIZE_T))
++#define CMFAIL               ((char*)(MFAIL)) /* defined for convenience */
++
++#if HAVE_MMAP
++
++#ifndef WIN32
++#define MUNMAP_DEFAULT(a, s)  munmap((a), (s))
++#define MMAP_PROT            (PROT_READ|PROT_WRITE)
++#if !defined(MAP_ANONYMOUS) && defined(MAP_ANON)
++#define MAP_ANONYMOUS        MAP_ANON
++#endif /* MAP_ANON */
++#ifdef MAP_ANONYMOUS
++#define MMAP_FLAGS           (MAP_PRIVATE|MAP_ANONYMOUS)
++#define MMAP_DEFAULT(s)       mmap(0, (s), MMAP_PROT, MMAP_FLAGS, -1, 0)
++#else /* MAP_ANONYMOUS */
++/*
++   Nearly all versions of mmap support MAP_ANONYMOUS, so the following
++   is unlikely to be needed, but is supplied just in case.
++*/
++#define MMAP_FLAGS           (MAP_PRIVATE)
++static int dev_zero_fd = -1; /* Cached file descriptor for /dev/zero. */
++#define MMAP_DEFAULT(s) ((dev_zero_fd < 0) ? \
++           (dev_zero_fd = open("/dev/zero", O_RDWR), \
++            mmap(0, (s), MMAP_PROT, MMAP_FLAGS, dev_zero_fd, 0)) : \
++            mmap(0, (s), MMAP_PROT, MMAP_FLAGS, dev_zero_fd, 0))
++#endif /* MAP_ANONYMOUS */
++
++#define DIRECT_MMAP_DEFAULT(s) MMAP_DEFAULT(s)
++
++#else /* WIN32 */
++
++/* Win32 MMAP via VirtualAlloc */
++static FORCEINLINE void* win32mmap(size_t size) {
++  void* ptr = VirtualAlloc(0, size, MEM_RESERVE|MEM_COMMIT, PAGE_READWRITE);
++  return (ptr != 0)? ptr: MFAIL;
++}
++
++/* For direct MMAP, use MEM_TOP_DOWN to minimize interference */
++static FORCEINLINE void* win32direct_mmap(size_t size) {
++  void* ptr = VirtualAlloc(0, size, MEM_RESERVE|MEM_COMMIT|MEM_TOP_DOWN,
++                           PAGE_READWRITE);
++  return (ptr != 0)? ptr: MFAIL;
++}
++
++/* This function supports releasing coalesed segments */
++static FORCEINLINE int win32munmap(void* ptr, size_t size) {
++  MEMORY_BASIC_INFORMATION minfo;
++  char* cptr = (char*)ptr;
++  while (size) {
++    if (VirtualQuery(cptr, &minfo, sizeof(minfo)) == 0)
++      return -1;
++    if (minfo.BaseAddress != cptr || minfo.AllocationBase != cptr ||
++        minfo.State != MEM_COMMIT || minfo.RegionSize > size)
++      return -1;
++    if (VirtualFree(cptr, 0, MEM_RELEASE) == 0)
++      return -1;
++    cptr += minfo.RegionSize;
++    size -= minfo.RegionSize;
++  }
++  return 0;
++}
++
++#define MMAP_DEFAULT(s)             win32mmap(s)
++#define MUNMAP_DEFAULT(a, s)        win32munmap((a), (s))
++#define DIRECT_MMAP_DEFAULT(s)      win32direct_mmap(s)
++#endif /* WIN32 */
++#endif /* HAVE_MMAP */
++
++#if HAVE_MREMAP
++#ifndef WIN32
++#define MREMAP_DEFAULT(addr, osz, nsz, mv) mremap((addr), (osz), (nsz), (mv))
++#endif /* WIN32 */
++#endif /* HAVE_MREMAP */
++
++/**
++ * Define CALL_MORECORE
++ */
++#if HAVE_MORECORE
++    #ifdef MORECORE
++        #define CALL_MORECORE(S)    MORECORE(S)
++    #else  /* MORECORE */
++        #define CALL_MORECORE(S)    MORECORE_DEFAULT(S)
++    #endif /* MORECORE */
++#else  /* HAVE_MORECORE */
++    #define CALL_MORECORE(S)        MFAIL
++#endif /* HAVE_MORECORE */
++
++/**
++ * Define CALL_MMAP/CALL_MUNMAP/CALL_DIRECT_MMAP
++ */
++#if HAVE_MMAP
++    #define USE_MMAP_BIT            (SIZE_T_ONE)
++
++    #ifdef MMAP
++        #define CALL_MMAP(s)        MMAP(s)
++    #else /* MMAP */
++        #define CALL_MMAP(s)        MMAP_DEFAULT(s)
++    #endif /* MMAP */
++    #ifdef MUNMAP
++        #define CALL_MUNMAP(a, s)   MUNMAP((a), (s))
++    #else /* MUNMAP */
++        #define CALL_MUNMAP(a, s)   MUNMAP_DEFAULT((a), (s))
++    #endif /* MUNMAP */
++    #ifdef DIRECT_MMAP
++        #define CALL_DIRECT_MMAP(s) DIRECT_MMAP(s)
++    #else /* DIRECT_MMAP */
++        #define CALL_DIRECT_MMAP(s) DIRECT_MMAP_DEFAULT(s)
++    #endif /* DIRECT_MMAP */
++#else  /* HAVE_MMAP */
++    #define USE_MMAP_BIT            (SIZE_T_ZERO)
++
++    #define MMAP(s)                 MFAIL
++    #define MUNMAP(a, s)            (-1)
++    #define DIRECT_MMAP(s)          MFAIL
++    #define CALL_DIRECT_MMAP(s)     DIRECT_MMAP(s)
++    #define CALL_MMAP(s)            MMAP(s)
++    #define CALL_MUNMAP(a, s)       MUNMAP((a), (s))
++#endif /* HAVE_MMAP */
++
++/**
++ * Define CALL_MREMAP
++ */
++#if HAVE_MMAP && HAVE_MREMAP
++    #ifdef MREMAP
++        #define CALL_MREMAP(addr, osz, nsz, mv) MREMAP((addr), (osz), (nsz), (mv))
++    #else /* MREMAP */
++        #define CALL_MREMAP(addr, osz, nsz, mv) MREMAP_DEFAULT((addr), (osz), (nsz), (mv))
++    #endif /* MREMAP */
++#else  /* HAVE_MMAP && HAVE_MREMAP */
++    #define CALL_MREMAP(addr, osz, nsz, mv)     MFAIL
++#endif /* HAVE_MMAP && HAVE_MREMAP */
++
++/* mstate bit set if continguous morecore disabled or failed */
++#define USE_NONCONTIGUOUS_BIT (4U)
++
++/* segment bit set in create_mspace_with_base */
++#define EXTERN_BIT            (8U)
++
++
++/* --------------------------- Lock preliminaries ------------------------ */
++
++/*
++  When locks are defined, there is one global lock, plus
++  one per-mspace lock.
++
++  The global lock_ensures that mparams.magic and other unique
++  mparams values are initialized only once. It also protects
++  sequences of calls to MORECORE.  In many cases sys_alloc requires
++  two calls, that should not be interleaved with calls by other
++  threads.  This does not protect against direct calls to MORECORE
++  by other threads not using this lock, so there is still code to
++  cope the best we can on interference.
++
++  Per-mspace locks surround calls to malloc, free, etc.
++  By default, locks are simple non-reentrant mutexes.
++
++  Because lock-protected regions generally have bounded times, it is
++  OK to use the supplied simple spinlocks. Spinlocks are likely to
++  improve performance for lightly contended applications, but worsen
++  performance under heavy contention.
++
++  If USE_LOCKS is > 1, the definitions of lock routines here are
++  bypassed, in which case you will need to define the type MLOCK_T,
++  and at least INITIAL_LOCK, DESTROY_LOCK, ACQUIRE_LOCK, RELEASE_LOCK
++  and TRY_LOCK.  You must also declare a
++    static MLOCK_T malloc_global_mutex = { initialization values };.
++
++*/
++
++#if !USE_LOCKS
++#define USE_LOCK_BIT               (0U)
++#define INITIAL_LOCK(l)            (0)
++#define DESTROY_LOCK(l)            (0)
++#define ACQUIRE_MALLOC_GLOBAL_LOCK()
++#define RELEASE_MALLOC_GLOBAL_LOCK()
++
++#else
++#if USE_LOCKS > 1
++/* -----------------------  User-defined locks ------------------------ */
++/* Define your own lock implementation here */
++/* #define INITIAL_LOCK(lk)  ... */
++/* #define DESTROY_LOCK(lk)  ... */
++/* #define ACQUIRE_LOCK(lk)  ... */
++/* #define RELEASE_LOCK(lk)  ... */
++/* #define TRY_LOCK(lk) ... */
++/* static MLOCK_T malloc_global_mutex = ... */
++
++#elif USE_SPIN_LOCKS
++
++/* First, define CAS_LOCK and CLEAR_LOCK on ints */
++/* Note CAS_LOCK defined to return 0 on success */
++
++#if defined(__GNUC__)&& (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 1))
++#define CAS_LOCK(sl)     __sync_lock_test_and_set(sl, 1)
++#define CLEAR_LOCK(sl)   __sync_lock_release(sl)
++
++#elif (defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__)))
++/* Custom spin locks for older gcc on x86 */
++static FORCEINLINE int x86_cas_lock(int *sl) {
++  int ret;
++  int val = 1;
++  int cmp = 0;
++  __asm__ __volatile__  ("lock; cmpxchgl %1, %2"
++                         : "=a" (ret)
++                         : "r" (val), "m" (*(sl)), "0"(cmp)
++                         : "memory", "cc");
++  return ret;
++}
++
++static FORCEINLINE void x86_clear_lock(int* sl) {
++  assert(*sl != 0);
++  int prev = 0;
++  int ret;
++  __asm__ __volatile__ ("lock; xchgl %0, %1"
++                        : "=r" (ret)
++                        : "m" (*(sl)), "0"(prev)
++                        : "memory");
++}
++
++#define CAS_LOCK(sl)     x86_cas_lock(sl)
++#define CLEAR_LOCK(sl)   x86_clear_lock(sl)
++
++#else /* Win32 MSC */
++#define CAS_LOCK(sl)     interlockedexchange(sl, (LONG)1)
++#define CLEAR_LOCK(sl)   interlockedexchange (sl, (LONG)0)
++
++#endif /* ... gcc spins locks ... */
++
++/* How to yield for a spin lock */
++#define SPINS_PER_YIELD       63
++#if defined(_MSC_VER)
++#define SLEEP_EX_DURATION     50 /* delay for yield/sleep */
++#define SPIN_LOCK_YIELD  SleepEx(SLEEP_EX_DURATION, FALSE)
++#elif defined (__SVR4) && defined (__sun) /* solaris */
++#define SPIN_LOCK_YIELD   thr_yield();
++#elif !defined(LACKS_SCHED_H)
++#define SPIN_LOCK_YIELD   sched_yield();
++#else
++#define SPIN_LOCK_YIELD
++#endif /* ... yield ... */
++
++#if !defined(USE_RECURSIVE_LOCKS) || USE_RECURSIVE_LOCKS == 0
++/* Plain spin locks use single word (embedded in malloc_states) */
++static int spin_acquire_lock(int *sl) {
++  int spins = 0;
++  while (*(volatile int *)sl != 0 || CAS_LOCK(sl)) {
++    if ((++spins & SPINS_PER_YIELD) == 0) {
++      SPIN_LOCK_YIELD;
++    }
++  }
++  return 0;
++}
++
++#define MLOCK_T               int
++#define TRY_LOCK(sl)          !CAS_LOCK(sl)
++#define RELEASE_LOCK(sl)      CLEAR_LOCK(sl)
++#define ACQUIRE_LOCK(sl)      (CAS_LOCK(sl)? spin_acquire_lock(sl) : 0)
++#define INITIAL_LOCK(sl)      (*sl = 0)
++#define DESTROY_LOCK(sl)      (0)
++static MLOCK_T malloc_global_mutex = 0;
++
++#else /* USE_RECURSIVE_LOCKS */
++/* types for lock owners */
++#ifdef WIN32
++#define THREAD_ID_T           DWORD
++#define CURRENT_THREAD        GetCurrentThreadId()
++#define EQ_OWNER(X,Y)         ((X) == (Y))
++#else
++/*
++  Note: the following assume that pthread_t is a type that can be
++  initialized to (casted) zero. If this is not the case, you will need to
++  somehow redefine these or not use spin locks.
++*/
++#define THREAD_ID_T           pthread_t
++#define CURRENT_THREAD        pthread_self()
++#define EQ_OWNER(X,Y)         pthread_equal(X, Y)
++#endif
++
++struct malloc_recursive_lock {
++  int sl;
++  unsigned int c;
++  THREAD_ID_T threadid;
++};
++
++#define MLOCK_T  struct malloc_recursive_lock
++static MLOCK_T malloc_global_mutex = { 0, 0, (THREAD_ID_T)0};
++
++static FORCEINLINE void recursive_release_lock(MLOCK_T *lk) {
++  assert(lk->sl != 0);
++  if (--lk->c == 0) {
++    CLEAR_LOCK(&lk->sl);
++  }
++}
++
++static FORCEINLINE int recursive_acquire_lock(MLOCK_T *lk) {
++  THREAD_ID_T mythreadid = CURRENT_THREAD;
++  int spins = 0;
++  for (;;) {
++    if (*((volatile int *)(&lk->sl)) == 0) {
++      if (!CAS_LOCK(&lk->sl)) {
++        lk->threadid = mythreadid;
++        lk->c = 1;
++        return 0;
++      }
++    }
++    else if (EQ_OWNER(lk->threadid, mythreadid)) {
++      ++lk->c;
++      return 0;
++    }
++    if ((++spins & SPINS_PER_YIELD) == 0) {
++      SPIN_LOCK_YIELD;
++    }
++  }
++}
++
++static FORCEINLINE int recursive_try_lock(MLOCK_T *lk) {
++  THREAD_ID_T mythreadid = CURRENT_THREAD;
++  if (*((volatile int *)(&lk->sl)) == 0) {
++    if (!CAS_LOCK(&lk->sl)) {
++      lk->threadid = mythreadid;
++      lk->c = 1;
++      return 1;
++    }
++  }
++  else if (EQ_OWNER(lk->threadid, mythreadid)) {
++    ++lk->c;
++    return 1;
++  }
++  return 0;
++}
++
++#define RELEASE_LOCK(lk)      recursive_release_lock(lk)
++#define TRY_LOCK(lk)          recursive_try_lock(lk)
++#define ACQUIRE_LOCK(lk)      recursive_acquire_lock(lk)
++#define INITIAL_LOCK(lk)      ((lk)->threadid = (THREAD_ID_T)0, (lk)->sl = 0, (lk)->c = 0)
++#define DESTROY_LOCK(lk)      (0)
++#endif /* USE_RECURSIVE_LOCKS */
++
++#elif defined(WIN32) /* Win32 critical sections */
++#define MLOCK_T               CRITICAL_SECTION
++#define ACQUIRE_LOCK(lk)      (EnterCriticalSection(lk), 0)
++#define RELEASE_LOCK(lk)      LeaveCriticalSection(lk)
++#define TRY_LOCK(lk)          TryEnterCriticalSection(lk)
++#define INITIAL_LOCK(lk)      (!InitializeCriticalSectionAndSpinCount((lk), 0x80000000|4000))
++#define DESTROY_LOCK(lk)      (DeleteCriticalSection(lk), 0)
++#define NEED_GLOBAL_LOCK_INIT
++
++static MLOCK_T malloc_global_mutex;
++static volatile LONG malloc_global_mutex_status;
++
++/* Use spin loop to initialize global lock */
++static void init_malloc_global_mutex() {
++  for (;;) {
++    long stat = malloc_global_mutex_status;
++    if (stat > 0)
++      return;
++    /* transition to < 0 while initializing, then to > 0) */
++    if (stat == 0 &&
++        interlockedcompareexchange(&malloc_global_mutex_status, (LONG)-1, (LONG)0) == 0) {
++      InitializeCriticalSection(&malloc_global_mutex);
++      interlockedexchange(&malloc_global_mutex_status, (LONG)1);
++      return;
++    }
++    SleepEx(0, FALSE);
++  }
++}
++
++#else /* pthreads-based locks */
++#define MLOCK_T               pthread_mutex_t
++#define ACQUIRE_LOCK(lk)      pthread_mutex_lock(lk)
++#define RELEASE_LOCK(lk)      pthread_mutex_unlock(lk)
++#define TRY_LOCK(lk)          (!pthread_mutex_trylock(lk))
++#define INITIAL_LOCK(lk)      pthread_init_lock(lk)
++#define DESTROY_LOCK(lk)      pthread_mutex_destroy(lk)
++
++#if defined(USE_RECURSIVE_LOCKS) && USE_RECURSIVE_LOCKS != 0 && defined(linux) && !defined(PTHREAD_MUTEX_RECURSIVE)
++/* Cope with old-style linux recursive lock initialization by adding */
++/* skipped internal declaration from pthread.h */
++extern int pthread_mutexattr_setkind_np __P ((pthread_mutexattr_t *__attr,
++                                              int __kind));
++#define PTHREAD_MUTEX_RECURSIVE PTHREAD_MUTEX_RECURSIVE_NP
++#define pthread_mutexattr_settype(x,y) pthread_mutexattr_setkind_np(x,y)
++#endif /* USE_RECURSIVE_LOCKS ... */
++
++static MLOCK_T malloc_global_mutex = PTHREAD_MUTEX_INITIALIZER;
++
++static int pthread_init_lock (MLOCK_T *lk) {
++  pthread_mutexattr_t attr;
++  if (pthread_mutexattr_init(&attr)) return 1;
++#if defined(USE_RECURSIVE_LOCKS) && USE_RECURSIVE_LOCKS != 0
++  if (pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE)) return 1;
++#endif
++  if (pthread_mutex_init(lk, &attr)) return 1;
++  if (pthread_mutexattr_destroy(&attr)) return 1;
++  return 0;
++}
++
++#endif /* ... lock types ... */
++
++/* Common code for all lock types */
++#define USE_LOCK_BIT               (2U)
++
++#ifndef ACQUIRE_MALLOC_GLOBAL_LOCK
++#define ACQUIRE_MALLOC_GLOBAL_LOCK()  ACQUIRE_LOCK(&malloc_global_mutex);
++#endif
++
++#ifndef RELEASE_MALLOC_GLOBAL_LOCK
++#define RELEASE_MALLOC_GLOBAL_LOCK()  RELEASE_LOCK(&malloc_global_mutex);
++#endif
++
++#endif /* USE_LOCKS */
++
++/* -----------------------  Chunk representations ------------------------ */
++
++/*
++  (The following includes lightly edited explanations by Colin Plumb.)
++
++  The malloc_chunk declaration below is misleading (but accurate and
++  necessary).  It declares a "view" into memory allowing access to
++  necessary fields at known offsets from a given base.
++
++  Chunks of memory are maintained using a `boundary tag' method as
++  originally described by Knuth.  (See the paper by Paul Wilson
++  ftp://ftp.cs.utexas.edu/pub/garbage/allocsrv.ps for a survey of such
++  techniques.)  Sizes of free chunks are stored both in the front of
++  each chunk and at the end.  This makes consolidating fragmented
++  chunks into bigger chunks fast.  The head fields also hold bits
++  representing whether chunks are free or in use.
++
++  Here are some pictures to make it clearer.  They are "exploded" to
++  show that the state of a chunk can be thought of as extending from
++  the high 31 bits of the head field of its header through the
++  prev_foot and PINUSE_BIT bit of the following chunk header.
++
++  A chunk that's in use looks like:
++
++   chunk-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
++           | Size of previous chunk (if P = 0)                             |
++           +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
++         +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |P|
++         | Size of this chunk                                         1| +-+
++   mem-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
++         |                                                               |
++         +-                                                             -+
++         |                                                               |
++         +-                                                             -+
++         |                                                               :
++         +-      size - sizeof(size_t) available payload bytes          -+
++         :                                                               |
++ chunk-> +-                                                             -+
++         |                                                               |
++         +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
++       +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |1|
++       | Size of next chunk (may or may not be in use)               | +-+
++ mem-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
++
++    And if it's free, it looks like this:
++
++   chunk-> +-                                                             -+
++           | User payload (must be in use, or we would have merged!)       |
++           +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
++         +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |P|
++         | Size of this chunk                                         0| +-+
++   mem-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
++         | Next pointer                                                  |
++         +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
++         | Prev pointer                                                  |
++         +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
++         |                                                               :
++         +-      size - sizeof(struct chunk) unused bytes               -+
++         :                                                               |
++ chunk-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
++         | Size of this chunk                                            |
++         +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
++       +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |0|
++       | Size of next chunk (must be in use, or we would have merged)| +-+
++ mem-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
++       |                                                               :
++       +- User payload                                                -+
++       :                                                               |
++       +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
++                                                                     |0|
++                                                                     +-+
++  Note that since we always merge adjacent free chunks, the chunks
++  adjacent to a free chunk must be in use.
++
++  Given a pointer to a chunk (which can be derived trivially from the
++  payload pointer) we can, in O(1) time, find out whether the adjacent
++  chunks are free, and if so, unlink them from the lists that they
++  are on and merge them with the current chunk.
++
++  Chunks always begin on even word boundaries, so the mem portion
++  (which is returned to the user) is also on an even word boundary, and
++  thus at least double-word aligned.
++
++  The P (PINUSE_BIT) bit, stored in the unused low-order bit of the
++  chunk size (which is always a multiple of two words), is an in-use
++  bit for the *previous* chunk.  If that bit is *clear*, then the
++  word before the current chunk size contains the previous chunk
++  size, and can be used to find the front of the previous chunk.
++  The very first chunk allocated always has this bit set, preventing
++  access to non-existent (or non-owned) memory. If pinuse is set for
++  any given chunk, then you CANNOT determine the size of the
++  previous chunk, and might even get a memory addressing fault when
++  trying to do so.
++
++  The C (CINUSE_BIT) bit, stored in the unused second-lowest bit of
++  the chunk size redundantly records whether the current chunk is
++  inuse (unless the chunk is mmapped). This redundancy enables usage
++  checks within free and realloc, and reduces indirection when freeing
++  and consolidating chunks.
++
++  Each freshly allocated chunk must have both cinuse and pinuse set.
++  That is, each allocated chunk borders either a previously allocated
++  and still in-use chunk, or the base of its memory arena. This is
++  ensured by making all allocations from the `lowest' part of any
++  found chunk.  Further, no free chunk physically borders another one,
++  so each free chunk is known to be preceded and followed by either
++  inuse chunks or the ends of memory.
++
++  Note that the `foot' of the current chunk is actually represented
++  as the prev_foot of the NEXT chunk. This makes it easier to
++  deal with alignments etc but can be very confusing when trying
++  to extend or adapt this code.
++
++  The exceptions to all this are
++
++     1. The special chunk `top' is the top-most available chunk (i.e.,
++        the one bordering the end of available memory). It is treated
++        specially.  Top is never included in any bin, is used only if
++        no other chunk is available, and is released back to the
++        system if it is very large (see M_TRIM_THRESHOLD).  In effect,
++        the top chunk is treated as larger (and thus less well
++        fitting) than any other available chunk.  The top chunk
++        doesn't update its trailing size field since there is no next
++        contiguous chunk that would have to index off it. However,
++        space is still allocated for it (TOP_FOOT_SIZE) to enable
++        separation or merging when space is extended.
++
++     3. Chunks allocated via mmap, have both cinuse and pinuse bits
++        cleared in their head fields.  Because they are allocated
++        one-by-one, each must carry its own prev_foot field, which is
++        also used to hold the offset this chunk has within its mmapped
++        region, which is needed to preserve alignment. Each mmapped
++        chunk is trailed by the first two fields of a fake next-chunk
++        for sake of usage checks.
++
++*/
++
++struct malloc_chunk {
++  size_t               prev_foot;  /* Size of previous chunk (if free).  */
++  size_t               head;       /* Size and inuse bits. */
++  struct malloc_chunk* fd;         /* double links -- used only if free. */
++  struct malloc_chunk* bk;
++};
++
++typedef struct malloc_chunk  mchunk;
++typedef struct malloc_chunk* mchunkptr;
++typedef struct malloc_chunk* sbinptr;  /* The type of bins of chunks */
++typedef unsigned int bindex_t;         /* Described below */
++typedef unsigned int binmap_t;         /* Described below */
++typedef unsigned int flag_t;           /* The type of various bit flag sets */
++
++/* ------------------- Chunks sizes and alignments ----------------------- */
++
++#define MCHUNK_SIZE         (sizeof(mchunk))
++
++#if FOOTERS
++#define CHUNK_OVERHEAD      (TWO_SIZE_T_SIZES)
++#else /* FOOTERS */
++#define CHUNK_OVERHEAD      (SIZE_T_SIZE)
++#endif /* FOOTERS */
++
++/* MMapped chunks need a second word of overhead ... */
++#define MMAP_CHUNK_OVERHEAD (TWO_SIZE_T_SIZES)
++/* ... and additional padding for fake next-chunk at foot */
++#define MMAP_FOOT_PAD       (FOUR_SIZE_T_SIZES)
++
++/* The smallest size we can malloc is an aligned minimal chunk */
++#define MIN_CHUNK_SIZE\
++  ((MCHUNK_SIZE + CHUNK_ALIGN_MASK) & ~CHUNK_ALIGN_MASK)
++
++/* conversion from malloc headers to user pointers, and back */
++#define chunk2mem(p)        ((void*)((char*)(p)       + TWO_SIZE_T_SIZES))
++#define mem2chunk(mem)      ((mchunkptr)((char*)(mem) - TWO_SIZE_T_SIZES))
++/* chunk associated with aligned address A */
++#define align_as_chunk(A)   (mchunkptr)((A) + align_offset(chunk2mem(A)))
++
++/* Bounds on request (not chunk) sizes. */
++#define MAX_REQUEST         ((-MIN_CHUNK_SIZE) << 2)
++#define MIN_REQUEST         (MIN_CHUNK_SIZE - CHUNK_OVERHEAD - SIZE_T_ONE)
++
++/* pad request bytes into a usable size */
++#define pad_request(req) \
++   (((req) + CHUNK_OVERHEAD + CHUNK_ALIGN_MASK) & ~CHUNK_ALIGN_MASK)
++
++/* pad request, checking for minimum (but not maximum) */
++#define request2size(req) \
++  (((req) < MIN_REQUEST)? MIN_CHUNK_SIZE : pad_request(req))
++
++
++/* ------------------ Operations on head and foot fields ----------------- */
++
++/*
++  The head field of a chunk is or'ed with PINUSE_BIT when previous
++  adjacent chunk in use, and or'ed with CINUSE_BIT if this chunk is in
++  use, unless mmapped, in which case both bits are cleared.
++
++  FLAG4_BIT is not used by this malloc, but might be useful in extensions.
++*/
++
++#define PINUSE_BIT          (SIZE_T_ONE)
++#define CINUSE_BIT          (SIZE_T_TWO)
++#define FLAG4_BIT           (SIZE_T_FOUR)
++#define INUSE_BITS          (PINUSE_BIT|CINUSE_BIT)
++#define FLAG_BITS           (PINUSE_BIT|CINUSE_BIT|FLAG4_BIT)
++
++/* Head value for fenceposts */
++#define FENCEPOST_HEAD      (INUSE_BITS|SIZE_T_SIZE)
++
++/* extraction of fields from head words */
++#define cinuse(p)           ((p)->head & CINUSE_BIT)
++#define pinuse(p)           ((p)->head & PINUSE_BIT)
++#define flag4inuse(p)       ((p)->head & FLAG4_BIT)
++#define is_inuse(p)         (((p)->head & INUSE_BITS) != PINUSE_BIT)
++#define is_mmapped(p)       (((p)->head & INUSE_BITS) == 0)
++
++#define chunksize(p)        ((p)->head & ~(FLAG_BITS))
++
++#define clear_pinuse(p)     ((p)->head &= ~PINUSE_BIT)
++#define set_flag4(p)        ((p)->head |= FLAG4_BIT)
++#define clear_flag4(p)      ((p)->head &= ~FLAG4_BIT)
++
++/* Treat space at ptr +/- offset as a chunk */
++#define chunk_plus_offset(p, s)  ((mchunkptr)(((char*)(p)) + (s)))
++#define chunk_minus_offset(p, s) ((mchunkptr)(((char*)(p)) - (s)))
++
++/* Ptr to next or previous physical malloc_chunk. */
++#define next_chunk(p) ((mchunkptr)( ((char*)(p)) + ((p)->head & ~FLAG_BITS)))
++#define prev_chunk(p) ((mchunkptr)( ((char*)(p)) - ((p)->prev_foot) ))
++
++/* extract next chunk's pinuse bit */
++#define next_pinuse(p)  ((next_chunk(p)->head) & PINUSE_BIT)
++
++/* Get/set size at footer */
++#define get_foot(p, s)  (((mchunkptr)((char*)(p) + (s)))->prev_foot)
++#define set_foot(p, s)  (((mchunkptr)((char*)(p) + (s)))->prev_foot = (s))
++
++/* Set size, pinuse bit, and foot */
++#define set_size_and_pinuse_of_free_chunk(p, s)\
++  ((p)->head = (s|PINUSE_BIT), set_foot(p, s))
++
++/* Set size, pinuse bit, foot, and clear next pinuse */
++#define set_free_with_pinuse(p, s, n)\
++  (clear_pinuse(n), set_size_and_pinuse_of_free_chunk(p, s))
++
++/* Get the internal overhead associated with chunk p */
++#define overhead_for(p)\
++ (is_mmapped(p)? MMAP_CHUNK_OVERHEAD : CHUNK_OVERHEAD)
++
++/* Return true if malloced space is not necessarily cleared */
++#if MMAP_CLEARS
++#define calloc_must_clear(p) (!is_mmapped(p))
++#else /* MMAP_CLEARS */
++#define calloc_must_clear(p) (1)
++#endif /* MMAP_CLEARS */
++
++/* ---------------------- Overlaid data structures ----------------------- */
++
++/*
++  When chunks are not in use, they are treated as nodes of either
++  lists or trees.
++
++  "Small"  chunks are stored in circular doubly-linked lists, and look
++  like this:
++
++    chunk-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
++            |             Size of previous chunk                            |
++            +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
++    `head:' |             Size of chunk, in bytes                         |P|
++      mem-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
++            |             Forward pointer to next chunk in list             |
++            +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
++            |             Back pointer to previous chunk in list            |
++            +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
++            |             Unused space (may be 0 bytes long)                .
++            .                                                               .
++            .                                                               |
++nextchunk-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
++    `foot:' |             Size of chunk, in bytes                           |
++            +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
++
++  Larger chunks are kept in a form of bitwise digital trees (aka
++  tries) keyed on chunksizes.  Because malloc_tree_chunks are only for
++  free chunks greater than 256 bytes, their size doesn't impose any
++  constraints on user chunk sizes.  Each node looks like:
++
++    chunk-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
++            |             Size of previous chunk                            |
++            +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
++    `head:' |             Size of chunk, in bytes                         |P|
++      mem-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
++            |             Forward pointer to next chunk of same size        |
++            +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
++            |             Back pointer to previous chunk of same size       |
++            +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
++            |             Pointer to left child (child[0])                  |
++            +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
++            |             Pointer to right child (child[1])                 |
++            +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
++            |             Pointer to parent                                 |
++            +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
++            |             bin index of this chunk                           |
++            +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
++            |             Unused space                                      .
++            .                                                               |
++nextchunk-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
++    `foot:' |             Size of chunk, in bytes                           |
++            +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
++
++  Each tree holding treenodes is a tree of unique chunk sizes.  Chunks
++  of the same size are arranged in a circularly-linked list, with only
++  the oldest chunk (the next to be used, in our FIFO ordering)
++  actually in the tree.  (Tree members are distinguished by a non-null
++  parent pointer.)  If a chunk with the same size an an existing node
++  is inserted, it is linked off the existing node using pointers that
++  work in the same way as fd/bk pointers of small chunks.
++
++  Each tree contains a power of 2 sized range of chunk sizes (the
++  smallest is 0x100 <= x < 0x180), which is is divided in half at each
++  tree level, with the chunks in the smaller half of the range (0x100
++  <= x < 0x140 for the top nose) in the left subtree and the larger
++  half (0x140 <= x < 0x180) in the right subtree.  This is, of course,
++  done by inspecting individual bits.
++
++  Using these rules, each node's left subtree contains all smaller
++  sizes than its right subtree.  However, the node at the root of each
++  subtree has no particular ordering relationship to either.  (The
++  dividing line between the subtree sizes is based on trie relation.)
++  If we remove the last chunk of a given size from the interior of the
++  tree, we need to replace it with a leaf node.  The tree ordering
++  rules permit a node to be replaced by any leaf below it.
++
++  The smallest chunk in a tree (a common operation in a best-fit
++  allocator) can be found by walking a path to the leftmost leaf in
++  the tree.  Unlike a usual binary tree, where we follow left child
++  pointers until we reach a null, here we follow the right child
++  pointer any time the left one is null, until we reach a leaf with
++  both child pointers null. The smallest chunk in the tree will be
++  somewhere along that path.
++
++  The worst case number of steps to add, find, or remove a node is
++  bounded by the number of bits differentiating chunks within
++  bins. Under current bin calculations, this ranges from 6 up to 21
++  (for 32 bit sizes) or up to 53 (for 64 bit sizes). The typical case
++  is of course much better.
++*/
++
++struct malloc_tree_chunk {
++  /* The first four fields must be compatible with malloc_chunk */
++  size_t                    prev_foot;
++  size_t                    head;
++  struct malloc_tree_chunk* fd;
++  struct malloc_tree_chunk* bk;
++
++  struct malloc_tree_chunk* child[2];
++  struct malloc_tree_chunk* parent;
++  bindex_t                  index;
++};
++
++typedef struct malloc_tree_chunk  tchunk;
++typedef struct malloc_tree_chunk* tchunkptr;
++typedef struct malloc_tree_chunk* tbinptr; /* The type of bins of trees */
++
++/* A little helper macro for trees */
++#define leftmost_child(t) ((t)->child[0] != 0? (t)->child[0] : (t)->child[1])
++
++/* ----------------------------- Segments -------------------------------- */
++
++/*
++  Each malloc space may include non-contiguous segments, held in a
++  list headed by an embedded malloc_segment record representing the
++  top-most space. Segments also include flags holding properties of
++  the space. Large chunks that are directly allocated by mmap are not
++  included in this list. They are instead independently created and
++  destroyed without otherwise keeping track of them.
++
++  Segment management mainly comes into play for spaces allocated by
++  MMAP.  Any call to MMAP might or might not return memory that is
++  adjacent to an existing segment.  MORECORE normally contiguously
++  extends the current space, so this space is almost always adjacent,
++  which is simpler and faster to deal with. (This is why MORECORE is
++  used preferentially to MMAP when both are available -- see
++  sys_alloc.)  When allocating using MMAP, we don't use any of the
++  hinting mechanisms (inconsistently) supported in various
++  implementations of unix mmap, or distinguish reserving from
++  committing memory. Instead, we just ask for space, and exploit
++  contiguity when we get it.  It is probably possible to do
++  better than this on some systems, but no general scheme seems
++  to be significantly better.
++
++  Management entails a simpler variant of the consolidation scheme
++  used for chunks to reduce fragmentation -- new adjacent memory is
++  normally prepended or appended to an existing segment. However,
++  there are limitations compared to chunk consolidation that mostly
++  reflect the fact that segment processing is relatively infrequent
++  (occurring only when getting memory from system) and that we
++  don't expect to have huge numbers of segments:
++
++  * Segments are not indexed, so traversal requires linear scans.  (It
++    would be possible to index these, but is not worth the extra
++    overhead and complexity for most programs on most platforms.)
++  * New segments are only appended to old ones when holding top-most
++    memory; if they cannot be prepended to others, they are held in
++    different segments.
++
++  Except for the top-most segment of an mstate, each segment record
++  is kept at the tail of its segment. Segments are added by pushing
++  segment records onto the list headed by &mstate.seg for the
++  containing mstate.
++
++  Segment flags control allocation/merge/deallocation policies:
++  * If EXTERN_BIT set, then we did not allocate this segment,
++    and so should not try to deallocate or merge with others.
++    (This currently holds only for the initial segment passed
++    into create_mspace_with_base.)
++  * If USE_MMAP_BIT set, the segment may be merged with
++    other surrounding mmapped segments and trimmed/de-allocated
++    using munmap.
++  * If neither bit is set, then the segment was obtained using
++    MORECORE so can be merged with surrounding MORECORE'd segments
++    and deallocated/trimmed using MORECORE with negative arguments.
++*/
++
++struct malloc_segment {
++  char*        base;             /* base address */
++  size_t       size;             /* allocated size */
++  struct malloc_segment* next;   /* ptr to next segment */
++  flag_t       sflags;           /* mmap and extern flag */
++};
++
++#define is_mmapped_segment(S)  ((S)->sflags & USE_MMAP_BIT)
++#define is_extern_segment(S)   ((S)->sflags & EXTERN_BIT)
++
++typedef struct malloc_segment  msegment;
++typedef struct malloc_segment* msegmentptr;
++
++/* ---------------------------- malloc_state ----------------------------- */
++
++/*
++   A malloc_state holds all of the bookkeeping for a space.
++   The main fields are:
++
++  Top
++    The topmost chunk of the currently active segment. Its size is
++    cached in topsize.  The actual size of topmost space is
++    topsize+TOP_FOOT_SIZE, which includes space reserved for adding
++    fenceposts and segment records if necessary when getting more
++    space from the system.  The size at which to autotrim top is
++    cached from mparams in trim_check, except that it is disabled if
++    an autotrim fails.
++
++  Designated victim (dv)
++    This is the preferred chunk for servicing small requests that
++    don't have exact fits.  It is normally the chunk split off most
++    recently to service another small request.  Its size is cached in
++    dvsize. The link fields of this chunk are not maintained since it
++    is not kept in a bin.
++
++  SmallBins
++    An array of bin headers for free chunks.  These bins hold chunks
++    with sizes less than MIN_LARGE_SIZE bytes. Each bin contains
++    chunks of all the same size, spaced 8 bytes apart.  To simplify
++    use in double-linked lists, each bin header acts as a malloc_chunk
++    pointing to the real first node, if it exists (else pointing to
++    itself).  This avoids special-casing for headers.  But to avoid
++    waste, we allocate only the fd/bk pointers of bins, and then use
++    repositioning tricks to treat these as the fields of a chunk.
++
++  TreeBins
++    Treebins are pointers to the roots of trees holding a range of
++    sizes. There are 2 equally spaced treebins for each power of two
++    from TREE_SHIFT to TREE_SHIFT+16. The last bin holds anything
++    larger.
++
++  Bin maps
++    There is one bit map for small bins ("smallmap") and one for
++    treebins ("treemap).  Each bin sets its bit when non-empty, and
++    clears the bit when empty.  Bit operations are then used to avoid
++    bin-by-bin searching -- nearly all "search" is done without ever
++    looking at bins that won't be selected.  The bit maps
++    conservatively use 32 bits per map word, even if on 64bit system.
++    For a good description of some of the bit-based techniques used
++    here, see Henry S. Warren Jr's book "Hacker's Delight" (and
++    supplement at http://hackersdelight.org/). Many of these are
++    intended to reduce the branchiness of paths through malloc etc, as
++    well as to reduce the number of memory locations read or written.
++
++  Segments
++    A list of segments headed by an embedded malloc_segment record
++    representing the initial space.
++
++  Address check support
++    The least_addr field is the least address ever obtained from
++    MORECORE or MMAP. Attempted frees and reallocs of any address less
++    than this are trapped (unless INSECURE is defined).
++
++  Magic tag
++    A cross-check field that should always hold same value as mparams.magic.
++
++  Max allowed footprint
++    The maximum allowed bytes to allocate from system (zero means no limit)
++
++  Flags
++    Bits recording whether to use MMAP, locks, or contiguous MORECORE
++
++  Statistics
++    Each space keeps track of current and maximum system memory
++    obtained via MORECORE or MMAP.
++
++  Trim support
++    Fields holding the amount of unused topmost memory that should trigger
++    trimming, and a counter to force periodic scanning to release unused
++    non-topmost segments.
++
++  Locking
++    If USE_LOCKS is defined, the "mutex" lock is acquired and released
++    around every public call using this mspace.
++
++  Extension support
++    A void* pointer and a size_t field that can be used to help implement
++    extensions to this malloc.
++*/
++
++/* Bin types, widths and sizes */
++#define NSMALLBINS        (32U)
++#define NTREEBINS         (32U)
++#define SMALLBIN_SHIFT    (3U)
++#define SMALLBIN_WIDTH    (SIZE_T_ONE << SMALLBIN_SHIFT)
++#define TREEBIN_SHIFT     (8U)
++#define MIN_LARGE_SIZE    (SIZE_T_ONE << TREEBIN_SHIFT)
++#define MAX_SMALL_SIZE    (MIN_LARGE_SIZE - SIZE_T_ONE)
++#define MAX_SMALL_REQUEST (MAX_SMALL_SIZE - CHUNK_ALIGN_MASK - CHUNK_OVERHEAD)
++
++struct malloc_state {
++  binmap_t   smallmap;
++  binmap_t   treemap;
++  size_t     dvsize;
++  size_t     topsize;
++  char*      least_addr;
++  mchunkptr  dv;
++  mchunkptr  top;
++  size_t     trim_check;
++  size_t     release_checks;
++  size_t     magic;
++  mchunkptr  smallbins[(NSMALLBINS+1)*2];
++  tbinptr    treebins[NTREEBINS];
++  size_t     footprint;
++  size_t     max_footprint;
++  size_t     footprint_limit; /* zero means no limit */
++  flag_t     mflags;
++#if USE_LOCKS
++  MLOCK_T    mutex;     /* locate lock among fields that rarely change */
++#endif /* USE_LOCKS */
++  msegment   seg;
++  void*      extp;      /* Unused but available for extensions */
++  size_t     exts;
++};
++
++typedef struct malloc_state*    mstate;
++
++/* ------------- Global malloc_state and malloc_params ------------------- */
++
++/*
++  malloc_params holds global properties, including those that can be
++  dynamically set using mallopt. There is a single instance, mparams,
++  initialized in init_mparams. Note that the non-zeroness of "magic"
++  also serves as an initialization flag.
++*/
++
++struct malloc_params {
++  size_t magic;
++  size_t page_size;
++  size_t granularity;
++  size_t mmap_threshold;
++  size_t trim_threshold;
++  flag_t default_mflags;
++};
++
++static struct malloc_params mparams;
++
++/* Ensure mparams initialized */
++#define ensure_initialization() (void)(mparams.magic != 0 || init_mparams())
++
++#if !ONLY_MSPACES
++
++/* The global malloc_state used for all non-"mspace" calls */
++static struct malloc_state _gm_;
++#define gm                 (&_gm_)
++#define is_global(M)       ((M) == &_gm_)
++
++#endif /* !ONLY_MSPACES */
++
++#define is_initialized(M)  ((M)->top != 0)
++
++/* -------------------------- system alloc setup ------------------------- */
++
++/* Operations on mflags */
++
++#define use_lock(M)           ((M)->mflags &   USE_LOCK_BIT)
++#define enable_lock(M)        ((M)->mflags |=  USE_LOCK_BIT)
++#if USE_LOCKS
++#define disable_lock(M)       ((M)->mflags &= ~USE_LOCK_BIT)
++#else
++#define disable_lock(M)
++#endif
++
++#define use_mmap(M)           ((M)->mflags &   USE_MMAP_BIT)
++#define enable_mmap(M)        ((M)->mflags |=  USE_MMAP_BIT)
++#if HAVE_MMAP
++#define disable_mmap(M)       ((M)->mflags &= ~USE_MMAP_BIT)
++#else
++#define disable_mmap(M)
++#endif
++
++#define use_noncontiguous(M)  ((M)->mflags &   USE_NONCONTIGUOUS_BIT)
++#define disable_contiguous(M) ((M)->mflags |=  USE_NONCONTIGUOUS_BIT)
++
++#define set_lock(M,L)\
++ ((M)->mflags = (L)?\
++  ((M)->mflags | USE_LOCK_BIT) :\
++  ((M)->mflags & ~USE_LOCK_BIT))
++
++/* page-align a size */
++#define page_align(S)\
++ (((S) + (mparams.page_size - SIZE_T_ONE)) & ~(mparams.page_size - SIZE_T_ONE))
++
++/* granularity-align a size */
++#define granularity_align(S)\
++  (((S) + (mparams.granularity - SIZE_T_ONE))\
++   & ~(mparams.granularity - SIZE_T_ONE))
++
++
++/* For mmap, use granularity alignment on windows, else page-align */
++#ifdef WIN32
++#define mmap_align(S) granularity_align(S)
++#else
++#define mmap_align(S) page_align(S)
++#endif
++
++/* For sys_alloc, enough padding to ensure can malloc request on success */
++#define SYS_ALLOC_PADDING (TOP_FOOT_SIZE + MALLOC_ALIGNMENT)
++
++#define is_page_aligned(S)\
++   (((size_t)(S) & (mparams.page_size - SIZE_T_ONE)) == 0)
++#define is_granularity_aligned(S)\
++   (((size_t)(S) & (mparams.granularity - SIZE_T_ONE)) == 0)
++
++/*  True if segment S holds address A */
++#define segment_holds(S, A)\
++  ((char*)(A) >= S->base && (char*)(A) < S->base + S->size)
++
++/* Return segment holding given address */
++static msegmentptr segment_holding(mstate m, char* addr) {
++  msegmentptr sp = &m->seg;
++  for (;;) {
++    if (addr >= sp->base && addr < sp->base + sp->size)
++      return sp;
++    if ((sp = sp->next) == 0)
++      return 0;
++  }
++}
++
++/* Return true if segment contains a segment link */
++static int has_segment_link(mstate m, msegmentptr ss) {
++  msegmentptr sp = &m->seg;
++  for (;;) {
++    if ((char*)sp >= ss->base && (char*)sp < ss->base + ss->size)
++      return 1;
++    if ((sp = sp->next) == 0)
++      return 0;
++  }
++}
++
++#ifndef MORECORE_CANNOT_TRIM
++#define should_trim(M,s)  ((s) > (M)->trim_check)
++#else  /* MORECORE_CANNOT_TRIM */
++#define should_trim(M,s)  (0)
++#endif /* MORECORE_CANNOT_TRIM */
++
++/*
++  TOP_FOOT_SIZE is padding at the end of a segment, including space
++  that may be needed to place segment records and fenceposts when new
++  noncontiguous segments are added.
++*/
++#define TOP_FOOT_SIZE\
++  (align_offset(chunk2mem(0))+pad_request(sizeof(struct malloc_segment))+MIN_CHUNK_SIZE)
++
++
++/* -------------------------------  Hooks -------------------------------- */
++
++/*
++  PREACTION should be defined to return 0 on success, and nonzero on
++  failure. If you are not using locking, you can redefine these to do
++  anything you like.
++*/
++
++#if USE_LOCKS
++#define PREACTION(M)  ((use_lock(M))? ACQUIRE_LOCK(&(M)->mutex) : 0)
++#define POSTACTION(M) { if (use_lock(M)) RELEASE_LOCK(&(M)->mutex); }
++#else /* USE_LOCKS */
++
++#ifndef PREACTION
++#define PREACTION(M) (0)
++#endif  /* PREACTION */
++
++#ifndef POSTACTION
++#define POSTACTION(M)
++#endif  /* POSTACTION */
++
++#endif /* USE_LOCKS */
++
++/*
++  CORRUPTION_ERROR_ACTION is triggered upon detected bad addresses.
++  USAGE_ERROR_ACTION is triggered on detected bad frees and
++  reallocs. The argument p is an address that might have triggered the
++  fault. It is ignored by the two predefined actions, but might be
++  useful in custom actions that try to help diagnose errors.
++*/
++
++#if PROCEED_ON_ERROR
++
++/* A count of the number of corruption errors causing resets */
++int malloc_corruption_error_count;
++
++/* default corruption action */
++static void reset_on_error(mstate m);
++
++#define CORRUPTION_ERROR_ACTION(m)  reset_on_error(m)
++#define USAGE_ERROR_ACTION(m, p)
++
++#else /* PROCEED_ON_ERROR */
++
++#ifndef CORRUPTION_ERROR_ACTION
++#define CORRUPTION_ERROR_ACTION(m) ABORT
++#endif /* CORRUPTION_ERROR_ACTION */
++
++#ifndef USAGE_ERROR_ACTION
++#define USAGE_ERROR_ACTION(m,p) ABORT
++#endif /* USAGE_ERROR_ACTION */
++
++#endif /* PROCEED_ON_ERROR */
++
++
++/* -------------------------- Debugging setup ---------------------------- */
++
++#if ! DEBUG
++
++#define check_free_chunk(M,P)
++#define check_inuse_chunk(M,P)
++#define check_malloced_chunk(M,P,N)
++#define check_mmapped_chunk(M,P)
++#define check_malloc_state(M)
++#define check_top_chunk(M,P)
++
++#else /* DEBUG */
++#define check_free_chunk(M,P)       do_check_free_chunk(M,P)
++#define check_inuse_chunk(M,P)      do_check_inuse_chunk(M,P)
++#define check_top_chunk(M,P)        do_check_top_chunk(M,P)
++#define check_malloced_chunk(M,P,N) do_check_malloced_chunk(M,P,N)
++#define check_mmapped_chunk(M,P)    do_check_mmapped_chunk(M,P)
++#define check_malloc_state(M)       do_check_malloc_state(M)
++
++static void   do_check_any_chunk(mstate m, mchunkptr p);
++static void   do_check_top_chunk(mstate m, mchunkptr p);
++static void   do_check_mmapped_chunk(mstate m, mchunkptr p);
++static void   do_check_inuse_chunk(mstate m, mchunkptr p);
++static void   do_check_free_chunk(mstate m, mchunkptr p);
++static void   do_check_malloced_chunk(mstate m, void* mem, size_t s);
++static void   do_check_tree(mstate m, tchunkptr t);
++static void   do_check_treebin(mstate m, bindex_t i);
++static void   do_check_smallbin(mstate m, bindex_t i);
++static void   do_check_malloc_state(mstate m);
++static int    bin_find(mstate m, mchunkptr x);
++static size_t traverse_and_check(mstate m);
++#endif /* DEBUG */
++
++/* ---------------------------- Indexing Bins ---------------------------- */
++
++#define is_small(s)         (((s) >> SMALLBIN_SHIFT) < NSMALLBINS)
++#define small_index(s)      (bindex_t)((s)  >> SMALLBIN_SHIFT)
++#define small_index2size(i) ((i)  << SMALLBIN_SHIFT)
++#define MIN_SMALL_INDEX     (small_index(MIN_CHUNK_SIZE))
++
++/* addressing by index. See above about smallbin repositioning */
++/* BEGIN android-changed: strict aliasing change: char* cast to void* */
++#define smallbin_at(M, i)   ((sbinptr)((void*)&((M)->smallbins[(i)<<1])))
++/* END android-changed */
++#define treebin_at(M,i)     (&((M)->treebins[i]))
++
++/* assign tree index for size S to variable I. Use x86 asm if possible  */
++#if defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__))
++#define compute_tree_index(S, I)\
++{\
++  unsigned int X = S >> TREEBIN_SHIFT;\
++  if (X == 0)\
++    I = 0;\
++  else if (X > 0xFFFF)\
++    I = NTREEBINS-1;\
++  else {\
++    unsigned int K = (unsigned) sizeof(X)*__CHAR_BIT__ - 1 - (unsigned) __builtin_clz(X); \
++    I =  (bindex_t)((K << 1) + ((S >> (K + (TREEBIN_SHIFT-1)) & 1)));\
++  }\
++}
++
++#elif defined (__INTEL_COMPILER)
++#define compute_tree_index(S, I)\
++{\
++  size_t X = S >> TREEBIN_SHIFT;\
++  if (X == 0)\
++    I = 0;\
++  else if (X > 0xFFFF)\
++    I = NTREEBINS-1;\
++  else {\
++    unsigned int K = _bit_scan_reverse (X); \
++    I =  (bindex_t)((K << 1) + ((S >> (K + (TREEBIN_SHIFT-1)) & 1)));\
++  }\
++}
++
++#elif defined(_MSC_VER) && _MSC_VER>=1300
++#define compute_tree_index(S, I)\
++{\
++  size_t X = S >> TREEBIN_SHIFT;\
++  if (X == 0)\
++    I = 0;\
++  else if (X > 0xFFFF)\
++    I = NTREEBINS-1;\
++  else {\
++    unsigned int K;\
++    _BitScanReverse((DWORD *) &K, (DWORD) X);\
++    I =  (bindex_t)((K << 1) + ((S >> (K + (TREEBIN_SHIFT-1)) & 1)));\
++  }\
++}
++
++#else /* GNUC */
++#define compute_tree_index(S, I)\
++{\
++  size_t X = S >> TREEBIN_SHIFT;\
++  if (X == 0)\
++    I = 0;\
++  else if (X > 0xFFFF)\
++    I = NTREEBINS-1;\
++  else {\
++    unsigned int Y = (unsigned int)X;\
++    unsigned int N = ((Y - 0x100) >> 16) & 8;\
++    unsigned int K = (((Y <<= N) - 0x1000) >> 16) & 4;\
++    N += K;\
++    N += K = (((Y <<= K) - 0x4000) >> 16) & 2;\
++    K = 14 - N + ((Y <<= K) >> 15);\
++    I = (K << 1) + ((S >> (K + (TREEBIN_SHIFT-1)) & 1));\
++  }\
++}
++#endif /* GNUC */
++
++/* Bit representing maximum resolved size in a treebin at i */
++#define bit_for_tree_index(i) \
++   (i == NTREEBINS-1)? (SIZE_T_BITSIZE-1) : (((i) >> 1) + TREEBIN_SHIFT - 2)
++
++/* Shift placing maximum resolved bit in a treebin at i as sign bit */
++#define leftshift_for_tree_index(i) \
++   ((i == NTREEBINS-1)? 0 : \
++    ((SIZE_T_BITSIZE-SIZE_T_ONE) - (((i) >> 1) + TREEBIN_SHIFT - 2)))
++
++/* The size of the smallest chunk held in bin with index i */
++#define minsize_for_tree_index(i) \
++   ((SIZE_T_ONE << (((i) >> 1) + TREEBIN_SHIFT)) |  \
++   (((size_t)((i) & SIZE_T_ONE)) << (((i) >> 1) + TREEBIN_SHIFT - 1)))
++
++
++/* ------------------------ Operations on bin maps ----------------------- */
++
++/* bit corresponding to given index */
++#define idx2bit(i)              ((binmap_t)(1) << (i))
++
++/* Mark/Clear bits with given index */
++#define mark_smallmap(M,i)      ((M)->smallmap |=  idx2bit(i))
++#define clear_smallmap(M,i)     ((M)->smallmap &= ~idx2bit(i))
++#define smallmap_is_marked(M,i) ((M)->smallmap &   idx2bit(i))
++
++#define mark_treemap(M,i)       ((M)->treemap  |=  idx2bit(i))
++#define clear_treemap(M,i)      ((M)->treemap  &= ~idx2bit(i))
++#define treemap_is_marked(M,i)  ((M)->treemap  &   idx2bit(i))
++
++/* isolate the least set bit of a bitmap */
++#define least_bit(x)         ((x) & -(x))
++
++/* mask with all bits to left of least bit of x on */
++#define left_bits(x)         ((x<<1) | -(x<<1))
++
++/* mask with all bits to left of or equal to least bit of x on */
++#define same_or_left_bits(x) ((x) | -(x))
++
++/* index corresponding to given bit. Use x86 asm if possible */
++
++#if defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__))
++#define compute_bit2idx(X, I)\
++{\
++  unsigned int J;\
++  J = __builtin_ctz(X); \
++  I = (bindex_t)J;\
++}
++
++#elif defined (__INTEL_COMPILER)
++#define compute_bit2idx(X, I)\
++{\
++  unsigned int J;\
++  J = _bit_scan_forward (X); \
++  I = (bindex_t)J;\
++}
++
++#elif defined(_MSC_VER) && _MSC_VER>=1300
++#define compute_bit2idx(X, I)\
++{\
++  unsigned int J;\
++  _BitScanForward((DWORD *) &J, X);\
++  I = (bindex_t)J;\
++}
++
++#elif USE_BUILTIN_FFS
++#define compute_bit2idx(X, I) I = ffs(X)-1
++
++#else
++#define compute_bit2idx(X, I)\
++{\
++  unsigned int Y = X - 1;\
++  unsigned int K = Y >> (16-4) & 16;\
++  unsigned int N = K;        Y >>= K;\
++  N += K = Y >> (8-3) &  8;  Y >>= K;\
++  N += K = Y >> (4-2) &  4;  Y >>= K;\
++  N += K = Y >> (2-1) &  2;  Y >>= K;\
++  N += K = Y >> (1-0) &  1;  Y >>= K;\
++  I = (bindex_t)(N + Y);\
++}
++#endif /* GNUC */
++
++
++/* ----------------------- Runtime Check Support ------------------------- */
++
++/*
++  For security, the main invariant is that malloc/free/etc never
++  writes to a static address other than malloc_state, unless static
++  malloc_state itself has been corrupted, which cannot occur via
++  malloc (because of these checks). In essence this means that we
++  believe all pointers, sizes, maps etc held in malloc_state, but
++  check all of those linked or offsetted from other embedded data
++  structures.  These checks are interspersed with main code in a way
++  that tends to minimize their run-time cost.
++
++  When FOOTERS is defined, in addition to range checking, we also
++  verify footer fields of inuse chunks, which can be used guarantee
++  that the mstate controlling malloc/free is intact.  This is a
++  streamlined version of the approach described by William Robertson
++  et al in "Run-time Detection of Heap-based Overflows" LISA'03
++  http://www.usenix.org/events/lisa03/tech/robertson.html The footer
++  of an inuse chunk holds the xor of its mstate and a random seed,
++  that is checked upon calls to free() and realloc().  This is
++  (probabalistically) unguessable from outside the program, but can be
++  computed by any code successfully malloc'ing any chunk, so does not
++  itself provide protection against code that has already broken
++  security through some other means.  Unlike Robertson et al, we
++  always dynamically check addresses of all offset chunks (previous,
++  next, etc). This turns out to be cheaper than relying on hashes.
++*/
++
++#if !INSECURE
++/* Check if address a is at least as high as any from MORECORE or MMAP */
++#define ok_address(M, a) ((char*)(a) >= (M)->least_addr)
++/* Check if address of next chunk n is higher than base chunk p */
++#define ok_next(p, n)    ((char*)(p) < (char*)(n))
++/* Check if p has inuse status */
++#define ok_inuse(p)     is_inuse(p)
++/* Check if p has its pinuse bit on */
++#define ok_pinuse(p)     pinuse(p)
++
++#else /* !INSECURE */
++#define ok_address(M, a) (1)
++#define ok_next(b, n)    (1)
++#define ok_inuse(p)      (1)
++#define ok_pinuse(p)     (1)
++#endif /* !INSECURE */
++
++#if (FOOTERS && !INSECURE)
++/* Check if (alleged) mstate m has expected magic field */
++#define ok_magic(M)      ((M)->magic == mparams.magic)
++#else  /* (FOOTERS && !INSECURE) */
++#define ok_magic(M)      (1)
++#endif /* (FOOTERS && !INSECURE) */
++
++/* In gcc, use __builtin_expect to minimize impact of checks */
++#if !INSECURE
++#if defined(__GNUC__) && __GNUC__ >= 3
++#define RTCHECK(e)  __builtin_expect(e, 1)
++#else /* GNUC */
++#define RTCHECK(e)  (e)
++#endif /* GNUC */
++#else /* !INSECURE */
++#define RTCHECK(e)  (1)
++#endif /* !INSECURE */
++
++/* macros to set up inuse chunks with or without footers */
++
++#if !FOOTERS
++
++#define mark_inuse_foot(M,p,s)
++
++/* Macros for setting head/foot of non-mmapped chunks */
++
++/* Set cinuse bit and pinuse bit of next chunk */
++#define set_inuse(M,p,s)\
++  ((p)->head = (((p)->head & PINUSE_BIT)|s|CINUSE_BIT),\
++  ((mchunkptr)(((char*)(p)) + (s)))->head |= PINUSE_BIT)
++
++/* Set cinuse and pinuse of this chunk and pinuse of next chunk */
++#define set_inuse_and_pinuse(M,p,s)\
++  ((p)->head = (s|PINUSE_BIT|CINUSE_BIT),\
++  ((mchunkptr)(((char*)(p)) + (s)))->head |= PINUSE_BIT)
++
++/* Set size, cinuse and pinuse bit of this chunk */
++#define set_size_and_pinuse_of_inuse_chunk(M, p, s)\
++  ((p)->head = (s|PINUSE_BIT|CINUSE_BIT))
++
++#else /* FOOTERS */
++
++/* Set foot of inuse chunk to be xor of mstate and seed */
++#define mark_inuse_foot(M,p,s)\
++  (((mchunkptr)((char*)(p) + (s)))->prev_foot = ((size_t)(M) ^ mparams.magic))
++
++#define get_mstate_for(p)\
++  ((mstate)(((mchunkptr)((char*)(p) +\
++    (chunksize(p))))->prev_foot ^ mparams.magic))
++
++#define set_inuse(M,p,s)\
++  ((p)->head = (((p)->head & PINUSE_BIT)|s|CINUSE_BIT),\
++  (((mchunkptr)(((char*)(p)) + (s)))->head |= PINUSE_BIT), \
++  mark_inuse_foot(M,p,s))
++
++#define set_inuse_and_pinuse(M,p,s)\
++  ((p)->head = (s|PINUSE_BIT|CINUSE_BIT),\
++  (((mchunkptr)(((char*)(p)) + (s)))->head |= PINUSE_BIT),\
++ mark_inuse_foot(M,p,s))
++
++#define set_size_and_pinuse_of_inuse_chunk(M, p, s)\
++  ((p)->head = (s|PINUSE_BIT|CINUSE_BIT),\
++  mark_inuse_foot(M, p, s))
++
++#endif /* !FOOTERS */
++
++/* ---------------------------- setting mparams -------------------------- */
++
++#if LOCK_AT_FORK
++static void pre_fork(void)         { ACQUIRE_LOCK(&(gm)->mutex); }
++static void post_fork_parent(void) { RELEASE_LOCK(&(gm)->mutex); }
++static void post_fork_child(void)  { INITIAL_LOCK(&(gm)->mutex); }
++#endif /* LOCK_AT_FORK */
++
++/* Initialize mparams */
++static int init_mparams(void) {
++  /* BEGIN android-added: move pthread_atfork outside of lock */
++  int first_run = 0;
++  /* END android-added */
++#ifdef NEED_GLOBAL_LOCK_INIT
++  if (malloc_global_mutex_status <= 0)
++    init_malloc_global_mutex();
++#endif
++
++  ACQUIRE_MALLOC_GLOBAL_LOCK();
++  if (mparams.magic == 0) {
++    size_t magic;
++    size_t psize;
++    size_t gsize;
++    /* BEGIN android-added: move pthread_atfork outside of lock */
++    first_run = 1;
++    /* END android-added */
++
++#ifndef WIN32
++    psize = malloc_getpagesize;
++    gsize = ((DEFAULT_GRANULARITY != 0)? DEFAULT_GRANULARITY : psize);
++#else /* WIN32 */
++    {
++      SYSTEM_INFO system_info;
++      GetSystemInfo(&system_info);
++      psize = system_info.dwPageSize;
++      gsize = ((DEFAULT_GRANULARITY != 0)?
++               DEFAULT_GRANULARITY : system_info.dwAllocationGranularity);
++    }
++#endif /* WIN32 */
++
++    /* Sanity-check configuration:
++       size_t must be unsigned and as wide as pointer type.
++       ints must be at least 4 bytes.
++       alignment must be at least 8.
++       Alignment, min chunk size, and page size must all be powers of 2.
++    */
++    if ((sizeof(size_t) != sizeof(char*)) ||
++        (MAX_SIZE_T < MIN_CHUNK_SIZE)  ||
++        (sizeof(int) < 4)  ||
++        (MALLOC_ALIGNMENT < (size_t)8U) ||
++        ((MALLOC_ALIGNMENT & (MALLOC_ALIGNMENT-SIZE_T_ONE)) != 0) ||
++        ((MCHUNK_SIZE      & (MCHUNK_SIZE-SIZE_T_ONE))      != 0) ||
++        ((gsize            & (gsize-SIZE_T_ONE))            != 0) ||
++        ((psize            & (psize-SIZE_T_ONE))            != 0))
++      ABORT;
++    mparams.granularity = gsize;
++    mparams.page_size = psize;
++    mparams.mmap_threshold = DEFAULT_MMAP_THRESHOLD;
++    mparams.trim_threshold = DEFAULT_TRIM_THRESHOLD;
++#if MORECORE_CONTIGUOUS
++    mparams.default_mflags = USE_LOCK_BIT|USE_MMAP_BIT;
++#else  /* MORECORE_CONTIGUOUS */
++    mparams.default_mflags = USE_LOCK_BIT|USE_MMAP_BIT|USE_NONCONTIGUOUS_BIT;
++#endif /* MORECORE_CONTIGUOUS */
++
++#if !ONLY_MSPACES
++    /* Set up lock for main malloc area */
++    gm->mflags = mparams.default_mflags;
++    (void)INITIAL_LOCK(&gm->mutex);
++#endif
++    /* BEGIN android-removed: move pthread_atfork outside of lock */
++#if 0 && LOCK_AT_FORK
++    pthread_atfork(&pre_fork, &post_fork_parent, &post_fork_child);
++#endif
++    /* END android-removed */
++
++    {
++#if USE_DEV_RANDOM
++      int fd;
++      unsigned char buf[sizeof(size_t)];
++      /* Try to use /dev/urandom, else fall back on using time */
++      if ((fd = open("/dev/urandom", O_RDONLY)) >= 0 &&
++          read(fd, buf, sizeof(buf)) == sizeof(buf)) {
++        magic = *((size_t *) buf);
++        close(fd);
++      }
++      else
++#endif /* USE_DEV_RANDOM */
++#ifdef WIN32
++      magic = (size_t)(GetTickCount() ^ (size_t)0x55555555U);
++#elif defined(LACKS_TIME_H)
++      magic = (size_t)&magic ^ (size_t)0x55555555U;
++#else
++      magic = (size_t)(time(0) ^ (size_t)0x55555555U);
++#endif
++      magic |= (size_t)8U;    /* ensure nonzero */
++      magic &= ~(size_t)7U;   /* improve chances of fault for bad values */
++      /* Until memory modes commonly available, use volatile-write */
++      (*(volatile size_t *)(&(mparams.magic))) = magic;
++    }
++  }
++
++  RELEASE_MALLOC_GLOBAL_LOCK();
++  /* BEGIN android-added: move pthread_atfork outside of lock */
++  if (first_run != 0) {
++#if LOCK_AT_FORK
++    pthread_atfork(&pre_fork, &post_fork_parent, &post_fork_child);
++#endif
++  }
++  /* END android-added */
++  return 1;
++}
++
++/* support for mallopt */
++static int change_mparam(int param_number, int value) {
++  size_t val;
++  ensure_initialization();
++  val = (value == -1)? MAX_SIZE_T : (size_t)value;
++  switch(param_number) {
++  case M_TRIM_THRESHOLD:
++    mparams.trim_threshold = val;
++    return 1;
++  case M_GRANULARITY:
++    if (val >= mparams.page_size && ((val & (val-1)) == 0)) {
++      mparams.granularity = val;
++      return 1;
++    }
++    else
++      return 0;
++  case M_MMAP_THRESHOLD:
++    mparams.mmap_threshold = val;
++    return 1;
++  default:
++    return 0;
++  }
++}
++
++#if DEBUG
++/* ------------------------- Debugging Support --------------------------- */
++
++/* Check properties of any chunk, whether free, inuse, mmapped etc  */
++static void do_check_any_chunk(mstate m, mchunkptr p) {
++  assert((is_aligned(chunk2mem(p))) || (p->head == FENCEPOST_HEAD));
++  assert(ok_address(m, p));
++}
++
++/* Check properties of top chunk */
++static void do_check_top_chunk(mstate m, mchunkptr p) {
++  msegmentptr sp = segment_holding(m, (char*)p);
++  size_t  sz = p->head & ~INUSE_BITS; /* third-lowest bit can be set! */
++  assert(sp != 0);
++  assert((is_aligned(chunk2mem(p))) || (p->head == FENCEPOST_HEAD));
++  assert(ok_address(m, p));
++  assert(sz == m->topsize);
++  assert(sz > 0);
++  assert(sz == ((sp->base + sp->size) - (char*)p) - TOP_FOOT_SIZE);
++  assert(pinuse(p));
++  assert(!pinuse(chunk_plus_offset(p, sz)));
++}
++
++/* Check properties of (inuse) mmapped chunks */
++static void do_check_mmapped_chunk(mstate m, mchunkptr p) {
++  size_t  sz = chunksize(p);
++  size_t len = (sz + (p->prev_foot) + MMAP_FOOT_PAD);
++  assert(is_mmapped(p));
++  assert(use_mmap(m));
++  assert((is_aligned(chunk2mem(p))) || (p->head == FENCEPOST_HEAD));
++  assert(ok_address(m, p));
++  assert(!is_small(sz));
++  assert((len & (mparams.page_size-SIZE_T_ONE)) == 0);
++  assert(chunk_plus_offset(p, sz)->head == FENCEPOST_HEAD);
++  assert(chunk_plus_offset(p, sz+SIZE_T_SIZE)->head == 0);
++}
++
++/* Check properties of inuse chunks */
++static void do_check_inuse_chunk(mstate m, mchunkptr p) {
++  do_check_any_chunk(m, p);
++  assert(is_inuse(p));
++  assert(next_pinuse(p));
++  /* If not pinuse and not mmapped, previous chunk has OK offset */
++  assert(is_mmapped(p) || pinuse(p) || next_chunk(prev_chunk(p)) == p);
++  if (is_mmapped(p))
++    do_check_mmapped_chunk(m, p);
++}
++
++/* Check properties of free chunks */
++static void do_check_free_chunk(mstate m, mchunkptr p) {
++  size_t sz = chunksize(p);
++  mchunkptr next = chunk_plus_offset(p, sz);
++  do_check_any_chunk(m, p);
++  assert(!is_inuse(p));
++  assert(!next_pinuse(p));
++  assert (!is_mmapped(p));
++  if (p != m->dv && p != m->top) {
++    if (sz >= MIN_CHUNK_SIZE) {
++      assert((sz & CHUNK_ALIGN_MASK) == 0);
++      assert(is_aligned(chunk2mem(p)));
++      assert(next->prev_foot == sz);
++      assert(pinuse(p));
++      assert (next == m->top || is_inuse(next));
++      assert(p->fd->bk == p);
++      assert(p->bk->fd == p);
++    }
++    else  /* markers are always of size SIZE_T_SIZE */
++      assert(sz == SIZE_T_SIZE);
++  }
++}
++
++/* Check properties of malloced chunks at the point they are malloced */
++static void do_check_malloced_chunk(mstate m, void* mem, size_t s) {
++  if (mem != 0) {
++    mchunkptr p = mem2chunk(mem);
++    size_t sz = p->head & ~INUSE_BITS;
++    do_check_inuse_chunk(m, p);
++    assert((sz & CHUNK_ALIGN_MASK) == 0);
++    assert(sz >= MIN_CHUNK_SIZE);
++    assert(sz >= s);
++    /* unless mmapped, size is less than MIN_CHUNK_SIZE more than request */
++    assert(is_mmapped(p) || sz < (s + MIN_CHUNK_SIZE));
++  }
++}
++
++/* Check a tree and its subtrees.  */
++static void do_check_tree(mstate m, tchunkptr t) {
++  tchunkptr head = 0;
++  tchunkptr u = t;
++  bindex_t tindex = t->index;
++  size_t tsize = chunksize(t);
++  bindex_t idx;
++  compute_tree_index(tsize, idx);
++  assert(tindex == idx);
++  assert(tsize >= MIN_LARGE_SIZE);
++  assert(tsize >= minsize_for_tree_index(idx));
++  assert((idx == NTREEBINS-1) || (tsize < minsize_for_tree_index((idx+1))));
++
++  do { /* traverse through chain of same-sized nodes */
++    do_check_any_chunk(m, ((mchunkptr)u));
++    assert(u->index == tindex);
++    assert(chunksize(u) == tsize);
++    assert(!is_inuse(u));
++    assert(!next_pinuse(u));
++    assert(u->fd->bk == u);
++    assert(u->bk->fd == u);
++    if (u->parent == 0) {
++      assert(u->child[0] == 0);
++      assert(u->child[1] == 0);
++    }
++    else {
++      assert(head == 0); /* only one node on chain has parent */
++      head = u;
++      assert(u->parent != u);
++      assert (u->parent->child[0] == u ||
++              u->parent->child[1] == u ||
++              *((tbinptr*)(u->parent)) == u);
++      if (u->child[0] != 0) {
++        assert(u->child[0]->parent == u);
++        assert(u->child[0] != u);
++        do_check_tree(m, u->child[0]);
++      }
++      if (u->child[1] != 0) {
++        assert(u->child[1]->parent == u);
++        assert(u->child[1] != u);
++        do_check_tree(m, u->child[1]);
++      }
++      if (u->child[0] != 0 && u->child[1] != 0) {
++        assert(chunksize(u->child[0]) < chunksize(u->child[1]));
++      }
++    }
++    u = u->fd;
++  } while (u != t);
++  assert(head != 0);
++}
++
++/*  Check all the chunks in a treebin.  */
++static void do_check_treebin(mstate m, bindex_t i) {
++  tbinptr* tb = treebin_at(m, i);
++  tchunkptr t = *tb;
++  int empty = (m->treemap & (1U << i)) == 0;
++  if (t == 0)
++    assert(empty);
++  if (!empty)
++    do_check_tree(m, t);
++}
++
++/*  Check all the chunks in a smallbin.  */
++static void do_check_smallbin(mstate m, bindex_t i) {
++  sbinptr b = smallbin_at(m, i);
++  mchunkptr p = b->bk;
++  unsigned int empty = (m->smallmap & (1U << i)) == 0;
++  if (p == b)
++    assert(empty);
++  if (!empty) {
++    for (; p != b; p = p->bk) {
++      size_t size = chunksize(p);
++      mchunkptr q;
++      /* each chunk claims to be free */
++      do_check_free_chunk(m, p);
++      /* chunk belongs in bin */
++      assert(small_index(size) == i);
++      assert(p->bk == b || chunksize(p->bk) == chunksize(p));
++      /* chunk is followed by an inuse chunk */
++      q = next_chunk(p);
++      if (q->head != FENCEPOST_HEAD)
++        do_check_inuse_chunk(m, q);
++    }
++  }
++}
++
++/* Find x in a bin. Used in other check functions. */
++static int bin_find(mstate m, mchunkptr x) {
++  size_t size = chunksize(x);
++  if (is_small(size)) {
++    bindex_t sidx = small_index(size);
++    sbinptr b = smallbin_at(m, sidx);
++    if (smallmap_is_marked(m, sidx)) {
++      mchunkptr p = b;
++      do {
++        if (p == x)
++          return 1;
++      } while ((p = p->fd) != b);
++    }
++  }
++  else {
++    bindex_t tidx;
++    compute_tree_index(size, tidx);
++    if (treemap_is_marked(m, tidx)) {
++      tchunkptr t = *treebin_at(m, tidx);
++      size_t sizebits = size << leftshift_for_tree_index(tidx);
++      while (t != 0 && chunksize(t) != size) {
++        t = t->child[(sizebits >> (SIZE_T_BITSIZE-SIZE_T_ONE)) & 1];
++        sizebits <<= 1;
++      }
++      if (t != 0) {
++        tchunkptr u = t;
++        do {
++          if (u == (tchunkptr)x)
++            return 1;
++        } while ((u = u->fd) != t);
++      }
++    }
++  }
++  return 0;
++}
++
++/* Traverse each chunk and check it; return total */
++static size_t traverse_and_check(mstate m) {
++  size_t sum = 0;
++  if (is_initialized(m)) {
++    msegmentptr s = &m->seg;
++    sum += m->topsize + TOP_FOOT_SIZE;
++    while (s != 0) {
++      mchunkptr q = align_as_chunk(s->base);
++      mchunkptr lastq = 0;
++      assert(pinuse(q));
++      while (segment_holds(s, q) &&
++             q != m->top && q->head != FENCEPOST_HEAD) {
++        sum += chunksize(q);
++        if (is_inuse(q)) {
++          assert(!bin_find(m, q));
++          do_check_inuse_chunk(m, q);
++        }
++        else {
++          assert(q == m->dv || bin_find(m, q));
++          assert(lastq == 0 || is_inuse(lastq)); /* Not 2 consecutive free */
++          do_check_free_chunk(m, q);
++        }
++        lastq = q;
++        q = next_chunk(q);
++      }
++      s = s->next;
++    }
++  }
++  return sum;
++}
++
++
++/* Check all properties of malloc_state. */
++static void do_check_malloc_state(mstate m) {
++  bindex_t i;
++  size_t total;
++  /* check bins */
++  for (i = 0; i < NSMALLBINS; ++i)
++    do_check_smallbin(m, i);
++  for (i = 0; i < NTREEBINS; ++i)
++    do_check_treebin(m, i);
++
++  if (m->dvsize != 0) { /* check dv chunk */
++    do_check_any_chunk(m, m->dv);
++    assert(m->dvsize == chunksize(m->dv));
++    assert(m->dvsize >= MIN_CHUNK_SIZE);
++    assert(bin_find(m, m->dv) == 0);
++  }
++
++  if (m->top != 0) {   /* check top chunk */
++    do_check_top_chunk(m, m->top);
++    /*assert(m->topsize == chunksize(m->top)); redundant */
++    assert(m->topsize > 0);
++    assert(bin_find(m, m->top) == 0);
++  }
++
++  total = traverse_and_check(m);
++  assert(total <= m->footprint);
++  assert(m->footprint <= m->max_footprint);
++}
++#endif /* DEBUG */
++
++/* ----------------------------- statistics ------------------------------ */
++
++#if !NO_MALLINFO
++static struct mallinfo internal_mallinfo(mstate m) {
++  struct mallinfo nm = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
++  ensure_initialization();
++  if (!PREACTION(m)) {
++    check_malloc_state(m);
++    if (is_initialized(m)) {
++      size_t nfree = SIZE_T_ONE; /* top always free */
++      size_t mfree = m->topsize + TOP_FOOT_SIZE;
++      size_t sum = mfree;
++      msegmentptr s = &m->seg;
++      while (s != 0) {
++        mchunkptr q = align_as_chunk(s->base);
++        while (segment_holds(s, q) &&
++               q != m->top && q->head != FENCEPOST_HEAD) {
++          size_t sz = chunksize(q);
++          sum += sz;
++          if (!is_inuse(q)) {
++            mfree += sz;
++            ++nfree;
++          }
++          q = next_chunk(q);
++        }
++        s = s->next;
++      }
++
++      nm.arena    = sum;
++      nm.ordblks  = nfree;
++      nm.hblkhd   = m->footprint - sum;
++      /* BEGIN android-changed: usmblks set to footprint from max_footprint */
++      nm.usmblks  = m->footprint;
++      /* END android-changed */
++      nm.uordblks = m->footprint - mfree;
++      nm.fordblks = mfree;
++      nm.keepcost = m->topsize;
++    }
++
++    POSTACTION(m);
++  }
++  return nm;
++}
++#endif /* !NO_MALLINFO */
++
++#if !NO_MALLOC_STATS
++static void internal_malloc_stats(mstate m) {
++  ensure_initialization();
++  if (!PREACTION(m)) {
++    size_t maxfp = 0;
++    size_t fp = 0;
++    size_t used = 0;
++    check_malloc_state(m);
++    if (is_initialized(m)) {
++      msegmentptr s = &m->seg;
++      maxfp = m->max_footprint;
++      fp = m->footprint;
++      used = fp - (m->topsize + TOP_FOOT_SIZE);
++
++      while (s != 0) {
++        mchunkptr q = align_as_chunk(s->base);
++        while (segment_holds(s, q) &&
++               q != m->top && q->head != FENCEPOST_HEAD) {
++          if (!is_inuse(q))
++            used -= chunksize(q);
++          q = next_chunk(q);
++        }
++        s = s->next;
++      }
++    }
++    POSTACTION(m); /* drop lock */
++    fprintf(stderr, "max system bytes = %10lu\n", (unsigned long)(maxfp));
++    fprintf(stderr, "system bytes     = %10lu\n", (unsigned long)(fp));
++    fprintf(stderr, "in use bytes     = %10lu\n", (unsigned long)(used));
++  }
++}
++#endif /* NO_MALLOC_STATS */
++
++/* ----------------------- Operations on smallbins ----------------------- */
++
++/*
++  Various forms of linking and unlinking are defined as macros.  Even
++  the ones for trees, which are very long but have very short typical
++  paths.  This is ugly but reduces reliance on inlining support of
++  compilers.
++*/
++
++/* Link a free chunk into a smallbin  */
++#define insert_small_chunk(M, P, S) {\
++  bindex_t I  = small_index(S);\
++  mchunkptr B = smallbin_at(M, I);\
++  mchunkptr F = B;\
++  assert(S >= MIN_CHUNK_SIZE);\
++  if (!smallmap_is_marked(M, I))\
++    mark_smallmap(M, I);\
++  else if (RTCHECK(ok_address(M, B->fd)))\
++    F = B->fd;\
++  else {\
++    CORRUPTION_ERROR_ACTION(M);\
++  }\
++  B->fd = P;\
++  F->bk = P;\
++  P->fd = F;\
++  P->bk = B;\
++}
++
++/* Unlink a chunk from a smallbin  */
++#define unlink_small_chunk(M, P, S) {\
++  mchunkptr F = P->fd;\
++  mchunkptr B = P->bk;\
++  bindex_t I = small_index(S);\
++  assert(P != B);\
++  assert(P != F);\
++  assert(chunksize(P) == small_index2size(I));\
++  if (RTCHECK(F == smallbin_at(M,I) || (ok_address(M, F) && F->bk == P))) { \
++    if (B == F) {\
++      clear_smallmap(M, I);\
++    }\
++    else if (RTCHECK(B == smallbin_at(M,I) ||\
++                     (ok_address(M, B) && B->fd == P))) {\
++      F->bk = B;\
++      B->fd = F;\
++    }\
++    else {\
++      CORRUPTION_ERROR_ACTION(M);\
++    }\
++  }\
++  else {\
++    CORRUPTION_ERROR_ACTION(M);\
++  }\
++}
++
++/* Unlink the first chunk from a smallbin */
++#define unlink_first_small_chunk(M, B, P, I) {\
++  mchunkptr F = P->fd;\
++  assert(P != B);\
++  assert(P != F);\
++  assert(chunksize(P) == small_index2size(I));\
++  if (B == F) {\
++    clear_smallmap(M, I);\
++  }\
++  else if (RTCHECK(ok_address(M, F) && F->bk == P)) {\
++    F->bk = B;\
++    B->fd = F;\
++  }\
++  else {\
++    CORRUPTION_ERROR_ACTION(M);\
++  }\
++}
++
++/* Replace dv node, binning the old one */
++/* Used only when dvsize known to be small */
++#define replace_dv(M, P, S) {\
++  size_t DVS = M->dvsize;\
++  assert(is_small(DVS));\
++  if (DVS != 0) {\
++    mchunkptr DV = M->dv;\
++    insert_small_chunk(M, DV, DVS);\
++  }\
++  M->dvsize = S;\
++  M->dv = P;\
++}
++
++/* ------------------------- Operations on trees ------------------------- */
++
++/* Insert chunk into tree */
++#define insert_large_chunk(M, X, S) {\
++  tbinptr* H;\
++  bindex_t I;\
++  compute_tree_index(S, I);\
++  H = treebin_at(M, I);\
++  X->index = I;\
++  X->child[0] = X->child[1] = 0;\
++  if (!treemap_is_marked(M, I)) {\
++    mark_treemap(M, I);\
++    *H = X;\
++    X->parent = (tchunkptr)H;\
++    X->fd = X->bk = X;\
++  }\
++  else {\
++    tchunkptr T = *H;\
++    size_t K = S << leftshift_for_tree_index(I);\
++    for (;;) {\
++      if (chunksize(T) != S) {\
++        tchunkptr* C = &(T->child[(K >> (SIZE_T_BITSIZE-SIZE_T_ONE)) & 1]);\
++        K <<= 1;\
++        if (*C != 0)\
++          T = *C;\
++        else if (RTCHECK(ok_address(M, C))) {\
++          *C = X;\
++          X->parent = T;\
++          X->fd = X->bk = X;\
++          break;\
++        }\
++        else {\
++          CORRUPTION_ERROR_ACTION(M);\
++          break;\
++        }\
++      }\
++      else {\
++        tchunkptr F = T->fd;\
++        if (RTCHECK(ok_address(M, T) && ok_address(M, F))) {\
++          T->fd = F->bk = X;\
++          X->fd = F;\
++          X->bk = T;\
++          X->parent = 0;\
++          break;\
++        }\
++        else {\
++          CORRUPTION_ERROR_ACTION(M);\
++          break;\
++        }\
++      }\
++    }\
++  }\
++}
++
++/*
++  Unlink steps:
++
++  1. If x is a chained node, unlink it from its same-sized fd/bk links
++     and choose its bk node as its replacement.
++  2. If x was the last node of its size, but not a leaf node, it must
++     be replaced with a leaf node (not merely one with an open left or
++     right), to make sure that lefts and rights of descendents
++     correspond properly to bit masks.  We use the rightmost descendent
++     of x.  We could use any other leaf, but this is easy to locate and
++     tends to counteract removal of leftmosts elsewhere, and so keeps
++     paths shorter than minimally guaranteed.  This doesn't loop much
++     because on average a node in a tree is near the bottom.
++  3. If x is the base of a chain (i.e., has parent links) relink
++     x's parent and children to x's replacement (or null if none).
++*/
++
++#define unlink_large_chunk(M, X) {\
++  tchunkptr XP = X->parent;\
++  tchunkptr R;\
++  if (X->bk != X) {\
++    tchunkptr F = X->fd;\
++    R = X->bk;\
++    if (RTCHECK(ok_address(M, F) && F->bk == X && R->fd == X)) {\
++      F->bk = R;\
++      R->fd = F;\
++    }\
++    else {\
++      CORRUPTION_ERROR_ACTION(M);\
++    }\
++  }\
++  else {\
++    tchunkptr* RP;\
++    if (((R = *(RP = &(X->child[1]))) != 0) ||\
++        ((R = *(RP = &(X->child[0]))) != 0)) {\
++      tchunkptr* CP;\
++      while ((*(CP = &(R->child[1])) != 0) ||\
++             (*(CP = &(R->child[0])) != 0)) {\
++        R = *(RP = CP);\
++      }\
++      if (RTCHECK(ok_address(M, RP)))\
++        *RP = 0;\
++      else {\
++        CORRUPTION_ERROR_ACTION(M);\
++      }\
++    }\
++  }\
++  if (XP != 0) {\
++    tbinptr* H = treebin_at(M, X->index);\
++    if (X == *H) {\
++      if ((*H = R) == 0) \
++        clear_treemap(M, X->index);\
++    }\
++    else if (RTCHECK(ok_address(M, XP))) {\
++      if (XP->child[0] == X) \
++        XP->child[0] = R;\
++      else \
++        XP->child[1] = R;\
++    }\
++    else\
++      CORRUPTION_ERROR_ACTION(M);\
++    if (R != 0) {\
++      if (RTCHECK(ok_address(M, R))) {\
++        tchunkptr C0, C1;\
++        R->parent = XP;\
++        if ((C0 = X->child[0]) != 0) {\
++          if (RTCHECK(ok_address(M, C0))) {\
++            R->child[0] = C0;\
++            C0->parent = R;\
++          }\
++          else\
++            CORRUPTION_ERROR_ACTION(M);\
++        }\
++        if ((C1 = X->child[1]) != 0) {\
++          if (RTCHECK(ok_address(M, C1))) {\
++            R->child[1] = C1;\
++            C1->parent = R;\
++          }\
++          else\
++            CORRUPTION_ERROR_ACTION(M);\
++        }\
++      }\
++      else\
++        CORRUPTION_ERROR_ACTION(M);\
++    }\
++  }\
++}
++
++/* Relays to large vs small bin operations */
++
++#define insert_chunk(M, P, S)\
++  if (is_small(S)) insert_small_chunk(M, P, S)\
++  else { tchunkptr TP = (tchunkptr)(P); insert_large_chunk(M, TP, S); }
++
++#define unlink_chunk(M, P, S)\
++  if (is_small(S)) unlink_small_chunk(M, P, S)\
++  else { tchunkptr TP = (tchunkptr)(P); unlink_large_chunk(M, TP); }
++
++
++/* Relays to internal calls to malloc/free from realloc, memalign etc */
++
++#if ONLY_MSPACES
++#define internal_malloc(m, b) mspace_malloc(m, b)
++#define internal_free(m, mem) mspace_free(m,mem);
++#else /* ONLY_MSPACES */
++#if MSPACES
++#define internal_malloc(m, b)\
++  ((m == gm)? dlmalloc(b) : mspace_malloc(m, b))
++#define internal_free(m, mem)\
++   if (m == gm) dlfree(mem); else mspace_free(m,mem);
++#else /* MSPACES */
++#define internal_malloc(m, b) dlmalloc(b)
++#define internal_free(m, mem) dlfree(mem)
++#endif /* MSPACES */
++#endif /* ONLY_MSPACES */
++
++/* -----------------------  Direct-mmapping chunks ----------------------- */
++
++/*
++  Directly mmapped chunks are set up with an offset to the start of
++  the mmapped region stored in the prev_foot field of the chunk. This
++  allows reconstruction of the required argument to MUNMAP when freed,
++  and also allows adjustment of the returned chunk to meet alignment
++  requirements (especially in memalign).
++*/
++
++/* Malloc using mmap */
++static void* mmap_alloc(mstate m, size_t nb) {
++  size_t mmsize = mmap_align(nb + SIX_SIZE_T_SIZES + CHUNK_ALIGN_MASK);
++  if (m->footprint_limit != 0) {
++    size_t fp = m->footprint + mmsize;
++    if (fp <= m->footprint || fp > m->footprint_limit)
++      return 0;
++  }
++  if (mmsize > nb) {     /* Check for wrap around 0 */
++    char* mm = (char*)(CALL_DIRECT_MMAP(mmsize));
++    if (mm != CMFAIL) {
++      size_t offset = align_offset(chunk2mem(mm));
++      size_t psize = mmsize - offset - MMAP_FOOT_PAD;
++      mchunkptr p = (mchunkptr)(mm + offset);
++      p->prev_foot = offset;
++      p->head = psize;
++      mark_inuse_foot(m, p, psize);
++      chunk_plus_offset(p, psize)->head = FENCEPOST_HEAD;
++      chunk_plus_offset(p, psize+SIZE_T_SIZE)->head = 0;
++
++      if (m->least_addr == 0 || mm < m->least_addr)
++        m->least_addr = mm;
++      if ((m->footprint += mmsize) > m->max_footprint)
++        m->max_footprint = m->footprint;
++      assert(is_aligned(chunk2mem(p)));
++      check_mmapped_chunk(m, p);
++      return chunk2mem(p);
++    }
++  }
++  return 0;
++}
++
++/* Realloc using mmap */
++static mchunkptr mmap_resize(mstate m, mchunkptr oldp, size_t nb, int flags) {
++  size_t oldsize = chunksize(oldp);
++  (void)flags; /* placate people compiling -Wunused */
++  if (is_small(nb)) /* Can't shrink mmap regions below small size */
++    return 0;
++  /* Keep old chunk if big enough but not too big */
++  if (oldsize >= nb + SIZE_T_SIZE &&
++      (oldsize - nb) <= (mparams.granularity << 1))
++    return oldp;
++  else {
++    size_t offset = oldp->prev_foot;
++    size_t oldmmsize = oldsize + offset + MMAP_FOOT_PAD;
++    size_t newmmsize = mmap_align(nb + SIX_SIZE_T_SIZES + CHUNK_ALIGN_MASK);
++    char* cp = (char*)CALL_MREMAP((char*)oldp - offset,
++                                  oldmmsize, newmmsize, flags);
++    if (cp != CMFAIL) {
++      mchunkptr newp = (mchunkptr)(cp + offset);
++      size_t psize = newmmsize - offset - MMAP_FOOT_PAD;
++      newp->head = psize;
++      mark_inuse_foot(m, newp, psize);
++      chunk_plus_offset(newp, psize)->head = FENCEPOST_HEAD;
++      chunk_plus_offset(newp, psize+SIZE_T_SIZE)->head = 0;
++
++      if (cp < m->least_addr)
++        m->least_addr = cp;
++      if ((m->footprint += newmmsize - oldmmsize) > m->max_footprint)
++        m->max_footprint = m->footprint;
++      check_mmapped_chunk(m, newp);
++      return newp;
++    }
++  }
++  return 0;
++}
++
++
++/* -------------------------- mspace management -------------------------- */
++
++/* Initialize top chunk and its size */
++static void init_top(mstate m, mchunkptr p, size_t psize) {
++  /* Ensure alignment */
++  size_t offset = align_offset(chunk2mem(p));
++  p = (mchunkptr)((char*)p + offset);
++  psize -= offset;
++
++  m->top = p;
++  m->topsize = psize;
++  p->head = psize | PINUSE_BIT;
++  /* set size of fake trailing chunk holding overhead space only once */
++  chunk_plus_offset(p, psize)->head = TOP_FOOT_SIZE;
++  m->trim_check = mparams.trim_threshold; /* reset on each update */
++}
++
++/* Initialize bins for a new mstate that is otherwise zeroed out */
++static void init_bins(mstate m) {
++  /* Establish circular links for smallbins */
++  bindex_t i;
++  for (i = 0; i < NSMALLBINS; ++i) {
++    sbinptr bin = smallbin_at(m,i);
++    bin->fd = bin->bk = bin;
++  }
++}
++
++#if PROCEED_ON_ERROR
++
++/* default corruption action */
++static void reset_on_error(mstate m) {
++  int i;
++  ++malloc_corruption_error_count;
++  /* Reinitialize fields to forget about all memory */
++  m->smallmap = m->treemap = 0;
++  m->dvsize = m->topsize = 0;
++  m->seg.base = 0;
++  m->seg.size = 0;
++  m->seg.next = 0;
++  m->top = m->dv = 0;
++  for (i = 0; i < NTREEBINS; ++i)
++    *treebin_at(m, i) = 0;
++  init_bins(m);
++}
++#endif /* PROCEED_ON_ERROR */
++
++/* Allocate chunk and prepend remainder with chunk in successor base. */
++static void* prepend_alloc(mstate m, char* newbase, char* oldbase,
++                           size_t nb) {
++  mchunkptr p = align_as_chunk(newbase);
++  mchunkptr oldfirst = align_as_chunk(oldbase);
++  size_t psize = (char*)oldfirst - (char*)p;
++  mchunkptr q = chunk_plus_offset(p, nb);
++  size_t qsize = psize - nb;
++  set_size_and_pinuse_of_inuse_chunk(m, p, nb);
++
++  assert((char*)oldfirst > (char*)q);
++  assert(pinuse(oldfirst));
++  assert(qsize >= MIN_CHUNK_SIZE);
++
++  /* consolidate remainder with first chunk of old base */
++  if (oldfirst == m->top) {
++    size_t tsize = m->topsize += qsize;
++    m->top = q;
++    q->head = tsize | PINUSE_BIT;
++    check_top_chunk(m, q);
++  }
++  else if (oldfirst == m->dv) {
++    size_t dsize = m->dvsize += qsize;
++    m->dv = q;
++    set_size_and_pinuse_of_free_chunk(q, dsize);
++  }
++  else {
++    if (!is_inuse(oldfirst)) {
++      size_t nsize = chunksize(oldfirst);
++      unlink_chunk(m, oldfirst, nsize);
++      oldfirst = chunk_plus_offset(oldfirst, nsize);
++      qsize += nsize;
++    }
++    set_free_with_pinuse(q, qsize, oldfirst);
++    insert_chunk(m, q, qsize);
++    check_free_chunk(m, q);
++  }
++
++  check_malloced_chunk(m, chunk2mem(p), nb);
++  return chunk2mem(p);
++}
++
++/* Add a segment to hold a new noncontiguous region */
++static void add_segment(mstate m, char* tbase, size_t tsize, flag_t mmapped) {
++  /* Determine locations and sizes of segment, fenceposts, old top */
++  char* old_top = (char*)m->top;
++  msegmentptr oldsp = segment_holding(m, old_top);
++  char* old_end = oldsp->base + oldsp->size;
++  size_t ssize = pad_request(sizeof(struct malloc_segment));
++  char* rawsp = old_end - (ssize + FOUR_SIZE_T_SIZES + CHUNK_ALIGN_MASK);
++  size_t offset = align_offset(chunk2mem(rawsp));
++  char* asp = rawsp + offset;
++  char* csp = (asp < (old_top + MIN_CHUNK_SIZE))? old_top : asp;
++  mchunkptr sp = (mchunkptr)csp;
++  msegmentptr ss = (msegmentptr)(chunk2mem(sp));
++  mchunkptr tnext = chunk_plus_offset(sp, ssize);
++  mchunkptr p = tnext;
++  int nfences = 0;
++
++  /* reset top to new space */
++  init_top(m, (mchunkptr)tbase, tsize - TOP_FOOT_SIZE);
++
++  /* Set up segment record */
++  assert(is_aligned(ss));
++  set_size_and_pinuse_of_inuse_chunk(m, sp, ssize);
++  *ss = m->seg; /* Push current record */
++  m->seg.base = tbase;
++  m->seg.size = tsize;
++  m->seg.sflags = mmapped;
++  m->seg.next = ss;
++
++  /* Insert trailing fenceposts */
++  for (;;) {
++    mchunkptr nextp = chunk_plus_offset(p, SIZE_T_SIZE);
++    p->head = FENCEPOST_HEAD;
++    ++nfences;
++    if ((char*)(&(nextp->head)) < old_end)
++      p = nextp;
++    else
++      break;
++  }
++  assert(nfences >= 2);
++
++  /* Insert the rest of old top into a bin as an ordinary free chunk */
++  if (csp != old_top) {
++    mchunkptr q = (mchunkptr)old_top;
++    size_t psize = csp - old_top;
++    mchunkptr tn = chunk_plus_offset(q, psize);
++    set_free_with_pinuse(q, psize, tn);
++    insert_chunk(m, q, psize);
++  }
++
++  check_top_chunk(m, m->top);
++}
++
++/* -------------------------- System allocation -------------------------- */
++
++/* Get memory from system using MORECORE or MMAP */
++static void* sys_alloc(mstate m, size_t nb) {
++  char* tbase = CMFAIL;
++  size_t tsize = 0;
++  flag_t mmap_flag = 0;
++  size_t asize; /* allocation size */
++
++  ensure_initialization();
++
++  /* Directly map large chunks, but only if already initialized */
++  if (use_mmap(m) && nb >= mparams.mmap_threshold && m->topsize != 0) {
++    void* mem = mmap_alloc(m, nb);
++    if (mem != 0)
++      return mem;
++  }
++
++  asize = granularity_align(nb + SYS_ALLOC_PADDING);
++  if (asize <= nb) {
++    /* BEGIN android-added: set errno */
++    MALLOC_FAILURE_ACTION;
++    /* END android-added */
++    return 0; /* wraparound */
++  }
++  if (m->footprint_limit != 0) {
++    size_t fp = m->footprint + asize;
++    if (fp <= m->footprint || fp > m->footprint_limit) {
++      /* BEGIN android-added: set errno */
++      MALLOC_FAILURE_ACTION;
++      /* END android-added */
++      return 0;
++    }
++  }
++
++  /*
++    Try getting memory in any of three ways (in most-preferred to
++    least-preferred order):
++    1. A call to MORECORE that can normally contiguously extend memory.
++       (disabled if not MORECORE_CONTIGUOUS or not HAVE_MORECORE or
++       or main space is mmapped or a previous contiguous call failed)
++    2. A call to MMAP new space (disabled if not HAVE_MMAP).
++       Note that under the default settings, if MORECORE is unable to
++       fulfill a request, and HAVE_MMAP is true, then mmap is
++       used as a noncontiguous system allocator. This is a useful backup
++       strategy for systems with holes in address spaces -- in this case
++       sbrk cannot contiguously expand the heap, but mmap may be able to
++       find space.
++    3. A call to MORECORE that cannot usually contiguously extend memory.
++       (disabled if not HAVE_MORECORE)
++
++   In all cases, we need to request enough bytes from system to ensure
++   we can malloc nb bytes upon success, so pad with enough space for
++   top_foot, plus alignment-pad to make sure we don't lose bytes if
++   not on boundary, and round this up to a granularity unit.
++  */
++
++  if (MORECORE_CONTIGUOUS && !use_noncontiguous(m)) {
++    char* br = CMFAIL;
++    size_t ssize = asize; /* sbrk call size */
++    msegmentptr ss = (m->top == 0)? 0 : segment_holding(m, (char*)m->top);
++    ACQUIRE_MALLOC_GLOBAL_LOCK();
++
++    if (ss == 0) {  /* First time through or recovery */
++      char* base = (char*)CALL_MORECORE(0);
++      if (base != CMFAIL) {
++        size_t fp;
++        /* Adjust to end on a page boundary */
++        if (!is_page_aligned(base))
++          ssize += (page_align((size_t)base) - (size_t)base);
++        fp = m->footprint + ssize; /* recheck limits */
++        if (ssize > nb && ssize < HALF_MAX_SIZE_T &&
++            (m->footprint_limit == 0 ||
++             (fp > m->footprint && fp <= m->footprint_limit)) &&
++            (br = (char*)(CALL_MORECORE(ssize))) == base) {
++          tbase = base;
++          tsize = ssize;
++        }
++      }
++    }
++    else {
++      /* Subtract out existing available top space from MORECORE request. */
++      ssize = granularity_align(nb - m->topsize + SYS_ALLOC_PADDING);
++      /* Use mem here only if it did continuously extend old space */
++      if (ssize < HALF_MAX_SIZE_T &&
++          (br = (char*)(CALL_MORECORE(ssize))) == ss->base+ss->size) {
++        tbase = br;
++        tsize = ssize;
++      }
++    }
++
++    if (tbase == CMFAIL) {    /* Cope with partial failure */
++      if (br != CMFAIL) {    /* Try to use/extend the space we did get */
++        if (ssize < HALF_MAX_SIZE_T &&
++            ssize < nb + SYS_ALLOC_PADDING) {
++          size_t esize = granularity_align(nb + SYS_ALLOC_PADDING - ssize);
++          if (esize < HALF_MAX_SIZE_T) {
++            char* end = (char*)CALL_MORECORE(esize);
++            if (end != CMFAIL)
++              ssize += esize;
++            else {            /* Can't use; try to release */
++              (void) CALL_MORECORE(-ssize);
++              br = CMFAIL;
++            }
++          }
++        }
++      }
++      if (br != CMFAIL) {    /* Use the space we did get */
++        tbase = br;
++        tsize = ssize;
++      }
++      else
++        disable_contiguous(m); /* Don't try contiguous path in the future */
++    }
++
++    RELEASE_MALLOC_GLOBAL_LOCK();
++  }
++
++  if (HAVE_MMAP && tbase == CMFAIL) {  /* Try MMAP */
++    char* mp = (char*)(CALL_MMAP(asize));
++    if (mp != CMFAIL) {
++      tbase = mp;
++      tsize = asize;
++      mmap_flag = USE_MMAP_BIT;
++    }
++  }
++
++  if (HAVE_MORECORE && tbase == CMFAIL) { /* Try noncontiguous MORECORE */
++    if (asize < HALF_MAX_SIZE_T) {
++      char* br = CMFAIL;
++      char* end = CMFAIL;
++      ACQUIRE_MALLOC_GLOBAL_LOCK();
++      br = (char*)(CALL_MORECORE(asize));
++      end = (char*)(CALL_MORECORE(0));
++      RELEASE_MALLOC_GLOBAL_LOCK();
++      if (br != CMFAIL && end != CMFAIL && br < end) {
++        size_t ssize = end - br;
++        if (ssize > nb + TOP_FOOT_SIZE) {
++          tbase = br;
++          tsize = ssize;
++        }
++      }
++    }
++  }
++
++  if (tbase != CMFAIL) {
++
++    if ((m->footprint += tsize) > m->max_footprint)
++      m->max_footprint = m->footprint;
++
++    if (!is_initialized(m)) { /* first-time initialization */
++      if (m->least_addr == 0 || tbase < m->least_addr)
++        m->least_addr = tbase;
++      m->seg.base = tbase;
++      m->seg.size = tsize;
++      m->seg.sflags = mmap_flag;
++      m->magic = mparams.magic;
++      m->release_checks = MAX_RELEASE_CHECK_RATE;
++      init_bins(m);
++#if !ONLY_MSPACES
++      if (is_global(m))
++        init_top(m, (mchunkptr)tbase, tsize - TOP_FOOT_SIZE);
++      else
++#endif
++      {
++        /* Offset top by embedded malloc_state */
++        mchunkptr mn = next_chunk(mem2chunk(m));
++        init_top(m, mn, (size_t)((tbase + tsize) - (char*)mn) -TOP_FOOT_SIZE);
++      }
++    }
++
++    else {
++      /* Try to merge with an existing segment */
++      msegmentptr sp = &m->seg;
++      /* Only consider most recent segment if traversal suppressed */
++      while (sp != 0 && tbase != sp->base + sp->size)
++        sp = (NO_SEGMENT_TRAVERSAL) ? 0 : sp->next;
++      if (sp != 0 &&
++          !is_extern_segment(sp) &&
++          (sp->sflags & USE_MMAP_BIT) == mmap_flag &&
++          segment_holds(sp, m->top)) { /* append */
++        sp->size += tsize;
++        init_top(m, m->top, m->topsize + tsize);
++      }
++      else {
++        if (tbase < m->least_addr)
++          m->least_addr = tbase;
++        sp = &m->seg;
++        while (sp != 0 && sp->base != tbase + tsize)
++          sp = (NO_SEGMENT_TRAVERSAL) ? 0 : sp->next;
++        if (sp != 0 &&
++            !is_extern_segment(sp) &&
++            (sp->sflags & USE_MMAP_BIT) == mmap_flag) {
++          char* oldbase = sp->base;
++          sp->base = tbase;
++          sp->size += tsize;
++          return prepend_alloc(m, tbase, oldbase, nb);
++        }
++        else
++          add_segment(m, tbase, tsize, mmap_flag);
++      }
++    }
++
++    if (nb < m->topsize) { /* Allocate from new or extended top space */
++      size_t rsize = m->topsize -= nb;
++      mchunkptr p = m->top;
++      mchunkptr r = m->top = chunk_plus_offset(p, nb);
++      r->head = rsize | PINUSE_BIT;
++      set_size_and_pinuse_of_inuse_chunk(m, p, nb);
++      check_top_chunk(m, m->top);
++      check_malloced_chunk(m, chunk2mem(p), nb);
++      return chunk2mem(p);
++    }
++  }
++
++  MALLOC_FAILURE_ACTION;
++  return 0;
++}
++
++/* -----------------------  system deallocation -------------------------- */
++
++/* Unmap and unlink any mmapped segments that don't contain used chunks */
++static size_t release_unused_segments(mstate m) {
++  size_t released = 0;
++  int nsegs = 0;
++  msegmentptr pred = &m->seg;
++  msegmentptr sp = pred->next;
++  while (sp != 0) {
++    char* base = sp->base;
++    size_t size = sp->size;
++    msegmentptr next = sp->next;
++    ++nsegs;
++    if (is_mmapped_segment(sp) && !is_extern_segment(sp)) {
++      mchunkptr p = align_as_chunk(base);
++      size_t psize = chunksize(p);
++      /* Can unmap if first chunk holds entire segment and not pinned */
++      if (!is_inuse(p) && (char*)p + psize >= base + size - TOP_FOOT_SIZE) {
++        tchunkptr tp = (tchunkptr)p;
++        assert(segment_holds(sp, (char*)sp));
++        if (p == m->dv) {
++          m->dv = 0;
++          m->dvsize = 0;
++        }
++        else {
++          unlink_large_chunk(m, tp);
++        }
++        if (CALL_MUNMAP(base, size) == 0) {
++          released += size;
++          m->footprint -= size;
++          /* unlink obsoleted record */
++          sp = pred;
++          sp->next = next;
++        }
++        else { /* back out if cannot unmap */
++          insert_large_chunk(m, tp, psize);
++        }
++      }
++    }
++    if (NO_SEGMENT_TRAVERSAL) /* scan only first segment */
++      break;
++    pred = sp;
++    sp = next;
++  }
++  /* Reset check counter */
++  m->release_checks = (((size_t) nsegs > (size_t) MAX_RELEASE_CHECK_RATE)?
++                       (size_t) nsegs : (size_t) MAX_RELEASE_CHECK_RATE);
++  return released;
++}
++
++static int sys_trim(mstate m, size_t pad) {
++  size_t released = 0;
++  ensure_initialization();
++  if (pad < MAX_REQUEST && is_initialized(m)) {
++    pad += TOP_FOOT_SIZE; /* ensure enough room for segment overhead */
++
++    if (m->topsize > pad) {
++      /* Shrink top space in granularity-size units, keeping at least one */
++      size_t unit = mparams.granularity;
++      size_t extra = ((m->topsize - pad + (unit - SIZE_T_ONE)) / unit -
++                      SIZE_T_ONE) * unit;
++      msegmentptr sp = segment_holding(m, (char*)m->top);
++
++      if (!is_extern_segment(sp)) {
++        if (is_mmapped_segment(sp)) {
++          if (HAVE_MMAP &&
++              sp->size >= extra &&
++              !has_segment_link(m, sp)) { /* can't shrink if pinned */
++            size_t newsize = sp->size - extra;
++            (void)newsize; /* placate people compiling -Wunused-variable */
++            /* Prefer mremap, fall back to munmap */
++            if ((CALL_MREMAP(sp->base, sp->size, newsize, 0) != MFAIL) ||
++                (CALL_MUNMAP(sp->base + newsize, extra) == 0)) {
++              released = extra;
++            }
++          }
++        }
++        else if (HAVE_MORECORE) {
++          if (extra >= HALF_MAX_SIZE_T) /* Avoid wrapping negative */
++            extra = (HALF_MAX_SIZE_T) + SIZE_T_ONE - unit;
++          ACQUIRE_MALLOC_GLOBAL_LOCK();
++          {
++            /* Make sure end of memory is where we last set it. */
++            char* old_br = (char*)(CALL_MORECORE(0));
++            if (old_br == sp->base + sp->size) {
++              char* rel_br = (char*)(CALL_MORECORE(-extra));
++              char* new_br = (char*)(CALL_MORECORE(0));
++              if (rel_br != CMFAIL && new_br < old_br)
++                released = old_br - new_br;
++            }
++          }
++          RELEASE_MALLOC_GLOBAL_LOCK();
++        }
++      }
++
++      if (released != 0) {
++        sp->size -= released;
++        m->footprint -= released;
++        init_top(m, m->top, m->topsize - released);
++        check_top_chunk(m, m->top);
++      }
++    }
++
++    /* Unmap any unused mmapped segments */
++    if (HAVE_MMAP)
++      released += release_unused_segments(m);
++
++    /* On failure, disable autotrim to avoid repeated failed future calls */
++    if (released == 0 && m->topsize > m->trim_check)
++      m->trim_check = MAX_SIZE_T;
++  }
++
++  return (released != 0)? 1 : 0;
++}
++
++/* Consolidate and bin a chunk. Differs from exported versions
++   of free mainly in that the chunk need not be marked as inuse.
++*/
++static void dispose_chunk(mstate m, mchunkptr p, size_t psize) {
++  mchunkptr next = chunk_plus_offset(p, psize);
++  if (!pinuse(p)) {
++    mchunkptr prev;
++    size_t prevsize = p->prev_foot;
++    if (is_mmapped(p)) {
++      psize += prevsize + MMAP_FOOT_PAD;
++      if (CALL_MUNMAP((char*)p - prevsize, psize) == 0)
++        m->footprint -= psize;
++      return;
++    }
++    prev = chunk_minus_offset(p, prevsize);
++    psize += prevsize;
++    p = prev;
++    if (RTCHECK(ok_address(m, prev))) { /* consolidate backward */
++      if (p != m->dv) {
++        unlink_chunk(m, p, prevsize);
++      }
++      else if ((next->head & INUSE_BITS) == INUSE_BITS) {
++        m->dvsize = psize;
++        set_free_with_pinuse(p, psize, next);
++        return;
++      }
++    }
++    else {
++      CORRUPTION_ERROR_ACTION(m);
++      return;
++    }
++  }
++  if (RTCHECK(ok_address(m, next))) {
++    if (!cinuse(next)) {  /* consolidate forward */
++      if (next == m->top) {
++        size_t tsize = m->topsize += psize;
++        m->top = p;
++        p->head = tsize | PINUSE_BIT;
++        if (p == m->dv) {
++          m->dv = 0;
++          m->dvsize = 0;
++        }
++        return;
++      }
++      else if (next == m->dv) {
++        size_t dsize = m->dvsize += psize;
++        m->dv = p;
++        set_size_and_pinuse_of_free_chunk(p, dsize);
++        return;
++      }
++      else {
++        size_t nsize = chunksize(next);
++        psize += nsize;
++        unlink_chunk(m, next, nsize);
++        set_size_and_pinuse_of_free_chunk(p, psize);
++        if (p == m->dv) {
++          m->dvsize = psize;
++          return;
++        }
++      }
++    }
++    else {
++      set_free_with_pinuse(p, psize, next);
++    }
++    insert_chunk(m, p, psize);
++  }
++  else {
++    CORRUPTION_ERROR_ACTION(m);
++  }
++}
++
++/* ---------------------------- malloc --------------------------- */
++
++/* allocate a large request from the best fitting chunk in a treebin */
++static void* tmalloc_large(mstate m, size_t nb) {
++  tchunkptr v = 0;
++  size_t rsize = -nb; /* Unsigned negation */
++  tchunkptr t;
++  bindex_t idx;
++  compute_tree_index(nb, idx);
++  if ((t = *treebin_at(m, idx)) != 0) {
++    /* Traverse tree for this bin looking for node with size == nb */
++    size_t sizebits = nb << leftshift_for_tree_index(idx);
++    tchunkptr rst = 0;  /* The deepest untaken right subtree */
++    for (;;) {
++      tchunkptr rt;
++      size_t trem = chunksize(t) - nb;
++      if (trem < rsize) {
++        v = t;
++        if ((rsize = trem) == 0)
++          break;
++      }
++      rt = t->child[1];
++      t = t->child[(sizebits >> (SIZE_T_BITSIZE-SIZE_T_ONE)) & 1];
++      if (rt != 0 && rt != t)
++        rst = rt;
++      if (t == 0) {
++        t = rst; /* set t to least subtree holding sizes > nb */
++        break;
++      }
++      sizebits <<= 1;
++    }
++  }
++  if (t == 0 && v == 0) { /* set t to root of next non-empty treebin */
++    binmap_t leftbits = left_bits(idx2bit(idx)) & m->treemap;
++    if (leftbits != 0) {
++      bindex_t i;
++      binmap_t leastbit = least_bit(leftbits);
++      compute_bit2idx(leastbit, i);
++      t = *treebin_at(m, i);
++    }
++  }
++
++  while (t != 0) { /* find smallest of tree or subtree */
++    size_t trem = chunksize(t) - nb;
++    if (trem < rsize) {
++      rsize = trem;
++      v = t;
++    }
++    t = leftmost_child(t);
++  }
++
++  /*  If dv is a better fit, return 0 so malloc will use it */
++  if (v != 0 && rsize < (size_t)(m->dvsize - nb)) {
++    if (RTCHECK(ok_address(m, v))) { /* split */
++      mchunkptr r = chunk_plus_offset(v, nb);
++      assert(chunksize(v) == rsize + nb);
++      if (RTCHECK(ok_next(v, r))) {
++        unlink_large_chunk(m, v);
++        if (rsize < MIN_CHUNK_SIZE)
++          set_inuse_and_pinuse(m, v, (rsize + nb));
++        else {
++          set_size_and_pinuse_of_inuse_chunk(m, v, nb);
++          set_size_and_pinuse_of_free_chunk(r, rsize);
++          insert_chunk(m, r, rsize);
++        }
++        return chunk2mem(v);
++      }
++    }
++    CORRUPTION_ERROR_ACTION(m);
++  }
++  return 0;
++}
++
++/* allocate a small request from the best fitting chunk in a treebin */
++static void* tmalloc_small(mstate m, size_t nb) {
++  tchunkptr t, v;
++  size_t rsize;
++  bindex_t i;
++  binmap_t leastbit = least_bit(m->treemap);
++  compute_bit2idx(leastbit, i);
++  v = t = *treebin_at(m, i);
++  rsize = chunksize(t) - nb;
++
++  while ((t = leftmost_child(t)) != 0) {
++    size_t trem = chunksize(t) - nb;
++    if (trem < rsize) {
++      rsize = trem;
++      v = t;
++    }
++  }
++
++  if (RTCHECK(ok_address(m, v))) {
++    mchunkptr r = chunk_plus_offset(v, nb);
++    assert(chunksize(v) == rsize + nb);
++    if (RTCHECK(ok_next(v, r))) {
++      unlink_large_chunk(m, v);
++      if (rsize < MIN_CHUNK_SIZE)
++        set_inuse_and_pinuse(m, v, (rsize + nb));
++      else {
++        set_size_and_pinuse_of_inuse_chunk(m, v, nb);
++        set_size_and_pinuse_of_free_chunk(r, rsize);
++        replace_dv(m, r, rsize);
++      }
++      return chunk2mem(v);
++    }
++  }
++
++  CORRUPTION_ERROR_ACTION(m);
++  return 0;
++}
++
++#if !ONLY_MSPACES
++
++void* dlmalloc(size_t bytes) {
++  /*
++     Basic algorithm:
++     If a small request (< 256 bytes minus per-chunk overhead):
++       1. If one exists, use a remainderless chunk in associated smallbin.
++          (Remainderless means that there are too few excess bytes to
++          represent as a chunk.)
++       2. If it is big enough, use the dv chunk, which is normally the
++          chunk adjacent to the one used for the most recent small request.
++       3. If one exists, split the smallest available chunk in a bin,
++          saving remainder in dv.
++       4. If it is big enough, use the top chunk.
++       5. If available, get memory from system and use it
++     Otherwise, for a large request:
++       1. Find the smallest available binned chunk that fits, and use it
++          if it is better fitting than dv chunk, splitting if necessary.
++       2. If better fitting than any binned chunk, use the dv chunk.
++       3. If it is big enough, use the top chunk.
++       4. If request size >= mmap threshold, try to directly mmap this chunk.
++       5. If available, get memory from system and use it
++
++     The ugly goto's here ensure that postaction occurs along all paths.
++  */
++
++#if USE_LOCKS
++  ensure_initialization(); /* initialize in sys_alloc if not using locks */
++#endif
++
++  if (!PREACTION(gm)) {
++    void* mem;
++    size_t nb;
++    if (bytes <= MAX_SMALL_REQUEST) {
++      bindex_t idx;
++      binmap_t smallbits;
++      nb = (bytes < MIN_REQUEST)? MIN_CHUNK_SIZE : pad_request(bytes);
++      idx = small_index(nb);
++      smallbits = gm->smallmap >> idx;
++
++      if ((smallbits & 0x3U) != 0) { /* Remainderless fit to a smallbin. */
++        mchunkptr b, p;
++        idx += ~smallbits & 1;       /* Uses next bin if idx empty */
++        b = smallbin_at(gm, idx);
++        p = b->fd;
++        assert(chunksize(p) == small_index2size(idx));
++        unlink_first_small_chunk(gm, b, p, idx);
++        set_inuse_and_pinuse(gm, p, small_index2size(idx));
++        mem = chunk2mem(p);
++        check_malloced_chunk(gm, mem, nb);
++        goto postaction;
++      }
++
++      else if (nb > gm->dvsize) {
++        if (smallbits != 0) { /* Use chunk in next nonempty smallbin */
++          mchunkptr b, p, r;
++          size_t rsize;
++          bindex_t i;
++          binmap_t leftbits = (smallbits << idx) & left_bits(idx2bit(idx));
++          binmap_t leastbit = least_bit(leftbits);
++          compute_bit2idx(leastbit, i);
++          b = smallbin_at(gm, i);
++          p = b->fd;
++          assert(chunksize(p) == small_index2size(i));
++          unlink_first_small_chunk(gm, b, p, i);
++          rsize = small_index2size(i) - nb;
++          /* Fit here cannot be remainderless if 4byte sizes */
++          if (SIZE_T_SIZE != 4 && rsize < MIN_CHUNK_SIZE)
++            set_inuse_and_pinuse(gm, p, small_index2size(i));
++          else {
++            set_size_and_pinuse_of_inuse_chunk(gm, p, nb);
++            r = chunk_plus_offset(p, nb);
++            set_size_and_pinuse_of_free_chunk(r, rsize);
++            replace_dv(gm, r, rsize);
++          }
++          mem = chunk2mem(p);
++          check_malloced_chunk(gm, mem, nb);
++          goto postaction;
++        }
++
++        else if (gm->treemap != 0 && (mem = tmalloc_small(gm, nb)) != 0) {
++          check_malloced_chunk(gm, mem, nb);
++          goto postaction;
++        }
++      }
++    }
++    else if (bytes >= MAX_REQUEST)
++      nb = MAX_SIZE_T; /* Too big to allocate. Force failure (in sys alloc) */
++    else {
++      nb = pad_request(bytes);
++      if (gm->treemap != 0 && (mem = tmalloc_large(gm, nb)) != 0) {
++        check_malloced_chunk(gm, mem, nb);
++        goto postaction;
++      }
++    }
++
++    if (nb <= gm->dvsize) {
++      size_t rsize = gm->dvsize - nb;
++      mchunkptr p = gm->dv;
++      if (rsize >= MIN_CHUNK_SIZE) { /* split dv */
++        mchunkptr r = gm->dv = chunk_plus_offset(p, nb);
++        gm->dvsize = rsize;
++        set_size_and_pinuse_of_free_chunk(r, rsize);
++        set_size_and_pinuse_of_inuse_chunk(gm, p, nb);
++      }
++      else { /* exhaust dv */
++        size_t dvs = gm->dvsize;
++        gm->dvsize = 0;
++        gm->dv = 0;
++        set_inuse_and_pinuse(gm, p, dvs);
++      }
++      mem = chunk2mem(p);
++      check_malloced_chunk(gm, mem, nb);
++      goto postaction;
++    }
++
++    else if (nb < gm->topsize) { /* Split top */
++      size_t rsize = gm->topsize -= nb;
++      mchunkptr p = gm->top;
++      mchunkptr r = gm->top = chunk_plus_offset(p, nb);
++      r->head = rsize | PINUSE_BIT;
++      set_size_and_pinuse_of_inuse_chunk(gm, p, nb);
++      mem = chunk2mem(p);
++      check_top_chunk(gm, gm->top);
++      check_malloced_chunk(gm, mem, nb);
++      goto postaction;
++    }
++
++    mem = sys_alloc(gm, nb);
++
++  postaction:
++    POSTACTION(gm);
++    return mem;
++  }
++
++  return 0;
++}
++
++/* ---------------------------- free --------------------------- */
++
++void dlfree(void* mem) {
++  /*
++     Consolidate freed chunks with preceeding or succeeding bordering
++     free chunks, if they exist, and then place in a bin.  Intermixed
++     with special cases for top, dv, mmapped chunks, and usage errors.
++  */
++
++  if (mem != 0) {
++    mchunkptr p  = mem2chunk(mem);
++#if FOOTERS
++    mstate fm = get_mstate_for(p);
++    if (!ok_magic(fm)) {
++      USAGE_ERROR_ACTION(fm, p);
++      return;
++    }
++#else /* FOOTERS */
++#define fm gm
++#endif /* FOOTERS */
++    if (!PREACTION(fm)) {
++      check_inuse_chunk(fm, p);
++      if (RTCHECK(ok_address(fm, p) && ok_inuse(p))) {
++        size_t psize = chunksize(p);
++        mchunkptr next = chunk_plus_offset(p, psize);
++        if (!pinuse(p)) {
++          size_t prevsize = p->prev_foot;
++          if (is_mmapped(p)) {
++            psize += prevsize + MMAP_FOOT_PAD;
++            if (CALL_MUNMAP((char*)p - prevsize, psize) == 0)
++              fm->footprint -= psize;
++            goto postaction;
++          }
++          else {
++            mchunkptr prev = chunk_minus_offset(p, prevsize);
++            psize += prevsize;
++            p = prev;
++            if (RTCHECK(ok_address(fm, prev))) { /* consolidate backward */
++              if (p != fm->dv) {
++                unlink_chunk(fm, p, prevsize);
++              }
++              else if ((next->head & INUSE_BITS) == INUSE_BITS) {
++                fm->dvsize = psize;
++                set_free_with_pinuse(p, psize, next);
++                goto postaction;
++              }
++            }
++            else
++              goto erroraction;
++          }
++        }
++
++        if (RTCHECK(ok_next(p, next) && ok_pinuse(next))) {
++          if (!cinuse(next)) {  /* consolidate forward */
++            if (next == fm->top) {
++              size_t tsize = fm->topsize += psize;
++              fm->top = p;
++              p->head = tsize | PINUSE_BIT;
++              if (p == fm->dv) {
++                fm->dv = 0;
++                fm->dvsize = 0;
++              }
++              if (should_trim(fm, tsize))
++                sys_trim(fm, 0);
++              goto postaction;
++            }
++            else if (next == fm->dv) {
++              size_t dsize = fm->dvsize += psize;
++              fm->dv = p;
++              set_size_and_pinuse_of_free_chunk(p, dsize);
++              goto postaction;
++            }
++            else {
++              size_t nsize = chunksize(next);
++              psize += nsize;
++              unlink_chunk(fm, next, nsize);
++              set_size_and_pinuse_of_free_chunk(p, psize);
++              if (p == fm->dv) {
++                fm->dvsize = psize;
++                goto postaction;
++              }
++            }
++          }
++          else
++            set_free_with_pinuse(p, psize, next);
++
++          if (is_small(psize)) {
++            insert_small_chunk(fm, p, psize);
++            check_free_chunk(fm, p);
++          }
++          else {
++            tchunkptr tp = (tchunkptr)p;
++            insert_large_chunk(fm, tp, psize);
++            check_free_chunk(fm, p);
++            if (--fm->release_checks == 0)
++              release_unused_segments(fm);
++          }
++          goto postaction;
++        }
++      }
++    erroraction:
++      USAGE_ERROR_ACTION(fm, p);
++    postaction:
++      POSTACTION(fm);
++    }
++  }
++#if !FOOTERS
++#undef fm
++#endif /* FOOTERS */
++}
++
++void* dlcalloc(size_t n_elements, size_t elem_size) {
++  void* mem;
++  size_t req = 0;
++  if (n_elements != 0) {
++    req = n_elements * elem_size;
++    if (((n_elements | elem_size) & ~(size_t)0xffff) &&
++        (req / n_elements != elem_size))
++      req = MAX_SIZE_T; /* force downstream failure on overflow */
++  }
++  mem = dlmalloc(req);
++  if (mem != 0) {
++    mchunkptr p = mem2chunk(mem);
++    if (calloc_must_clear(p)) {
++      /* Make sure to clear all of the buffer, not just the requested size. */
++      memset(mem, 0, chunksize(p) - overhead_for(p));
++    }
++  }
++  return mem;
++}
++
++#endif /* !ONLY_MSPACES */
++
++/* ------------ Internal support for realloc, memalign, etc -------------- */
++
++/* Try to realloc; only in-place unless can_move true */
++static mchunkptr try_realloc_chunk(mstate m, mchunkptr p, size_t nb,
++                                   int can_move) {
++  mchunkptr newp = 0;
++  size_t oldsize = chunksize(p);
++  mchunkptr next = chunk_plus_offset(p, oldsize);
++  if (RTCHECK(ok_address(m, p) && ok_inuse(p) &&
++              ok_next(p, next) && ok_pinuse(next))) {
++    if (is_mmapped(p)) {
++      newp = mmap_resize(m, p, nb, can_move);
++    }
++    else if (oldsize >= nb) {             /* already big enough */
++      size_t rsize = oldsize - nb;
++      if (rsize >= MIN_CHUNK_SIZE) {      /* split off remainder */
++        mchunkptr r = chunk_plus_offset(p, nb);
++        set_inuse(m, p, nb);
++        set_inuse(m, r, rsize);
++        dispose_chunk(m, r, rsize);
++      }
++      newp = p;
++    }
++    else if (next == m->top) {  /* extend into top */
++      if (oldsize + m->topsize > nb) {
++        size_t newsize = oldsize + m->topsize;
++        size_t newtopsize = newsize - nb;
++        mchunkptr newtop = chunk_plus_offset(p, nb);
++        set_inuse(m, p, nb);
++        newtop->head = newtopsize |PINUSE_BIT;
++        m->top = newtop;
++        m->topsize = newtopsize;
++        newp = p;
++      }
++    }
++    else if (next == m->dv) { /* extend into dv */
++      size_t dvs = m->dvsize;
++      if (oldsize + dvs >= nb) {
++        size_t dsize = oldsize + dvs - nb;
++        if (dsize >= MIN_CHUNK_SIZE) {
++          mchunkptr r = chunk_plus_offset(p, nb);
++          mchunkptr n = chunk_plus_offset(r, dsize);
++          set_inuse(m, p, nb);
++          set_size_and_pinuse_of_free_chunk(r, dsize);
++          clear_pinuse(n);
++          m->dvsize = dsize;
++          m->dv = r;
++        }
++        else { /* exhaust dv */
++          size_t newsize = oldsize + dvs;
++          set_inuse(m, p, newsize);
++          m->dvsize = 0;
++          m->dv = 0;
++        }
++        newp = p;
++      }
++    }
++    else if (!cinuse(next)) { /* extend into next free chunk */
++      size_t nextsize = chunksize(next);
++      if (oldsize + nextsize >= nb) {
++        size_t rsize = oldsize + nextsize - nb;
++        unlink_chunk(m, next, nextsize);
++        if (rsize < MIN_CHUNK_SIZE) {
++          size_t newsize = oldsize + nextsize;
++          set_inuse(m, p, newsize);
++        }
++        else {
++          mchunkptr r = chunk_plus_offset(p, nb);
++          set_inuse(m, p, nb);
++          set_inuse(m, r, rsize);
++          dispose_chunk(m, r, rsize);
++        }
++        newp = p;
++      }
++    }
++  }
++  else {
++    USAGE_ERROR_ACTION(m, chunk2mem(p));
++  }
++  return newp;
++}
++
++static void* internal_memalign(mstate m, size_t alignment, size_t bytes) {
++  void* mem = 0;
++  if (alignment <  MIN_CHUNK_SIZE) /* must be at least a minimum chunk size */
++    alignment = MIN_CHUNK_SIZE;
++  if ((alignment & (alignment-SIZE_T_ONE)) != 0) {/* Ensure a power of 2 */
++    size_t a = MALLOC_ALIGNMENT << 1;
++    while (a < alignment) a <<= 1;
++    alignment = a;
++  }
++  if (bytes >= MAX_REQUEST - alignment) {
++    if (m != 0)  { /* Test isn't needed but avoids compiler warning */
++      MALLOC_FAILURE_ACTION;
++    }
++  }
++  else {
++    size_t nb = request2size(bytes);
++    size_t req = nb + alignment + MIN_CHUNK_SIZE - CHUNK_OVERHEAD;
++    mem = internal_malloc(m, req);
++    if (mem != 0) {
++      mchunkptr p = mem2chunk(mem);
++      if (PREACTION(m))
++        return 0;
++      if ((((size_t)(mem)) & (alignment - 1)) != 0) { /* misaligned */
++        /*
++          Find an aligned spot inside chunk.  Since we need to give
++          back leading space in a chunk of at least MIN_CHUNK_SIZE, if
++          the first calculation places us at a spot with less than
++          MIN_CHUNK_SIZE leader, we can move to the next aligned spot.
++          We've allocated enough total room so that this is always
++          possible.
++        */
++        char* br = (char*)mem2chunk((size_t)(((size_t)((char*)mem + alignment -
++                                                       SIZE_T_ONE)) &
++                                             -alignment));
++        char* pos = ((size_t)(br - (char*)(p)) >= MIN_CHUNK_SIZE)?
++          br : br+alignment;
++        mchunkptr newp = (mchunkptr)pos;
++        size_t leadsize = pos - (char*)(p);
++        size_t newsize = chunksize(p) - leadsize;
++
++        if (is_mmapped(p)) { /* For mmapped chunks, just adjust offset */
++          newp->prev_foot = p->prev_foot + leadsize;
++          newp->head = newsize;
++        }
++        else { /* Otherwise, give back leader, use the rest */
++          set_inuse(m, newp, newsize);
++          set_inuse(m, p, leadsize);
++          dispose_chunk(m, p, leadsize);
++        }
++        p = newp;
++      }
++
++      /* Give back spare room at the end */
++      if (!is_mmapped(p)) {
++        size_t size = chunksize(p);
++        if (size > nb + MIN_CHUNK_SIZE) {
++          size_t remainder_size = size - nb;
++          mchunkptr remainder = chunk_plus_offset(p, nb);
++          set_inuse(m, p, nb);
++          set_inuse(m, remainder, remainder_size);
++          dispose_chunk(m, remainder, remainder_size);
++        }
++      }
++
++      mem = chunk2mem(p);
++      assert (chunksize(p) >= nb);
++      assert(((size_t)mem & (alignment - 1)) == 0);
++      check_inuse_chunk(m, p);
++      POSTACTION(m);
++    }
++  }
++  return mem;
++}
++
++/*
++  Common support for independent_X routines, handling
++    all of the combinations that can result.
++  The opts arg has:
++    bit 0 set if all elements are same size (using sizes[0])
++    bit 1 set if elements should be zeroed
++*/
++static void** ialloc(mstate m,
++                     size_t n_elements,
++                     size_t* sizes,
++                     int opts,
++                     void* chunks[]) {
++
++  size_t    element_size;   /* chunksize of each element, if all same */
++  size_t    contents_size;  /* total size of elements */
++  size_t    array_size;     /* request size of pointer array */
++  void*     mem;            /* malloced aggregate space */
++  mchunkptr p;              /* corresponding chunk */
++  size_t    remainder_size; /* remaining bytes while splitting */
++  void**    marray;         /* either "chunks" or malloced ptr array */
++  mchunkptr array_chunk;    /* chunk for malloced ptr array */
++  flag_t    was_enabled;    /* to disable mmap */
++  size_t    size;
++  size_t    i;
++
++  ensure_initialization();
++  /* compute array length, if needed */
++  if (chunks != 0) {
++    if (n_elements == 0)
++      return chunks; /* nothing to do */
++    marray = chunks;
++    array_size = 0;
++  }
++  else {
++    /* if empty req, must still return chunk representing empty array */
++    if (n_elements == 0)
++      return (void**)internal_malloc(m, 0);
++    marray = 0;
++    array_size = request2size(n_elements * (sizeof(void*)));
++  }
++
++  /* compute total element size */
++  if (opts & 0x1) { /* all-same-size */
++    element_size = request2size(*sizes);
++    contents_size = n_elements * element_size;
++  }
++  else { /* add up all the sizes */
++    element_size = 0;
++    contents_size = 0;
++    for (i = 0; i != n_elements; ++i)
++      contents_size += request2size(sizes[i]);
++  }
++
++  size = contents_size + array_size;
++
++  /*
++     Allocate the aggregate chunk.  First disable direct-mmapping so
++     malloc won't use it, since we would not be able to later
++     free/realloc space internal to a segregated mmap region.
++  */
++  was_enabled = use_mmap(m);
++  disable_mmap(m);
++  mem = internal_malloc(m, size - CHUNK_OVERHEAD);
++  if (was_enabled)
++    enable_mmap(m);
++  if (mem == 0)
++    return 0;
++
++  if (PREACTION(m)) return 0;
++  p = mem2chunk(mem);
++  remainder_size = chunksize(p);
++
++  assert(!is_mmapped(p));
++
++  if (opts & 0x2) {       /* optionally clear the elements */
++    memset((size_t*)mem, 0, remainder_size - SIZE_T_SIZE - array_size);
++  }
++
++  /* If not provided, allocate the pointer array as final part of chunk */
++  if (marray == 0) {
++    size_t  array_chunk_size;
++    array_chunk = chunk_plus_offset(p, contents_size);
++    array_chunk_size = remainder_size - contents_size;
++    marray = (void**) (chunk2mem(array_chunk));
++    set_size_and_pinuse_of_inuse_chunk(m, array_chunk, array_chunk_size);
++    remainder_size = contents_size;
++  }
++
++  /* split out elements */
++  for (i = 0; ; ++i) {
++    marray[i] = chunk2mem(p);
++    if (i != n_elements-1) {
++      if (element_size != 0)
++        size = element_size;
++      else
++        size = request2size(sizes[i]);
++      remainder_size -= size;
++      set_size_and_pinuse_of_inuse_chunk(m, p, size);
++      p = chunk_plus_offset(p, size);
++    }
++    else { /* the final element absorbs any overallocation slop */
++      set_size_and_pinuse_of_inuse_chunk(m, p, remainder_size);
++      break;
++    }
++  }
++
++#if DEBUG
++  if (marray != chunks) {
++    /* final element must have exactly exhausted chunk */
++    if (element_size != 0) {
++      assert(remainder_size == element_size);
++    }
++    else {
++      assert(remainder_size == request2size(sizes[i]));
++    }
++    check_inuse_chunk(m, mem2chunk(marray));
++  }
++  for (i = 0; i != n_elements; ++i)
++    check_inuse_chunk(m, mem2chunk(marray[i]));
++
++#endif /* DEBUG */
++
++  POSTACTION(m);
++  return marray;
++}
++
++/* Try to free all pointers in the given array.
++   Note: this could be made faster, by delaying consolidation,
++   at the price of disabling some user integrity checks, We
++   still optimize some consolidations by combining adjacent
++   chunks before freeing, which will occur often if allocated
++   with ialloc or the array is sorted.
++*/
++static size_t internal_bulk_free(mstate m, void* array[], size_t nelem) {
++  size_t unfreed = 0;
++  if (!PREACTION(m)) {
++    void** a;
++    void** fence = &(array[nelem]);
++    for (a = array; a != fence; ++a) {
++      void* mem = *a;
++      if (mem != 0) {
++        mchunkptr p = mem2chunk(mem);
++        size_t psize = chunksize(p);
++#if FOOTERS
++        if (get_mstate_for(p) != m) {
++          ++unfreed;
++          continue;
++        }
++#endif
++        check_inuse_chunk(m, p);
++        *a = 0;
++        if (RTCHECK(ok_address(m, p) && ok_inuse(p))) {
++          void ** b = a + 1; /* try to merge with next chunk */
++          mchunkptr next = next_chunk(p);
++          if (b != fence && *b == chunk2mem(next)) {
++            size_t newsize = chunksize(next) + psize;
++            set_inuse(m, p, newsize);
++            *b = chunk2mem(p);
++          }
++          else
++            dispose_chunk(m, p, psize);
++        }
++        else {
++          CORRUPTION_ERROR_ACTION(m);
++          break;
++        }
++      }
++    }
++    if (should_trim(m, m->topsize))
++      sys_trim(m, 0);
++    POSTACTION(m);
++  }
++  return unfreed;
++}
++
++/* Traversal */
++#if MALLOC_INSPECT_ALL
++static void internal_inspect_all(mstate m,
++                                 void(*handler)(void *start,
++                                                void *end,
++                                                size_t used_bytes,
++                                                void* callback_arg),
++                                 void* arg) {
++  if (is_initialized(m)) {
++    mchunkptr top = m->top;
++    msegmentptr s;
++    for (s = &m->seg; s != 0; s = s->next) {
++      mchunkptr q = align_as_chunk(s->base);
++      while (segment_holds(s, q) && q->head != FENCEPOST_HEAD) {
++        mchunkptr next = next_chunk(q);
++        size_t sz = chunksize(q);
++        size_t used;
++        void* start;
++        if (is_inuse(q)) {
++          used = sz - CHUNK_OVERHEAD; /* must not be mmapped */
++          start = chunk2mem(q);
++        }
++        else {
++          used = 0;
++          if (is_small(sz)) {     /* offset by possible bookkeeping */
++            start = (void*)((char*)q + sizeof(struct malloc_chunk));
++          }
++          else {
++            start = (void*)((char*)q + sizeof(struct malloc_tree_chunk));
++          }
++        }
++        if (start < (void*)next)  /* skip if all space is bookkeeping */
++          handler(start, next, used, arg);
++        if (q == top)
++          break;
++        q = next;
++      }
++    }
++  }
++}
++#endif /* MALLOC_INSPECT_ALL */
++
++/* ------------------ Exported realloc, memalign, etc -------------------- */
++
++#if !ONLY_MSPACES
++
++void* dlrealloc(void* oldmem, size_t bytes) {
++  void* mem = 0;
++  if (oldmem == 0) {
++    mem = dlmalloc(bytes);
++  }
++  else if (bytes >= MAX_REQUEST) {
++    MALLOC_FAILURE_ACTION;
++  }
++#ifdef REALLOC_ZERO_BYTES_FREES
++  else if (bytes == 0) {
++    dlfree(oldmem);
++  }
++#endif /* REALLOC_ZERO_BYTES_FREES */
++  else {
++    size_t nb = request2size(bytes);
++    mchunkptr oldp = mem2chunk(oldmem);
++#if ! FOOTERS
++    mstate m = gm;
++#else /* FOOTERS */
++    mstate m = get_mstate_for(oldp);
++    if (!ok_magic(m)) {
++      USAGE_ERROR_ACTION(m, oldmem);
++      return 0;
++    }
++#endif /* FOOTERS */
++    if (!PREACTION(m)) {
++      mchunkptr newp = try_realloc_chunk(m, oldp, nb, 1);
++      POSTACTION(m);
++      if (newp != 0) {
++        check_inuse_chunk(m, newp);
++        mem = chunk2mem(newp);
++      }
++      else {
++        mem = internal_malloc(m, bytes);
++        if (mem != 0) {
++          size_t oc = chunksize(oldp) - overhead_for(oldp);
++          memcpy(mem, oldmem, (oc < bytes)? oc : bytes);
++          internal_free(m, oldmem);
++        }
++      }
++    }
++  }
++  return mem;
++}
++
++void* dlrealloc_in_place(void* oldmem, size_t bytes) {
++  void* mem = 0;
++  if (oldmem != 0) {
++    if (bytes >= MAX_REQUEST) {
++      MALLOC_FAILURE_ACTION;
++    }
++    else {
++      size_t nb = request2size(bytes);
++      mchunkptr oldp = mem2chunk(oldmem);
++#if ! FOOTERS
++      mstate m = gm;
++#else /* FOOTERS */
++      mstate m = get_mstate_for(oldp);
++      if (!ok_magic(m)) {
++        USAGE_ERROR_ACTION(m, oldmem);
++        return 0;
++      }
++#endif /* FOOTERS */
++      if (!PREACTION(m)) {
++        mchunkptr newp = try_realloc_chunk(m, oldp, nb, 0);
++        POSTACTION(m);
++        if (newp == oldp) {
++          check_inuse_chunk(m, newp);
++          mem = oldmem;
++        }
++      }
++    }
++  }
++  return mem;
++}
++
++void* dlmemalign(size_t alignment, size_t bytes) {
++  if (alignment <= MALLOC_ALIGNMENT) {
++    return dlmalloc(bytes);
++  }
++  return internal_memalign(gm, alignment, bytes);
++}
++
++int dlposix_memalign(void** pp, size_t alignment, size_t bytes) {
++  void* mem = 0;
++  if (alignment == MALLOC_ALIGNMENT)
++    mem = dlmalloc(bytes);
++  else {
++    size_t d = alignment / sizeof(void*);
++    size_t r = alignment % sizeof(void*);
++    if (r != 0 || d == 0 || (d & (d-SIZE_T_ONE)) != 0)
++      return EINVAL;
++    else if (bytes <= MAX_REQUEST - alignment) {
++      if (alignment <  MIN_CHUNK_SIZE)
++        alignment = MIN_CHUNK_SIZE;
++      mem = internal_memalign(gm, alignment, bytes);
++    }
++  }
++  if (mem == 0)
++    return ENOMEM;
++  else {
++    *pp = mem;
++    return 0;
++  }
++}
++
++void* dlvalloc(size_t bytes) {
++  size_t pagesz;
++  ensure_initialization();
++  pagesz = mparams.page_size;
++  return dlmemalign(pagesz, bytes);
++}
++
++/* BEGIN android-changed: added overflow check */
++void* dlpvalloc(size_t bytes) {
++  size_t pagesz;
++  size_t size;
++  ensure_initialization();
++  pagesz = mparams.page_size;
++  size = (bytes + pagesz - SIZE_T_ONE) & ~(pagesz - SIZE_T_ONE);
++  if (size < bytes) {
++    return NULL;
++  }
++  return dlmemalign(pagesz, size);
++}
++/* END android-change */
++
++void** dlindependent_calloc(size_t n_elements, size_t elem_size,
++                            void* chunks[]) {
++  size_t sz = elem_size; /* serves as 1-element array */
++  return ialloc(gm, n_elements, &sz, 3, chunks);
++}
++
++void** dlindependent_comalloc(size_t n_elements, size_t sizes[],
++                              void* chunks[]) {
++  return ialloc(gm, n_elements, sizes, 0, chunks);
++}
++
++size_t dlbulk_free(void* array[], size_t nelem) {
++  return internal_bulk_free(gm, array, nelem);
++}
++
++#if MALLOC_INSPECT_ALL
++void dlmalloc_inspect_all(void(*handler)(void *start,
++                                         void *end,
++                                         size_t used_bytes,
++                                         void* callback_arg),
++                          void* arg) {
++  ensure_initialization();
++  if (!PREACTION(gm)) {
++    internal_inspect_all(gm, handler, arg);
++    POSTACTION(gm);
++  }
++}
++#endif /* MALLOC_INSPECT_ALL */
++
++int dlmalloc_trim(size_t pad) {
++  int result = 0;
++  ensure_initialization();
++  if (!PREACTION(gm)) {
++    result = sys_trim(gm, pad);
++    POSTACTION(gm);
++  }
++  return result;
++}
++
++size_t dlmalloc_footprint(void) {
++  return gm->footprint;
++}
++
++size_t dlmalloc_max_footprint(void) {
++  return gm->max_footprint;
++}
++
++size_t dlmalloc_footprint_limit(void) {
++  size_t maf = gm->footprint_limit;
++  return maf == 0 ? MAX_SIZE_T : maf;
++}
++
++size_t dlmalloc_set_footprint_limit(size_t bytes) {
++  size_t result;  /* invert sense of 0 */
++  if (bytes == 0)
++    result = granularity_align(1); /* Use minimal size */
++  if (bytes == MAX_SIZE_T)
++    result = 0;                    /* disable */
++  else
++    result = granularity_align(bytes);
++  return gm->footprint_limit = result;
++}
++
++#if !NO_MALLINFO
++struct mallinfo dlmallinfo(void) {
++  return internal_mallinfo(gm);
++}
++#endif /* NO_MALLINFO */
++
++#if !NO_MALLOC_STATS
++void dlmalloc_stats() {
++  internal_malloc_stats(gm);
++}
++#endif /* NO_MALLOC_STATS */
++
++int dlmallopt(int param_number, int value) {
++  return change_mparam(param_number, value);
++}
++
++/* BEGIN android-changed: added const */
++size_t dlmalloc_usable_size(const void* mem) {
++/* END android-change */
++  if (mem != 0) {
++    mchunkptr p = mem2chunk(mem);
++    if (is_inuse(p))
++      return chunksize(p) - overhead_for(p);
++  }
++  return 0;
++}
++
++#endif /* !ONLY_MSPACES */
++
++/* ----------------------------- user mspaces ---------------------------- */
++
++#if MSPACES
++
++static mstate init_user_mstate(char* tbase, size_t tsize) {
++  size_t msize = pad_request(sizeof(struct malloc_state));
++  mchunkptr mn;
++  mchunkptr msp = align_as_chunk(tbase);
++  mstate m = (mstate)(chunk2mem(msp));
++  memset(m, 0, msize);
++  (void)INITIAL_LOCK(&m->mutex);
++  msp->head = (msize|INUSE_BITS);
++  m->seg.base = m->least_addr = tbase;
++  m->seg.size = m->footprint = m->max_footprint = tsize;
++  m->magic = mparams.magic;
++  m->release_checks = MAX_RELEASE_CHECK_RATE;
++  m->mflags = mparams.default_mflags;
++  m->extp = 0;
++  m->exts = 0;
++  disable_contiguous(m);
++  init_bins(m);
++  mn = next_chunk(mem2chunk(m));
++  init_top(m, mn, (size_t)((tbase + tsize) - (char*)mn) - TOP_FOOT_SIZE);
++  check_top_chunk(m, m->top);
++  return m;
++}
++
++mspace create_mspace(size_t capacity, int locked) {
++  mstate m = 0;
++  size_t msize;
++  ensure_initialization();
++  msize = pad_request(sizeof(struct malloc_state));
++  if (capacity < (size_t) -(msize + TOP_FOOT_SIZE + mparams.page_size)) {
++    size_t rs = ((capacity == 0)? mparams.granularity :
++                 (capacity + TOP_FOOT_SIZE + msize));
++    size_t tsize = granularity_align(rs);
++    char* tbase = (char*)(CALL_MMAP(tsize));
++    if (tbase != CMFAIL) {
++      m = init_user_mstate(tbase, tsize);
++      m->seg.sflags = USE_MMAP_BIT;
++      set_lock(m, locked);
++    }
++  }
++  return (mspace)m;
++}
++
++mspace create_mspace_with_base(void* base, size_t capacity, int locked) {
++  mstate m = 0;
++  size_t msize;
++  ensure_initialization();
++  msize = pad_request(sizeof(struct malloc_state));
++  if (capacity > msize + TOP_FOOT_SIZE &&
++      capacity < (size_t) -(msize + TOP_FOOT_SIZE + mparams.page_size)) {
++    m = init_user_mstate((char*)base, capacity);
++    m->seg.sflags = EXTERN_BIT;
++    set_lock(m, locked);
++  }
++  return (mspace)m;
++}
++
++int mspace_track_large_chunks(mspace msp, int enable) {
++  int ret = 0;
++  mstate ms = (mstate)msp;
++  if (!PREACTION(ms)) {
++    if (!use_mmap(ms)) {
++      ret = 1;
++    }
++    if (!enable) {
++      enable_mmap(ms);
++    } else {
++      disable_mmap(ms);
++    }
++    POSTACTION(ms);
++  }
++  return ret;
++}
++
++size_t destroy_mspace(mspace msp) {
++  size_t freed = 0;
++  mstate ms = (mstate)msp;
++  if (ok_magic(ms)) {
++    msegmentptr sp = &ms->seg;
++    (void)DESTROY_LOCK(&ms->mutex); /* destroy before unmapped */
++    while (sp != 0) {
++      char* base = sp->base;
++      size_t size = sp->size;
++      flag_t flag = sp->sflags;
++      (void)base; /* placate people compiling -Wunused-variable */
++      sp = sp->next;
++      if ((flag & USE_MMAP_BIT) && !(flag & EXTERN_BIT) &&
++          CALL_MUNMAP(base, size) == 0)
++        freed += size;
++    }
++  }
++  else {
++    USAGE_ERROR_ACTION(ms,ms);
++  }
++  return freed;
++}
++
++/*
++  mspace versions of routines are near-clones of the global
++  versions. This is not so nice but better than the alternatives.
++*/
++
++void* mspace_malloc(mspace msp, size_t bytes) {
++  mstate ms = (mstate)msp;
++  if (!ok_magic(ms)) {
++    USAGE_ERROR_ACTION(ms,ms);
++    return 0;
++  }
++  if (!PREACTION(ms)) {
++    void* mem;
++    size_t nb;
++    if (bytes <= MAX_SMALL_REQUEST) {
++      bindex_t idx;
++      binmap_t smallbits;
++      nb = (bytes < MIN_REQUEST)? MIN_CHUNK_SIZE : pad_request(bytes);
++      idx = small_index(nb);
++      smallbits = ms->smallmap >> idx;
++
++      if ((smallbits & 0x3U) != 0) { /* Remainderless fit to a smallbin. */
++        mchunkptr b, p;
++        idx += ~smallbits & 1;       /* Uses next bin if idx empty */
++        b = smallbin_at(ms, idx);
++        p = b->fd;
++        assert(chunksize(p) == small_index2size(idx));
++        unlink_first_small_chunk(ms, b, p, idx);
++        set_inuse_and_pinuse(ms, p, small_index2size(idx));
++        mem = chunk2mem(p);
++        check_malloced_chunk(ms, mem, nb);
++        goto postaction;
++      }
++
++      else if (nb > ms->dvsize) {
++        if (smallbits != 0) { /* Use chunk in next nonempty smallbin */
++          mchunkptr b, p, r;
++          size_t rsize;
++          bindex_t i;
++          binmap_t leftbits = (smallbits << idx) & left_bits(idx2bit(idx));
++          binmap_t leastbit = least_bit(leftbits);
++          compute_bit2idx(leastbit, i);
++          b = smallbin_at(ms, i);
++          p = b->fd;
++          assert(chunksize(p) == small_index2size(i));
++          unlink_first_small_chunk(ms, b, p, i);
++          rsize = small_index2size(i) - nb;
++          /* Fit here cannot be remainderless if 4byte sizes */
++          if (SIZE_T_SIZE != 4 && rsize < MIN_CHUNK_SIZE)
++            set_inuse_and_pinuse(ms, p, small_index2size(i));
++          else {
++            set_size_and_pinuse_of_inuse_chunk(ms, p, nb);
++            r = chunk_plus_offset(p, nb);
++            set_size_and_pinuse_of_free_chunk(r, rsize);
++            replace_dv(ms, r, rsize);
++          }
++          mem = chunk2mem(p);
++          check_malloced_chunk(ms, mem, nb);
++          goto postaction;
++        }
++
++        else if (ms->treemap != 0 && (mem = tmalloc_small(ms, nb)) != 0) {
++          check_malloced_chunk(ms, mem, nb);
++          goto postaction;
++        }
++      }
++    }
++    else if (bytes >= MAX_REQUEST)
++      nb = MAX_SIZE_T; /* Too big to allocate. Force failure (in sys alloc) */
++    else {
++      nb = pad_request(bytes);
++      if (ms->treemap != 0 && (mem = tmalloc_large(ms, nb)) != 0) {
++        check_malloced_chunk(ms, mem, nb);
++        goto postaction;
++      }
++    }
++
++    if (nb <= ms->dvsize) {
++      size_t rsize = ms->dvsize - nb;
++      mchunkptr p = ms->dv;
++      if (rsize >= MIN_CHUNK_SIZE) { /* split dv */
++        mchunkptr r = ms->dv = chunk_plus_offset(p, nb);
++        ms->dvsize = rsize;
++        set_size_and_pinuse_of_free_chunk(r, rsize);
++        set_size_and_pinuse_of_inuse_chunk(ms, p, nb);
++      }
++      else { /* exhaust dv */
++        size_t dvs = ms->dvsize;
++        ms->dvsize = 0;
++        ms->dv = 0;
++        set_inuse_and_pinuse(ms, p, dvs);
++      }
++      mem = chunk2mem(p);
++      check_malloced_chunk(ms, mem, nb);
++      goto postaction;
++    }
++
++    else if (nb < ms->topsize) { /* Split top */
++      size_t rsize = ms->topsize -= nb;
++      mchunkptr p = ms->top;
++      mchunkptr r = ms->top = chunk_plus_offset(p, nb);
++      r->head = rsize | PINUSE_BIT;
++      set_size_and_pinuse_of_inuse_chunk(ms, p, nb);
++      mem = chunk2mem(p);
++      check_top_chunk(ms, ms->top);
++      check_malloced_chunk(ms, mem, nb);
++      goto postaction;
++    }
++
++    mem = sys_alloc(ms, nb);
++
++  postaction:
++    POSTACTION(ms);
++    return mem;
++  }
++
++  return 0;
++}
++
++void mspace_free(mspace msp, void* mem) {
++  if (mem != 0) {
++    mchunkptr p  = mem2chunk(mem);
++#if FOOTERS
++    mstate fm = get_mstate_for(p);
++    (void)msp; /* placate people compiling -Wunused */
++#else /* FOOTERS */
++    mstate fm = (mstate)msp;
++#endif /* FOOTERS */
++    if (!ok_magic(fm)) {
++      USAGE_ERROR_ACTION(fm, p);
++      return;
++    }
++    if (!PREACTION(fm)) {
++      check_inuse_chunk(fm, p);
++      if (RTCHECK(ok_address(fm, p) && ok_inuse(p))) {
++        size_t psize = chunksize(p);
++        mchunkptr next = chunk_plus_offset(p, psize);
++        if (!pinuse(p)) {
++          size_t prevsize = p->prev_foot;
++          if (is_mmapped(p)) {
++            psize += prevsize + MMAP_FOOT_PAD;
++            if (CALL_MUNMAP((char*)p - prevsize, psize) == 0)
++              fm->footprint -= psize;
++            goto postaction;
++          }
++          else {
++            mchunkptr prev = chunk_minus_offset(p, prevsize);
++            psize += prevsize;
++            p = prev;
++            if (RTCHECK(ok_address(fm, prev))) { /* consolidate backward */
++              if (p != fm->dv) {
++                unlink_chunk(fm, p, prevsize);
++              }
++              else if ((next->head & INUSE_BITS) == INUSE_BITS) {
++                fm->dvsize = psize;
++                set_free_with_pinuse(p, psize, next);
++                goto postaction;
++              }
++            }
++            else
++              goto erroraction;
++          }
++        }
++
++        if (RTCHECK(ok_next(p, next) && ok_pinuse(next))) {
++          if (!cinuse(next)) {  /* consolidate forward */
++            if (next == fm->top) {
++              size_t tsize = fm->topsize += psize;
++              fm->top = p;
++              p->head = tsize | PINUSE_BIT;
++              if (p == fm->dv) {
++                fm->dv = 0;
++                fm->dvsize = 0;
++              }
++              if (should_trim(fm, tsize))
++                sys_trim(fm, 0);
++              goto postaction;
++            }
++            else if (next == fm->dv) {
++              size_t dsize = fm->dvsize += psize;
++              fm->dv = p;
++              set_size_and_pinuse_of_free_chunk(p, dsize);
++              goto postaction;
++            }
++            else {
++              size_t nsize = chunksize(next);
++              psize += nsize;
++              unlink_chunk(fm, next, nsize);
++              set_size_and_pinuse_of_free_chunk(p, psize);
++              if (p == fm->dv) {
++                fm->dvsize = psize;
++                goto postaction;
++              }
++            }
++          }
++          else
++            set_free_with_pinuse(p, psize, next);
++
++          if (is_small(psize)) {
++            insert_small_chunk(fm, p, psize);
++            check_free_chunk(fm, p);
++          }
++          else {
++            tchunkptr tp = (tchunkptr)p;
++            insert_large_chunk(fm, tp, psize);
++            check_free_chunk(fm, p);
++            if (--fm->release_checks == 0)
++              release_unused_segments(fm);
++          }
++          goto postaction;
++        }
++      }
++    erroraction:
++      USAGE_ERROR_ACTION(fm, p);
++    postaction:
++      POSTACTION(fm);
++    }
++  }
++}
++
++void* mspace_calloc(mspace msp, size_t n_elements, size_t elem_size) {
++  void* mem;
++  size_t req = 0;
++  mstate ms = (mstate)msp;
++  if (!ok_magic(ms)) {
++    USAGE_ERROR_ACTION(ms,ms);
++    return 0;
++  }
++  if (n_elements != 0) {
++    req = n_elements * elem_size;
++    if (((n_elements | elem_size) & ~(size_t)0xffff) &&
++        (req / n_elements != elem_size))
++      req = MAX_SIZE_T; /* force downstream failure on overflow */
++  }
++  mem = internal_malloc(ms, req);
++  if (mem != 0 && calloc_must_clear(mem2chunk(mem)))
++    memset(mem, 0, req);
++  return mem;
++}
++
++void* mspace_realloc(mspace msp, void* oldmem, size_t bytes) {
++  void* mem = 0;
++  if (oldmem == 0) {
++    mem = mspace_malloc(msp, bytes);
++  }
++  else if (bytes >= MAX_REQUEST) {
++    MALLOC_FAILURE_ACTION;
++  }
++#ifdef REALLOC_ZERO_BYTES_FREES
++  else if (bytes == 0) {
++    mspace_free(msp, oldmem);
++  }
++#endif /* REALLOC_ZERO_BYTES_FREES */
++  else {
++    size_t nb = request2size(bytes);
++    mchunkptr oldp = mem2chunk(oldmem);
++#if ! FOOTERS
++    mstate m = (mstate)msp;
++#else /* FOOTERS */
++    mstate m = get_mstate_for(oldp);
++    if (!ok_magic(m)) {
++      USAGE_ERROR_ACTION(m, oldmem);
++      return 0;
++    }
++#endif /* FOOTERS */
++    if (!PREACTION(m)) {
++      mchunkptr newp = try_realloc_chunk(m, oldp, nb, 1);
++      POSTACTION(m);
++      if (newp != 0) {
++        check_inuse_chunk(m, newp);
++        mem = chunk2mem(newp);
++      }
++      else {
++        mem = mspace_malloc(m, bytes);
++        if (mem != 0) {
++          size_t oc = chunksize(oldp) - overhead_for(oldp);
++          memcpy(mem, oldmem, (oc < bytes)? oc : bytes);
++          mspace_free(m, oldmem);
++        }
++      }
++    }
++  }
++  return mem;
++}
++
++void* mspace_realloc_in_place(mspace msp, void* oldmem, size_t bytes) {
++  void* mem = 0;
++  if (oldmem != 0) {
++    if (bytes >= MAX_REQUEST) {
++      MALLOC_FAILURE_ACTION;
++    }
++    else {
++      size_t nb = request2size(bytes);
++      mchunkptr oldp = mem2chunk(oldmem);
++#if ! FOOTERS
++      mstate m = (mstate)msp;
++#else /* FOOTERS */
++      mstate m = get_mstate_for(oldp);
++      (void)msp; /* placate people compiling -Wunused */
++      if (!ok_magic(m)) {
++        USAGE_ERROR_ACTION(m, oldmem);
++        return 0;
++      }
++#endif /* FOOTERS */
++      if (!PREACTION(m)) {
++        mchunkptr newp = try_realloc_chunk(m, oldp, nb, 0);
++        POSTACTION(m);
++        if (newp == oldp) {
++          check_inuse_chunk(m, newp);
++          mem = oldmem;
++        }
++      }
++    }
++  }
++  return mem;
++}
++
++void* mspace_memalign(mspace msp, size_t alignment, size_t bytes) {
++  mstate ms = (mstate)msp;
++  if (!ok_magic(ms)) {
++    USAGE_ERROR_ACTION(ms,ms);
++    return 0;
++  }
++  if (alignment <= MALLOC_ALIGNMENT)
++    return mspace_malloc(msp, bytes);
++  return internal_memalign(ms, alignment, bytes);
++}
++
++void** mspace_independent_calloc(mspace msp, size_t n_elements,
++                                 size_t elem_size, void* chunks[]) {
++  size_t sz = elem_size; /* serves as 1-element array */
++  mstate ms = (mstate)msp;
++  if (!ok_magic(ms)) {
++    USAGE_ERROR_ACTION(ms,ms);
++    return 0;
++  }
++  return ialloc(ms, n_elements, &sz, 3, chunks);
++}
++
++void** mspace_independent_comalloc(mspace msp, size_t n_elements,
++                                   size_t sizes[], void* chunks[]) {
++  mstate ms = (mstate)msp;
++  if (!ok_magic(ms)) {
++    USAGE_ERROR_ACTION(ms,ms);
++    return 0;
++  }
++  return ialloc(ms, n_elements, sizes, 0, chunks);
++}
++
++size_t mspace_bulk_free(mspace msp, void* array[], size_t nelem) {
++  return internal_bulk_free((mstate)msp, array, nelem);
++}
++
++#if MALLOC_INSPECT_ALL
++void mspace_inspect_all(mspace msp,
++                        void(*handler)(void *start,
++                                       void *end,
++                                       size_t used_bytes,
++                                       void* callback_arg),
++                        void* arg) {
++  mstate ms = (mstate)msp;
++  if (ok_magic(ms)) {
++    if (!PREACTION(ms)) {
++      internal_inspect_all(ms, handler, arg);
++      POSTACTION(ms);
++    }
++  }
++  else {
++    USAGE_ERROR_ACTION(ms,ms);
++  }
++}
++#endif /* MALLOC_INSPECT_ALL */
++
++int mspace_trim(mspace msp, size_t pad) {
++  int result = 0;
++  mstate ms = (mstate)msp;
++  if (ok_magic(ms)) {
++    if (!PREACTION(ms)) {
++      result = sys_trim(ms, pad);
++      POSTACTION(ms);
++    }
++  }
++  else {
++    USAGE_ERROR_ACTION(ms,ms);
++  }
++  return result;
++}
++
++#if !NO_MALLOC_STATS
++void mspace_malloc_stats(mspace msp) {
++  mstate ms = (mstate)msp;
++  if (ok_magic(ms)) {
++    internal_malloc_stats(ms);
++  }
++  else {
++    USAGE_ERROR_ACTION(ms,ms);
++  }
++}
++#endif /* NO_MALLOC_STATS */
++
++size_t mspace_footprint(mspace msp) {
++  size_t result = 0;
++  mstate ms = (mstate)msp;
++  if (ok_magic(ms)) {
++    result = ms->footprint;
++  }
++  else {
++    USAGE_ERROR_ACTION(ms,ms);
++  }
++  return result;
++}
++
++size_t mspace_max_footprint(mspace msp) {
++  size_t result = 0;
++  mstate ms = (mstate)msp;
++  if (ok_magic(ms)) {
++    result = ms->max_footprint;
++  }
++  else {
++    USAGE_ERROR_ACTION(ms,ms);
++  }
++  return result;
++}
++
++size_t mspace_footprint_limit(mspace msp) {
++  size_t result = 0;
++  mstate ms = (mstate)msp;
++  if (ok_magic(ms)) {
++    size_t maf = ms->footprint_limit;
++    result = (maf == 0) ? MAX_SIZE_T : maf;
++  }
++  else {
++    USAGE_ERROR_ACTION(ms,ms);
++  }
++  return result;
++}
++
++size_t mspace_set_footprint_limit(mspace msp, size_t bytes) {
++  size_t result = 0;
++  mstate ms = (mstate)msp;
++  if (ok_magic(ms)) {
++    if (bytes == 0)
++      result = granularity_align(1); /* Use minimal size */
++    if (bytes == MAX_SIZE_T)
++      result = 0;                    /* disable */
++    else
++      result = granularity_align(bytes);
++    ms->footprint_limit = result;
++  }
++  else {
++    USAGE_ERROR_ACTION(ms,ms);
++  }
++  return result;
++}
++
++#if !NO_MALLINFO
++struct mallinfo mspace_mallinfo(mspace msp) {
++  mstate ms = (mstate)msp;
++  if (!ok_magic(ms)) {
++    USAGE_ERROR_ACTION(ms,ms);
++  }
++  return internal_mallinfo(ms);
++}
++#endif /* NO_MALLINFO */
++
++size_t mspace_usable_size(const void* mem) {
++  if (mem != 0) {
++    mchunkptr p = mem2chunk(mem);
++    if (is_inuse(p))
++      return chunksize(p) - overhead_for(p);
++  }
++  return 0;
++}
++
++int mspace_mallopt(int param_number, int value) {
++  return change_mparam(param_number, value);
++}
++
++#endif /* MSPACES */
++
++
++/* -------------------- Alternative MORECORE functions ------------------- */
++
++/*
++  Guidelines for creating a custom version of MORECORE:
++
++  * For best performance, MORECORE should allocate in multiples of pagesize.
++  * MORECORE may allocate more memory than requested. (Or even less,
++      but this will usually result in a malloc failure.)
++  * MORECORE must not allocate memory when given argument zero, but
++      instead return one past the end address of memory from previous
++      nonzero call.
++  * For best performance, consecutive calls to MORECORE with positive
++      arguments should return increasing addresses, indicating that
++      space has been contiguously extended.
++  * Even though consecutive calls to MORECORE need not return contiguous
++      addresses, it must be OK for malloc'ed chunks to span multiple
++      regions in those cases where they do happen to be contiguous.
++  * MORECORE need not handle negative arguments -- it may instead
++      just return MFAIL when given negative arguments.
++      Negative arguments are always multiples of pagesize. MORECORE
++      must not misinterpret negative args as large positive unsigned
++      args. You can suppress all such calls from even occurring by defining
++      MORECORE_CANNOT_TRIM,
++
++  As an example alternative MORECORE, here is a custom allocator
++  kindly contributed for pre-OSX macOS.  It uses virtually but not
++  necessarily physically contiguous non-paged memory (locked in,
++  present and won't get swapped out).  You can use it by uncommenting
++  this section, adding some #includes, and setting up the appropriate
++  defines above:
++
++      #define MORECORE osMoreCore
++
++  There is also a shutdown routine that should somehow be called for
++  cleanup upon program exit.
++
++  #define MAX_POOL_ENTRIES 100
++  #define MINIMUM_MORECORE_SIZE  (64 * 1024U)
++  static int next_os_pool;
++  void *our_os_pools[MAX_POOL_ENTRIES];
++
++  void *osMoreCore(int size)
++  {
++    void *ptr = 0;
++    static void *sbrk_top = 0;
++
++    if (size > 0)
++    {
++      if (size < MINIMUM_MORECORE_SIZE)
++         size = MINIMUM_MORECORE_SIZE;
++      if (CurrentExecutionLevel() == kTaskLevel)
++         ptr = PoolAllocateResident(size + RM_PAGE_SIZE, 0);
++      if (ptr == 0)
++      {
++        return (void *) MFAIL;
++      }
++      // save ptrs so they can be freed during cleanup
++      our_os_pools[next_os_pool] = ptr;
++      next_os_pool++;
++      ptr = (void *) ((((size_t) ptr) + RM_PAGE_MASK) & ~RM_PAGE_MASK);
++      sbrk_top = (char *) ptr + size;
++      return ptr;
++    }
++    else if (size < 0)
++    {
++      // we don't currently support shrink behavior
++      return (void *) MFAIL;
++    }
++    else
++    {
++      return sbrk_top;
++    }
++  }
++
++  // cleanup any allocated memory pools
++  // called as last thing before shutting down driver
++
++  void osCleanupMem(void)
++  {
++    void **ptr;
++
++    for (ptr = our_os_pools; ptr < &our_os_pools[MAX_POOL_ENTRIES]; ptr++)
++      if (*ptr)
++      {
++         PoolDeallocate(*ptr);
++         *ptr = 0;
++      }
++  }
++
++*/
++
++
++/* -----------------------------------------------------------------------
++History:
++    v2.8.6 Wed Aug 29 06:57:58 2012  Doug Lea
++      * fix bad comparison in dlposix_memalign
++      * don't reuse adjusted asize in sys_alloc
++      * add LOCK_AT_FORK -- thanks to Kirill Artamonov for the suggestion
++      * reduce compiler warnings -- thanks to all who reported/suggested these
++
++    v2.8.5 Sun May 22 10:26:02 2011  Doug Lea  (dl at gee)
++      * Always perform unlink checks unless INSECURE
++      * Add posix_memalign.
++      * Improve realloc to expand in more cases; expose realloc_in_place.
++        Thanks to Peter Buhr for the suggestion.
++      * Add footprint_limit, inspect_all, bulk_free. Thanks
++        to Barry Hayes and others for the suggestions.
++      * Internal refactorings to avoid calls while holding locks
++      * Use non-reentrant locks by default. Thanks to Roland McGrath
++        for the suggestion.
++      * Small fixes to mspace_destroy, reset_on_error.
++      * Various configuration extensions/changes. Thanks
++         to all who contributed these.
++
++    V2.8.4a Thu Apr 28 14:39:43 2011 (dl at gee.cs.oswego.edu)
++      * Update Creative Commons URL
++
++    V2.8.4 Wed May 27 09:56:23 2009  Doug Lea  (dl at gee)
++      * Use zeros instead of prev foot for is_mmapped
++      * Add mspace_track_large_chunks; thanks to Jean Brouwers
++      * Fix set_inuse in internal_realloc; thanks to Jean Brouwers
++      * Fix insufficient sys_alloc padding when using 16byte alignment
++      * Fix bad error check in mspace_footprint
++      * Adaptations for ptmalloc; thanks to Wolfram Gloger.
++      * Reentrant spin locks; thanks to Earl Chew and others
++      * Win32 improvements; thanks to Niall Douglas and Earl Chew
++      * Add NO_SEGMENT_TRAVERSAL and MAX_RELEASE_CHECK_RATE options
++      * Extension hook in malloc_state
++      * Various small adjustments to reduce warnings on some compilers
++      * Various configuration extensions/changes for more platforms. Thanks
++         to all who contributed these.
++
++    V2.8.3 Thu Sep 22 11:16:32 2005  Doug Lea  (dl at gee)
++      * Add max_footprint functions
++      * Ensure all appropriate literals are size_t
++      * Fix conditional compilation problem for some #define settings
++      * Avoid concatenating segments with the one provided
++        in create_mspace_with_base
++      * Rename some variables to avoid compiler shadowing warnings
++      * Use explicit lock initialization.
++      * Better handling of sbrk interference.
++      * Simplify and fix segment insertion, trimming and mspace_destroy
++      * Reinstate REALLOC_ZERO_BYTES_FREES option from 2.7.x
++      * Thanks especially to Dennis Flanagan for help on these.
++
++    V2.8.2 Sun Jun 12 16:01:10 2005  Doug Lea  (dl at gee)
++      * Fix memalign brace error.
++
++    V2.8.1 Wed Jun  8 16:11:46 2005  Doug Lea  (dl at gee)
++      * Fix improper #endif nesting in C++
++      * Add explicit casts needed for C++
++
++    V2.8.0 Mon May 30 14:09:02 2005  Doug Lea  (dl at gee)
++      * Use trees for large bins
++      * Support mspaces
++      * Use segments to unify sbrk-based and mmap-based system allocation,
++        removing need for emulation on most platforms without sbrk.
++      * Default safety checks
++      * Optional footer checks. Thanks to William Robertson for the idea.
++      * Internal code refactoring
++      * Incorporate suggestions and platform-specific changes.
++        Thanks to Dennis Flanagan, Colin Plumb, Niall Douglas,
++        Aaron Bachmann,  Emery Berger, and others.
++      * Speed up non-fastbin processing enough to remove fastbins.
++      * Remove useless cfree() to avoid conflicts with other apps.
++      * Remove internal memcpy, memset. Compilers handle builtins better.
++      * Remove some options that no one ever used and rename others.
++
++    V2.7.2 Sat Aug 17 09:07:30 2002  Doug Lea  (dl at gee)
++      * Fix malloc_state bitmap array misdeclaration
++
++    V2.7.1 Thu Jul 25 10:58:03 2002  Doug Lea  (dl at gee)
++      * Allow tuning of FIRST_SORTED_BIN_SIZE
++      * Use PTR_UINT as type for all ptr->int casts. Thanks to John Belmonte.
++      * Better detection and support for non-contiguousness of MORECORE.
++        Thanks to Andreas Mueller, Conal Walsh, and Wolfram Gloger
++      * Bypass most of malloc if no frees. Thanks To Emery Berger.
++      * Fix freeing of old top non-contiguous chunk im sysmalloc.
++      * Raised default trim and map thresholds to 256K.
++      * Fix mmap-related #defines. Thanks to Lubos Lunak.
++      * Fix copy macros; added LACKS_FCNTL_H. Thanks to Neal Walfield.
++      * Branch-free bin calculation
++      * Default trim and mmap thresholds now 256K.
++
++    V2.7.0 Sun Mar 11 14:14:06 2001  Doug Lea  (dl at gee)
++      * Introduce independent_comalloc and independent_calloc.
++        Thanks to Michael Pachos for motivation and help.
++      * Make optional .h file available
++      * Allow > 2GB requests on 32bit systems.
++      * new WIN32 sbrk, mmap, munmap, lock code from <Walter@GeNeSys-e.de>.
++        Thanks also to Andreas Mueller <a.mueller at paradatec.de>,
++        and Anonymous.
++      * Allow override of MALLOC_ALIGNMENT (Thanks to Ruud Waij for
++        helping test this.)
++      * memalign: check alignment arg
++      * realloc: don't try to shift chunks backwards, since this
++        leads to  more fragmentation in some programs and doesn't
++        seem to help in any others.
++      * Collect all cases in malloc requiring system memory into sysmalloc
++      * Use mmap as backup to sbrk
++      * Place all internal state in malloc_state
++      * Introduce fastbins (although similar to 2.5.1)
++      * Many minor tunings and cosmetic improvements
++      * Introduce USE_PUBLIC_MALLOC_WRAPPERS, USE_MALLOC_LOCK
++      * Introduce MALLOC_FAILURE_ACTION, MORECORE_CONTIGUOUS
++        Thanks to Tony E. Bennett <tbennett@nvidia.com> and others.
++      * Include errno.h to support default failure action.
++
++    V2.6.6 Sun Dec  5 07:42:19 1999  Doug Lea  (dl at gee)
++      * return null for negative arguments
++      * Added Several WIN32 cleanups from Martin C. Fong <mcfong at yahoo.com>
++         * Add 'LACKS_SYS_PARAM_H' for those systems without 'sys/param.h'
++          (e.g. WIN32 platforms)
++         * Cleanup header file inclusion for WIN32 platforms
++         * Cleanup code to avoid Microsoft Visual C++ compiler complaints
++         * Add 'USE_DL_PREFIX' to quickly allow co-existence with existing
++           memory allocation routines
++         * Set 'malloc_getpagesize' for WIN32 platforms (needs more work)
++         * Use 'assert' rather than 'ASSERT' in WIN32 code to conform to
++           usage of 'assert' in non-WIN32 code
++         * Improve WIN32 'sbrk()' emulation's 'findRegion()' routine to
++           avoid infinite loop
++      * Always call 'fREe()' rather than 'free()'
++
++    V2.6.5 Wed Jun 17 15:57:31 1998  Doug Lea  (dl at gee)
++      * Fixed ordering problem with boundary-stamping
++
++    V2.6.3 Sun May 19 08:17:58 1996  Doug Lea  (dl at gee)
++      * Added pvalloc, as recommended by H.J. Liu
++      * Added 64bit pointer support mainly from Wolfram Gloger
++      * Added anonymously donated WIN32 sbrk emulation
++      * Malloc, calloc, getpagesize: add optimizations from Raymond Nijssen
++      * malloc_extend_top: fix mask error that caused wastage after
++        foreign sbrks
++      * Add linux mremap support code from HJ Liu
++
++    V2.6.2 Tue Dec  5 06:52:55 1995  Doug Lea  (dl at gee)
++      * Integrated most documentation with the code.
++      * Add support for mmap, with help from
++        Wolfram Gloger (Gloger@lrz.uni-muenchen.de).
++      * Use last_remainder in more cases.
++      * Pack bins using idea from  colin@nyx10.cs.du.edu
++      * Use ordered bins instead of best-fit threshhold
++      * Eliminate block-local decls to simplify tracing and debugging.
++      * Support another case of realloc via move into top
++      * Fix error occuring when initial sbrk_base not word-aligned.
++      * Rely on page size for units instead of SBRK_UNIT to
++        avoid surprises about sbrk alignment conventions.
++      * Add mallinfo, mallopt. Thanks to Raymond Nijssen
++        (raymond@es.ele.tue.nl) for the suggestion.
++      * Add `pad' argument to malloc_trim and top_pad mallopt parameter.
++      * More precautions for cases where other routines call sbrk,
++        courtesy of Wolfram Gloger (Gloger@lrz.uni-muenchen.de).
++      * Added macros etc., allowing use in linux libc from
++        H.J. Lu (hjl@gnu.ai.mit.edu)
++      * Inverted this history list
++
++    V2.6.1 Sat Dec  2 14:10:57 1995  Doug Lea  (dl at gee)
++      * Re-tuned and fixed to behave more nicely with V2.6.0 changes.
++      * Removed all preallocation code since under current scheme
++        the work required to undo bad preallocations exceeds
++        the work saved in good cases for most test programs.
++      * No longer use return list or unconsolidated bins since
++        no scheme using them consistently outperforms those that don't
++        given above changes.
++      * Use best fit for very large chunks to prevent some worst-cases.
++      * Added some support for debugging
++
++    V2.6.0 Sat Nov  4 07:05:23 1995  Doug Lea  (dl at gee)
++      * Removed footers when chunks are in use. Thanks to
++        Paul Wilson (wilson@cs.texas.edu) for the suggestion.
++
++    V2.5.4 Wed Nov  1 07:54:51 1995  Doug Lea  (dl at gee)
++      * Added malloc_trim, with help from Wolfram Gloger
++        (wmglo@Dent.MED.Uni-Muenchen.DE).
++
++    V2.5.3 Tue Apr 26 10:16:01 1994  Doug Lea  (dl at g)
++
++    V2.5.2 Tue Apr  5 16:20:40 1994  Doug Lea  (dl at g)
++      * realloc: try to expand in both directions
++      * malloc: swap order of clean-bin strategy;
++      * realloc: only conditionally expand backwards
++      * Try not to scavenge used bins
++      * Use bin counts as a guide to preallocation
++      * Occasionally bin return list chunks in first scan
++      * Add a few optimizations from colin@nyx10.cs.du.edu
++
++    V2.5.1 Sat Aug 14 15:40:43 1993  Doug Lea  (dl at g)
++      * faster bin computation & slightly different binning
++      * merged all consolidations to one part of malloc proper
++         (eliminating old malloc_find_space & malloc_clean_bin)
++      * Scan 2 returns chunks (not just 1)
++      * Propagate failure in realloc if malloc returns 0
++      * Add stuff to allow compilation on non-ANSI compilers
++          from kpv@research.att.com
++
++    V2.5 Sat Aug  7 07:41:59 1993  Doug Lea  (dl at g.oswego.edu)
++      * removed potential for odd address access in prev_chunk
++      * removed dependency on getpagesize.h
++      * misc cosmetics and a bit more internal documentation
++      * anticosmetics: mangled names in macros to evade debugger strangeness
++      * tested on sparc, hp-700, dec-mips, rs6000
++          with gcc & native cc (hp, dec only) allowing
++          Detlefs & Zorn comparison study (in SIGPLAN Notices.)
++
++    Trial version Fri Aug 28 13:14:29 1992  Doug Lea  (dl at g.oswego.edu)
++      * Based loosely on libg++-1.2X malloc. (It retains some of the overall
++         structure of old version,  but most details differ.)
++
++*/
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..e52c9e5a412aaa20e682c7cd354516160591ca9a
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,620 @@@
++/*
++  Default header file for malloc-2.8.x, written by Doug Lea
++  and released to the public domain, as explained at
++  http://creativecommons.org/publicdomain/zero/1.0/ 
++ 
++  This header is for ANSI C/C++ only.  You can set any of
++  the following #defines before including:
++
++  * If USE_DL_PREFIX is defined, it is assumed that malloc.c 
++    was also compiled with this option, so all routines
++    have names starting with "dl".
++
++  * If HAVE_USR_INCLUDE_MALLOC_H is defined, it is assumed that this
++    file will be #included AFTER <malloc.h>. This is needed only if
++    your system defines a struct mallinfo that is incompatible with the
++    standard one declared here.  Otherwise, you can include this file
++    INSTEAD of your system system <malloc.h>.  At least on ANSI, all
++    declarations should be compatible with system versions
++
++  * If MSPACES is defined, declarations for mspace versions are included.
++*/
++
++#ifndef MALLOC_280_H
++#define MALLOC_280_H
++
++#ifdef __cplusplus
++extern "C" {
++#endif
++
++#include <stddef.h>   /* for size_t */
++
++#ifndef ONLY_MSPACES
++#define ONLY_MSPACES 0     /* define to a value */
++#elif ONLY_MSPACES != 0
++#define ONLY_MSPACES 1
++#endif  /* ONLY_MSPACES */
++#ifndef NO_MALLINFO
++#define NO_MALLINFO 0
++#endif  /* NO_MALLINFO */
++
++#ifndef MSPACES
++#if ONLY_MSPACES
++#define MSPACES 1
++#else   /* ONLY_MSPACES */
++#define MSPACES 0
++#endif  /* ONLY_MSPACES */
++#endif  /* MSPACES */
++
++#if !ONLY_MSPACES
++
++#ifndef USE_DL_PREFIX
++#define dlcalloc               calloc
++#define dlfree                 free
++#define dlmalloc               malloc
++#define dlmemalign             memalign
++#define dlposix_memalign       posix_memalign
++#define dlrealloc              realloc
++#define dlvalloc               valloc
++#define dlpvalloc              pvalloc
++#define dlmallinfo             mallinfo
++#define dlmallopt              mallopt
++#define dlmalloc_trim          malloc_trim
++#define dlmalloc_stats         malloc_stats
++#define dlmalloc_usable_size   malloc_usable_size
++#define dlmalloc_footprint     malloc_footprint
++#define dlmalloc_max_footprint malloc_max_footprint
++#define dlmalloc_footprint_limit malloc_footprint_limit
++#define dlmalloc_set_footprint_limit malloc_set_footprint_limit
++#define dlmalloc_inspect_all   malloc_inspect_all
++#define dlindependent_calloc   independent_calloc
++#define dlindependent_comalloc independent_comalloc
++#define dlbulk_free            bulk_free
++#endif /* USE_DL_PREFIX */
++
++#if !NO_MALLINFO 
++#ifndef HAVE_USR_INCLUDE_MALLOC_H
++#ifndef _MALLOC_H
++#ifndef MALLINFO_FIELD_TYPE
++#define MALLINFO_FIELD_TYPE size_t
++#endif /* MALLINFO_FIELD_TYPE */
++#ifndef STRUCT_MALLINFO_DECLARED
++#define STRUCT_MALLINFO_DECLARED 1
++struct mallinfo {
++  MALLINFO_FIELD_TYPE arena;    /* non-mmapped space allocated from system */
++  MALLINFO_FIELD_TYPE ordblks;  /* number of free chunks */
++  MALLINFO_FIELD_TYPE smblks;   /* always 0 */
++  MALLINFO_FIELD_TYPE hblks;    /* always 0 */
++  MALLINFO_FIELD_TYPE hblkhd;   /* space in mmapped regions */
++  MALLINFO_FIELD_TYPE usmblks;  /* maximum total allocated space */
++  MALLINFO_FIELD_TYPE fsmblks;  /* always 0 */
++  MALLINFO_FIELD_TYPE uordblks; /* total allocated space */
++  MALLINFO_FIELD_TYPE fordblks; /* total free space */
++  MALLINFO_FIELD_TYPE keepcost; /* releasable (via malloc_trim) space */
++};
++#endif /* STRUCT_MALLINFO_DECLARED */
++#endif  /* _MALLOC_H */
++#endif  /* HAVE_USR_INCLUDE_MALLOC_H */
++#endif  /* !NO_MALLINFO */
++
++/*
++  malloc(size_t n)
++  Returns a pointer to a newly allocated chunk of at least n bytes, or
++  null if no space is available, in which case errno is set to ENOMEM
++  on ANSI C systems.
++
++  If n is zero, malloc returns a minimum-sized chunk. (The minimum
++  size is 16 bytes on most 32bit systems, and 32 bytes on 64bit
++  systems.)  Note that size_t is an unsigned type, so calls with
++  arguments that would be negative if signed are interpreted as
++  requests for huge amounts of space, which will often fail. The
++  maximum supported value of n differs across systems, but is in all
++  cases less than the maximum representable value of a size_t.
++*/
++void* dlmalloc(size_t);
++
++/*
++  free(void* p)
++  Releases the chunk of memory pointed to by p, that had been previously
++  allocated using malloc or a related routine such as realloc.
++  It has no effect if p is null. If p was not malloced or already
++  freed, free(p) will by default cuase the current program to abort.
++*/
++void  dlfree(void*);
++
++/*
++  calloc(size_t n_elements, size_t element_size);
++  Returns a pointer to n_elements * element_size bytes, with all locations
++  set to zero.
++*/
++void* dlcalloc(size_t, size_t);
++
++/*
++  realloc(void* p, size_t n)
++  Returns a pointer to a chunk of size n that contains the same data
++  as does chunk p up to the minimum of (n, p's size) bytes, or null
++  if no space is available.
++
++  The returned pointer may or may not be the same as p. The algorithm
++  prefers extending p in most cases when possible, otherwise it
++  employs the equivalent of a malloc-copy-free sequence.
++
++  If p is null, realloc is equivalent to malloc.
++
++  If space is not available, realloc returns null, errno is set (if on
++  ANSI) and p is NOT freed.
++
++  if n is for fewer bytes than already held by p, the newly unused
++  space is lopped off and freed if possible.  realloc with a size
++  argument of zero (re)allocates a minimum-sized chunk.
++
++  The old unix realloc convention of allowing the last-free'd chunk
++  to be used as an argument to realloc is not supported.
++*/
++void* dlrealloc(void*, size_t);
++
++/*
++  realloc_in_place(void* p, size_t n)
++  Resizes the space allocated for p to size n, only if this can be
++  done without moving p (i.e., only if there is adjacent space
++  available if n is greater than p's current allocated size, or n is
++  less than or equal to p's size). This may be used instead of plain
++  realloc if an alternative allocation strategy is needed upon failure
++  to expand space; for example, reallocation of a buffer that must be
++  memory-aligned or cleared. You can use realloc_in_place to trigger
++  these alternatives only when needed.
++
++  Returns p if successful; otherwise null.
++*/
++void* dlrealloc_in_place(void*, size_t);
++
++/*
++  memalign(size_t alignment, size_t n);
++  Returns a pointer to a newly allocated chunk of n bytes, aligned
++  in accord with the alignment argument.
++
++  The alignment argument should be a power of two. If the argument is
++  not a power of two, the nearest greater power is used.
++  8-byte alignment is guaranteed by normal malloc calls, so don't
++  bother calling memalign with an argument of 8 or less.
++
++  Overreliance on memalign is a sure way to fragment space.
++*/
++void* dlmemalign(size_t, size_t);
++
++/*
++  int posix_memalign(void** pp, size_t alignment, size_t n);
++  Allocates a chunk of n bytes, aligned in accord with the alignment
++  argument. Differs from memalign only in that it (1) assigns the
++  allocated memory to *pp rather than returning it, (2) fails and
++  returns EINVAL if the alignment is not a power of two (3) fails and
++  returns ENOMEM if memory cannot be allocated.
++*/
++int dlposix_memalign(void**, size_t, size_t);
++
++/*
++  valloc(size_t n);
++  Equivalent to memalign(pagesize, n), where pagesize is the page
++  size of the system. If the pagesize is unknown, 4096 is used.
++*/
++void* dlvalloc(size_t);
++
++/*
++  mallopt(int parameter_number, int parameter_value)
++  Sets tunable parameters The format is to provide a
++  (parameter-number, parameter-value) pair.  mallopt then sets the
++  corresponding parameter to the argument value if it can (i.e., so
++  long as the value is meaningful), and returns 1 if successful else
++  0.  SVID/XPG/ANSI defines four standard param numbers for mallopt,
++  normally defined in malloc.h.  None of these are use in this malloc,
++  so setting them has no effect. But this malloc also supports other
++  options in mallopt:
++
++  Symbol            param #  default    allowed param values
++  M_TRIM_THRESHOLD     -1   2*1024*1024   any   (-1U disables trimming)
++  M_GRANULARITY        -2     page size   any power of 2 >= page size
++  M_MMAP_THRESHOLD     -3      256*1024   any   (or 0 if no MMAP support)
++*/
++int dlmallopt(int, int);
++
++#define M_TRIM_THRESHOLD     (-1)
++#define M_GRANULARITY        (-2)
++#define M_MMAP_THRESHOLD     (-3)
++
++
++/*
++  malloc_footprint();
++  Returns the number of bytes obtained from the system.  The total
++  number of bytes allocated by malloc, realloc etc., is less than this
++  value. Unlike mallinfo, this function returns only a precomputed
++  result, so can be called frequently to monitor memory consumption.
++  Even if locks are otherwise defined, this function does not use them,
++  so results might not be up to date.
++*/
++size_t dlmalloc_footprint(void);
++
++/*
++  malloc_max_footprint();
++  Returns the maximum number of bytes obtained from the system. This
++  value will be greater than current footprint if deallocated space
++  has been reclaimed by the system. The peak number of bytes allocated
++  by malloc, realloc etc., is less than this value. Unlike mallinfo,
++  this function returns only a precomputed result, so can be called
++  frequently to monitor memory consumption.  Even if locks are
++  otherwise defined, this function does not use them, so results might
++  not be up to date.
++*/
++size_t dlmalloc_max_footprint(void);
++
++/*
++  malloc_footprint_limit();
++  Returns the number of bytes that the heap is allowed to obtain from
++  the system, returning the last value returned by
++  malloc_set_footprint_limit, or the maximum size_t value if
++  never set. The returned value reflects a permission. There is no
++  guarantee that this number of bytes can actually be obtained from
++  the system.  
++*/
++size_t dlmalloc_footprint_limit(void);
++
++/*
++  malloc_set_footprint_limit();
++  Sets the maximum number of bytes to obtain from the system, causing
++  failure returns from malloc and related functions upon attempts to
++  exceed this value. The argument value may be subject to page
++  rounding to an enforceable limit; this actual value is returned.
++  Using an argument of the maximum possible size_t effectively
++  disables checks. If the argument is less than or equal to the
++  current malloc_footprint, then all future allocations that require
++  additional system memory will fail. However, invocation cannot
++  retroactively deallocate existing used memory.
++*/
++size_t dlmalloc_set_footprint_limit(size_t bytes);
++
++/*
++  malloc_inspect_all(void(*handler)(void *start,
++                                    void *end,
++                                    size_t used_bytes,
++                                    void* callback_arg),
++                      void* arg);
++  Traverses the heap and calls the given handler for each managed
++  region, skipping all bytes that are (or may be) used for bookkeeping
++  purposes.  Traversal does not include include chunks that have been
++  directly memory mapped. Each reported region begins at the start
++  address, and continues up to but not including the end address.  The
++  first used_bytes of the region contain allocated data. If
++  used_bytes is zero, the region is unallocated. The handler is
++  invoked with the given callback argument. If locks are defined, they
++  are held during the entire traversal. It is a bad idea to invoke
++  other malloc functions from within the handler.
++
++  For example, to count the number of in-use chunks with size greater
++  than 1000, you could write:
++  static int count = 0;
++  void count_chunks(void* start, void* end, size_t used, void* arg) {
++    if (used >= 1000) ++count;
++  }
++  then:
++    malloc_inspect_all(count_chunks, NULL);
++
++  malloc_inspect_all is compiled only if MALLOC_INSPECT_ALL is defined.
++*/
++void dlmalloc_inspect_all(void(*handler)(void*, void *, size_t, void*),
++                           void* arg);
++
++#if !NO_MALLINFO
++/*
++  mallinfo()
++  Returns (by copy) a struct containing various summary statistics:
++
++  arena:     current total non-mmapped bytes allocated from system
++  ordblks:   the number of free chunks
++  smblks:    always zero.
++  hblks:     current number of mmapped regions
++  hblkhd:    total bytes held in mmapped regions
++  usmblks:   the maximum total allocated space. This will be greater
++                than current total if trimming has occurred.
++  fsmblks:   always zero
++  uordblks:  current total allocated space (normal or mmapped)
++  fordblks:  total free space
++  keepcost:  the maximum number of bytes that could ideally be released
++               back to system via malloc_trim. ("ideally" means that
++               it ignores page restrictions etc.)
++
++  Because these fields are ints, but internal bookkeeping may
++  be kept as longs, the reported values may wrap around zero and
++  thus be inaccurate.
++*/
++
++struct mallinfo dlmallinfo(void);
++#endif  /* NO_MALLINFO */
++
++/*
++  independent_calloc(size_t n_elements, size_t element_size, void* chunks[]);
++
++  independent_calloc is similar to calloc, but instead of returning a
++  single cleared space, it returns an array of pointers to n_elements
++  independent elements that can hold contents of size elem_size, each
++  of which starts out cleared, and can be independently freed,
++  realloc'ed etc. The elements are guaranteed to be adjacently
++  allocated (this is not guaranteed to occur with multiple callocs or
++  mallocs), which may also improve cache locality in some
++  applications.
++
++  The "chunks" argument is optional (i.e., may be null, which is
++  probably the most typical usage). If it is null, the returned array
++  is itself dynamically allocated and should also be freed when it is
++  no longer needed. Otherwise, the chunks array must be of at least
++  n_elements in length. It is filled in with the pointers to the
++  chunks.
++
++  In either case, independent_calloc returns this pointer array, or
++  null if the allocation failed.  If n_elements is zero and "chunks"
++  is null, it returns a chunk representing an array with zero elements
++  (which should be freed if not wanted).
++
++  Each element must be freed when it is no longer needed. This can be
++  done all at once using bulk_free.
++
++  independent_calloc simplifies and speeds up implementations of many
++  kinds of pools.  It may also be useful when constructing large data
++  structures that initially have a fixed number of fixed-sized nodes,
++  but the number is not known at compile time, and some of the nodes
++  may later need to be freed. For example:
++
++  struct Node { int item; struct Node* next; };
++
++  struct Node* build_list() {
++    struct Node** pool;
++    int n = read_number_of_nodes_needed();
++    if (n <= 0) return 0;
++    pool = (struct Node**)(independent_calloc(n, sizeof(struct Node), 0);
++    if (pool == 0) die();
++    // organize into a linked list...
++    struct Node* first = pool[0];
++    for (i = 0; i < n-1; ++i)
++      pool[i]->next = pool[i+1];
++    free(pool);     // Can now free the array (or not, if it is needed later)
++    return first;
++  }
++*/
++void** dlindependent_calloc(size_t, size_t, void**);
++
++/*
++  independent_comalloc(size_t n_elements, size_t sizes[], void* chunks[]);
++
++  independent_comalloc allocates, all at once, a set of n_elements
++  chunks with sizes indicated in the "sizes" array.    It returns
++  an array of pointers to these elements, each of which can be
++  independently freed, realloc'ed etc. The elements are guaranteed to
++  be adjacently allocated (this is not guaranteed to occur with
++  multiple callocs or mallocs), which may also improve cache locality
++  in some applications.
++
++  The "chunks" argument is optional (i.e., may be null). If it is null
++  the returned array is itself dynamically allocated and should also
++  be freed when it is no longer needed. Otherwise, the chunks array
++  must be of at least n_elements in length. It is filled in with the
++  pointers to the chunks.
++
++  In either case, independent_comalloc returns this pointer array, or
++  null if the allocation failed.  If n_elements is zero and chunks is
++  null, it returns a chunk representing an array with zero elements
++  (which should be freed if not wanted).
++
++  Each element must be freed when it is no longer needed. This can be
++  done all at once using bulk_free.
++
++  independent_comallac differs from independent_calloc in that each
++  element may have a different size, and also that it does not
++  automatically clear elements.
++
++  independent_comalloc can be used to speed up allocation in cases
++  where several structs or objects must always be allocated at the
++  same time.  For example:
++
++  struct Head { ... }
++  struct Foot { ... }
++
++  void send_message(char* msg) {
++    int msglen = strlen(msg);
++    size_t sizes[3] = { sizeof(struct Head), msglen, sizeof(struct Foot) };
++    void* chunks[3];
++    if (independent_comalloc(3, sizes, chunks) == 0)
++      die();
++    struct Head* head = (struct Head*)(chunks[0]);
++    char*        body = (char*)(chunks[1]);
++    struct Foot* foot = (struct Foot*)(chunks[2]);
++    // ...
++  }
++
++  In general though, independent_comalloc is worth using only for
++  larger values of n_elements. For small values, you probably won't
++  detect enough difference from series of malloc calls to bother.
++
++  Overuse of independent_comalloc can increase overall memory usage,
++  since it cannot reuse existing noncontiguous small chunks that
++  might be available for some of the elements.
++*/
++void** dlindependent_comalloc(size_t, size_t*, void**);
++
++/*
++  bulk_free(void* array[], size_t n_elements)
++  Frees and clears (sets to null) each non-null pointer in the given
++  array.  This is likely to be faster than freeing them one-by-one.
++  If footers are used, pointers that have been allocated in different
++  mspaces are not freed or cleared, and the count of all such pointers
++  is returned.  For large arrays of pointers with poor locality, it
++  may be worthwhile to sort this array before calling bulk_free.
++*/
++size_t  dlbulk_free(void**, size_t n_elements);
++
++/*
++  pvalloc(size_t n);
++  Equivalent to valloc(minimum-page-that-holds(n)), that is,
++  round up n to nearest pagesize.
++ */
++void*  dlpvalloc(size_t);
++
++/*
++  malloc_trim(size_t pad);
++
++  If possible, gives memory back to the system (via negative arguments
++  to sbrk) if there is unused memory at the `high' end of the malloc
++  pool or in unused MMAP segments. You can call this after freeing
++  large blocks of memory to potentially reduce the system-level memory
++  requirements of a program. However, it cannot guarantee to reduce
++  memory. Under some allocation patterns, some large free blocks of
++  memory will be locked between two used chunks, so they cannot be
++  given back to the system.
++
++  The `pad' argument to malloc_trim represents the amount of free
++  trailing space to leave untrimmed. If this argument is zero, only
++  the minimum amount of memory to maintain internal data structures
++  will be left. Non-zero arguments can be supplied to maintain enough
++  trailing space to service future expected allocations without having
++  to re-obtain memory from the system.
++
++  Malloc_trim returns 1 if it actually released any memory, else 0.
++*/
++int  dlmalloc_trim(size_t);
++
++/*
++  malloc_stats();
++  Prints on stderr the amount of space obtained from the system (both
++  via sbrk and mmap), the maximum amount (which may be more than
++  current if malloc_trim and/or munmap got called), and the current
++  number of bytes allocated via malloc (or realloc, etc) but not yet
++  freed. Note that this is the number of bytes allocated, not the
++  number requested. It will be larger than the number requested
++  because of alignment and bookkeeping overhead. Because it includes
++  alignment wastage as being in use, this figure may be greater than
++  zero even when no user-level chunks are allocated.
++
++  The reported current and maximum system memory can be inaccurate if
++  a program makes other calls to system memory allocation functions
++  (normally sbrk) outside of malloc.
++
++  malloc_stats prints only the most commonly interesting statistics.
++  More information can be obtained by calling mallinfo.
++  
++  malloc_stats is not compiled if NO_MALLOC_STATS is defined.
++*/
++void  dlmalloc_stats(void);
++
++#endif /* !ONLY_MSPACES */
++
++/*
++  malloc_usable_size(void* p);
++
++  Returns the number of bytes you can actually use in
++  an allocated chunk, which may be more than you requested (although
++  often not) due to alignment and minimum size constraints.
++  You can use this many bytes without worrying about
++  overwriting other allocated objects. This is not a particularly great
++  programming practice. malloc_usable_size can be more useful in
++  debugging and assertions, for example:
++
++  p = malloc(n);
++  assert(malloc_usable_size(p) >= 256);
++*/
++size_t dlmalloc_usable_size(const void*);
++
++#if MSPACES
++
++/*
++  mspace is an opaque type representing an independent
++  region of space that supports mspace_malloc, etc.
++*/
++typedef void* mspace;
++
++/*
++  create_mspace creates and returns a new independent space with the
++  given initial capacity, or, if 0, the default granularity size.  It
++  returns null if there is no system memory available to create the
++  space.  If argument locked is non-zero, the space uses a separate
++  lock to control access. The capacity of the space will grow
++  dynamically as needed to service mspace_malloc requests.  You can
++  control the sizes of incremental increases of this space by
++  compiling with a different DEFAULT_GRANULARITY or dynamically
++  setting with mallopt(M_GRANULARITY, value).
++*/
++mspace create_mspace(size_t capacity, int locked);
++
++/*
++  destroy_mspace destroys the given space, and attempts to return all
++  of its memory back to the system, returning the total number of
++  bytes freed. After destruction, the results of access to all memory
++  used by the space become undefined.
++*/
++size_t destroy_mspace(mspace msp);
++
++/*
++  create_mspace_with_base uses the memory supplied as the initial base
++  of a new mspace. Part (less than 128*sizeof(size_t) bytes) of this
++  space is used for bookkeeping, so the capacity must be at least this
++  large. (Otherwise 0 is returned.) When this initial space is
++  exhausted, additional memory will be obtained from the system.
++  Destroying this space will deallocate all additionally allocated
++  space (if possible) but not the initial base.
++*/
++mspace create_mspace_with_base(void* base, size_t capacity, int locked);
++
++/*
++  mspace_track_large_chunks controls whether requests for large chunks
++  are allocated in their own untracked mmapped regions, separate from
++  others in this mspace. By default large chunks are not tracked,
++  which reduces fragmentation. However, such chunks are not
++  necessarily released to the system upon destroy_mspace.  Enabling
++  tracking by setting to true may increase fragmentation, but avoids
++  leakage when relying on destroy_mspace to release all memory
++  allocated using this space.  The function returns the previous
++  setting.
++*/
++int mspace_track_large_chunks(mspace msp, int enable);
++
++#if !NO_MALLINFO
++/*
++  mspace_mallinfo behaves as mallinfo, but reports properties of
++  the given space.
++*/
++struct mallinfo mspace_mallinfo(mspace msp);
++#endif /* NO_MALLINFO */
++
++/*
++  An alias for mallopt.
++*/
++int mspace_mallopt(int, int);
++
++/*
++  The following operate identically to their malloc counterparts
++  but operate only for the given mspace argument
++*/
++void* mspace_malloc(mspace msp, size_t bytes);
++void mspace_free(mspace msp, void* mem);
++void* mspace_calloc(mspace msp, size_t n_elements, size_t elem_size);
++void* mspace_realloc(mspace msp, void* mem, size_t newsize);
++void* mspace_realloc_in_place(mspace msp, void* mem, size_t newsize);
++void* mspace_memalign(mspace msp, size_t alignment, size_t bytes);
++void** mspace_independent_calloc(mspace msp, size_t n_elements,
++                                 size_t elem_size, void* chunks[]);
++void** mspace_independent_comalloc(mspace msp, size_t n_elements,
++                                   size_t sizes[], void* chunks[]);
++size_t mspace_bulk_free(mspace msp, void**, size_t n_elements);
++size_t mspace_usable_size(const void* mem);
++void mspace_malloc_stats(mspace msp);
++int mspace_trim(mspace msp, size_t pad);
++size_t mspace_footprint(mspace msp);
++size_t mspace_max_footprint(mspace msp);
++size_t mspace_footprint_limit(mspace msp);
++size_t mspace_set_footprint_limit(mspace msp, size_t bytes);
++void mspace_inspect_all(mspace msp, 
++                        void(*handler)(void *, void *, size_t, void*),
++                        void* arg);
++#endif  /* MSPACES */
++
++#ifdef __cplusplus
++};  /* end of extern "C" */
++#endif
++
++#endif /* MALLOC_280_H */
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..132d13f0ed71837b3e82c50541af7c4ae5f4dede
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,1 @@@
++NOTICE
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..44afcfc1ad4d5d72e67038f2c6dc93a6836e43b1
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,1 @@@
++debian/out/dmtracedump    usr/lib/android-sdk/platform-tools
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..637133937891b6991a6bdf54cc19ff8b4f95cc52
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,1 @@@
++usr/lib/android-sdk/platform-tools/dmtracedump   usr/bin/dmtracedump
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..1173895be34ecf844588283c59ad1c28a8101a04
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,1 @@@
++debian/out/dmtracedump.1
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..75a0ba2dbc47826eb17634fa7cc580abdf557231
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,7 @@@
++NAME = dmtracedump
++SOURCES = tracedump.cc
++SOURCES := $(foreach source, $(SOURCES), tools/dmtracedump/$(source))
++CPPFLAGS += -Itools/dmtracedump
++
++debian/out/$(NAME): $(SOURCES)
++      $(CXX) $^ -o $@ $(CXXFLAGS) $(CPPFLAGS) $(LDFLAGS)
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..5292682ca98f12e68c9573d214e8e381eb96d8c4
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,516 @@@
++NAME = libart
++
++SOURCES_runtime = \
++  aot_class_linker.cc \
++  art_field.cc \
++  art_method.cc \
++  backtrace_helper.cc \
++  barrier.cc \
++  base/locks.cc \
++  base/mem_map_arena_pool.cc \
++  base/mutex.cc \
++  base/quasi_atomic.cc \
++  base/timing_logger.cc \
++  cha.cc \
++  class_linker.cc \
++  class_loader_context.cc \
++  class_root.cc \
++  class_table.cc \
++  common_throws.cc \
++  compiler_filter.cc \
++  debug_print.cc \
++  debugger.cc \
++  dex/dex_file_annotations.cc \
++  dex_register_location.cc \
++  dex_to_dex_decompiler.cc \
++  elf_file.cc \
++  exec_utils.cc \
++  fault_handler.cc \
++  gc/allocation_record.cc \
++  gc/allocator/dlmalloc.cc \
++  gc/allocator/rosalloc.cc \
++  gc/accounting/bitmap.cc \
++  gc/accounting/card_table.cc \
++  gc/accounting/heap_bitmap.cc \
++  gc/accounting/mod_union_table.cc \
++  gc/accounting/remembered_set.cc \
++  gc/accounting/space_bitmap.cc \
++  gc/collector/concurrent_copying.cc \
++  gc/collector/garbage_collector.cc \
++  gc/collector/immune_region.cc \
++  gc/collector/immune_spaces.cc \
++  gc/collector/mark_sweep.cc \
++  gc/collector/partial_mark_sweep.cc \
++  gc/collector/semi_space.cc \
++  gc/collector/sticky_mark_sweep.cc \
++  gc/gc_cause.cc \
++  gc/heap.cc \
++  gc/reference_processor.cc \
++  gc/reference_queue.cc \
++  gc/scoped_gc_critical_section.cc \
++  gc/space/bump_pointer_space.cc \
++  gc/space/dlmalloc_space.cc \
++  gc/space/image_space.cc \
++  gc/space/large_object_space.cc \
++  gc/space/malloc_space.cc \
++  gc/space/region_space.cc \
++  gc/space/rosalloc_space.cc \
++  gc/space/space.cc \
++  gc/space/zygote_space.cc \
++  gc/task_processor.cc \
++  gc/verification.cc \
++  hidden_api.cc \
++  hprof/hprof.cc \
++  image.cc \
++  index_bss_mapping.cc \
++  indirect_reference_table.cc \
++  instrumentation.cc \
++  intern_table.cc \
++  interpreter/interpreter.cc \
++  interpreter/interpreter_cache.cc \
++  interpreter/interpreter_common.cc \
++  interpreter/interpreter_intrinsics.cc \
++  interpreter/interpreter_switch_impl0.cc \
++  interpreter/interpreter_switch_impl1.cc \
++  interpreter/interpreter_switch_impl2.cc \
++  interpreter/interpreter_switch_impl3.cc \
++  interpreter/lock_count_data.cc \
++  interpreter/shadow_frame.cc \
++  interpreter/unstarted_runtime.cc \
++  java_frame_root_info.cc \
++  jdwp/jdwp_event.cc \
++  jdwp/jdwp_expand_buf.cc \
++  jdwp/jdwp_handler.cc \
++  jdwp/jdwp_main.cc \
++  jdwp/jdwp_request.cc \
++  jdwp/jdwp_socket.cc \
++  jdwp/object_registry.cc \
++  jit/debugger_interface.cc \
++  jit/jit.cc \
++  jit/jit_code_cache.cc \
++  jit/profiling_info.cc \
++  jit/profile_saver.cc \
++  jni/check_jni.cc \
++  jni/java_vm_ext.cc \
++  jni/jni_env_ext.cc \
++  jni/jni_internal.cc \
++  linear_alloc.cc \
++  managed_stack.cc \
++  method_handles.cc \
++  mirror/array.cc \
++  mirror/class.cc \
++  mirror/class_ext.cc \
++  mirror/dex_cache.cc \
++  mirror/emulated_stack_frame.cc \
++  mirror/executable.cc \
++  mirror/field.cc \
++  mirror/method.cc \
++  mirror/method_handle_impl.cc \
++  mirror/method_handles_lookup.cc \
++  mirror/method_type.cc \
++  mirror/object.cc \
++  mirror/stack_trace_element.cc \
++  mirror/string.cc \
++  mirror/throwable.cc \
++  mirror/var_handle.cc \
++  monitor.cc \
++  monitor_objects_stack_visitor.cc \
++  native_bridge_art_interface.cc \
++  native_stack_dump.cc \
++  native/dalvik_system_DexFile.cc \
++  native/dalvik_system_VMDebug.cc \
++  native/dalvik_system_VMRuntime.cc \
++  native/dalvik_system_VMStack.cc \
++  native/dalvik_system_ZygoteHooks.cc \
++  native/java_lang_Class.cc \
++  native/java_lang_Object.cc \
++  native/java_lang_String.cc \
++  native/java_lang_StringFactory.cc \
++  native/java_lang_System.cc \
++  native/java_lang_Thread.cc \
++  native/java_lang_Throwable.cc \
++  native/java_lang_VMClassLoader.cc \
++  native/java_lang_invoke_MethodHandleImpl.cc \
++  native/java_lang_ref_FinalizerReference.cc \
++  native/java_lang_ref_Reference.cc \
++  native/java_lang_reflect_Array.cc \
++  native/java_lang_reflect_Constructor.cc \
++  native/java_lang_reflect_Executable.cc \
++  native/java_lang_reflect_Field.cc \
++  native/java_lang_reflect_Method.cc \
++  native/java_lang_reflect_Parameter.cc \
++  native/java_lang_reflect_Proxy.cc \
++  native/java_util_concurrent_atomic_AtomicLong.cc \
++  native/libcore_util_CharsetUtils.cc \
++  native/org_apache_harmony_dalvik_ddmc_DdmServer.cc \
++  native/org_apache_harmony_dalvik_ddmc_DdmVmInternal.cc \
++  native/sun_misc_Unsafe.cc \
++  non_debuggable_classes.cc \
++  oat.cc \
++  oat_file.cc \
++  oat_file_assistant.cc \
++  oat_file_manager.cc \
++  oat_quick_method_header.cc \
++  object_lock.cc \
++  offsets.cc \
++  parsed_options.cc \
++  plugin.cc \
++  quick_exception_handler.cc \
++  read_barrier.cc \
++  reference_table.cc \
++  reflection.cc \
++  runtime.cc \
++  runtime_callbacks.cc \
++  runtime_common.cc \
++  runtime_intrinsics.cc \
++  runtime_options.cc \
++  scoped_thread_state_change.cc \
++  signal_catcher.cc \
++  stack.cc \
++  stack_map.cc \
++  thread.cc \
++  thread_list.cc \
++  thread_pool.cc \
++  ti/agent.cc \
++  trace.cc \
++  transaction.cc \
++  var_handles.cc \
++  vdex_file.cc \
++  verifier/class_verifier.cc \
++  verifier/instruction_flags.cc \
++  verifier/method_verifier.cc \
++  verifier/reg_type.cc \
++  verifier/reg_type_cache.cc \
++  verifier/register_line.cc \
++  verifier/verifier_deps.cc \
++  verify_object.cc \
++  well_known_classes.cc \
++  arch/context.cc \
++  arch/instruction_set_features.cc \
++  arch/memcmp16.cc \
++  arch/arm/instruction_set_features_arm.cc \
++  arch/arm/registers_arm.cc \
++  arch/arm64/instruction_set_features_arm64.cc \
++  arch/arm64/registers_arm64.cc \
++  arch/mips/instruction_set_features_mips.cc \
++  arch/mips/registers_mips.cc \
++  arch/mips64/instruction_set_features_mips64.cc \
++  arch/mips64/registers_mips64.cc \
++  arch/x86/instruction_set_features_x86.cc \
++  arch/x86/registers_x86.cc \
++  arch/x86_64/registers_x86_64.cc \
++  entrypoints/entrypoint_utils.cc \
++  entrypoints/jni/jni_entrypoints.cc \
++  entrypoints/math_entrypoints.cc \
++  entrypoints/quick/quick_alloc_entrypoints.cc \
++  entrypoints/quick/quick_cast_entrypoints.cc \
++  entrypoints/quick/quick_deoptimization_entrypoints.cc \
++  entrypoints/quick/quick_dexcache_entrypoints.cc \
++  entrypoints/quick/quick_entrypoints_enum.cc \
++  entrypoints/quick/quick_field_entrypoints.cc \
++  entrypoints/quick/quick_fillarray_entrypoints.cc \
++  entrypoints/quick/quick_jni_entrypoints.cc \
++  entrypoints/quick/quick_lock_entrypoints.cc \
++  entrypoints/quick/quick_math_entrypoints.cc \
++  entrypoints/quick/quick_thread_entrypoints.cc \
++  entrypoints/quick/quick_throw_entrypoints.cc \
++  entrypoints/quick/quick_trampoline_entrypoints.cc \
++
++# Sources for a host library
++SOURCES_runtime += \
++  monitor_linux.cc \
++  runtime_linux.cc \
++  thread_linux.cc
++
++# Architecture specific sources, which come from runtime/Android.bp
++SOURCES_runtime_arm = \
++  interpreter/mterp/mterp.cc \
++  arch/arm/context_arm.cc \
++  arch/arm/entrypoints_init_arm.cc \
++  arch/arm/instruction_set_features_assembly_tests.S \
++  arch/arm/jni_entrypoints_arm.S \
++  arch/arm/memcmp16_arm.S \
++  arch/arm/quick_entrypoints_arm.S \
++  arch/arm/quick_entrypoints_cc_arm.cc \
++  arch/arm/thread_arm.cc \
++  arch/arm/fault_handler_arm.cc \
++
++SOURCES_runtime_arm64 = \
++  interpreter/mterp/mterp.cc \
++  arch/arm64/context_arm64.cc \
++  arch/arm64/entrypoints_init_arm64.cc \
++  arch/arm64/jni_entrypoints_arm64.S \
++  arch/arm64/memcmp16_arm64.S \
++  arch/arm64/quick_entrypoints_arm64.S \
++  arch/arm64/thread_arm64.cc \
++  monitor_pool.cc \
++  arch/arm64/fault_handler_arm64.cc \
++
++SOURCES_runtime_x86 = \
++  interpreter/mterp/mterp.cc \
++  arch/x86/context_x86.cc \
++  arch/x86/entrypoints_init_x86.cc \
++  arch/x86/jni_entrypoints_x86.S \
++  arch/x86/memcmp16_x86.S \
++  arch/x86/quick_entrypoints_x86.S \
++  arch/x86/thread_x86.cc \
++  arch/x86/fault_handler_x86.cc \
++
++SOURCES_runtime_x86_64 = \
++  interpreter/mterp/mterp.cc \
++  arch/x86_64/context_x86_64.cc \
++  arch/x86_64/entrypoints_init_x86_64.cc \
++  arch/x86_64/jni_entrypoints_x86_64.S \
++  arch/x86_64/memcmp16_x86_64.S \
++  arch/x86_64/quick_entrypoints_x86_64.S \
++  arch/x86_64/thread_x86_64.cc \
++  monitor_pool.cc \
++  arch/x86/fault_handler_x86.cc \
++
++SOURCES_runtime_mips = \
++  interpreter/mterp/mterp.cc \
++  arch/mips/context_mips.cc \
++  arch/mips/entrypoints_init_mips.cc \
++  arch/mips/jni_entrypoints_mips.S \
++  arch/mips/memcmp16_mips.S \
++  arch/mips/quick_entrypoints_mips.S \
++  arch/mips/thread_mips.cc \
++  arch/mips/fault_handler_mips.cc \
++
++SOURCES_runtime_mips64 = \
++  interpreter/mterp/mterp.cc \
++  arch/mips64/context_mips64.cc \
++  arch/mips64/entrypoints_init_mips64.cc \
++  arch/mips64/jni_entrypoints_mips64.S \
++  arch/mips64/memcmp16_mips64.S \
++  arch/mips64/quick_entrypoints_mips64.S \
++  arch/mips64/thread_mips64.cc \
++  monitor_pool.cc \
++  arch/mips64/fault_handler_mips64.cc \
++
++
++include debian/detect-arch.mk
++SOURCES_runtime += $(SOURCES_runtime_$(CPU))
++
++# From libartbase/Android.bp
++SOURCES_libartbase = \
++         arch/instruction_set.cc \
++         base/allocator.cc \
++         base/arena_allocator.cc \
++         base/arena_bit_vector.cc \
++         base/bit_vector.cc \
++         base/enums.cc \
++         base/file_magic.cc \
++         base/file_utils.cc \
++         base/hex_dump.cc \
++         base/hiddenapi_flags.cc \
++         base/logging.cc \
++         base/malloc_arena_pool.cc \
++         base/membarrier.cc \
++         base/memfd.cc \
++         base/memory_region.cc \
++         base/mem_map.cc \
++         base/os_linux.cc \
++         base/runtime_debug.cc \
++         base/safe_copy.cc \
++         base/scoped_arena_allocator.cc \
++         base/scoped_flock.cc \
++         base/socket_peer_is_trusted.cc \
++         base/time_utils.cc \
++         base/unix_file/fd_file.cc \
++         base/unix_file/random_access_file_utils.cc \
++         base/utils.cc \
++         base/zip_archive.cc \
++         base/mem_map_unix.cc \
++
++# From libdexfile/Android.bp
++SOURCES_libdexfile = \
++         dex/art_dex_file_loader.cc \
++         dex/compact_dex_file.cc \
++         dex/compact_offset_table.cc \
++         dex/descriptors_names.cc \
++         dex/dex_file.cc \
++         dex/dex_file_exception_helpers.cc \
++         dex/dex_file_layout.cc \
++         dex/dex_file_loader.cc \
++         dex/dex_file_tracking_registrar.cc \
++         dex/dex_file_verifier.cc \
++         dex/dex_instruction.cc \
++         dex/modifiers.cc \
++         dex/primitive.cc \
++         dex/signature.cc \
++         dex/standard_dex_file.cc \
++         dex/type_lookup_table.cc \
++         dex/utf.cc \
++         external/dex_file_ext.cc \
++         external/dex_file_supp.cc \
++
++SOURCES := $(foreach source, $(SOURCES_libartbase), libartbase/$(source)) \
++           $(foreach source, $(SOURCES_libdexfile), libdexfile/$(source)) \
++           $(foreach source, $(SOURCES_runtime), runtime/$(source)) \
++           libartpalette/system/palette_fake.cc \
++           libprofile/profile/profile_compilation_info.cc \
++
++
++# Add generated operator_out.cc and mterp.S
++SOURCES += \
++  debian/out/operator_out.cc \
++  debian/out/mterp.S
++
++# from runtime/Android.bp
++SOURCES_OPERATOR = \
++  base/callee_save_type.h \
++  base/locks.h \
++  class_loader_context.h \
++  class_status.h \
++  debugger.h \
++  gc_root.h \
++  gc/allocator_type.h \
++  gc/allocator/rosalloc.h \
++  gc/collector_type.h \
++  gc/collector/gc_type.h \
++  gc/heap.h \
++  gc/space/region_space.h \
++  gc/space/space.h \
++  gc/weak_root_state.h \
++  image.h \
++  instrumentation.h \
++  indirect_reference_table.h \
++  jdwp_provider.h \
++  jdwp/jdwp.h \
++  jdwp/jdwp_constants.h \
++  lock_word.h \
++  oat.h \
++  object_callbacks.h \
++  process_state.h \
++  stack.h \
++  suspend_reason.h \
++  thread.h \
++  thread_state.h \
++  ti/agent.h \
++  trace.h \
++  verifier/verifier_enums.h
++SOURCES_OPERATOR := $(foreach source, $(SOURCES_OPERATOR), runtime/$(source))
++
++# from libartbase/Android.bp, and libdexfile/Android.bp
++SOURCES_OPERATOR += \
++  libartbase/arch/instruction_set.h \
++  libartbase/base/allocator.h \
++  libartbase/base/unix_file/fd_file.h \
++  \
++  libdexfile/dex/dex_file.h \
++  libdexfile/dex/dex_file_layout.h \
++  libdexfile/dex/dex_instruction.h \
++  libdexfile/dex/dex_instruction_utils.h \
++  libdexfile/dex/invoke_type.h \
++  libdexfile/dex/method_reference.h \
++
++# If directly compile all sources together, it will take a huge amount of time
++# and potentially huge amount of memory. Not good for devel-time.
++# On the other hand, individual compiling every source allows incremental
++# compilation and multi-thread accelration.
++OBJECTS_ASSEMBLY = $(SOURCES_ASSEMBLY:.S=.o)
++OBJECTS_CXX = $(SOURCES_CXX:.cc=.o)
++SOURCES_ASSEMBLY = $(filter %.S,$(SOURCES))
++SOURCES_CXX = $(filter %.cc,$(SOURCES))
++
++CFLAGS += -c -D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE=1 -Wa,--noexecstack -fcommon \
++  -fno-rtti -fstrict-aliasing -fvisibility=protected \
++
++CXXFLAGS += -c -std=gnu++17 \
++  -Wno-invalid-offsetof -Wno-invalid-partial-specialization \
++  -D__STDC_FORMAT_MACROS -D__STDC_CONSTANT_MACROS \
++  -fno-rtti -fstrict-aliasing -fvisibility=protected -fno-omit-frame-pointer \
++
++CPPFLAGS += \
++  -DART_BASE_ADDRESS_MAX_DELTA=0x1000000 \
++  -DART_BASE_ADDRESS_MIN_DELTA=-0x1000000 \
++  -DART_BASE_ADDRESS=0x60000000 \
++  -DART_DEFAULT_COMPACT_DEX_LEVEL=fast \
++  -DART_DEFAULT_GC_TYPE_IS_CMS \
++  -DART_ENABLE_ADDRESS_SANITIZER=1 \
++  -DART_ENABLE_CODEGEN_${CPU} \
++  -DART_FRAME_SIZE_LIMIT=1736 \
++  -DART_READ_BARRIER_TYPE_IS_BAKER=1 \
++  -DART_STACK_OVERFLOW_GAP_arm=8192 \
++  -DART_STACK_OVERFLOW_GAP_arm64=8192 \
++  -DART_STACK_OVERFLOW_GAP_mips=16384 \
++  -DART_STACK_OVERFLOW_GAP_mips64=16384 \
++  -DART_STACK_OVERFLOW_GAP_x86_64=8192 \
++  -DART_STACK_OVERFLOW_GAP_x86=8192 \
++  -DART_USE_READ_BARRIER=1 \
++  -DBUILDING_LIBART=1 \
++  -DIMT_SIZE=43 \
++  -DUSE_D8_DESUGAR=1 \
++  -I. \
++  -I/usr/include/android/nativehelper \
++  -Icmdline \
++  -Iruntime \
++  -Ilibartbase \
++  -Ilibartbase/arch \
++  -Ilibartpalette/include \
++  -Ilibdexfile \
++  -Ilibdexfile/external/include \
++  -Ilibelffile \
++  -Ilibprofile \
++  -Isigchainlib \
++  -Itools/cpp-define-generator \
++  -Idebian/out \
++
++LDFLAGS += \
++  -fuse-ld=gold \
++  -L/usr/lib/$(DEB_HOST_MULTIARCH)/android \
++  -Ldebian/out \
++  -Wl,-rpath=/usr/lib/$(DEB_HOST_MULTIARCH)/android \
++  -shared -Wl,-soname,$(NAME).so.0
++LIBRARIES_FLAGS = \
++  -latomic \
++  -lbacktrace \
++  -lbase \
++  -ldl \
++  -llz4 \
++  -lnativebridge \
++  -lnativeloader \
++  -lpthread \
++  -lsigchain \
++  -lz \
++  -lziparchive \
++
++CC_ASSEMBLY = clang
++ifeq ($(CPU),arm)
++  # Clang does not support the `ADRL` instruction. See <https://bugs.llvm.org/show_bug.cgi?id=24350>
++  CC_ASSEMBLY = gcc
++endif
++
++debian/out/$(NAME).so.0: $(OBJECTS_CXX) $(OBJECTS_ASSEMBLY)
++      $(CXX) -o $@ $(LDFLAGS) $^ $(LIBRARIES_FLAGS)
++      ln -s $(NAME).so.0 debian/out/$(NAME).so
++
++clean:
++      $(RM) $(NAME).so* debian/out/operator_out.cc debian/out/mterp.S
++      $(RM) $(OBJECTS_CXX)
++      $(RM) $(OBJECTS_ASSEMBLY)
++
++.PHONY: clean
++
++$(OBJECTS_CXX): %.o: %.cc
++      $(CXX) -o $@ $(CXXFLAGS) $(CPPFLAGS) $^
++
++$(OBJECTS_ASSEMBLY): %.o: %.S
++      $(CC_ASSEMBLY) -o $@ $(CFLAGS) $(CPPFLAGS) $^
++
++debian/out/operator_out.cc: $(SOURCES_OPERATOR)
++      python3 tools/generate_operator_out.py art/libartbase $^ > $@
++
++debian/out/mterp.S: runtime/interpreter/mterp/$(CPU)/*.S
++      python3 runtime/interpreter/mterp/gen_mterp.py $@ $^
++
++debian/out/asm_defines.h: debian/out/asm_defines.output
++      python3 tools/cpp-define-generator/make_header.py $^ > $@
++
++debian/out/asm_defines.output: tools/cpp-define-generator/asm_defines.cc
++      $(CXX) \
++              $(CPPFLAGS) \
++              $(CXXFLAGS) \
++              -S \
++              -o $@ $^
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..7a39aa4ce26ff22c9e68ef6566a3ffbe6bad71ba
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,20 @@@
++NAME = libdexfile_external
++
++SOURCES = libdexfile/external/dex_file_ext.cc
++CPPFLAGS += \
++  -Ilibartbase \
++  -Ilibdexfile \
++  -Ilibdexfile/external/include \
++  -I/usr/include/android/nativehelper \
++
++CXXFLAGS += -std=gnu++17
++LDFLAGS += \
++  -shared \
++  -Wl,-soname,$(NAME).so.0
++LIBRARIES_FLAGS = \
++  -ldl \
++  -lpthread \
++
++debian/out/$(NAME).so.0: $(SOURCES)
++      $(CXX) -o $@ $(CXXFLAGS) $(CPPFLAGS) $(LDFLAGS) $^ $(LIBRARIES_FLAGS)
++      ln -s $(NAME).so.0 debian/out/$(NAME).so
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..4b449a9ab3fcea906a8707e943aa409042ce0d87
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,20 @@@
++NAME = libdexfile_support
++
++SOURCES = libdexfile/external/dex_file_supp.cc
++CPPFLAGS += \
++  -DNO_DEXFILE_SUPPORT \
++  -Ilibartbase \
++  -Ilibdexfile \
++  -Ilibdexfile/external/include \
++
++CXXFLAGS += -std=gnu++17
++LDFLAGS += \
++  -shared \
++  -Wl,-soname,$(NAME).so.0
++LIBRARIES_FLAGS = \
++  -ldl \
++  -lpthread \
++
++debian/out/$(NAME).so.0: $(SOURCES)
++      $(CXX) -o $@ $(CXXFLAGS) $(CPPFLAGS) $(LDFLAGS) $^ $(LIBRARIES_FLAGS)
++      ln -s $(NAME).so.0 debian/out/$(NAME).so
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..cf8cdfaa14f38a57550f79f47997d8b4f11f26ed
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,17 @@@
++NAME = libsigchain
++
++SOURCES = sigchain.cc
++SOURCES := $(foreach source, $(SOURCES), sigchainlib/$(source))
++
++CPPFLAGS += -Isigchainlib
++CXXFLAGS += -std=gnu++17
++LDFLAGS += \
++  -shared \
++  -Wl,-soname,$(NAME).so.0
++LIBRARIES_FLAGS = \
++  -ldl \
++  -lpthread \
++
++debian/out/$(NAME).so.0: $(SOURCES)
++      $(CXX) -o $@ $(CXXFLAGS) $(CPPFLAGS) $(LDFLAGS) $^ $(LIBRARIES_FLAGS)
++      ln -s $(NAME).so.0 debian/out/$(NAME).so
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..f6e2d10ddce711b92a4d8da2e7213b80bff0b8bc
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,31 @@@
++From: Roger Shimizu <rosh@debian.org>
++Date: Sat, 22 Jan 2022 00:23:15 +0900
++Subject: Fix ftbfs for c++17
++
++Closes: #983964
++---
++ libdexfile/dex/compact_offset_table.h | 4 ++--
++ 1 file changed, 2 insertions(+), 2 deletions(-)
++
++diff --git a/libdexfile/dex/compact_offset_table.h b/libdexfile/dex/compact_offset_table.h
++index ec759e2..e651363 100644
++--- a/libdexfile/dex/compact_offset_table.h
+++++ b/libdexfile/dex/compact_offset_table.h
++@@ -28,7 +28,7 @@ class CompactOffsetTable {
++  public:
++   // This value is coupled with the leb chunk bitmask. That logic must also be adjusted when the
++   // integer is modified.
++-  static constexpr size_t kElementsPerIndex = 16;
+++  static constexpr std::size_t kElementsPerIndex = 16;
++ 
++   // Leb block format:
++   // [uint16_t] 16 bit mask for what indexes actually have a non zero offset for the chunk.
++@@ -61,7 +61,7 @@ class CompactOffsetTable {
++                     uint32_t* out_table_offset);
++ 
++   // 32 bit aligned for the offset table.
++-  static constexpr size_t kAlignment = sizeof(uint32_t);
+++  static constexpr std::size_t kAlignment = sizeof(uint32_t);
++ };
++ 
++ }  // namespace art
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..ecb81f86080fb4c6629cc8697ec62249b2d9d0d3
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,13 @@@
++Description: Adapt asm output of clang that no #/$ is placed before data
++Forwarded: not-needed
++--- a/tools/cpp-define-generator/make_header.py
+++++ b/tools/cpp-define-generator/make_header.py
++@@ -31,7 +31,7 @@ import sys
++ def convert(input):
++   """Find all defines in the compiler generated assembly and convert them to #define pragmas"""
++ 
++-  asm_define_re = re.compile(r'">>(\w+) (?:\$|#)([-0-9]+) (?:\$|#)(0|1)<<"')
+++  asm_define_re = re.compile(r'">>(\w+) (?:\$|#|)([-0-9]+) (?:\$|#|)(0|1)<<"')
++   asm_defines = asm_define_re.findall(input)
++   if not asm_defines:
++     raise RuntimeError("Failed to find any asm defines in the input")
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..7a0b2ca2395d7a3966673f93173b2a51e35c5e15
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,13 @@@
++Description: arm asm instruction
++Forwarded: not-needed
++--- a/runtime/interpreter/mterp/arm/main.S
+++++ b/runtime/interpreter/mterp/arm/main.S
++@@ -602,7 +602,7 @@ MterpCommonTakenBranch:
++ #endif
++     cmp     rPROFILE, #JIT_CHECK_OSR
++     beq     .L_osr_check
++-    subsgt  rPROFILE, #1
+++    subgt   rPROFILE, #1
++     beq     .L_add_batch                @ counted down to zero - report
++ .L_resume_backward_branch:
++     ldr     lr, [rSELF, #THREAD_FLAGS_OFFSET]
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..3c91ea26aa1df549aa97d8c21edb6c5df3f4947d
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,45 @@@
++Description: Conforms with the exception specification of `std::atomic`
++ All constructors of `std::atomic` require `noexcept`. As a result, its members
++ must also be able to instantiate without any exception throwing.
++--- a/runtime/mirror/dex_cache.h
+++++ b/runtime/mirror/dex_cache.h
++@@ -68,7 +68,7 @@
++   // Set the initial state for the 0th entry to be {0,1} which is guaranteed to fail
++   // the lookup id == stored id branch.
++   DexCachePair(ObjPtr<T> object, uint32_t index);
++-  DexCachePair() : index(0) {}
+++  DexCachePair() noexcept : index(0) {}
++   DexCachePair(const DexCachePair<T>&) = default;
++   DexCachePair& operator=(const DexCachePair<T>&) = default;
++ 
++@@ -91,7 +91,7 @@
++   NativeDexCachePair(T* object, uint32_t index)
++       : object(object),
++         index(index) {}
++-  NativeDexCachePair() : object(nullptr), index(0u) { }
+++  NativeDexCachePair() noexcept : object(nullptr), index(0u) { }
++   NativeDexCachePair(const NativeDexCachePair<T>&) = default;
++   NativeDexCachePair& operator=(const NativeDexCachePair<T>&) = default;
++ 
++--- a/runtime/mirror/object_reference.h
+++++ b/runtime/mirror/object_reference.h
++@@ -164,7 +164,7 @@
++ template<class MirrorType>
++ class MANAGED CompressedReference : public mirror::ObjectReference<false, MirrorType> {
++  public:
++-  CompressedReference<MirrorType>() REQUIRES_SHARED(Locks::mutator_lock_)
+++  CompressedReference<MirrorType>() noexcept REQUIRES_SHARED(Locks::mutator_lock_)
++       : mirror::ObjectReference<false, MirrorType>(nullptr) {}
++ 
++   static CompressedReference<MirrorType> FromMirrorPtr(MirrorType* p)
++--- a/runtime/gc_root.h
+++++ b/runtime/gc_root.h
++@@ -213,7 +213,7 @@
++     return root_.IsNull();
++   }
++ 
++-  ALWAYS_INLINE GcRoot() {}
+++  ALWAYS_INLINE GcRoot() noexcept {}
++   explicit ALWAYS_INLINE GcRoot(MirrorType* ref)
++       REQUIRES_SHARED(Locks::mutator_lock_);
++   explicit ALWAYS_INLINE GcRoot(ObjPtr<MirrorType> ref)
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..96d2f18b0e7730a613678e4b6fd67c1ecce3835b
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,19 @@@
++Description: non-x86 arches do not have PAGE_SIZE
++Forwarded: not-needed
++--- a/libartbase/base/safe_copy.cc
+++++ b/libartbase/base/safe_copy.cc
++@@ -56,10 +56,11 @@ ssize_t SafeCopy(void *dst, const void *src, size_t len) {
++     }
++ 
++     src_iovs[iovecs_used].iov_base = const_cast<char*>(cur);
++-    if (!IsAlignedParam(cur, PAGE_SIZE)) {
++-      src_iovs[iovecs_used].iov_len = AlignUp(cur, PAGE_SIZE) - cur;
+++    size_t pagesize = static_cast<size_t>(sysconf(_SC_PAGE_SIZE));
+++    if (!IsAlignedParam(cur, pagesize)) {
+++      src_iovs[iovecs_used].iov_len = AlignUp(cur, pagesize) - cur;
++     } else {
++-      src_iovs[iovecs_used].iov_len = PAGE_SIZE;
+++      src_iovs[iovecs_used].iov_len = pagesize;
++     }
++ 
++     src_iovs[iovecs_used].iov_len = std::min(src_iovs[iovecs_used].iov_len, len);
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..9b473d4d99c2fbdeaaf45e51f1f6fe053df4e4f5
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,122 @@@
++From: David Srbecky <dsrbecky@google.com>
++Date: Thu, 4 Apr 2019 16:16:17 +0100
++Subject: [PATCH] Fix mterp assembly to use uxtw instead of lsl where needed.
++
++Bug: https://bugs.llvm.org/show_bug.cgi?id=41504
++Origin: https://android-review.googlesource.com/c/platform/art/+/940018
++
++The old instructions are invalid according to the ARM spec.
++
++Event though UXTW and LSL are aliases this is binary change:
++"add x0, x1, w2, lsl #1" was invalid and would be treated as
++"add x0, x1, x2, uxtx #1" which would keep the high bits.
++
++With uxtw, we ignore the high bits, as expected in code.
++
++Test: test.py -r --target --interpreter
++Change-Id: I66f67ccc5a401d0cf6ac5b42d41d8df26a190046
++---
++ runtime/interpreter/mterp/arm64/array.S |  6 +++---
++ runtime/interpreter/mterp/arm64/main.S  | 18 +++++++++---------
++ runtime/interpreter/mterp/arm64/other.S |  2 +-
++ 3 files changed, 13 insertions(+), 13 deletions(-)
++
++diff --git a/runtime/interpreter/mterp/arm64/array.S b/runtime/interpreter/mterp/arm64/array.S
++index a023d22..628f832 100644
++--- a/runtime/interpreter/mterp/arm64/array.S
+++++ b/runtime/interpreter/mterp/arm64/array.S
++@@ -75,7 +75,7 @@
++     GET_VREG w1, w3                     // w1<- vCC (requested index)
++     cbz     w0, common_errNullObject        // yes, bail
++     ldr     w3, [x0, #MIRROR_ARRAY_LENGTH_OFFSET]    // w3<- arrayObj->length
++-    add     x0, x0, w1, lsl #3          // w0<- arrayObj + index*width
+++    add     x0, x0, w1, uxtw #3         // w0<- arrayObj + index*width
++     cmp     w1, w3                      // compare unsigned index, length
++     bcs     common_errArrayIndex        // index >= length, bail
++     FETCH_ADVANCE_INST 2                // advance rPC, load wINST
++@@ -104,7 +104,7 @@
++     GET_VREG w1, w3                     // w1<- vCC (requested index)
++     cbz     w0, common_errNullObject    // bail if null
++     ldr     w3, [x0, #MIRROR_ARRAY_LENGTH_OFFSET]     // w3<- arrayObj->length
++-    add     x0, x0, w1, lsl #$shift     // w0<- arrayObj + index*width
+++    add     x0, x0, w1, uxtw #$shift    // w0<- arrayObj + index*width
++     cmp     w1, w3                      // compare unsigned index, length
++     bcs     common_errArrayIndex        // index >= length, bail
++     FETCH_ADVANCE_INST 2                // advance rPC, load rINST
++@@ -154,7 +154,7 @@
++     GET_VREG w1, w3                     // w1<- vCC (requested index)
++     cbz     w0, common_errNullObject    // bail if null
++     ldr     w3, [x0, #MIRROR_ARRAY_LENGTH_OFFSET]    // w3<- arrayObj->length
++-    add     x0, x0, w1, lsl #3          // w0<- arrayObj + index*width
+++    add     x0, x0, w1, uxtw #3         // w0<- arrayObj + index*width
++     cmp     w1, w3                      // compare unsigned index, length
++     bcs     common_errArrayIndex        // index >= length, bail
++     GET_VREG_WIDE x1, w4
++diff --git a/runtime/interpreter/mterp/arm64/main.S b/runtime/interpreter/mterp/arm64/main.S
++index aefec61..fd745f1 100644
++--- a/runtime/interpreter/mterp/arm64/main.S
+++++ b/runtime/interpreter/mterp/arm64/main.S
++@@ -268,23 +268,23 @@ codes.
++  * Get/set the 64-bit value from a Dalvik register.
++  */
++ .macro GET_VREG_WIDE reg, vreg
++-    add     ip2, xFP, \vreg, lsl #2
+++    add     ip2, xFP, \vreg, uxtw #2
++     ldr     \reg, [ip2]
++ .endm
++ .macro SET_VREG_WIDE reg, vreg
++-    add     ip2, xFP, \vreg, lsl #2
+++    add     ip2, xFP, \vreg, uxtw #2
++     str     \reg, [ip2]
++-    add     ip2, xREFS, \vreg, lsl #2
+++    add     ip2, xREFS, \vreg, uxtw #2
++     str     xzr, [ip2]
++ .endm
++ .macro GET_VREG_DOUBLE reg, vreg
++-    add     ip2, xFP, \vreg, lsl #2
+++    add     ip2, xFP, \vreg, uxtw #2
++     ldr     \reg, [ip2]
++ .endm
++ .macro SET_VREG_DOUBLE reg, vreg
++-    add     ip2, xFP, \vreg, lsl #2
+++    add     ip2, xFP, \vreg, uxtw #2
++     str     \reg, [ip2]
++-    add     ip2, xREFS, \vreg, lsl #2
+++    add     ip2, xREFS, \vreg, uxtw #2
++     str     xzr, [ip2]
++ .endm
++ 
++@@ -300,7 +300,7 @@ codes.
++  * Convert a virtual register index into an address.
++  */
++ .macro VREG_INDEX_TO_ADDR reg, vreg
++-    add     \reg, xFP, \vreg, lsl #2   /* WARNING: handle shadow frame vreg zero if store */
+++    add     \reg, xFP, \vreg, uxtw #2   /* WARNING: handle shadow frame vreg zero if store */
++ .endm
++ 
++ /*
++@@ -418,9 +418,9 @@ ENTRY ExecuteMterpImpl
++     mov     xSELF, x0
++     ldr     w0, [x2, #SHADOWFRAME_NUMBER_OF_VREGS_OFFSET]
++     add     xFP, x2, #SHADOWFRAME_VREGS_OFFSET     // point to vregs.
++-    add     xREFS, xFP, w0, lsl #2                 // point to reference array in shadow frame
+++    add     xREFS, xFP, w0, uxtw #2                // point to reference array in shadow frame
++     ldr     w0, [x2, #SHADOWFRAME_DEX_PC_OFFSET]   // Get starting dex_pc.
++-    add     xPC, x1, w0, lsl #1                    // Create direct pointer to 1st dex opcode
+++    add     xPC, x1, w0, uxtw #1                   // Create direct pointer to 1st dex opcode
++     CFI_DEFINE_DEX_PC_WITH_OFFSET(CFI_TMP, CFI_DEX, 0)
++     EXPORT_PC
++ 
++diff --git a/runtime/interpreter/mterp/arm64/other.S b/runtime/interpreter/mterp/arm64/other.S
++index f1d0ef3..eccd521 100644
++--- a/runtime/interpreter/mterp/arm64/other.S
+++++ b/runtime/interpreter/mterp/arm64/other.S
++@@ -263,7 +263,7 @@
++     ldr     x0, [xFP, #OFF_FP_RESULT_REGISTER]  // get pointer to result JType.
++     ldr     x0, [x0]                    // r0 <- result.i.
++     GET_INST_OPCODE ip                  // extract opcode from wINST
++-    SET_VREG_WIDE x0, x2                // fp[AA]<- r0
+++    SET_VREG_WIDE x0, w2                // fp[AA]<- r0
++     GOTO_OPCODE ip                      // jump to next instruction
++ 
++ %def op_move_wide():
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..3956b362b1a0489a98bc7c9095e6efd0102a8f59
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,20 @@@
++--- a/runtime/gc/space/image_space.cc
+++++ b/runtime/gc/space/image_space.cc
++@@ -1432,7 +1432,7 @@ class ImageSpace::BootImageLoader {
++ 
++     if (VLOG_IS_ON(image)) {
++       LOG(INFO) << "ImageSpace::BootImageLoader::LoadFromSystem exiting "
++-          << boot_image_spaces->front();
+++          << *boot_image_spaces->front();
++       logger.Dump(LOG_STREAM(INFO));
++     }
++     return true;
++@@ -1459,7 +1459,7 @@ class ImageSpace::BootImageLoader {
++ 
++     if (VLOG_IS_ON(image)) {
++       LOG(INFO) << "ImageSpace::BootImageLoader::LoadFromDalvikCache exiting "
++-          << boot_image_spaces->front();
+++          << *boot_image_spaces->front();
++       logger.Dump(LOG_STREAM(INFO));
++     }
++     return true;
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..7a261b0c45101c18afa2fa0652d4aa248a40ecab
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,35 @@@
++--- a/libdexfile/dex/method_reference.h
+++++ b/libdexfile/dex/method_reference.h
++@@ -52,20 +52,20 @@ struct MethodReferenceValueComparator {
++     // Compare the class descriptors first.
++     const dex::MethodId& mid1 = mr1.GetMethodId();
++     const dex::MethodId& mid2 = mr2.GetMethodId();
++-    int descriptor_diff = strcmp(mr1.dex_file->StringByTypeIdx(mid1.class_idx_),
+++    int descriptor_diff = std::strcmp(mr1.dex_file->StringByTypeIdx(mid1.class_idx_),
++                                  mr2.dex_file->StringByTypeIdx(mid2.class_idx_));
++     if (descriptor_diff != 0) {
++       return descriptor_diff < 0;
++     }
++     // Compare names second.
++-    int name_diff = strcmp(mr1.dex_file->GetMethodName(mid1), mr2.dex_file->GetMethodName(mid2));
+++    int name_diff = std::strcmp(mr1.dex_file->GetMethodName(mid1), mr2.dex_file->GetMethodName(mid2));
++     if (name_diff != 0) {
++       return name_diff < 0;
++     }
++     // And then compare proto ids, starting with return type comparison.
++     const dex::ProtoId& prid1 = mr1.dex_file->GetProtoId(mid1.proto_idx_);
++     const dex::ProtoId& prid2 = mr2.dex_file->GetProtoId(mid2.proto_idx_);
++-    int return_type_diff = strcmp(mr1.dex_file->StringByTypeIdx(prid1.return_type_idx_),
+++    int return_type_diff = std::strcmp(mr1.dex_file->StringByTypeIdx(prid1.return_type_idx_),
++                                   mr2.dex_file->StringByTypeIdx(prid2.return_type_idx_));
++     if (return_type_diff != 0) {
++       return return_type_diff < 0;
++@@ -76,7 +76,7 @@ struct MethodReferenceValueComparator {
++     const dex::TypeList* params2 = mr2.dex_file->GetProtoParameters(prid2);
++     size_t param2_size = (params2 != nullptr) ? params2->Size() : 0u;
++     for (size_t i = 0, num = std::min(param1_size, param2_size); i != num; ++i) {
++-      int param_diff = strcmp(mr1.dex_file->StringByTypeIdx(params1->GetTypeItem(i).type_idx_),
+++      int param_diff = std::strcmp(mr1.dex_file->StringByTypeIdx(params1->GetTypeItem(i).type_idx_),
++                               mr2.dex_file->StringByTypeIdx(params2->GetTypeItem(i).type_idx_));
++       if (param_diff != 0) {
++         return param_diff < 0;
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..69926f2076dba0e0f9867b1b0713303d2d5358c5
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,287 @@@
++Description: somehow upstream builds don't need these headers :-/
++Forwarded: not-needed
++--- a/runtime/runtime_common.h
+++++ b/runtime/runtime_common.h
++@@ -27,6 +27,7 @@
++ 
++ #include <sys/utsname.h>
++ #include <ucontext.h>
+++#include <signal.h>
++ 
++ #include <iomanip>
++ 
++--- a/sigchainlib/sigchain.cc
+++++ b/sigchainlib/sigchain.cc
++@@ -27,6 +27,7 @@
++ #include <mutex>
++ #include <type_traits>
++ #include <utility>
+++#include <climits>
++ 
++ #include "log.h"
++ #include "sigchain.h"
++--- a/runtime/base/mutex.cc
+++++ b/runtime/base/mutex.cc
++@@ -18,6 +18,7 @@
++ 
++ #include <errno.h>
++ #include <sys/time.h>
+++#include <algorithm>
++ 
++ #include "android-base/stringprintf.h"
++ 
++--- a/runtime/exec_utils.cc
+++++ b/runtime/exec_utils.cc
++@@ -20,6 +20,7 @@
++ #include <sys/wait.h>
++ #include <string>
++ #include <vector>
+++#include <cstring>
++ 
++ #include "android-base/stringprintf.h"
++ #include "android-base/strings.h"
++--- a/runtime/gc/accounting/heap_bitmap.cc
+++++ b/runtime/gc/accounting/heap_bitmap.cc
++@@ -16,6 +16,8 @@
++ 
++ #include "heap_bitmap.h"
++ 
+++#include <algorithm>
+++
++ #include "gc/accounting/space_bitmap-inl.h"
++ #include "gc/space/space.h"
++ 
++--- a/runtime/gc/accounting/read_barrier_table.h
+++++ b/runtime/gc/accounting/read_barrier_table.h
++@@ -18,6 +18,7 @@
++ #define ART_RUNTIME_GC_ACCOUNTING_READ_BARRIER_TABLE_H_
++ 
++ #include <sys/mman.h>  // For the PROT_* and MAP_* constants.
+++#include <cstring>
++ 
++ #include "base/bit_utils.h"
++ #include "base/locks.h"
++--- a/runtime/jdwp/jdwp_handler.cc
+++++ b/runtime/jdwp/jdwp_handler.cc
++@@ -19,6 +19,7 @@
++ #include <unistd.h>
++ #include <memory>
++ #include <string>
+++#include <algorithm>
++ 
++ #include "android-base/stringprintf.h"
++ 
++--- a/runtime/jit/profiling_info.h
+++++ b/runtime/jit/profiling_info.h
++@@ -18,6 +18,7 @@
++ #define ART_RUNTIME_JIT_PROFILING_INFO_H_
++ 
++ #include <vector>
+++#include <cstring>
++ 
++ #include "base/macros.h"
++ #include "gc_root.h"
++--- a/runtime/arch/instruction_set_features.cc
+++++ b/runtime/arch/instruction_set_features.cc
++@@ -21,6 +21,8 @@
++ #include <algorithm>
++ #include <ostream>
++ 
+++#include <algorithm>
+++
++ #include "android-base/strings.h"
++ 
++ #include "base/casts.h"
++--- a/runtime/arch/mips/instruction_set_features_mips.cc
+++++ b/runtime/arch/mips/instruction_set_features_mips.cc
++@@ -18,6 +18,7 @@
++ 
++ #include <fstream>
++ #include <sstream>
+++#include <cstring>
++ 
++ #include <android-base/stringprintf.h>
++ #include <android-base/strings.h>
++--- a/runtime/monitor.h
+++++ b/runtime/monitor.h
++@@ -24,6 +24,7 @@
++ #include <iosfwd>
++ #include <list>
++ #include <vector>
+++#include <cstring>
++ 
++ #include "base/allocator.h"
++ #include "base/atomic.h"
++--- a/runtime/arch/x86/context_x86.cc
+++++ b/runtime/arch/x86/context_x86.cc
++@@ -16,6 +16,8 @@
++ 
++ #include "context_x86.h"
++ 
+++#include <cstring>
+++
++ #include "base/bit_utils.h"
++ #include "base/bit_utils_iterator.h"
++ #include "base/memory_tool.h"
++--- a/libartbase/base/arena_allocator.h
+++++ b/libartbase/base/arena_allocator.h
++@@ -17,6 +17,7 @@
++ #ifndef ART_LIBARTBASE_BASE_ARENA_ALLOCATOR_H_
++ #define ART_LIBARTBASE_BASE_ARENA_ALLOCATOR_H_
++ 
+++#include <cstring>
++ #include <stddef.h>
++ #include <stdint.h>
++ 
++--- a/libdexfile/dex/dex_file_types.h
+++++ b/libdexfile/dex/dex_file_types.h
++@@ -17,6 +17,8 @@
++ #ifndef ART_LIBDEXFILE_DEX_DEX_FILE_TYPES_H_
++ #define ART_LIBDEXFILE_DEX_DEX_FILE_TYPES_H_
++ 
+++#include <cstdint>
+++#include <functional>
++ #include <iosfwd>
++ #include <limits>
++ #include <utility>
++--- a/libdexfile/dex/method_reference.h
+++++ b/libdexfile/dex/method_reference.h
++@@ -17,6 +17,7 @@
++ #ifndef ART_LIBDEXFILE_DEX_METHOD_REFERENCE_H_
++ #define ART_LIBDEXFILE_DEX_METHOD_REFERENCE_H_
++ 
+++#include <cstring>
++ #include <stdint.h>
++ #include <string>
++ #include "dex/dex_file.h"
++--- a/libartbase/base/arena_containers.h
+++++ b/libartbase/base/arena_containers.h
++@@ -17,6 +17,7 @@
++ #ifndef ART_LIBARTBASE_BASE_ARENA_CONTAINERS_H_
++ #define ART_LIBARTBASE_BASE_ARENA_CONTAINERS_H_
++ 
+++#include <cstring>
++ #include <deque>
++ #include <queue>
++ #include <set>
++--- a/libartbase/arch/instruction_set.cc
+++++ b/libartbase/arch/instruction_set.cc
++@@ -19,6 +19,7 @@
++ #include "android-base/logging.h"
++ #include "base/bit_utils.h"
++ #include "base/globals.h"
+++#include <cstring>
++ 
++ namespace art {
++ 
++--- a/libartbase/base/bit_vector-inl.h
+++++ b/libartbase/base/bit_vector-inl.h
++@@ -20,6 +20,7 @@
++ #include "bit_vector.h"
++ 
++ #include <android-base/logging.h>
+++#include <cstring>
++ 
++ #include "bit_utils.h"
++ 
++--- a/libartbase/base/bit_vector.cc
+++++ b/libartbase/base/bit_vector.cc
++@@ -16,6 +16,7 @@
++ 
++ #include "bit_vector.h"
++ 
+++#include <cstring>
++ #include <limits>
++ #include <sstream>
++ 
++--- a/libartbase/base/file_utils.cc
+++++ b/libartbase/base/file_utils.cc
++@@ -40,6 +40,7 @@
++ 
++ 
++ #include <memory>
+++#include <cstring>
++ 
++ #include "android-base/stringprintf.h"
++ #include "android-base/strings.h"
++--- a/libartbase/base/bit_vector.h
+++++ b/libartbase/base/bit_vector.h
++@@ -18,6 +18,7 @@
++ #define ART_LIBARTBASE_BASE_BIT_VECTOR_H_
++ 
++ #include <stdint.h>
+++#include <cstring>
++ #include <iterator>
++ 
++ #include "bit_utils.h"
++--- a/libartbase/base/file_magic.cc
+++++ b/libartbase/base/file_magic.cc
++@@ -19,6 +19,7 @@
++ #include <fcntl.h>
++ #include <sys/stat.h>
++ #include <sys/types.h>
+++#include <cstring>
++ 
++ #include <android-base/logging.h>
++ #include <android-base/stringprintf.h>
++--- a/libartbase/base/logging.cc
+++++ b/libartbase/base/logging.cc
++@@ -16,6 +16,7 @@
++ 
++ #include "logging.h"
++ 
+++#include <cstring>
++ #include <iostream>
++ #include <limits>
++ #include <sstream>
++--- a/libartbase/base/memfd.cc
+++++ b/libartbase/base/memfd.cc
++@@ -24,6 +24,7 @@
++ #include <unistd.h>
++ #endif
++ 
+++#include <cstring>
++ #include "macros.h"
++ 
++ // When building for linux host, glibc in prebuilts does not include memfd_create system call
++--- a/libartbase/base/scoped_flock.cc
+++++ b/libartbase/base/scoped_flock.cc
++@@ -19,6 +19,8 @@
++ #include <sys/file.h>
++ #include <sys/stat.h>
++ 
+++#include <cstring>
+++
++ #include <android-base/logging.h>
++ #include <android-base/stringprintf.h>
++ 
++--- a/libartbase/base/unix_file/fd_file.cc
+++++ b/libartbase/base/unix_file/fd_file.cc
++@@ -29,6 +29,7 @@
++ #include <windows.h>
++ #endif
++ 
+++#include <cstring>
++ #include <limits>
++ 
++ #include <android-base/file.h>
++--- a/libdexfile/dex/descriptors_names.cc
+++++ b/libdexfile/dex/descriptors_names.cc
++@@ -21,6 +21,7 @@
++ 
++ #include "base/macros.h"
++ #include "dex/utf-inl.h"
+++#include <cstring>
++ 
++ namespace art {
++ 
++--- a/libdexfile/dex/dex_file_loader.h
+++++ b/libdexfile/dex/dex_file_loader.h
++@@ -18,6 +18,7 @@
++ #define ART_LIBDEXFILE_DEX_DEX_FILE_LOADER_H_
++ 
++ #include <cstdint>
+++#include <cstring>
++ #include <memory>
++ #include <string>
++ #include <vector>
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..fe06ea2328cb99afda2fd486224bf67e1666e7e5
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,45 @@@
++diff --git a/runtime/interpreter/mterp/common/gen_setup.py b/runtime/interpreter/mterp/common/gen_setup.py
++index 2684ab2..ac0606b 100644
++--- a/runtime/interpreter/mterp/common/gen_setup.py
+++++ b/runtime/interpreter/mterp/common/gen_setup.py
++@@ -19,7 +19,7 @@
++ # the templated snippets. Those define all the helper functions used below.
++ 
++ import sys, re
++-from cStringIO import StringIO
+++from io import StringIO
++ 
++ out = StringIO()  # File-like in-memory buffer.
++ handler_size_bytes = "MTERP_HANDLER_SIZE"
++diff --git a/runtime/interpreter/mterp/gen_mterp.py b/runtime/interpreter/mterp/gen_mterp.py
++index 5d25955..8534e99 100755
++--- a/runtime/interpreter/mterp/gen_mterp.py
+++++ b/runtime/interpreter/mterp/gen_mterp.py
++@@ -1,4 +1,4 @@
++-#!/usr/bin/env python
+++#!/usr/bin/env python3
++ #
++ # Copyright (C) 2016 The Android Open Source Project
++ #
++@@ -15,7 +15,7 @@
++ # limitations under the License.
++ 
++ import sys, re, os
++-from cStringIO import StringIO
+++from io import StringIO
++ 
++ SCRIPT_DIR = os.path.dirname(sys.argv[0])
++ # This file is included verbatim at the start of the in-memory python script.
++@@ -37,9 +37,9 @@ def getOpcodeList():
++   opcode_fp.close()
++ 
++   if len(opcodes) != NUM_PACKED_OPCODES:
++-    print "ERROR: found %d opcodes in Interp.h (expected %d)" \
++-        % (len(opcodes), NUM_PACKED_OPCODES)
++-    raise SyntaxError, "bad opcode count"
+++    print("ERROR: found %d opcodes in Interp.h (expected %d)" \
+++        % (len(opcodes), NUM_PACKED_OPCODES))
+++    raise SyntaxError("bad opcode count")
++   return opcodes
++ 
++ indent_re = re.compile(r"^%( *)")
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..b0ad5b7c9d9cdd0d2a7c8e700e694e255470d98b
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,15 @@@
++use-android-dlmalloc.patch
++missing-system-includes.patch
++ucontext.patch
++atomic-exception-specification.patch
++image-space-dereference.patch
++storage-mode-concat.patch
++method-reference-std-ns.patch
++python3-gen_mterp.patch
++stats-incomplete-def.patch
++fix-build-on-non-x86.patch
++workaround-cacheflush-on-arm.patch
++adapt-asm-output-of-clang-that-no-is-placed-before-data.patch
++arm-asm-instruction.patch
++fix-mterp-assembly-to-use-uxtw-instead-of-lsl-where-needed.patch
++Fix-ftbfs-for-c-17.patch
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..867603ba8dcbb84a2749085f8bfa9a9c4efed97f
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,31 @@@
++--- a/libartbase/base/stats.h
+++++ b/libartbase/base/stats.h
++@@ -28,8 +28,8 @@ class Stats {
++  public:
++   double Value() const { return value_; }
++   size_t Count() const { return count_; }
++-  Stats* Child(const char* name) { return &children_[name]; }
++-  const std::unordered_map<const char*, Stats>& Children() const { return children_; }
+++  Stats* Child(const char* name) { return &(*children_)[name]; }
+++  const std::unordered_map<const char*, Stats>& Children() const { return *children_; }
++ 
++   void AddBytes(double bytes, size_t count = 1) { Add(bytes, count); }
++   void AddBits(double bits, size_t count = 1) { Add(bits / kBitsPerByte, count); }
++@@ -38,7 +38,7 @@ class Stats {
++ 
++   double SumChildrenValues() const {
++     double sum = 0.0;
++-    for (auto it : children_) {
+++    for (auto it : *children_) {
++       sum += it.second.Value();
++     }
++     return sum;
++@@ -52,7 +52,7 @@ class Stats {
++ 
++   double value_ = 0.0;  // Commutative sum of the collected statistic in basic units.
++   size_t count_ = 0;    // The number of samples for this node.
++-  std::unordered_map<const char*, Stats> children_;
+++  std::unordered_map<const char*, Stats>* children_;
++ };
++ 
++ }  // namespace art
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..517c2480331a6449aeb148d6baafa990c5b18cad
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,11 @@@
++--- a/runtime/image.cc
+++++ b/runtime/image.cc
++@@ -172,7 +172,7 @@ bool ImageHeader::Block::Decompress(uint8_t* out_ptr,
++     }
++     default: {
++       if (error_msg != nullptr) {
++-        *error_msg = (std::ostringstream() << "Invalid image format " << storage_mode_).str();
+++        *error_msg = "Invalid image format " + storage_mode_;
++       }
++       return false;
++     }
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..544f5a6867f434fa5dbbc3f32018b43bb159feea
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,208 @@@
++Description: Use `ucontext_t` instead of `ucontext`
++ Both Bionic and glibc define a struct called `ucontext_t` but only Bionic
++ defines an alias `ucontext_t`. Let's use the more standardized one.
++--- a/runtime/native_stack_dump.cc
+++++ b/runtime/native_stack_dump.cc
++@@ -38,6 +38,7 @@
++ #include <stdlib.h>
++ #include <sys/time.h>
++ #include <sys/types.h>
+++#include <sys/ucontext.h>
++ 
++ #include "android-base/stringprintf.h"
++ #include "android-base/strings.h"
++@@ -328,7 +329,7 @@
++   }
++   std::unique_ptr<Backtrace> backtrace(Backtrace::Create(BACKTRACE_CURRENT_PROCESS, tid, map));
++   backtrace->SetSkipFrames(skip_frames);
++-  if (!backtrace->Unwind(0, reinterpret_cast<ucontext*>(ucontext_ptr))) {
+++  if (!backtrace->Unwind(0, reinterpret_cast<ucontext_t*>(ucontext_ptr))) {
++     os << prefix << "(backtrace::Unwind failed for thread " << tid
++        << ": " <<  backtrace->GetErrorString(backtrace->GetError()) << ")" << std::endl;
++     return;
++--- a/runtime/arch/x86/fault_handler_x86.cc
+++++ b/runtime/arch/x86/fault_handler_x86.cc
++@@ -280,7 +280,7 @@
++ void FaultManager::GetMethodAndReturnPcAndSp(siginfo_t* siginfo, void* context,
++                                              ArtMethod** out_method,
++                                              uintptr_t* out_return_pc, uintptr_t* out_sp) {
++-  struct ucontext* uc = reinterpret_cast<struct ucontext*>(context);
+++  struct ucontext_t* uc = reinterpret_cast<struct ucontext_t*>(context);
++   *out_sp = static_cast<uintptr_t>(uc->CTX_ESP);
++   VLOG(signals) << "sp: " << std::hex << *out_sp;
++   if (*out_sp == 0) {
++@@ -325,7 +325,7 @@
++   if (!IsValidImplicitCheck(sig)) {
++     return false;
++   }
++-  struct ucontext *uc = reinterpret_cast<struct ucontext*>(context);
+++  struct ucontext_t *uc = reinterpret_cast<struct ucontext_t*>(context);
++   uint8_t* pc = reinterpret_cast<uint8_t*>(uc->CTX_EIP);
++   uint8_t* sp = reinterpret_cast<uint8_t*>(uc->CTX_ESP);
++ 
++@@ -381,7 +381,7 @@
++ #endif
++   uint8_t checkinst2[] = {0x85, 0x00};
++ 
++-  struct ucontext *uc = reinterpret_cast<struct ucontext*>(context);
+++  struct ucontext_t *uc = reinterpret_cast<struct ucontext_t*>(context);
++   uint8_t* pc = reinterpret_cast<uint8_t*>(uc->CTX_EIP);
++   uint8_t* sp = reinterpret_cast<uint8_t*>(uc->CTX_ESP);
++ 
++@@ -437,7 +437,7 @@
++ // address for the previous method is on the stack at ESP.
++ 
++ bool StackOverflowHandler::Action(int, siginfo_t* info, void* context) {
++-  struct ucontext *uc = reinterpret_cast<struct ucontext*>(context);
+++  struct ucontext_t *uc = reinterpret_cast<struct ucontext_t*>(context);
++   uintptr_t sp = static_cast<uintptr_t>(uc->CTX_ESP);
++ 
++   uintptr_t fault_addr = reinterpret_cast<uintptr_t>(info->si_addr);
++--- a/runtime/arch/arm64/fault_handler_arm64.cc
+++++ b/runtime/arch/arm64/fault_handler_arm64.cc
++@@ -41,7 +41,7 @@
++ void FaultManager::GetMethodAndReturnPcAndSp(siginfo_t* siginfo ATTRIBUTE_UNUSED, void* context,
++                                              ArtMethod** out_method,
++                                              uintptr_t* out_return_pc, uintptr_t* out_sp) {
++-  struct ucontext *uc = reinterpret_cast<struct ucontext *>(context);
+++  struct ucontext_t *uc = reinterpret_cast<struct ucontext_t *>(context);
++   struct sigcontext *sc = reinterpret_cast<struct sigcontext*>(&uc->uc_mcontext);
++   *out_sp = static_cast<uintptr_t>(sc->sp);
++   VLOG(signals) << "sp: " << *out_sp;
++@@ -77,7 +77,7 @@
++   // PC at the point of call.  For Null checks we insert a GC map that is immediately after
++   // the load/store instruction that might cause the fault.
++ 
++-  struct ucontext *uc = reinterpret_cast<struct ucontext*>(context);
+++  struct ucontext_t *uc = reinterpret_cast<struct ucontext_t*>(context);
++   struct sigcontext *sc = reinterpret_cast<struct sigcontext*>(&uc->uc_mcontext);
++ 
++   // Push the gc map location to the stack and pass the fault address in LR.
++@@ -106,7 +106,7 @@
++       (Thread::ThreadSuspendTriggerOffset<PointerSize::k64>().Int32Value() << 7);
++   uint32_t checkinst2 = 0xf9400000;
++ 
++-  struct ucontext *uc = reinterpret_cast<struct ucontext *>(context);
+++  struct ucontext_t *uc = reinterpret_cast<struct ucontext_t *>(context);
++   struct sigcontext *sc = reinterpret_cast<struct sigcontext*>(&uc->uc_mcontext);
++   uint8_t* ptr2 = reinterpret_cast<uint8_t*>(sc->pc);
++   uint8_t* ptr1 = ptr2 - 4;
++@@ -152,7 +152,7 @@
++ 
++ bool StackOverflowHandler::Action(int sig ATTRIBUTE_UNUSED, siginfo_t* info ATTRIBUTE_UNUSED,
++                                   void* context) {
++-  struct ucontext *uc = reinterpret_cast<struct ucontext *>(context);
+++  struct ucontext_t *uc = reinterpret_cast<struct ucontext_t *>(context);
++   struct sigcontext *sc = reinterpret_cast<struct sigcontext*>(&uc->uc_mcontext);
++   VLOG(signals) << "stack overflow handler with sp at " << std::hex << &uc;
++   VLOG(signals) << "sigcontext: " << std::hex << sc;
++--- a/runtime/arch/arm/fault_handler_arm.cc
+++++ b/runtime/arch/arm/fault_handler_arm.cc
++@@ -48,7 +48,7 @@
++ void FaultManager::GetMethodAndReturnPcAndSp(siginfo_t* siginfo ATTRIBUTE_UNUSED, void* context,
++                                              ArtMethod** out_method,
++                                              uintptr_t* out_return_pc, uintptr_t* out_sp) {
++-  struct ucontext* uc = reinterpret_cast<struct ucontext*>(context);
+++  struct ucontext_t* uc = reinterpret_cast<struct ucontext_t*>(context);
++   struct sigcontext *sc = reinterpret_cast<struct sigcontext*>(&uc->uc_mcontext);
++   *out_sp = static_cast<uintptr_t>(sc->arm_sp);
++   VLOG(signals) << "sp: " << std::hex << *out_sp;
++@@ -99,7 +99,7 @@
++   // register in order to find the mapping.
++ 
++   // Need to work out the size of the instruction that caused the exception.
++-  struct ucontext *uc = reinterpret_cast<struct ucontext*>(context);
+++  struct ucontext_t *uc = reinterpret_cast<struct ucontext_t*>(context);
++   struct sigcontext *sc = reinterpret_cast<struct sigcontext*>(&uc->uc_mcontext);
++   uint8_t* ptr = reinterpret_cast<uint8_t*>(sc->arm_pc);
++   uint32_t instr_size = GetInstructionSize(ptr);
++@@ -132,7 +132,7 @@
++       + Thread::ThreadSuspendTriggerOffset<PointerSize::k32>().Int32Value();
++   uint16_t checkinst2 = 0x6800;
++ 
++-  struct ucontext* uc = reinterpret_cast<struct ucontext*>(context);
+++  struct ucontext_t* uc = reinterpret_cast<struct ucontext_t*>(context);
++   struct sigcontext *sc = reinterpret_cast<struct sigcontext*>(&uc->uc_mcontext);
++   uint8_t* ptr2 = reinterpret_cast<uint8_t*>(sc->arm_pc);
++   uint8_t* ptr1 = ptr2 - 4;
++@@ -197,7 +197,7 @@
++ 
++ bool StackOverflowHandler::Action(int sig ATTRIBUTE_UNUSED, siginfo_t* info ATTRIBUTE_UNUSED,
++                                   void* context) {
++-  struct ucontext* uc = reinterpret_cast<struct ucontext*>(context);
+++  struct ucontext_t* uc = reinterpret_cast<struct ucontext_t*>(context);
++   struct sigcontext *sc = reinterpret_cast<struct sigcontext*>(&uc->uc_mcontext);
++   VLOG(signals) << "stack overflow handler with sp at " << std::hex << &uc;
++   VLOG(signals) << "sigcontext: " << std::hex << sc;
++--- a/runtime/arch/arm/instruction_set_features_arm.cc
+++++ b/runtime/arch/arm/instruction_set_features_arm.cc
++@@ -223,8 +223,9 @@
++                             siginfo_t* si ATTRIBUTE_UNUSED,
++                             void* data) {
++ #if defined(__arm__)
++-  struct ucontext *uc = (struct ucontext *)data;
++-  struct sigcontext *sc = &uc->uc_mcontext;
+++  struct ucontext_t *uc = (struct ucontext_t *)data;
+++  // See the starting chunk of `FaultManager::GetMethodAndReturnPcAndSp()` in `fault_handler_arm.cc`
+++  struct sigcontext *sc = reinterpret_cast<struct sigcontext*>(&uc->uc_mcontext);
++   sc->arm_r0 = 0;     // Set R0 to #0 to signal error.
++   sc->arm_pc += 4;    // Skip offending instruction.
++ #else
++--- a/runtime/arch/mips/fault_handler_mips.cc
+++++ b/runtime/arch/mips/fault_handler_mips.cc
++@@ -40,7 +40,7 @@
++ void FaultManager::GetMethodAndReturnPcAndSp(siginfo_t* siginfo, void* context,
++                                              ArtMethod** out_method,
++                                              uintptr_t* out_return_pc, uintptr_t* out_sp) {
++-  struct ucontext* uc = reinterpret_cast<struct ucontext*>(context);
+++  struct ucontext_t* uc = reinterpret_cast<struct ucontext_t*>(context);
++   struct sigcontext *sc = reinterpret_cast<struct sigcontext*>(&uc->uc_mcontext);
++   *out_sp = static_cast<uintptr_t>(sc->sc_regs[mips::SP]);
++   VLOG(signals) << "sp: " << *out_sp;
++@@ -77,7 +77,7 @@
++   // PC at the point of call.  For Null checks we insert a GC map that is immediately after
++   // the load/store instruction that might cause the fault.
++ 
++-  struct ucontext *uc = reinterpret_cast<struct ucontext*>(context);
+++  struct ucontext_t *uc = reinterpret_cast<struct ucontext_t*>(context);
++   struct sigcontext *sc = reinterpret_cast<struct sigcontext*>(&uc->uc_mcontext);
++ 
++   // Decrement $sp by the frame size of the kSaveEverything method and store
++@@ -112,7 +112,7 @@
++ // to the overflow region below the protected region.
++ 
++ bool StackOverflowHandler::Action(int sig ATTRIBUTE_UNUSED, siginfo_t* info, void* context) {
++-  struct ucontext* uc = reinterpret_cast<struct ucontext*>(context);
+++  struct ucontext_t* uc = reinterpret_cast<struct ucontext_t*>(context);
++   struct sigcontext *sc = reinterpret_cast<struct sigcontext*>(&uc->uc_mcontext);
++   VLOG(signals) << "stack overflow handler with sp at " << std::hex << &uc;
++   VLOG(signals) << "sigcontext: " << std::hex << sc;
++--- a/runtime/arch/mips64/fault_handler_mips64.cc
+++++ b/runtime/arch/mips64/fault_handler_mips64.cc
++@@ -41,7 +41,7 @@
++ void FaultManager::GetMethodAndReturnPcAndSp(siginfo_t* siginfo, void* context,
++                                              ArtMethod** out_method,
++                                              uintptr_t* out_return_pc, uintptr_t* out_sp) {
++-  struct ucontext* uc = reinterpret_cast<struct ucontext*>(context);
+++  struct ucontext_t* uc = reinterpret_cast<struct ucontext_t*>(context);
++   struct sigcontext *sc = reinterpret_cast<struct sigcontext*>(&uc->uc_mcontext);
++   *out_sp = static_cast<uintptr_t>(sc->sc_regs[mips64::SP]);
++   VLOG(signals) << "sp: " << *out_sp;
++@@ -79,7 +79,7 @@
++   // PC at the point of call.  For Null checks we insert a GC map that is immediately after
++   // the load/store instruction that might cause the fault.
++ 
++-  struct ucontext *uc = reinterpret_cast<struct ucontext*>(context);
+++  struct ucontext_t *uc = reinterpret_cast<struct ucontext_t*>(context);
++   struct sigcontext *sc = reinterpret_cast<struct sigcontext*>(&uc->uc_mcontext);
++ 
++   // Decrement $sp by the frame size of the kSaveEverything method and store
++@@ -114,7 +114,7 @@
++ // to the overflow region below the protected region.
++ 
++ bool StackOverflowHandler::Action(int sig ATTRIBUTE_UNUSED, siginfo_t* info, void* context) {
++-  struct ucontext* uc = reinterpret_cast<struct ucontext*>(context);
+++  struct ucontext_t* uc = reinterpret_cast<struct ucontext_t*>(context);
++   struct sigcontext *sc = reinterpret_cast<struct sigcontext*>(&uc->uc_mcontext);
++   VLOG(signals) << "stack overflow handler with sp at " << std::hex << &uc;
++   VLOG(signals) << "sigcontext: " << std::hex << sc;
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..b3ddc9411b9739698c73e4357ff54e4b807eb872
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,22 @@@
++--- a/runtime/gc/allocator/dlmalloc.h
+++++ b/runtime/gc/allocator/dlmalloc.h
++@@ -33,7 +33,7 @@
++ #pragma GCC diagnostic push
++ #pragma GCC diagnostic ignored "-Wredundant-decls"
++ #pragma GCC diagnostic ignored "-Wnull-pointer-arithmetic"
++-#include "../../external/dlmalloc/malloc.h"
+++#include "debian/dlmalloc/malloc.h"
++ #pragma GCC diagnostic pop
++ 
++ // Callback for dlmalloc_inspect_all or mspace_inspect_all that will madvise(2) unused
++--- a/runtime/gc/allocator/dlmalloc.cc
+++++ b/runtime/gc/allocator/dlmalloc.cc
++@@ -39,7 +39,7 @@
++ #pragma GCC diagnostic ignored "-Wstrict-aliasing"
++ #pragma GCC diagnostic ignored "-Wnull-pointer-arithmetic"
++ #pragma GCC diagnostic ignored "-Wexpansion-to-defined"
++-#include "../../../external/dlmalloc/malloc.c"
+++#include "debian/dlmalloc/malloc.c"
++ // Note: malloc.c uses a DEBUG define to drive debug code. This interferes with the DEBUG severity
++ //       of libbase, so undefine it now.
++ #undef DEBUG
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..8075b6fba7ef3c398d6d2c5e70d670eeb3f73103
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,16 @@@
++Description: Workaround cacheflush on arm
++Forwarded: not-needed
++--- a/libartbase/base/utils.cc
+++++ b/libartbase/base/utils.cc
++@@ -76,7 +76,10 @@ static constexpr size_t kMaxFlushAttempts = 4;
++ int CacheFlush(uintptr_t start, uintptr_t limit) {
++   // The signature of cacheflush(2) seems to vary by source. On ARM the system call wrapper
++   //    (bionic/SYSCALLS.TXT) has the form: int cacheflush(long start, long end, long flags);
++-  int r = cacheflush(start, limit, kCacheFlushFlags);
+++//  int r = cacheflush(start, limit, kCacheFlushFlags);
+++//This is only for ARM
+++//Workaround/skip cacheflush until we find the real replacement
+++  int r = 0;
++   if (r == -1) {
++     CHECK_NE(errno, EINVAL);
++   }
diff --cc debian/rules
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..d1ee29d46be8be8b95b7a459fd9448d34ca88183
new file mode 100755 (executable)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,83 @@@
++#!/usr/bin/make -f
++
++include /usr/share/dpkg/architecture.mk
++include /usr/share/dpkg/pkg-info.mk
++
++export DEB_HOST_MULTIARCH
++
++# Security Hardening
++export DEB_BUILD_MAINT_OPTIONS = hardening=+all
++export DEB_CFLAGS_MAINT_APPEND = -fPIC
++export DEB_CXXFLAGS_MAINT_APPEND = -fPIC
++export DEB_LDFLAGS_MAINT_APPEND = -fPIC
++
++DEB_CPPFLAGS_MAINT_APPEND += \
++  -DNDEBUG \
++  -I/usr/include/android \
++  -UDEBUG
++# Clang defines a macro `mips = 1` which disrupts the namespace declaration `art::mips`
++DEB_CPPFLAGS_MAINT_APPEND += -Umips
++export DEB_CPPFLAGS_MAINT_APPEND
++
++
++COMPONENTS = debian/out/dmtracedump
++MAN_COMPONENTS = debian/out/dmtracedump.1
++
++# MIPS is left out because ART only supports MIPSr6 while Debian is by default MIPSr2
++ifneq ($(filter amd64 i386 armel armhf arm64,$(DEB_HOST_ARCH)),)
++ ifeq ($(findstring stage1,$(DEB_VERSION)),)
++  COMPONENTS += debian/out/dexdump debian/out/dexlist
++  MAN_COMPONENTS += debian/out/dexdump.1
++ endif
++  COMPONENTS += debian/out/libdexfile_external.so debian/out/libdexfile_support.so
++  export CC=clang
++  export CXX=clang++
++endif
++
++debian/out:
++      mkdir -p $@
++
++debian/out/dmtracedump: debian/dmtracedump.mk
++      dh_auto_build --buildsystem=makefile -- --file=$<
++
++debian/out/libdexfile_support.so: debian/libdexfile_support.mk
++      dh_auto_build --buildsystem=makefile -- --file=$<
++
++debian/out/libsigchain.so: debian/libsigchain.mk
++      dh_auto_build --buildsystem=makefile -- --file=$<
++
++debian/out/dexlist: debian/out/libart.so
++      dh_auto_build --buildsystem=makefile -- --file=debian/dexlist.mk
++
++debian/out/dexdump: debian/out/libart.so
++      dh_auto_build --buildsystem=makefile -- --file=debian/dexdump.mk
++
++debian/out/libdexfile_external.so: debian/out/libart.so
++      dh_auto_build --buildsystem=makefile -- --file=debian/libdexfile_external.mk
++
++debian/out/libart.so: debian/out/asm_defines.h debian/out/libsigchain.so
++      dh_auto_build --buildsystem=makefile -- --file=debian/libart.mk
++
++# Only for debug purpose to build standalone object
++debian/out/asm_defines.h debian/out/operator_out.cc: debian/out
++      dh_auto_build --buildsystem=makefile -- --file=debian/libart.mk $@
++debian/out/mterp.S: debian/out debian/out/asm_defines.h
++      dh_auto_build --buildsystem=makefile -- --file=debian/libart.mk $@
++runtime/%.o libartbase/%.o libdexfile/%.o debian/out/%.o: debian/out
++      dh_auto_build --buildsystem=makefile -- --file=debian/libart.mk $@
++
++debian/out/%.1: debian/out/%
++      help2man -N -n "Dex Tool" --no-discard-stderr --version-string="$(DEB_VERSION)" \
++              -o $@ $<
++
++%:
++      dh $@
++
++override_dh_auto_build: debian/out $(COMPONENTS) $(MAN_COMPONENTS)
++
++override_dh_auto_clean:
++      dh_auto_clean
++      make clean --file=debian/libart.mk
++
++override_dh_shlibdeps:
++      dh_shlibdeps -l/usr/lib/$(DEB_HOST_MULTIARCH)/android
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..46ebe0266599c4440c3cc958b9e769927a55dbd4
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,1 @@@
++3.0 (quilt)
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..027eab5409ce4867ceb40f2f4453f48b75851963
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,6 @@@
++Test-Command: 2>&1 dmtracedump |  grep 'Turn on HTML output'
++Depends: dmtracedump
++
++# <!stage1>
++Tests: dexdump-dexlist
++Depends: dexdump, dexlist
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..98d4ec5dd2a5823205e30cdfa7d9a49bd615c140
new file mode 100755 (executable)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,4 @@@
++#!/usr/bin/env bash
++
++export ANDROID_HOST_OUT=/usr
++test/dexdump/run-all-tests
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..8b9528d74c66162a9cc01fbbfc121db1d57eaeb1
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,7 @@@
++---
++Archive: Google Git
++Bug-Database: https://issuetracker.google.com/issues?q=componentid:192728%20status:open
++Bug-Submit: https://developer.android.com/studio/report-bugs
++Homepage: https://source.android.com/source/developing.html
++Repository-Browse: https://android.googlesource.com/platform/art
++Repository: https://android.googlesource.com/platform/art
diff --cc debian/watch
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..f1315dc93d8f4b355d113b40aa005c8b1877a70b
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,6 @@@
++version=4
++opts="pagemangle=s%\">android-%\.tar\.gz\">android-%g;s%/\+/refs/tags/%/+archive/%g, \
++      uversionmangle=s%\.(\d+)\.\.tar\.gz%\+r$1%, \
++      filenamemangle=s%[\w\/]+\+archive\/android-%@PACKAGE@-%" \
++https://android.googlesource.com/platform/art/+refs \
++    [\w\/]+\+archive\/android-([0-9\.]+)_r(\d+|\d+\.\d+|\w)(\.tar\.gz) debian uupdate