blob: a45804cf5275eb3674695bd42c73d2c44a20ef7e [file] [log] [blame]
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001// Copyright 2012 the V8 project authors. All rights reserved.
Ben Murdochb8a8cc12014-11-26 15:28:44 +00002// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
Ben Murdoch3ef787d2012-04-12 10:51:47 +01004
Ben Murdochb8a8cc12014-11-26 15:28:44 +00005#include "src/v8.h"
Ben Murdoch3ef787d2012-04-12 10:51:47 +01006
Ben Murdochb8a8cc12014-11-26 15:28:44 +00007#include "src/interface.h"
Ben Murdoch3ef787d2012-04-12 10:51:47 +01008
Emily Bernierd0a1eb72015-03-24 16:35:39 -04009#include "src/base/lazy-instance.h"
10
Ben Murdoch3ef787d2012-04-12 10:51:47 +010011namespace v8 {
12namespace internal {
13
Emily Bernierd0a1eb72015-03-24 16:35:39 -040014// ---------------------------------------------------------------------------
15// Initialization.
16
17struct Interface::Cache {
18 template<int flags>
19 struct Create {
20 static void Construct(Interface* ptr) { ::new (ptr) Interface(flags); }
21 };
22 typedef Create<VALUE + FROZEN> ValueCreate;
23 typedef Create<VALUE + CONST + FROZEN> ConstCreate;
24
25 static base::LazyInstance<Interface, ValueCreate>::type value_interface;
26 static base::LazyInstance<Interface, ConstCreate>::type const_interface;
27};
28
29
30base::LazyInstance<Interface, Interface::Cache::ValueCreate>::type
31 Interface::Cache::value_interface = LAZY_INSTANCE_INITIALIZER;
32
33base::LazyInstance<Interface, Interface::Cache::ConstCreate>::type
34 Interface::Cache::const_interface = LAZY_INSTANCE_INITIALIZER;
35
36
37Interface* Interface::NewValue() {
38 return Cache::value_interface.Pointer(); // Cached.
39}
40
41
42Interface* Interface::NewConst() {
43 return Cache::const_interface.Pointer(); // Cached.
44}
45
46
47// ---------------------------------------------------------------------------
48// Lookup.
49
Ben Murdochb8a8cc12014-11-26 15:28:44 +000050Interface* Interface::Lookup(Handle<String> name, Zone* zone) {
51 DCHECK(IsModule());
Ben Murdoch3ef787d2012-04-12 10:51:47 +010052 ZoneHashMap* map = Chase()->exports_;
Emily Bernierd0a1eb72015-03-24 16:35:39 -040053 if (map == nullptr) return nullptr;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000054 ZoneAllocationPolicy allocator(zone);
Emily Bernierd0a1eb72015-03-24 16:35:39 -040055 ZoneHashMap::Entry* p =
56 map->Lookup(name.location(), name->Hash(), false, allocator);
57 if (p == nullptr) return nullptr;
Ben Murdochb8a8cc12014-11-26 15:28:44 +000058 DCHECK(*static_cast<String**>(p->key) == *name);
Emily Bernierd0a1eb72015-03-24 16:35:39 -040059 DCHECK(p->value != nullptr);
Ben Murdoch3ef787d2012-04-12 10:51:47 +010060 return static_cast<Interface*>(p->value);
61}
62
63
Emily Bernierd0a1eb72015-03-24 16:35:39 -040064// ---------------------------------------------------------------------------
65// Addition.
66
Ben Murdoch3ef787d2012-04-12 10:51:47 +010067#ifdef DEBUG
68// Current nesting depth for debug output.
69class Nesting {
70 public:
71 Nesting() { current_ += 2; }
72 ~Nesting() { current_ -= 2; }
73 static int current() { return current_; }
74 private:
75 static int current_;
76};
77
78int Nesting::current_ = 0;
79#endif
80
81
Ben Murdochb8a8cc12014-11-26 15:28:44 +000082void Interface::DoAdd(const void* name, uint32_t hash, Interface* interface,
83 Zone* zone, bool* ok) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +010084 MakeModule(ok);
85 if (!*ok) return;
86
87#ifdef DEBUG
88 if (FLAG_print_interface_details) {
89 PrintF("%*s# Adding...\n", Nesting::current(), "");
90 PrintF("%*sthis = ", Nesting::current(), "");
91 this->Print(Nesting::current());
Emily Bernierd0a1eb72015-03-24 16:35:39 -040092 const AstRawString* raw = static_cast<const AstRawString*>(name);
93 PrintF("%*s%.*s : ", Nesting::current(), "",
94 raw->length(), raw->raw_data());
Ben Murdoch3ef787d2012-04-12 10:51:47 +010095 interface->Print(Nesting::current());
96 }
97#endif
98
99 ZoneHashMap** map = &Chase()->exports_;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000100 ZoneAllocationPolicy allocator(zone);
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100101
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400102 if (*map == nullptr) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000103 *map = new(zone->New(sizeof(ZoneHashMap)))
104 ZoneHashMap(ZoneHashMap::PointersMatch,
105 ZoneHashMap::kDefaultHashMapCapacity, allocator);
106 }
107
108 ZoneHashMap::Entry* p =
109 (*map)->Lookup(const_cast<void*>(name), hash, !IsFrozen(), allocator);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400110 if (p == nullptr) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100111 // This didn't have name but was frozen already, that's an error.
112 *ok = false;
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400113 } else if (p->value == nullptr) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100114 p->value = interface;
115 } else {
116#ifdef DEBUG
117 Nesting nested;
118#endif
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000119 static_cast<Interface*>(p->value)->Unify(interface, zone, ok);
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100120 }
121
122#ifdef DEBUG
123 if (FLAG_print_interface_details) {
124 PrintF("%*sthis' = ", Nesting::current(), "");
125 this->Print(Nesting::current());
126 PrintF("%*s# Added.\n", Nesting::current(), "");
127 }
128#endif
129}
130
131
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400132// ---------------------------------------------------------------------------
133// Unification.
134
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000135void Interface::Unify(Interface* that, Zone* zone, bool* ok) {
136 if (this->forward_) return this->Chase()->Unify(that, zone, ok);
137 if (that->forward_) return this->Unify(that->Chase(), zone, ok);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400138 DCHECK(this->forward_ == nullptr);
139 DCHECK(that->forward_ == nullptr);
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100140
141 *ok = true;
142 if (this == that) return;
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000143 if (this->IsValue()) {
144 that->MakeValue(ok);
145 if (*ok && this->IsConst()) that->MakeConst(ok);
146 return;
147 }
148 if (that->IsValue()) {
149 this->MakeValue(ok);
150 if (*ok && that->IsConst()) this->MakeConst(ok);
151 return;
152 }
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100153
154#ifdef DEBUG
155 if (FLAG_print_interface_details) {
156 PrintF("%*s# Unifying...\n", Nesting::current(), "");
157 PrintF("%*sthis = ", Nesting::current(), "");
158 this->Print(Nesting::current());
159 PrintF("%*sthat = ", Nesting::current(), "");
160 that->Print(Nesting::current());
161 }
162#endif
163
164 // Merge the smaller interface into the larger, for performance.
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400165 if (this->exports_ != nullptr && (that->exports_ == nullptr ||
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100166 this->exports_->occupancy() >= that->exports_->occupancy())) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000167 this->DoUnify(that, ok, zone);
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100168 } else {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000169 that->DoUnify(this, ok, zone);
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100170 }
171
172#ifdef DEBUG
173 if (FLAG_print_interface_details) {
174 PrintF("%*sthis' = ", Nesting::current(), "");
175 this->Print(Nesting::current());
176 PrintF("%*sthat' = ", Nesting::current(), "");
177 that->Print(Nesting::current());
178 PrintF("%*s# Unified.\n", Nesting::current(), "");
179 }
180#endif
181}
182
183
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000184void Interface::DoUnify(Interface* that, bool* ok, Zone* zone) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400185 DCHECK(this->forward_ == nullptr);
186 DCHECK(that->forward_ == nullptr);
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000187 DCHECK(!this->IsValue());
188 DCHECK(!that->IsValue());
189 DCHECK(this->index_ == -1);
190 DCHECK(that->index_ == -1);
191 DCHECK(*ok);
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100192
193#ifdef DEBUG
194 Nesting nested;
195#endif
196
197 // Try to merge all members from that into this.
198 ZoneHashMap* map = that->exports_;
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400199 if (map != nullptr) {
200 for (ZoneHashMap::Entry* p = map->Start(); p != nullptr; p = map->Next(p)) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000201 this->DoAdd(p->key, p->hash, static_cast<Interface*>(p->value), zone, ok);
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100202 if (!*ok) return;
203 }
204 }
205
206 // If the new interface is larger than that's, then there were members in
207 // 'this' which 'that' didn't have. If 'that' was frozen that is an error.
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400208 int this_size = this->exports_ == nullptr ? 0 : this->exports_->occupancy();
209 int that_size = map == nullptr ? 0 : map->occupancy();
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100210 if (that->IsFrozen() && this_size > that_size) {
211 *ok = false;
212 return;
213 }
214
215 // Merge interfaces.
216 this->flags_ |= that->flags_;
217 that->forward_ = this;
218}
219
220
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400221// ---------------------------------------------------------------------------
222// Printing.
223
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100224#ifdef DEBUG
225void Interface::Print(int n) {
226 int n0 = n > 0 ? n : 0;
227
228 if (FLAG_print_interface_details) {
229 PrintF("%p", static_cast<void*>(this));
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400230 for (Interface* link = this->forward_; link != nullptr;
231 link = link->forward_) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100232 PrintF("->%p", static_cast<void*>(link));
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400233 }
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100234 PrintF(" ");
235 }
236
237 if (IsUnknown()) {
238 PrintF("unknown\n");
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000239 } else if (IsConst()) {
240 PrintF("const\n");
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100241 } else if (IsValue()) {
242 PrintF("value\n");
243 } else if (IsModule()) {
Ben Murdochb8a8cc12014-11-26 15:28:44 +0000244 PrintF("module %d %s{", Index(), IsFrozen() ? "" : "(unresolved) ");
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100245 ZoneHashMap* map = Chase()->exports_;
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400246 if (map == nullptr || map->occupancy() == 0) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100247 PrintF("}\n");
248 } else if (n < 0 || n0 >= 2 * FLAG_print_interface_depth) {
249 // Avoid infinite recursion on cyclic types.
250 PrintF("...}\n");
251 } else {
252 PrintF("\n");
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400253 for (ZoneHashMap::Entry* p = map->Start();
254 p != nullptr; p = map->Next(p)) {
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100255 String* name = *static_cast<String**>(p->key);
256 Interface* interface = static_cast<Interface*>(p->value);
257 PrintF("%*s%s : ", n0 + 2, "", name->ToAsciiArray());
258 interface->Print(n0 + 2);
259 }
260 PrintF("%*s}\n", n0, "");
261 }
262 }
263}
264#endif
265
266} } // namespace v8::internal