1 // Copyright 2015 the V8 project authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #ifndef V8_CODEGEN_SIGNATURE_H_
6 #define V8_CODEGEN_SIGNATURE_H_
7
8 #include "src/base/functional.h"
9 #include "src/base/iterator.h"
10 #include "src/codegen/machine-type.h"
11 #include "src/zone/zone.h"
12
13 namespace v8 {
14 namespace internal {
15
16 // Describes the inputs and outputs of a function or call.
17 template <typename T>
18 class Signature : public ZoneObject {
19 public:
Signature(size_t return_count,size_t parameter_count,const T * reps)20 constexpr Signature(size_t return_count, size_t parameter_count,
21 const T* reps)
22 : return_count_(return_count),
23 parameter_count_(parameter_count),
24 reps_(reps) {
25 DCHECK_EQ(kReturnCountOffset, offsetof(Signature, return_count_));
26 DCHECK_EQ(kParameterCountOffset, offsetof(Signature, parameter_count_));
27 DCHECK_EQ(kRepsOffset, offsetof(Signature, reps_));
28 STATIC_ASSERT(std::is_standard_layout<Signature<T>>::value);
29 }
30
return_count()31 size_t return_count() const { return return_count_; }
parameter_count()32 size_t parameter_count() const { return parameter_count_; }
33
GetParam(size_t index)34 T GetParam(size_t index) const {
35 DCHECK_LT(index, parameter_count_);
36 return reps_[return_count_ + index];
37 }
38
39 T GetReturn(size_t index = 0) const {
40 DCHECK_LT(index, return_count_);
41 return reps_[index];
42 }
43
44 // Iteration support.
parameters()45 base::iterator_range<const T*> parameters() const {
46 return {reps_ + return_count_, reps_ + return_count_ + parameter_count_};
47 }
returns()48 base::iterator_range<const T*> returns() const {
49 return {reps_, reps_ + return_count_};
50 }
all()51 base::iterator_range<const T*> all() const {
52 return {reps_, reps_ + return_count_ + parameter_count_};
53 }
54
55 bool operator==(const Signature& other) const {
56 if (this == &other) return true;
57 if (parameter_count() != other.parameter_count()) return false;
58 if (return_count() != other.return_count()) return false;
59 return std::equal(all().begin(), all().end(), other.all().begin());
60 }
61 bool operator!=(const Signature& other) const { return !(*this == other); }
62
63 // For incrementally building signatures.
64 class Builder {
65 public:
Builder(Zone * zone,size_t return_count,size_t parameter_count)66 Builder(Zone* zone, size_t return_count, size_t parameter_count)
67 : return_count_(return_count),
68 parameter_count_(parameter_count),
69 zone_(zone),
70 rcursor_(0),
71 pcursor_(0),
72 buffer_(zone->NewArray<T>(
73 static_cast<int>(return_count + parameter_count))) {}
74
75 const size_t return_count_;
76 const size_t parameter_count_;
77
AddReturn(T val)78 void AddReturn(T val) {
79 DCHECK_LT(rcursor_, return_count_);
80 buffer_[rcursor_++] = val;
81 }
82
AddParam(T val)83 void AddParam(T val) {
84 DCHECK_LT(pcursor_, parameter_count_);
85 buffer_[return_count_ + pcursor_++] = val;
86 }
87
AddParamAt(size_t index,T val)88 void AddParamAt(size_t index, T val) {
89 DCHECK_LT(index, parameter_count_);
90 buffer_[return_count_ + index] = val;
91 pcursor_ = std::max(pcursor_, index + 1);
92 }
93
Build()94 Signature<T>* Build() {
95 DCHECK_EQ(rcursor_, return_count_);
96 DCHECK_EQ(pcursor_, parameter_count_);
97 return zone_->New<Signature<T>>(return_count_, parameter_count_, buffer_);
98 }
99
100 private:
101 Zone* zone_;
102 size_t rcursor_;
103 size_t pcursor_;
104 T* buffer_;
105 };
106
Build(Zone * zone,std::initializer_list<T> returns,std::initializer_list<T> params)107 static Signature<T>* Build(Zone* zone, std::initializer_list<T> returns,
108 std::initializer_list<T> params) {
109 Builder builder(zone, returns.size(), params.size());
110 for (T ret : returns) builder.AddReturn(ret);
111 for (T param : params) builder.AddParam(param);
112 return builder.Build();
113 }
114
115 static constexpr size_t kReturnCountOffset = 0;
116 static constexpr size_t kParameterCountOffset =
117 kReturnCountOffset + kSizetSize;
118 static constexpr size_t kRepsOffset = kParameterCountOffset + kSizetSize;
119
120 protected:
121 size_t return_count_;
122 size_t parameter_count_;
123 const T* reps_;
124 };
125
126 using MachineSignature = Signature<MachineType>;
127
128 template <typename T>
hash_value(const Signature<T> & sig)129 size_t hash_value(const Signature<T>& sig) {
130 // Hash over all contained representations, plus the parameter count to
131 // differentiate signatures with the same representation array but different
132 // parameter/return count.
133 size_t seed = base::hash_value(sig.parameter_count());
134 for (T rep : sig.all()) seed = base::hash_combine(seed, base::hash<T>{}(rep));
135 return seed;
136 }
137
138 template <typename T, size_t kNumReturns = 0, size_t kNumParams = 0>
139 class FixedSizeSignature : public Signature<T> {
140 public:
141 // Add return types to this signature (only allowed if there are none yet).
142 template <typename... ReturnTypes>
Returns(ReturnTypes...return_types)143 auto Returns(ReturnTypes... return_types) const {
144 static_assert(kNumReturns == 0, "Please specify all return types at once");
145 return FixedSizeSignature<T, sizeof...(ReturnTypes), kNumParams>{
146 std::initializer_list<T>{return_types...}.begin(), reps_};
147 }
148
149 // Add parameters to this signature (only allowed if there are none yet).
150 template <typename... ParamTypes>
Params(ParamTypes...param_types)151 auto Params(ParamTypes... param_types) const {
152 static_assert(kNumParams == 0, "Please specify all parameters at once");
153 return FixedSizeSignature<T, kNumReturns, sizeof...(ParamTypes)>{
154 reps_, std::initializer_list<T>{param_types...}.begin()};
155 }
156
157 private:
158 // Other template instantiations can call the private constructor.
159 template <typename T2, size_t kNumReturns2, size_t kNumParams2>
160 friend class FixedSizeSignature;
161
FixedSizeSignature(const T * returns,const T * params)162 FixedSizeSignature(const T* returns, const T* params)
163 : Signature<T>(kNumReturns, kNumParams, reps_) {
164 std::copy(returns, returns + kNumReturns, reps_);
165 std::copy(params, params + kNumParams, reps_ + kNumReturns);
166 }
167
168 T reps_[kNumReturns + kNumParams];
169 };
170
171 // Specialization for zero-sized signatures.
172 template <typename T>
173 class FixedSizeSignature<T, 0, 0> : public Signature<T> {
174 public:
FixedSizeSignature()175 constexpr FixedSizeSignature() : Signature<T>(0, 0, nullptr) {}
176
177 // Add return types.
178 template <typename... ReturnTypes>
Returns(ReturnTypes...return_types)179 static auto Returns(ReturnTypes... return_types) {
180 return FixedSizeSignature<T, sizeof...(ReturnTypes), 0>{
181 std::initializer_list<T>{return_types...}.begin(), nullptr};
182 }
183
184 // Add parameters.
185 template <typename... ParamTypes>
Params(ParamTypes...param_types)186 static auto Params(ParamTypes... param_types) {
187 return FixedSizeSignature<T, 0, sizeof...(ParamTypes)>{
188 nullptr, std::initializer_list<T>{param_types...}.begin()};
189 }
190 };
191
192 } // namespace internal
193 } // namespace v8
194
195 #endif // V8_CODEGEN_SIGNATURE_H_
196