1*795d594fSAndroid Build Coastguard Worker /*
2*795d594fSAndroid Build Coastguard Worker * Copyright (C) 2015 The Android Open Source Project
3*795d594fSAndroid Build Coastguard Worker *
4*795d594fSAndroid Build Coastguard Worker * Licensed under the Apache License, Version 2.0 (the "License");
5*795d594fSAndroid Build Coastguard Worker * you may not use this file except in compliance with the License.
6*795d594fSAndroid Build Coastguard Worker * You may obtain a copy of the License at
7*795d594fSAndroid Build Coastguard Worker *
8*795d594fSAndroid Build Coastguard Worker * http://www.apache.org/licenses/LICENSE-2.0
9*795d594fSAndroid Build Coastguard Worker *
10*795d594fSAndroid Build Coastguard Worker * Unless required by applicable law or agreed to in writing, software
11*795d594fSAndroid Build Coastguard Worker * distributed under the License is distributed on an "AS IS" BASIS,
12*795d594fSAndroid Build Coastguard Worker * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*795d594fSAndroid Build Coastguard Worker * See the License for the specific language governing permissions and
14*795d594fSAndroid Build Coastguard Worker * limitations under the License.
15*795d594fSAndroid Build Coastguard Worker */
16*795d594fSAndroid Build Coastguard Worker
17*795d594fSAndroid Build Coastguard Worker #ifndef ART_RUNTIME_LINEAR_ALLOC_INL_H_
18*795d594fSAndroid Build Coastguard Worker #define ART_RUNTIME_LINEAR_ALLOC_INL_H_
19*795d594fSAndroid Build Coastguard Worker
20*795d594fSAndroid Build Coastguard Worker #include "linear_alloc.h"
21*795d594fSAndroid Build Coastguard Worker
22*795d594fSAndroid Build Coastguard Worker #include "base/gc_visited_arena_pool.h"
23*795d594fSAndroid Build Coastguard Worker #include "thread-current-inl.h"
24*795d594fSAndroid Build Coastguard Worker
25*795d594fSAndroid Build Coastguard Worker namespace art HIDDEN {
26*795d594fSAndroid Build Coastguard Worker
SetFirstObject(void * begin,size_t bytes)27*795d594fSAndroid Build Coastguard Worker inline void LinearAlloc::SetFirstObject(void* begin, size_t bytes) const {
28*795d594fSAndroid Build Coastguard Worker DCHECK(track_allocations_);
29*795d594fSAndroid Build Coastguard Worker if (ArenaAllocator::IsRunningOnMemoryTool()) {
30*795d594fSAndroid Build Coastguard Worker bytes += ArenaAllocator::kMemoryToolRedZoneBytes;
31*795d594fSAndroid Build Coastguard Worker }
32*795d594fSAndroid Build Coastguard Worker uint8_t* end = static_cast<uint8_t*>(begin) + bytes;
33*795d594fSAndroid Build Coastguard Worker Arena* arena = allocator_.GetHeadArena();
34*795d594fSAndroid Build Coastguard Worker DCHECK_NE(arena, nullptr);
35*795d594fSAndroid Build Coastguard Worker // The object would either be in the head arena or the next one.
36*795d594fSAndroid Build Coastguard Worker if (UNLIKELY(begin < arena->Begin() || begin >= arena->End())) {
37*795d594fSAndroid Build Coastguard Worker arena = arena->Next();
38*795d594fSAndroid Build Coastguard Worker }
39*795d594fSAndroid Build Coastguard Worker DCHECK(begin >= arena->Begin() && end <= arena->End());
40*795d594fSAndroid Build Coastguard Worker down_cast<TrackedArena*>(arena)->SetFirstObject(static_cast<uint8_t*>(begin), end);
41*795d594fSAndroid Build Coastguard Worker }
42*795d594fSAndroid Build Coastguard Worker
ConvertToNoGcRoots(void * ptr,LinearAllocKind orig_kind)43*795d594fSAndroid Build Coastguard Worker inline void LinearAlloc::ConvertToNoGcRoots(void* ptr, LinearAllocKind orig_kind) {
44*795d594fSAndroid Build Coastguard Worker if (track_allocations_ && ptr != nullptr) {
45*795d594fSAndroid Build Coastguard Worker TrackingHeader* header = static_cast<TrackingHeader*>(ptr);
46*795d594fSAndroid Build Coastguard Worker header--;
47*795d594fSAndroid Build Coastguard Worker DCHECK_EQ(header->GetKind(), orig_kind);
48*795d594fSAndroid Build Coastguard Worker DCHECK_GT(header->GetSize(), 0u);
49*795d594fSAndroid Build Coastguard Worker // 16-byte allocations are not supported yet.
50*795d594fSAndroid Build Coastguard Worker DCHECK(!header->Is16Aligned());
51*795d594fSAndroid Build Coastguard Worker header->SetKind(LinearAllocKind::kNoGCRoots);
52*795d594fSAndroid Build Coastguard Worker }
53*795d594fSAndroid Build Coastguard Worker }
54*795d594fSAndroid Build Coastguard Worker
SetupForPostZygoteFork(Thread * self)55*795d594fSAndroid Build Coastguard Worker inline void LinearAlloc::SetupForPostZygoteFork(Thread* self) {
56*795d594fSAndroid Build Coastguard Worker MutexLock mu(self, lock_);
57*795d594fSAndroid Build Coastguard Worker DCHECK(track_allocations_);
58*795d594fSAndroid Build Coastguard Worker allocator_.ResetCurrentArena();
59*795d594fSAndroid Build Coastguard Worker }
60*795d594fSAndroid Build Coastguard Worker
Realloc(Thread * self,void * ptr,size_t old_size,size_t new_size,LinearAllocKind kind)61*795d594fSAndroid Build Coastguard Worker inline void* LinearAlloc::Realloc(Thread* self,
62*795d594fSAndroid Build Coastguard Worker void* ptr,
63*795d594fSAndroid Build Coastguard Worker size_t old_size,
64*795d594fSAndroid Build Coastguard Worker size_t new_size,
65*795d594fSAndroid Build Coastguard Worker LinearAllocKind kind) {
66*795d594fSAndroid Build Coastguard Worker MutexLock mu(self, lock_);
67*795d594fSAndroid Build Coastguard Worker if (track_allocations_) {
68*795d594fSAndroid Build Coastguard Worker if (ptr != nullptr) {
69*795d594fSAndroid Build Coastguard Worker // Realloc cannot be called on 16-byte aligned as Realloc doesn't guarantee
70*795d594fSAndroid Build Coastguard Worker // that. So the header must be immediately prior to ptr.
71*795d594fSAndroid Build Coastguard Worker TrackingHeader* header = reinterpret_cast<TrackingHeader*>(ptr) - 1;
72*795d594fSAndroid Build Coastguard Worker DCHECK_EQ(header->GetKind(), kind);
73*795d594fSAndroid Build Coastguard Worker old_size += sizeof(TrackingHeader);
74*795d594fSAndroid Build Coastguard Worker DCHECK_EQ(header->GetSize(), old_size);
75*795d594fSAndroid Build Coastguard Worker ptr = header;
76*795d594fSAndroid Build Coastguard Worker } else {
77*795d594fSAndroid Build Coastguard Worker DCHECK_EQ(old_size, 0u);
78*795d594fSAndroid Build Coastguard Worker }
79*795d594fSAndroid Build Coastguard Worker new_size += sizeof(TrackingHeader);
80*795d594fSAndroid Build Coastguard Worker void* ret = allocator_.Realloc(ptr, old_size, new_size);
81*795d594fSAndroid Build Coastguard Worker new (ret) TrackingHeader(new_size, kind);
82*795d594fSAndroid Build Coastguard Worker SetFirstObject(ret, new_size);
83*795d594fSAndroid Build Coastguard Worker return static_cast<TrackingHeader*>(ret) + 1;
84*795d594fSAndroid Build Coastguard Worker } else {
85*795d594fSAndroid Build Coastguard Worker return allocator_.Realloc(ptr, old_size, new_size);
86*795d594fSAndroid Build Coastguard Worker }
87*795d594fSAndroid Build Coastguard Worker }
88*795d594fSAndroid Build Coastguard Worker
Alloc(Thread * self,size_t size,LinearAllocKind kind)89*795d594fSAndroid Build Coastguard Worker inline void* LinearAlloc::Alloc(Thread* self, size_t size, LinearAllocKind kind) {
90*795d594fSAndroid Build Coastguard Worker MutexLock mu(self, lock_);
91*795d594fSAndroid Build Coastguard Worker if (track_allocations_) {
92*795d594fSAndroid Build Coastguard Worker size += sizeof(TrackingHeader);
93*795d594fSAndroid Build Coastguard Worker TrackingHeader* storage = new (allocator_.Alloc(size)) TrackingHeader(size, kind);
94*795d594fSAndroid Build Coastguard Worker SetFirstObject(storage, size);
95*795d594fSAndroid Build Coastguard Worker return storage + 1;
96*795d594fSAndroid Build Coastguard Worker } else {
97*795d594fSAndroid Build Coastguard Worker return allocator_.Alloc(size);
98*795d594fSAndroid Build Coastguard Worker }
99*795d594fSAndroid Build Coastguard Worker }
100*795d594fSAndroid Build Coastguard Worker
AllocAlign16(Thread * self,size_t size,LinearAllocKind kind)101*795d594fSAndroid Build Coastguard Worker inline void* LinearAlloc::AllocAlign16(Thread* self, size_t size, LinearAllocKind kind) {
102*795d594fSAndroid Build Coastguard Worker MutexLock mu(self, lock_);
103*795d594fSAndroid Build Coastguard Worker DCHECK_ALIGNED(size, 16);
104*795d594fSAndroid Build Coastguard Worker if (track_allocations_) {
105*795d594fSAndroid Build Coastguard Worker size_t mem_tool_bytes = ArenaAllocator::IsRunningOnMemoryTool()
106*795d594fSAndroid Build Coastguard Worker ? ArenaAllocator::kMemoryToolRedZoneBytes : 0;
107*795d594fSAndroid Build Coastguard Worker uint8_t* ptr = allocator_.CurrentPtr() + sizeof(TrackingHeader);
108*795d594fSAndroid Build Coastguard Worker uintptr_t padding =
109*795d594fSAndroid Build Coastguard Worker RoundUp(reinterpret_cast<uintptr_t>(ptr), 16) - reinterpret_cast<uintptr_t>(ptr);
110*795d594fSAndroid Build Coastguard Worker DCHECK_LT(padding, 16u);
111*795d594fSAndroid Build Coastguard Worker size_t required_size = size + sizeof(TrackingHeader) + padding;
112*795d594fSAndroid Build Coastguard Worker
113*795d594fSAndroid Build Coastguard Worker if (allocator_.CurrentArenaUnusedBytes() < required_size + mem_tool_bytes) {
114*795d594fSAndroid Build Coastguard Worker // The allocator will require a new arena, which is expected to be
115*795d594fSAndroid Build Coastguard Worker // 16-byte aligned.
116*795d594fSAndroid Build Coastguard Worker static_assert(ArenaAllocator::kArenaAlignment >= 16,
117*795d594fSAndroid Build Coastguard Worker "Expecting sufficient alignment for new Arena.");
118*795d594fSAndroid Build Coastguard Worker required_size = size + RoundUp(sizeof(TrackingHeader), 16);
119*795d594fSAndroid Build Coastguard Worker }
120*795d594fSAndroid Build Coastguard Worker // Using ArenaAllocator's AllocAlign16 now would disturb the alignment by
121*795d594fSAndroid Build Coastguard Worker // trying to make header 16-byte aligned. The alignment requirements are
122*795d594fSAndroid Build Coastguard Worker // already addressed here. Now we want allocator to just bump the pointer.
123*795d594fSAndroid Build Coastguard Worker ptr = static_cast<uint8_t*>(allocator_.Alloc(required_size));
124*795d594fSAndroid Build Coastguard Worker new (ptr) TrackingHeader(required_size, kind, /*is_16_aligned=*/true);
125*795d594fSAndroid Build Coastguard Worker SetFirstObject(ptr, required_size);
126*795d594fSAndroid Build Coastguard Worker return AlignUp(ptr + sizeof(TrackingHeader), 16);
127*795d594fSAndroid Build Coastguard Worker } else {
128*795d594fSAndroid Build Coastguard Worker return allocator_.AllocAlign16(size);
129*795d594fSAndroid Build Coastguard Worker }
130*795d594fSAndroid Build Coastguard Worker }
131*795d594fSAndroid Build Coastguard Worker
GetUsedMemory()132*795d594fSAndroid Build Coastguard Worker inline size_t LinearAlloc::GetUsedMemory() const {
133*795d594fSAndroid Build Coastguard Worker MutexLock mu(Thread::Current(), lock_);
134*795d594fSAndroid Build Coastguard Worker return allocator_.BytesUsed();
135*795d594fSAndroid Build Coastguard Worker }
136*795d594fSAndroid Build Coastguard Worker
GetArenaPool()137*795d594fSAndroid Build Coastguard Worker inline ArenaPool* LinearAlloc::GetArenaPool() {
138*795d594fSAndroid Build Coastguard Worker MutexLock mu(Thread::Current(), lock_);
139*795d594fSAndroid Build Coastguard Worker return allocator_.GetArenaPool();
140*795d594fSAndroid Build Coastguard Worker }
141*795d594fSAndroid Build Coastguard Worker
Contains(void * ptr)142*795d594fSAndroid Build Coastguard Worker inline bool LinearAlloc::Contains(void* ptr) const {
143*795d594fSAndroid Build Coastguard Worker MutexLock mu(Thread::Current(), lock_);
144*795d594fSAndroid Build Coastguard Worker return allocator_.Contains(ptr);
145*795d594fSAndroid Build Coastguard Worker }
146*795d594fSAndroid Build Coastguard Worker
147*795d594fSAndroid Build Coastguard Worker } // namespace art
148*795d594fSAndroid Build Coastguard Worker
149*795d594fSAndroid Build Coastguard Worker #endif // ART_RUNTIME_LINEAR_ALLOC_INL_H_
150