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