1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
|
// Copyright 2020 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "src/codegen/aligned-slot-allocator.h"
#include "src/base/bits.h"
#include "src/base/logging.h"
namespace v8 {
namespace internal {
int AlignedSlotAllocator::NextSlot(int n) const {
DCHECK(n == 1 || n == 2 || n == 4);
if (n <= 1 && IsValid(next1_)) return next1_;
if (n <= 2 && IsValid(next2_)) return next2_;
DCHECK(IsValid(next4_));
return next4_;
}
int AlignedSlotAllocator::Allocate(int n) {
DCHECK(n == 1 || n == 2 || n == 4);
// Check invariants.
DCHECK_EQ(0, next4_ & 3);
DCHECK_IMPLIES(IsValid(next2_), (next2_ & 1) == 0);
// The sentinel value kInvalidSlot is used to indicate no slot.
// next1_ is the index of the 1 slot fragment, or kInvalidSlot.
// next2_ is the 2-aligned index of the 2 slot fragment, or kInvalidSlot.
// next4_ is the 4-aligned index of the next 4 slot group. It is always valid.
// In order to ensure we only have a single 1- or 2-slot fragment, we greedily
// use any fragment that satisfies the request.
int result = kInvalidSlot;
switch (n) {
case 1: {
if (IsValid(next1_)) {
result = next1_;
next1_ = kInvalidSlot;
} else if (IsValid(next2_)) {
result = next2_;
next1_ = result + 1;
next2_ = kInvalidSlot;
} else {
result = next4_;
next1_ = result + 1;
next2_ = result + 2;
next4_ += 4;
}
break;
}
case 2: {
if (IsValid(next2_)) {
result = next2_;
next2_ = kInvalidSlot;
} else {
result = next4_;
next2_ = result + 2;
next4_ += 4;
}
break;
}
case 4: {
result = next4_;
next4_ += 4;
break;
}
default:
UNREACHABLE();
}
DCHECK(IsValid(result));
size_ = std::max(size_, result + n);
return result;
}
int AlignedSlotAllocator::AllocateUnaligned(int n) {
DCHECK_GE(n, 0);
// Check invariants.
DCHECK_EQ(0, next4_ & 3);
DCHECK_IMPLIES(IsValid(next2_), (next2_ & 1) == 0);
// Reserve |n| slots at |size_|, invalidate fragments below the new |size_|,
// and add any new fragments beyond the new |size_|.
int result = size_;
size_ += n;
switch (size_ & 3) {
case 0: {
next1_ = next2_ = kInvalidSlot;
next4_ = size_;
break;
}
case 1: {
next1_ = size_;
next2_ = size_ + 1;
next4_ = size_ + 3;
break;
}
case 2: {
next1_ = kInvalidSlot;
next2_ = size_;
next4_ = size_ + 2;
break;
}
case 3: {
next1_ = size_;
next2_ = kInvalidSlot;
next4_ = size_ + 1;
break;
}
}
return result;
}
int AlignedSlotAllocator::Align(int n) {
DCHECK(base::bits::IsPowerOfTwo(n));
DCHECK_LE(n, 4);
int mask = n - 1;
int misalignment = size_ & mask;
int padding = (n - misalignment) & mask;
AllocateUnaligned(padding);
return padding;
}
} // namespace internal
} // namespace v8
|