From 7bf5d870174fc2f18126bdf5719ebb6209a2ab1d Mon Sep 17 00:00:00 2001 From: Ben Konyi Date: Fri, 20 Jan 2017 15:26:58 -0800 Subject: [PATCH] Reintroducing MallocHooks changes with fix for infinite loop in MallocHooks on Platform::Exit. BUG= R=zra@google.com Review-Url: https://codereview.chromium.org/2643303003 . --- runtime/BUILD.gn | 8 + runtime/bin/BUILD.gn | 5 +- runtime/bin/bin.gypi | 6 - runtime/bin/gen_snapshot.cc | 1 + runtime/vm/dart.cc | 4 +- runtime/vm/hash_map.h | 63 ++++++ runtime/vm/hash_map_test.cc | 61 ++++++ runtime/vm/malloc_hooks.cc | 259 ++++++++++++++++++++++++- runtime/vm/malloc_hooks.h | 8 +- runtime/vm/malloc_hooks_test.cc | 80 ++++++++ runtime/vm/malloc_hooks_unsupported.cc | 30 ++- runtime/vm/vm.gypi | 28 --- runtime/vm/vm_sources.gypi | 3 +- 13 files changed, 510 insertions(+), 46 deletions(-) create mode 100644 runtime/vm/malloc_hooks_test.cc diff --git a/runtime/BUILD.gn b/runtime/BUILD.gn index 36983b6a75c..a70b6b27be4 100644 --- a/runtime/BUILD.gn +++ b/runtime/BUILD.gn @@ -2,6 +2,8 @@ # for details. All rights reserved. Use of this source code is governed by a # BSD-style license that can be found in the LICENSE file. +import("runtime_args.gni") + declare_args() { # Instead of using is_debug, we introduce a different flag for specifying a # Debug build of Dart so that clients can still use a Release build of Dart @@ -146,6 +148,12 @@ config("dart_config") { defines += [ "NDEBUG" ] } + include_dirs = [] + if (dart_use_tcmalloc) { + defines += [ "DART_USE_TCMALLOC" ] + include_dirs += [ "../third_party/tcmalloc/gperftools/src" ] + } + if (!is_win) { cflags = [ "-Werror", diff --git a/runtime/bin/BUILD.gn b/runtime/bin/BUILD.gn index c3140f0d76a..5d8d56bfdb4 100644 --- a/runtime/bin/BUILD.gn +++ b/runtime/bin/BUILD.gn @@ -297,6 +297,10 @@ executable("gen_snapshot") { include_dirs = [ ".." ] + if (dart_use_tcmalloc) { + deps += [ "//third_party/tcmalloc" ] + } + if (is_mac) { libs = [ "CoreFoundation.framework", @@ -574,7 +578,6 @@ template("dart_executable") { if (dart_use_tcmalloc) { deps += [ "//third_party/tcmalloc" ] - defines += [ "DART_USE_TCMALLOC" ] } sources = [ diff --git a/runtime/bin/bin.gypi b/runtime/bin/bin.gypi index d5466386345..be196cf71cf 100644 --- a/runtime/bin/bin.gypi +++ b/runtime/bin/bin.gypi @@ -1151,9 +1151,6 @@ 'dependencies': [ '../third_party/tcmalloc/tcmalloc.gypi:tcmalloc', ], - 'defines': [ - 'DART_USE_TCMALLOC' - ], }], ], 'configurations': { @@ -1348,9 +1345,6 @@ 'dependencies': [ '../third_party/tcmalloc/tcmalloc.gypi:tcmalloc', ], - 'defines': [ - 'DART_USE_TCMALLOC' - ], }], ], 'configurations': { diff --git a/runtime/bin/gen_snapshot.cc b/runtime/bin/gen_snapshot.cc index 3ebc8fb986e..d97f29ea59d 100644 --- a/runtime/bin/gen_snapshot.cc +++ b/runtime/bin/gen_snapshot.cc @@ -383,6 +383,7 @@ static void WriteSnapshotFile(const char* filename, Log::PrintErr("Error: Unable to write snapshot file: %s\n\n", filename); Dart_ExitScope(); Dart_ShutdownIsolate(); + Dart_Cleanup(); exit(kErrorExitCode); } if (!file->WriteFully(buffer, size)) { diff --git a/runtime/vm/dart.cc b/runtime/vm/dart.cc index 57f5cbe759f..d50189f68dd 100644 --- a/runtime/vm/dart.cc +++ b/runtime/vm/dart.cc @@ -17,6 +17,7 @@ #include "vm/heap.h" #include "vm/isolate.h" #include "vm/kernel_isolate.h" +#include "vm/malloc_hooks.h" #include "vm/message_handler.h" #include "vm/metrics.h" #include "vm/object.h" @@ -154,6 +155,7 @@ char* Dart::InitOnce(const uint8_t* vm_isolate_snapshot, start_time_micros_ = OS::GetCurrentMonotonicMicros(); VirtualMemory::InitOnce(); OSThread::InitOnce(); + MallocHooks::InitOnce(); if (FLAG_support_timeline) { Timeline::InitOnce(); } @@ -491,7 +493,7 @@ const char* Dart::Cleanup() { if (FLAG_trace_shutdown) { OS::PrintErr("[+%" Pd64 "ms] SHUTDOWN: Done\n", UptimeMillis()); } - + MallocHooks::TearDown(); return NULL; } diff --git a/runtime/vm/hash_map.h b/runtime/vm/hash_map.h index 5aa5343b339..6526acaf5c6 100644 --- a/runtime/vm/hash_map.h +++ b/runtime/vm/hash_map.h @@ -33,6 +33,7 @@ class BaseDirectChainedHashMap : public B { } void Insert(typename KeyValueTrait::Pair kv); + bool Remove(typename KeyValueTrait::Key key); typename KeyValueTrait::Value LookupValue( typename KeyValueTrait::Key key) const; @@ -308,6 +309,68 @@ void BaseDirectChainedHashMap::Insert( } +template +bool BaseDirectChainedHashMap::Remove( + typename KeyValueTrait::Key key) { + uword pos = Bound(static_cast(KeyValueTrait::Hashcode(key))); + + // Check to see if the first element in the bucket is the one we want to + // remove. + if (KeyValueTrait::KeyOf(array_[pos].kv) == key) { + if (array_[pos].next == kNil) { + array_[pos] = HashMapListElement(); + } else { + intptr_t next = array_[pos].next; + array_[pos] = lists_[next]; + lists_[next] = HashMapListElement(); + lists_[next].next = free_list_head_; + free_list_head_ = next; + } + count_--; + return true; + } + + intptr_t current = array_[pos].next; + + // If there's only the single element in the bucket and it does not match the + // key to be removed, just return. + if (current == kNil) { + return false; + } + + // Check the case where the second element in the bucket is the one to be + // removed. + if (KeyValueTrait::KeyOf(lists_[current].kv) == key) { + array_[pos].next = lists_[current].next; + lists_[current] = HashMapListElement(); + lists_[current].next = free_list_head_; + free_list_head_ = current; + count_--; + return true; + } + + // Finally, iterate through the rest of the bucket to see if we can find the + // entry that matches our key. + intptr_t previous; + while (KeyValueTrait::KeyOf(lists_[current].kv) != key) { + previous = current; + current = lists_[current].next; + + if (current == kNil) { + // Could not find entry with provided key to remove. + return false; + } + } + + lists_[previous].next = lists_[current].next; + lists_[current] = HashMapListElement(); + lists_[current].next = free_list_head_; + free_list_head_ = current; + count_--; + return true; +} + + template class DirectChainedHashMap : public BaseDirectChainedHashMap { diff --git a/runtime/vm/hash_map_test.cc b/runtime/vm/hash_map_test.cc index b3afddedf49..2f49b362983 100644 --- a/runtime/vm/hash_map_test.cc +++ b/runtime/vm/hash_map_test.cc @@ -31,6 +31,9 @@ TEST_CASE(DirectChainedHashMap) { EXPECT(map.LookupValue(&v1) == &v1); EXPECT(map.LookupValue(&v2) == &v2); EXPECT(map.LookupValue(&v3) == &v1); + EXPECT(map.Remove(&v1)); + EXPECT(map.Lookup(&v1) == NULL); + map.Insert(&v1); DirectChainedHashMap > map2(map); EXPECT(map2.LookupValue(&v1) == &v1); EXPECT(map2.LookupValue(&v2) == &v2); @@ -38,6 +41,64 @@ TEST_CASE(DirectChainedHashMap) { } +TEST_CASE(DirectChainedHashMapInsertRemove) { + DirectChainedHashMap > map; + EXPECT(map.IsEmpty()); + TestValue v1(1); + TestValue v2(3); // Note: v1, v2, v3 should have the same hash. + TestValue v3(5); + + // Start with adding and removing the same element. + map.Insert(&v1); + EXPECT(map.LookupValue(&v1) == &v1); + EXPECT(map.Remove(&v1)); + EXPECT(map.Lookup(&v1) == NULL); + + // Inserting v2 first should put it at the head of the list. + map.Insert(&v2); + map.Insert(&v1); + EXPECT(map.LookupValue(&v2) == &v2); + EXPECT(map.LookupValue(&v1) == &v1); + + // Check to see if removing the head of the list causes issues. + EXPECT(map.Remove(&v2)); + EXPECT(map.Lookup(&v2) == NULL); + EXPECT(map.LookupValue(&v1) == &v1); + + // Reinsert v2, which will place it at the back of the hash map list. + map.Insert(&v2); + EXPECT(map.LookupValue(&v2) == &v2); + + // Remove from the back of the hash map list. + EXPECT(map.Remove(&v2)); + EXPECT(map.Lookup(&v2) == NULL); + EXPECT(map.Remove(&v1)); + EXPECT(map.Lookup(&v1) == NULL); + + // Check to see that removing an invalid element returns false. + EXPECT(!map.Remove(&v1)); + + // One last case: remove from the middle of a hash map list. + map.Insert(&v1); + map.Insert(&v2); + map.Insert(&v3); + + EXPECT(map.LookupValue(&v1) == &v1); + EXPECT(map.LookupValue(&v2) == &v2); + EXPECT(map.LookupValue(&v3) == &v3); + + EXPECT(map.Remove(&v2)); + EXPECT(map.LookupValue(&v1) == &v1); + EXPECT(map.Lookup(&v2) == NULL); + EXPECT(map.LookupValue(&v3) == &v3); + + EXPECT(map.Remove(&v1)); + EXPECT(map.Remove(&v3)); + + EXPECT(map.IsEmpty()); +} + + TEST_CASE(MallocDirectChainedHashMap) { MallocDirectChainedHashMap > map; EXPECT(map.IsEmpty()); diff --git a/runtime/vm/malloc_hooks.cc b/runtime/vm/malloc_hooks.cc index 65edca7bff7..dd471d977e7 100644 --- a/runtime/vm/malloc_hooks.cc +++ b/runtime/vm/malloc_hooks.cc @@ -2,16 +2,267 @@ // for details. All rights reserved. Use of this source code is governed by a // BSD-style license that can be found in the LICENSE file. -#if defined(DART_USE_TCMALLOC) +#include "platform/globals.h" + +#if defined(DART_USE_TCMALLOC) && !defined(PRODUCT) #include "vm/malloc_hooks.h" +#include "gperftools/malloc_hook.h" + +#include "platform/assert.h" +#include "vm/hash_map.h" +#include "vm/lockers.h" + namespace dart { -void MallocHooks::Init() { - // TODO(bkonyi): Implement +// A locker-type class to automatically grab and release the +// in_malloc_hook_flag_. +class MallocHookScope { + public: + static void InitMallocHookFlag() { + ASSERT(in_malloc_hook_flag_ == kUnsetThreadLocalKey); + in_malloc_hook_flag_ = OSThread::CreateThreadLocal(); + OSThread::SetThreadLocal(in_malloc_hook_flag_, 0); + } + + static void DestroyMallocHookFlag() { + ASSERT(in_malloc_hook_flag_ != kUnsetThreadLocalKey); + OSThread::DeleteThreadLocal(in_malloc_hook_flag_); + in_malloc_hook_flag_ = kUnsetThreadLocalKey; + } + + MallocHookScope() { + ASSERT(in_malloc_hook_flag_ != kUnsetThreadLocalKey); + OSThread::SetThreadLocal(in_malloc_hook_flag_, 1); + } + + ~MallocHookScope() { + ASSERT(in_malloc_hook_flag_ != kUnsetThreadLocalKey); + OSThread::SetThreadLocal(in_malloc_hook_flag_, 0); + } + + static bool IsInHook() { + ASSERT(in_malloc_hook_flag_ != kUnsetThreadLocalKey); + return OSThread::GetThreadLocal(in_malloc_hook_flag_); + } + + private: + static ThreadLocalKey in_malloc_hook_flag_; + + DISALLOW_ALLOCATION(); + DISALLOW_COPY_AND_ASSIGN(MallocHookScope); +}; + + +// Custom key/value trait specifically for address/size pairs. Unlike +// RawPointerKeyValueTrait, the default value is -1 as 0 can be a valid entry. +class AddressKeyValueTrait { + public: + typedef const void* Key; + typedef intptr_t Value; + + struct Pair { + Key key; + Value value; + Pair() : key(NULL), value(-1) {} + Pair(const Key key, const Value& value) : key(key), value(value) {} + Pair(const Pair& other) : key(other.key), value(other.value) {} + }; + + static Key KeyOf(Pair kv) { return kv.key; } + static Value ValueOf(Pair kv) { return kv.value; } + static intptr_t Hashcode(Key key) { return reinterpret_cast(key); } + static bool IsKeyEqual(Pair kv, Key key) { return kv.key == key; } +}; + + +// Map class that will be used to store mappings between ptr -> allocation size. +class AddressMap : public MallocDirectChainedHashMap { + public: + typedef AddressKeyValueTrait::Key Key; + typedef AddressKeyValueTrait::Value Value; + typedef AddressKeyValueTrait::Pair Pair; + + inline void Insert(const Key& key, const Value& value) { + Pair pair(key, value); + MallocDirectChainedHashMap::Insert(pair); + } + + inline bool Lookup(const Key& key, Value* value) { + ASSERT(value != NULL); + Pair* pair = MallocDirectChainedHashMap::Lookup(key); + if (pair == NULL) { + return false; + } else { + *value = pair->value; + return true; + } + } +}; + + +class MallocHooksState { + public: + static void RecordAllocHook(const void* ptr, size_t size); + static void RecordFreeHook(const void* ptr); + + static bool initialized() { return initialized_; } + static void Init() { + address_map_ = new AddressMap(); + initialized_ = true; + } + + static Mutex* malloc_hook_mutex() { return malloc_hook_mutex_; } + + static intptr_t allocation_count() { return allocation_count_; } + + static intptr_t heap_allocated_memory_in_bytes() { + return heap_allocated_memory_in_bytes_; + } + + static void IncrementHeapAllocatedMemoryInBytes(intptr_t size) { + ASSERT(size >= 0); + heap_allocated_memory_in_bytes_ += size; + ++allocation_count_; + } + + static void DecrementHeapAllocatedMemoryInBytes(intptr_t size) { + ASSERT(size >= 0); + ASSERT(heap_allocated_memory_in_bytes_ >= size); + heap_allocated_memory_in_bytes_ -= size; + --allocation_count_; + ASSERT(allocation_count_ >= 0); + } + + static AddressMap* address_map() { return address_map_; } + + static void ResetStats() { + allocation_count_ = 0; + heap_allocated_memory_in_bytes_ = 0; + address_map_->Clear(); + } + + static void TearDown() { + initialized_ = false; + ResetStats(); + delete address_map_; + } + + private: + static bool initialized_; + static Mutex* malloc_hook_mutex_; + static intptr_t allocation_count_; + static intptr_t heap_allocated_memory_in_bytes_; + static AddressMap* address_map_; + + private: + DISALLOW_ALLOCATION(); + DISALLOW_COPY_AND_ASSIGN(MallocHooksState); +}; + + +// MallocHooks state / locks. +ThreadLocalKey MallocHookScope::in_malloc_hook_flag_ = kUnsetThreadLocalKey; +bool MallocHooksState::initialized_ = false; +Mutex* MallocHooksState::malloc_hook_mutex_ = new Mutex(); + +// Memory allocation state information. +intptr_t MallocHooksState::allocation_count_ = 0; +intptr_t MallocHooksState::heap_allocated_memory_in_bytes_ = 0; +AddressMap* MallocHooksState::address_map_ = NULL; + + +void MallocHooks::InitOnce() { + MutexLocker ml(MallocHooksState::malloc_hook_mutex()); + ASSERT(!MallocHooksState::initialized()); + + MallocHookScope::InitMallocHookFlag(); + MallocHooksState::Init(); + + // Register malloc hooks. + bool success = false; + success = MallocHook::AddNewHook(&MallocHooksState::RecordAllocHook); + ASSERT(success); + success = MallocHook::AddDeleteHook(&MallocHooksState::RecordFreeHook); + ASSERT(success); +} + + +void MallocHooks::TearDown() { + MutexLocker ml(MallocHooksState::malloc_hook_mutex()); + ASSERT(MallocHooksState::initialized()); + + // Remove malloc hooks. + bool success = false; + success = MallocHook::RemoveNewHook(&MallocHooksState::RecordAllocHook); + ASSERT(success); + success = MallocHook::RemoveDeleteHook(&MallocHooksState::RecordFreeHook); + ASSERT(success); + + MallocHooksState::TearDown(); + MallocHookScope::DestroyMallocHookFlag(); +} + + +void MallocHooks::ResetStats() { + MutexLocker ml(MallocHooksState::malloc_hook_mutex()); + ASSERT(MallocHooksState::initialized()); + + MallocHooksState::ResetStats(); +} + + +intptr_t MallocHooks::allocation_count() { + MutexLocker ml(MallocHooksState::malloc_hook_mutex()); + return MallocHooksState::allocation_count(); +} + + +intptr_t MallocHooks::heap_allocated_memory_in_bytes() { + MutexLocker ml(MallocHooksState::malloc_hook_mutex()); + return MallocHooksState::heap_allocated_memory_in_bytes(); +} + + +void MallocHooksState::RecordAllocHook(const void* ptr, size_t size) { + if (MallocHookScope::IsInHook()) { + return; + } + + // Set the malloc hook flag before grabbing the mutex to avoid calling hooks + // again. + MallocHookScope mhs; + MutexLocker ml(MallocHooksState::malloc_hook_mutex()); + ASSERT(MallocHooksState::initialized()); + + if (ptr != NULL) { + MallocHooksState::IncrementHeapAllocatedMemoryInBytes(size); + MallocHooksState::address_map()->Insert(ptr, size); + } +} + + +void MallocHooksState::RecordFreeHook(const void* ptr) { + if (MallocHookScope::IsInHook()) { + return; + } + + // Set the malloc hook flag before grabbing the mutex to avoid calling hooks + // again. + MallocHookScope mhs; + MutexLocker ml(MallocHooksState::malloc_hook_mutex()); + ASSERT(MallocHooksState::initialized()); + + if (ptr != NULL) { + intptr_t size = 0; + if (MallocHooksState::address_map()->Lookup(ptr, &size)) { + MallocHooksState::DecrementHeapAllocatedMemoryInBytes(size); + MallocHooksState::address_map()->Remove(ptr); + } + } } } // namespace dart -#endif // defined(DART_USE_TCMALLOC) +#endif // defined(DART_USE_TCMALLOC) && !defined(PRODUCT) diff --git a/runtime/vm/malloc_hooks.h b/runtime/vm/malloc_hooks.h index ae09402388d..d741a5f6375 100644 --- a/runtime/vm/malloc_hooks.h +++ b/runtime/vm/malloc_hooks.h @@ -10,7 +10,13 @@ namespace dart { class MallocHooks { - static void Init(); + public: + static void InitOnce(); + static void TearDown(); + static void ResetStats(); + + static intptr_t allocation_count(); + static intptr_t heap_allocated_memory_in_bytes(); private: DISALLOW_ALLOCATION(); diff --git a/runtime/vm/malloc_hooks_test.cc b/runtime/vm/malloc_hooks_test.cc new file mode 100644 index 00000000000..b0c5d361228 --- /dev/null +++ b/runtime/vm/malloc_hooks_test.cc @@ -0,0 +1,80 @@ +// Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +#include "platform/globals.h" + +#if defined(DART_USE_TCMALLOC) && !defined(PRODUCT) + +#include "platform/assert.h" +#include "vm/class_finalizer.h" +#include "vm/globals.h" +#include "vm/malloc_hooks.h" +#include "vm/symbols.h" +#include "vm/unit_test.h" + +namespace dart { + +// Note: for these tests, there is no need to call MallocHooks::Init() or +// MallocHooks::TearDown() as this is all done by the VM test framework. + +static void MallocHookTestBufferInitializer(volatile char* buffer, + uintptr_t size) { + // Run through the buffer and do something. If we don't do this and the memory + // in buffer isn't touched, the tcmalloc hooks won't be called. + for (uintptr_t i = 0; i < size; ++i) { + buffer[i] = i; + } +} + + +UNIT_TEST_CASE(BasicMallocHookTest) { + MallocHooks::ResetStats(); + EXPECT_EQ(0L, MallocHooks::allocation_count()); + EXPECT_EQ(0L, MallocHooks::heap_allocated_memory_in_bytes()); + + const intptr_t buffer_size = 10; + char* buffer = new char[buffer_size]; + MallocHookTestBufferInitializer(buffer, buffer_size); + + EXPECT_EQ(1L, MallocHooks::allocation_count()); + EXPECT_EQ(static_cast(sizeof(char) * buffer_size), + MallocHooks::heap_allocated_memory_in_bytes()); + + delete[] buffer; + EXPECT_EQ(0L, MallocHooks::allocation_count()); + EXPECT_EQ(0L, MallocHooks::heap_allocated_memory_in_bytes()); +} + + +UNIT_TEST_CASE(FreeUnseenMemoryMallocHookTest) { + const intptr_t pre_hook_buffer_size = 3; + char* pre_hook_buffer = new char[pre_hook_buffer_size]; + MallocHookTestBufferInitializer(pre_hook_buffer, pre_hook_buffer_size); + + MallocHooks::ResetStats(); + EXPECT_EQ(0L, MallocHooks::allocation_count()); + EXPECT_EQ(0L, MallocHooks::heap_allocated_memory_in_bytes()); + + const intptr_t buffer_size = 10; + volatile char* buffer = new char[buffer_size]; + MallocHookTestBufferInitializer(buffer, buffer_size); + + EXPECT_EQ(1L, MallocHooks::allocation_count()); + EXPECT_EQ(static_cast(sizeof(char) * buffer_size), + MallocHooks::heap_allocated_memory_in_bytes()); + + delete[] pre_hook_buffer; + EXPECT_EQ(1L, MallocHooks::allocation_count()); + EXPECT_EQ(static_cast(sizeof(char) * buffer_size), + MallocHooks::heap_allocated_memory_in_bytes()); + + + delete[] buffer; + EXPECT_EQ(0L, MallocHooks::allocation_count()); + EXPECT_EQ(0L, MallocHooks::heap_allocated_memory_in_bytes()); +} + +}; // namespace dart + +#endif // defined(DART_USE_TCMALLOC) && !defined(PRODUCT) diff --git a/runtime/vm/malloc_hooks_unsupported.cc b/runtime/vm/malloc_hooks_unsupported.cc index 65edca7bff7..8c479963d67 100644 --- a/runtime/vm/malloc_hooks_unsupported.cc +++ b/runtime/vm/malloc_hooks_unsupported.cc @@ -2,16 +2,38 @@ // for details. All rights reserved. Use of this source code is governed by a // BSD-style license that can be found in the LICENSE file. -#if defined(DART_USE_TCMALLOC) +#include "platform/globals.h" + +#if !defined(DART_USE_TCMALLOC) || defined(PRODUCT) #include "vm/malloc_hooks.h" namespace dart { -void MallocHooks::Init() { - // TODO(bkonyi): Implement +void MallocHooks::InitOnce() { + // Do nothing. +} + + +void MallocHooks::TearDown() { + // Do nothing. +} + + +void MallocHooks::ResetStats() { + // Do nothing. +} + + +intptr_t MallocHooks::allocation_count() { + return 0; +} + + +intptr_t MallocHooks::heap_allocated_memory_in_bytes() { + return 0; } } // namespace dart -#endif // defined(DART_USE_TCMALLOC) +#endif // defined(DART_USE_TCMALLOC) || defined(PRODUCT) diff --git a/runtime/vm/vm.gypi b/runtime/vm/vm.gypi index 1371285b1ee..a8c0e74ac4b 100644 --- a/runtime/vm/vm.gypi +++ b/runtime/vm/vm.gypi @@ -61,13 +61,6 @@ ], }, }], - # The following condition should be kept in sync with the corresponding - # configurations in runtime/bin/bin.gypi. - ['OS == "linux" and asan == 0 and msan == 0 and tsan == 0', { - 'defines': [ - 'DART_USE_TCMALLOC' - ], - }], ['OS=="android" and _toolset=="host"', { 'link_settings': { 'libraries': [ @@ -112,13 +105,6 @@ ], }, }], - # The following condition should be kept in sync with the corresponding - # configurations in runtime/bin/bin.gypi. - ['OS == "linux" and asan == 0 and msan == 0 and tsan == 0', { - 'defines': [ - 'DART_USE_TCMALLOC' - ], - }], ['OS=="android" and _toolset=="host"', { 'link_settings': { 'libraries': [ @@ -163,13 +149,6 @@ ], }, }], - # The following condition should be kept in sync with the corresponding - # configurations in runtime/bin/bin.gypi. - ['OS == "linux" and asan == 0 and msan == 0 and tsan == 0', { - 'defines': [ - 'DART_USE_TCMALLOC' - ], - }], ['OS=="android" and _toolset=="host"', { 'link_settings': { 'libraries': [ @@ -215,13 +194,6 @@ ], }, }], - # The following condition should be kept in sync with the corresponding - # configurations in runtime/bin/bin.gypi. - ['OS == "linux" and asan == 0 and msan == 0 and tsan == 0', { - 'defines': [ - 'DART_USE_TCMALLOC' - ], - }], ['OS=="android" and _toolset=="host"', { 'link_settings': { 'libraries': [ diff --git a/runtime/vm/vm_sources.gypi b/runtime/vm/vm_sources.gypi index e75af23a485..cd72fda195f 100644 --- a/runtime/vm/vm_sources.gypi +++ b/runtime/vm/vm_sources.gypi @@ -286,8 +286,9 @@ 'longjump.h', 'longjump_test.cc', 'malloc_hooks.cc', - 'malloc_hooks_unsupported.cc', 'malloc_hooks.h', + 'malloc_hooks_test.cc', + 'malloc_hooks_unsupported.cc', 'megamorphic_cache_table.cc', 'megamorphic_cache_table.h', 'memory_region.cc',