blob: 603dfe9b8639307e63cd21e4da94effba80fe2a7 [file] [log] [blame]
erik.corry@gmail.combbceb572012-03-09 10:52:05 +00001// Copyright 2012 the V8 project authors. All rights reserved.
2// Redistribution and use in source and binary forms, with or without
3// modification, are permitted provided that the following conditions are
4// met:
5//
6// * Redistributions of source code must retain the above copyright
7// notice, this list of conditions and the following disclaimer.
8// * Redistributions in binary form must reproduce the above
9// copyright notice, this list of conditions and the following
10// disclaimer in the documentation and/or other materials provided
11// with the distribution.
12// * Neither the name of Google Inc. nor the names of its
13// contributors may be used to endorse or promote products derived
14// from this software without specific prior written permission.
15//
16// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27
28#include "v8.h"
29
30#include "interface.h"
31
32namespace v8 {
33namespace internal {
34
35static bool Match(void* key1, void* key2) {
36 String* name1 = *static_cast<String**>(key1);
37 String* name2 = *static_cast<String**>(key2);
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +000038 ASSERT(name1->IsInternalizedString());
39 ASSERT(name2->IsInternalizedString());
erik.corry@gmail.combbceb572012-03-09 10:52:05 +000040 return name1 == name2;
41}
42
43
mmassi@chromium.org7028c052012-06-13 11:51:58 +000044Interface* Interface::Lookup(Handle<String> name, Zone* zone) {
erik.corry@gmail.combbceb572012-03-09 10:52:05 +000045 ASSERT(IsModule());
46 ZoneHashMap* map = Chase()->exports_;
47 if (map == NULL) return NULL;
mmassi@chromium.org7028c052012-06-13 11:51:58 +000048 ZoneAllocationPolicy allocator(zone);
49 ZoneHashMap::Entry* p = map->Lookup(name.location(), name->Hash(), false,
50 allocator);
erik.corry@gmail.combbceb572012-03-09 10:52:05 +000051 if (p == NULL) return NULL;
52 ASSERT(*static_cast<String**>(p->key) == *name);
53 ASSERT(p->value != NULL);
54 return static_cast<Interface*>(p->value);
55}
56
57
58#ifdef DEBUG
59// Current nesting depth for debug output.
60class Nesting {
61 public:
62 Nesting() { current_ += 2; }
63 ~Nesting() { current_ -= 2; }
64 static int current() { return current_; }
65 private:
66 static int current_;
67};
68
69int Nesting::current_ = 0;
70#endif
71
72
73void Interface::DoAdd(
mmassi@chromium.org7028c052012-06-13 11:51:58 +000074 void* name, uint32_t hash, Interface* interface, Zone* zone, bool* ok) {
erik.corry@gmail.combbceb572012-03-09 10:52:05 +000075 MakeModule(ok);
76 if (!*ok) return;
77
78#ifdef DEBUG
79 if (FLAG_print_interface_details) {
80 PrintF("%*s# Adding...\n", Nesting::current(), "");
81 PrintF("%*sthis = ", Nesting::current(), "");
82 this->Print(Nesting::current());
83 PrintF("%*s%s : ", Nesting::current(), "",
erik.corry@gmail.comed49e962012-04-17 11:57:53 +000084 (*static_cast<String**>(name))->ToAsciiArray());
erik.corry@gmail.combbceb572012-03-09 10:52:05 +000085 interface->Print(Nesting::current());
86 }
87#endif
88
89 ZoneHashMap** map = &Chase()->exports_;
mmassi@chromium.org7028c052012-06-13 11:51:58 +000090 ZoneAllocationPolicy allocator(zone);
erik.corry@gmail.combbceb572012-03-09 10:52:05 +000091
mmassi@chromium.org7028c052012-06-13 11:51:58 +000092 if (*map == NULL)
93 *map = new ZoneHashMap(Match, ZoneHashMap::kDefaultHashMapCapacity,
94 allocator);
95
96 ZoneHashMap::Entry* p = (*map)->Lookup(name, hash, !IsFrozen(), allocator);
erik.corry@gmail.combbceb572012-03-09 10:52:05 +000097 if (p == NULL) {
98 // This didn't have name but was frozen already, that's an error.
99 *ok = false;
100 } else if (p->value == NULL) {
101 p->value = interface;
102 } else {
103#ifdef DEBUG
104 Nesting nested;
105#endif
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000106 static_cast<Interface*>(p->value)->Unify(interface, zone, ok);
erik.corry@gmail.combbceb572012-03-09 10:52:05 +0000107 }
108
109#ifdef DEBUG
110 if (FLAG_print_interface_details) {
111 PrintF("%*sthis' = ", Nesting::current(), "");
112 this->Print(Nesting::current());
113 PrintF("%*s# Added.\n", Nesting::current(), "");
114 }
115#endif
116}
117
118
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000119void Interface::Unify(Interface* that, Zone* zone, bool* ok) {
120 if (this->forward_) return this->Chase()->Unify(that, zone, ok);
121 if (that->forward_) return this->Unify(that->Chase(), zone, ok);
erik.corry@gmail.combbceb572012-03-09 10:52:05 +0000122 ASSERT(this->forward_ == NULL);
123 ASSERT(that->forward_ == NULL);
124
125 *ok = true;
126 if (this == that) return;
jkummerow@chromium.org28583c92012-07-16 11:31:55 +0000127 if (this->IsValue()) {
128 that->MakeValue(ok);
129 if (*ok && this->IsConst()) that->MakeConst(ok);
130 return;
131 }
132 if (that->IsValue()) {
133 this->MakeValue(ok);
134 if (*ok && that->IsConst()) this->MakeConst(ok);
135 return;
136 }
erik.corry@gmail.combbceb572012-03-09 10:52:05 +0000137
138#ifdef DEBUG
139 if (FLAG_print_interface_details) {
140 PrintF("%*s# Unifying...\n", Nesting::current(), "");
141 PrintF("%*sthis = ", Nesting::current(), "");
142 this->Print(Nesting::current());
143 PrintF("%*sthat = ", Nesting::current(), "");
144 that->Print(Nesting::current());
145 }
146#endif
147
148 // Merge the smaller interface into the larger, for performance.
149 if (this->exports_ != NULL && (that->exports_ == NULL ||
150 this->exports_->occupancy() >= that->exports_->occupancy())) {
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000151 this->DoUnify(that, ok, zone);
erik.corry@gmail.combbceb572012-03-09 10:52:05 +0000152 } else {
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000153 that->DoUnify(this, ok, zone);
erik.corry@gmail.combbceb572012-03-09 10:52:05 +0000154 }
155
156#ifdef DEBUG
157 if (FLAG_print_interface_details) {
158 PrintF("%*sthis' = ", Nesting::current(), "");
159 this->Print(Nesting::current());
160 PrintF("%*sthat' = ", Nesting::current(), "");
161 that->Print(Nesting::current());
162 PrintF("%*s# Unified.\n", Nesting::current(), "");
163 }
164#endif
165}
166
167
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000168void Interface::DoUnify(Interface* that, bool* ok, Zone* zone) {
erik.corry@gmail.combbceb572012-03-09 10:52:05 +0000169 ASSERT(this->forward_ == NULL);
170 ASSERT(that->forward_ == NULL);
171 ASSERT(!this->IsValue());
172 ASSERT(!that->IsValue());
ulan@chromium.org8e8d8822012-11-23 14:36:46 +0000173 ASSERT(this->index_ == -1);
174 ASSERT(that->index_ == -1);
erik.corry@gmail.combbceb572012-03-09 10:52:05 +0000175 ASSERT(*ok);
176
177#ifdef DEBUG
178 Nesting nested;
179#endif
180
181 // Try to merge all members from that into this.
182 ZoneHashMap* map = that->exports_;
183 if (map != NULL) {
184 for (ZoneHashMap::Entry* p = map->Start(); p != NULL; p = map->Next(p)) {
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000185 this->DoAdd(p->key, p->hash, static_cast<Interface*>(p->value), zone, ok);
erik.corry@gmail.combbceb572012-03-09 10:52:05 +0000186 if (!*ok) return;
187 }
188 }
189
190 // If the new interface is larger than that's, then there were members in
191 // 'this' which 'that' didn't have. If 'that' was frozen that is an error.
192 int this_size = this->exports_ == NULL ? 0 : this->exports_->occupancy();
193 int that_size = map == NULL ? 0 : map->occupancy();
194 if (that->IsFrozen() && this_size > that_size) {
195 *ok = false;
196 return;
197 }
198
erik.corry@gmail.combbceb572012-03-09 10:52:05 +0000199 // Merge interfaces.
200 this->flags_ |= that->flags_;
201 that->forward_ = this;
202}
203
204
205#ifdef DEBUG
206void Interface::Print(int n) {
207 int n0 = n > 0 ? n : 0;
208
209 if (FLAG_print_interface_details) {
210 PrintF("%p", static_cast<void*>(this));
211 for (Interface* link = this->forward_; link != NULL; link = link->forward_)
212 PrintF("->%p", static_cast<void*>(link));
213 PrintF(" ");
214 }
215
216 if (IsUnknown()) {
217 PrintF("unknown\n");
jkummerow@chromium.org28583c92012-07-16 11:31:55 +0000218 } else if (IsConst()) {
219 PrintF("const\n");
erik.corry@gmail.combbceb572012-03-09 10:52:05 +0000220 } else if (IsValue()) {
221 PrintF("value\n");
222 } else if (IsModule()) {
ulan@chromium.org8e8d8822012-11-23 14:36:46 +0000223 PrintF("module %d %s{", Index(), IsFrozen() ? "" : "(unresolved) ");
erik.corry@gmail.combbceb572012-03-09 10:52:05 +0000224 ZoneHashMap* map = Chase()->exports_;
225 if (map == NULL || map->occupancy() == 0) {
226 PrintF("}\n");
227 } else if (n < 0 || n0 >= 2 * FLAG_print_interface_depth) {
228 // Avoid infinite recursion on cyclic types.
229 PrintF("...}\n");
230 } else {
231 PrintF("\n");
232 for (ZoneHashMap::Entry* p = map->Start(); p != NULL; p = map->Next(p)) {
233 String* name = *static_cast<String**>(p->key);
234 Interface* interface = static_cast<Interface*>(p->value);
235 PrintF("%*s%s : ", n0 + 2, "", name->ToAsciiArray());
236 interface->Print(n0 + 2);
237 }
238 PrintF("%*s}\n", n0, "");
239 }
240 }
241}
242#endif
243
244} } // namespace v8::internal