Ben Murdoch | 3ef787d | 2012-04-12 10:51:47 +0100 | [diff] [blame] | 1 | // Copyright 2012 the V8 project authors. All rights reserved. |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 2 | // Use of this source code is governed by a BSD-style license that can be |
| 3 | // found in the LICENSE file. |
Ben Murdoch | 3ef787d | 2012-04-12 10:51:47 +0100 | [diff] [blame] | 4 | |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 5 | #include "src/v8.h" |
Ben Murdoch | 3ef787d | 2012-04-12 10:51:47 +0100 | [diff] [blame] | 6 | |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 7 | #include "src/interface.h" |
Ben Murdoch | 3ef787d | 2012-04-12 10:51:47 +0100 | [diff] [blame] | 8 | |
Emily Bernier | d0a1eb7 | 2015-03-24 16:35:39 -0400 | [diff] [blame] | 9 | #include "src/base/lazy-instance.h" |
| 10 | |
Ben Murdoch | 3ef787d | 2012-04-12 10:51:47 +0100 | [diff] [blame] | 11 | namespace v8 { |
| 12 | namespace internal { |
| 13 | |
Emily Bernier | d0a1eb7 | 2015-03-24 16:35:39 -0400 | [diff] [blame] | 14 | // --------------------------------------------------------------------------- |
| 15 | // Initialization. |
| 16 | |
| 17 | struct 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 | |
| 30 | base::LazyInstance<Interface, Interface::Cache::ValueCreate>::type |
| 31 | Interface::Cache::value_interface = LAZY_INSTANCE_INITIALIZER; |
| 32 | |
| 33 | base::LazyInstance<Interface, Interface::Cache::ConstCreate>::type |
| 34 | Interface::Cache::const_interface = LAZY_INSTANCE_INITIALIZER; |
| 35 | |
| 36 | |
| 37 | Interface* Interface::NewValue() { |
| 38 | return Cache::value_interface.Pointer(); // Cached. |
| 39 | } |
| 40 | |
| 41 | |
| 42 | Interface* Interface::NewConst() { |
| 43 | return Cache::const_interface.Pointer(); // Cached. |
| 44 | } |
| 45 | |
| 46 | |
| 47 | // --------------------------------------------------------------------------- |
| 48 | // Lookup. |
| 49 | |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 50 | Interface* Interface::Lookup(Handle<String> name, Zone* zone) { |
| 51 | DCHECK(IsModule()); |
Ben Murdoch | 3ef787d | 2012-04-12 10:51:47 +0100 | [diff] [blame] | 52 | ZoneHashMap* map = Chase()->exports_; |
Emily Bernier | d0a1eb7 | 2015-03-24 16:35:39 -0400 | [diff] [blame] | 53 | if (map == nullptr) return nullptr; |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 54 | ZoneAllocationPolicy allocator(zone); |
Emily Bernier | d0a1eb7 | 2015-03-24 16:35:39 -0400 | [diff] [blame] | 55 | ZoneHashMap::Entry* p = |
| 56 | map->Lookup(name.location(), name->Hash(), false, allocator); |
| 57 | if (p == nullptr) return nullptr; |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 58 | DCHECK(*static_cast<String**>(p->key) == *name); |
Emily Bernier | d0a1eb7 | 2015-03-24 16:35:39 -0400 | [diff] [blame] | 59 | DCHECK(p->value != nullptr); |
Ben Murdoch | 3ef787d | 2012-04-12 10:51:47 +0100 | [diff] [blame] | 60 | return static_cast<Interface*>(p->value); |
| 61 | } |
| 62 | |
| 63 | |
Emily Bernier | d0a1eb7 | 2015-03-24 16:35:39 -0400 | [diff] [blame] | 64 | // --------------------------------------------------------------------------- |
| 65 | // Addition. |
| 66 | |
Ben Murdoch | 3ef787d | 2012-04-12 10:51:47 +0100 | [diff] [blame] | 67 | #ifdef DEBUG |
| 68 | // Current nesting depth for debug output. |
| 69 | class 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 | |
| 78 | int Nesting::current_ = 0; |
| 79 | #endif |
| 80 | |
| 81 | |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 82 | void Interface::DoAdd(const void* name, uint32_t hash, Interface* interface, |
| 83 | Zone* zone, bool* ok) { |
Ben Murdoch | 3ef787d | 2012-04-12 10:51:47 +0100 | [diff] [blame] | 84 | 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 Bernier | d0a1eb7 | 2015-03-24 16:35:39 -0400 | [diff] [blame] | 92 | const AstRawString* raw = static_cast<const AstRawString*>(name); |
| 93 | PrintF("%*s%.*s : ", Nesting::current(), "", |
| 94 | raw->length(), raw->raw_data()); |
Ben Murdoch | 3ef787d | 2012-04-12 10:51:47 +0100 | [diff] [blame] | 95 | interface->Print(Nesting::current()); |
| 96 | } |
| 97 | #endif |
| 98 | |
| 99 | ZoneHashMap** map = &Chase()->exports_; |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 100 | ZoneAllocationPolicy allocator(zone); |
Ben Murdoch | 3ef787d | 2012-04-12 10:51:47 +0100 | [diff] [blame] | 101 | |
Emily Bernier | d0a1eb7 | 2015-03-24 16:35:39 -0400 | [diff] [blame] | 102 | if (*map == nullptr) { |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 103 | *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 Bernier | d0a1eb7 | 2015-03-24 16:35:39 -0400 | [diff] [blame] | 110 | if (p == nullptr) { |
Ben Murdoch | 3ef787d | 2012-04-12 10:51:47 +0100 | [diff] [blame] | 111 | // This didn't have name but was frozen already, that's an error. |
| 112 | *ok = false; |
Emily Bernier | d0a1eb7 | 2015-03-24 16:35:39 -0400 | [diff] [blame] | 113 | } else if (p->value == nullptr) { |
Ben Murdoch | 3ef787d | 2012-04-12 10:51:47 +0100 | [diff] [blame] | 114 | p->value = interface; |
| 115 | } else { |
| 116 | #ifdef DEBUG |
| 117 | Nesting nested; |
| 118 | #endif |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 119 | static_cast<Interface*>(p->value)->Unify(interface, zone, ok); |
Ben Murdoch | 3ef787d | 2012-04-12 10:51:47 +0100 | [diff] [blame] | 120 | } |
| 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 Bernier | d0a1eb7 | 2015-03-24 16:35:39 -0400 | [diff] [blame] | 132 | // --------------------------------------------------------------------------- |
| 133 | // Unification. |
| 134 | |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 135 | void 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 Bernier | d0a1eb7 | 2015-03-24 16:35:39 -0400 | [diff] [blame] | 138 | DCHECK(this->forward_ == nullptr); |
| 139 | DCHECK(that->forward_ == nullptr); |
Ben Murdoch | 3ef787d | 2012-04-12 10:51:47 +0100 | [diff] [blame] | 140 | |
| 141 | *ok = true; |
| 142 | if (this == that) return; |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 143 | 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 Murdoch | 3ef787d | 2012-04-12 10:51:47 +0100 | [diff] [blame] | 153 | |
| 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 Bernier | d0a1eb7 | 2015-03-24 16:35:39 -0400 | [diff] [blame] | 165 | if (this->exports_ != nullptr && (that->exports_ == nullptr || |
Ben Murdoch | 3ef787d | 2012-04-12 10:51:47 +0100 | [diff] [blame] | 166 | this->exports_->occupancy() >= that->exports_->occupancy())) { |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 167 | this->DoUnify(that, ok, zone); |
Ben Murdoch | 3ef787d | 2012-04-12 10:51:47 +0100 | [diff] [blame] | 168 | } else { |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 169 | that->DoUnify(this, ok, zone); |
Ben Murdoch | 3ef787d | 2012-04-12 10:51:47 +0100 | [diff] [blame] | 170 | } |
| 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 Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 184 | void Interface::DoUnify(Interface* that, bool* ok, Zone* zone) { |
Emily Bernier | d0a1eb7 | 2015-03-24 16:35:39 -0400 | [diff] [blame] | 185 | DCHECK(this->forward_ == nullptr); |
| 186 | DCHECK(that->forward_ == nullptr); |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 187 | DCHECK(!this->IsValue()); |
| 188 | DCHECK(!that->IsValue()); |
| 189 | DCHECK(this->index_ == -1); |
| 190 | DCHECK(that->index_ == -1); |
| 191 | DCHECK(*ok); |
Ben Murdoch | 3ef787d | 2012-04-12 10:51:47 +0100 | [diff] [blame] | 192 | |
| 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 Bernier | d0a1eb7 | 2015-03-24 16:35:39 -0400 | [diff] [blame] | 199 | if (map != nullptr) { |
| 200 | for (ZoneHashMap::Entry* p = map->Start(); p != nullptr; p = map->Next(p)) { |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 201 | this->DoAdd(p->key, p->hash, static_cast<Interface*>(p->value), zone, ok); |
Ben Murdoch | 3ef787d | 2012-04-12 10:51:47 +0100 | [diff] [blame] | 202 | 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 Bernier | d0a1eb7 | 2015-03-24 16:35:39 -0400 | [diff] [blame] | 208 | int this_size = this->exports_ == nullptr ? 0 : this->exports_->occupancy(); |
| 209 | int that_size = map == nullptr ? 0 : map->occupancy(); |
Ben Murdoch | 3ef787d | 2012-04-12 10:51:47 +0100 | [diff] [blame] | 210 | 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 Bernier | d0a1eb7 | 2015-03-24 16:35:39 -0400 | [diff] [blame] | 221 | // --------------------------------------------------------------------------- |
| 222 | // Printing. |
| 223 | |
Ben Murdoch | 3ef787d | 2012-04-12 10:51:47 +0100 | [diff] [blame] | 224 | #ifdef DEBUG |
| 225 | void 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 Bernier | d0a1eb7 | 2015-03-24 16:35:39 -0400 | [diff] [blame] | 230 | for (Interface* link = this->forward_; link != nullptr; |
| 231 | link = link->forward_) { |
Ben Murdoch | 3ef787d | 2012-04-12 10:51:47 +0100 | [diff] [blame] | 232 | PrintF("->%p", static_cast<void*>(link)); |
Emily Bernier | d0a1eb7 | 2015-03-24 16:35:39 -0400 | [diff] [blame] | 233 | } |
Ben Murdoch | 3ef787d | 2012-04-12 10:51:47 +0100 | [diff] [blame] | 234 | PrintF(" "); |
| 235 | } |
| 236 | |
| 237 | if (IsUnknown()) { |
| 238 | PrintF("unknown\n"); |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 239 | } else if (IsConst()) { |
| 240 | PrintF("const\n"); |
Ben Murdoch | 3ef787d | 2012-04-12 10:51:47 +0100 | [diff] [blame] | 241 | } else if (IsValue()) { |
| 242 | PrintF("value\n"); |
| 243 | } else if (IsModule()) { |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 244 | PrintF("module %d %s{", Index(), IsFrozen() ? "" : "(unresolved) "); |
Ben Murdoch | 3ef787d | 2012-04-12 10:51:47 +0100 | [diff] [blame] | 245 | ZoneHashMap* map = Chase()->exports_; |
Emily Bernier | d0a1eb7 | 2015-03-24 16:35:39 -0400 | [diff] [blame] | 246 | if (map == nullptr || map->occupancy() == 0) { |
Ben Murdoch | 3ef787d | 2012-04-12 10:51:47 +0100 | [diff] [blame] | 247 | 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 Bernier | d0a1eb7 | 2015-03-24 16:35:39 -0400 | [diff] [blame] | 253 | for (ZoneHashMap::Entry* p = map->Start(); |
| 254 | p != nullptr; p = map->Next(p)) { |
Ben Murdoch | 3ef787d | 2012-04-12 10:51:47 +0100 | [diff] [blame] | 255 | 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 |