1// 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);
38  ASSERT(name1->IsSymbol());
39  ASSERT(name2->IsSymbol());
40  return name1 == name2;
41}
42
43
44Interface* Interface::Lookup(Handle<String> name) {
45  ASSERT(IsModule());
46  ZoneHashMap* map = Chase()->exports_;
47  if (map == NULL) return NULL;
48  ZoneHashMap::Entry* p = map->Lookup(name.location(), name->Hash(), false);
49  if (p == NULL) return NULL;
50  ASSERT(*static_cast<String**>(p->key) == *name);
51  ASSERT(p->value != NULL);
52  return static_cast<Interface*>(p->value);
53}
54
55
56#ifdef DEBUG
57// Current nesting depth for debug output.
58class Nesting {
59 public:
60  Nesting()  { current_ += 2; }
61  ~Nesting() { current_ -= 2; }
62  static int current() { return current_; }
63 private:
64  static int current_;
65};
66
67int Nesting::current_ = 0;
68#endif
69
70
71void Interface::DoAdd(
72    void* name, uint32_t hash, Interface* interface, bool* ok) {
73  MakeModule(ok);
74  if (!*ok) return;
75
76#ifdef DEBUG
77  if (FLAG_print_interface_details) {
78    PrintF("%*s# Adding...\n", Nesting::current(), "");
79    PrintF("%*sthis = ", Nesting::current(), "");
80    this->Print(Nesting::current());
81    PrintF("%*s%s : ", Nesting::current(), "",
82           (*reinterpret_cast<String**>(name))->ToAsciiArray());
83    interface->Print(Nesting::current());
84  }
85#endif
86
87  ZoneHashMap** map = &Chase()->exports_;
88  if (*map == NULL) *map = new ZoneHashMap(Match, 8);
89
90  ZoneHashMap::Entry* p = (*map)->Lookup(name, hash, !IsFrozen());
91  if (p == NULL) {
92    // This didn't have name but was frozen already, that's an error.
93    *ok = false;
94  } else if (p->value == NULL) {
95    p->value = interface;
96  } else {
97#ifdef DEBUG
98    Nesting nested;
99#endif
100    reinterpret_cast<Interface*>(p->value)->Unify(interface, ok);
101  }
102
103#ifdef DEBUG
104  if (FLAG_print_interface_details) {
105    PrintF("%*sthis' = ", Nesting::current(), "");
106    this->Print(Nesting::current());
107    PrintF("%*s# Added.\n", Nesting::current(), "");
108  }
109#endif
110}
111
112
113void Interface::Unify(Interface* that, bool* ok) {
114  if (this->forward_) return this->Chase()->Unify(that, ok);
115  if (that->forward_) return this->Unify(that->Chase(), ok);
116  ASSERT(this->forward_ == NULL);
117  ASSERT(that->forward_ == NULL);
118
119  *ok = true;
120  if (this == that) return;
121  if (this->IsValue()) return that->MakeValue(ok);
122  if (that->IsValue()) return this->MakeValue(ok);
123
124#ifdef DEBUG
125  if (FLAG_print_interface_details) {
126    PrintF("%*s# Unifying...\n", Nesting::current(), "");
127    PrintF("%*sthis = ", Nesting::current(), "");
128    this->Print(Nesting::current());
129    PrintF("%*sthat = ", Nesting::current(), "");
130    that->Print(Nesting::current());
131  }
132#endif
133
134  // Merge the smaller interface into the larger, for performance.
135  if (this->exports_ != NULL && (that->exports_ == NULL ||
136      this->exports_->occupancy() >= that->exports_->occupancy())) {
137    this->DoUnify(that, ok);
138  } else {
139    that->DoUnify(this, ok);
140  }
141
142#ifdef DEBUG
143  if (FLAG_print_interface_details) {
144    PrintF("%*sthis' = ", Nesting::current(), "");
145    this->Print(Nesting::current());
146    PrintF("%*sthat' = ", Nesting::current(), "");
147    that->Print(Nesting::current());
148    PrintF("%*s# Unified.\n", Nesting::current(), "");
149  }
150#endif
151}
152
153
154void Interface::DoUnify(Interface* that, bool* ok) {
155  ASSERT(this->forward_ == NULL);
156  ASSERT(that->forward_ == NULL);
157  ASSERT(!this->IsValue());
158  ASSERT(!that->IsValue());
159  ASSERT(*ok);
160
161#ifdef DEBUG
162    Nesting nested;
163#endif
164
165  // Try to merge all members from that into this.
166  ZoneHashMap* map = that->exports_;
167  if (map != NULL) {
168    for (ZoneHashMap::Entry* p = map->Start(); p != NULL; p = map->Next(p)) {
169      this->DoAdd(p->key, p->hash, static_cast<Interface*>(p->value), ok);
170      if (!*ok) return;
171    }
172  }
173
174  // If the new interface is larger than that's, then there were members in
175  // 'this' which 'that' didn't have. If 'that' was frozen that is an error.
176  int this_size = this->exports_ == NULL ? 0 : this->exports_->occupancy();
177  int that_size = map == NULL ? 0 : map->occupancy();
178  if (that->IsFrozen() && this_size > that_size) {
179    *ok = false;
180    return;
181  }
182
183  // Merge interfaces.
184  this->flags_ |= that->flags_;
185  that->forward_ = this;
186}
187
188
189#ifdef DEBUG
190void Interface::Print(int n) {
191  int n0 = n > 0 ? n : 0;
192
193  if (FLAG_print_interface_details) {
194    PrintF("%p", static_cast<void*>(this));
195    for (Interface* link = this->forward_; link != NULL; link = link->forward_)
196      PrintF("->%p", static_cast<void*>(link));
197    PrintF(" ");
198  }
199
200  if (IsUnknown()) {
201    PrintF("unknown\n");
202  } else if (IsValue()) {
203    PrintF("value\n");
204  } else if (IsModule()) {
205    PrintF("module %s{", IsFrozen() ? "" : "(unresolved) ");
206    ZoneHashMap* map = Chase()->exports_;
207    if (map == NULL || map->occupancy() == 0) {
208      PrintF("}\n");
209    } else if (n < 0 || n0 >= 2 * FLAG_print_interface_depth) {
210      // Avoid infinite recursion on cyclic types.
211      PrintF("...}\n");
212    } else {
213      PrintF("\n");
214      for (ZoneHashMap::Entry* p = map->Start(); p != NULL; p = map->Next(p)) {
215        String* name = *static_cast<String**>(p->key);
216        Interface* interface = static_cast<Interface*>(p->value);
217        PrintF("%*s%s : ", n0 + 2, "", name->ToAsciiArray());
218        interface->Print(n0 + 2);
219      }
220      PrintF("%*s}\n", n0, "");
221    }
222  }
223}
224#endif
225
226} }  // namespace v8::internal
227