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 #ifndef V8_INTERFACE_H_
6 #define V8_INTERFACE_H_
7 
8 #include "src/ast-value-factory.h"
9 #include "src/zone-inl.h"  // For operator new.
10 
11 namespace v8 {
12 namespace internal {
13 
14 
15 // This class implements the following abstract grammar of interfaces
16 // (i.e. module types):
17 //   interface ::= UNDETERMINED | VALUE | CONST | MODULE(exports)
18 //   exports ::= {name : interface, ...}
19 // A frozen type is one that is fully determined. Unification does not
20 // allow to turn non-const values into const, or adding additional exports to
21 // frozen interfaces. Otherwise, unifying modules merges their exports.
22 // Undetermined types are unification variables that can be unified freely.
23 // There is a natural subsort lattice that reflects the increase of knowledge:
24 //
25 //            undetermined
26 //           //     |    \\                                                    .
27 //       value  (frozen)  module
28 //      //   \\  /    \  //
29 //  const   fr.value  fr.module
30 //      \\    /
31 //     fr.const
32 //
33 // where the bold lines are the only transitions allowed.
34 
35 class Interface : public ZoneObject {
36  public:
37   // ---------------------------------------------------------------------------
38   // Factory methods.
39 
NewUnknown(Zone * zone)40   static Interface* NewUnknown(Zone* zone) {
41     return new(zone) Interface(NONE);
42   }
43 
NewValue()44   static Interface* NewValue() {
45     static Interface value_interface(VALUE + FROZEN);  // Cached.
46     return &value_interface;
47   }
48 
NewConst()49   static Interface* NewConst() {
50     static Interface value_interface(VALUE + CONST + FROZEN);  // Cached.
51     return &value_interface;
52   }
53 
NewModule(Zone * zone)54   static Interface* NewModule(Zone* zone) {
55     return new(zone) Interface(MODULE);
56   }
57 
58   // ---------------------------------------------------------------------------
59   // Mutators.
60 
61   // Add a name to the list of exports. If it already exists, unify with
62   // interface, otherwise insert unless this is closed.
Add(const AstRawString * name,Interface * interface,Zone * zone,bool * ok)63   void Add(const AstRawString* name, Interface* interface, Zone* zone,
64            bool* ok) {
65     DoAdd(name, name->hash(), interface, zone, ok);
66   }
67 
68   // Unify with another interface. If successful, both interface objects will
69   // represent the same type, and changes to one are reflected in the other.
70   void Unify(Interface* that, Zone* zone, bool* ok);
71 
72   // Determine this interface to be a value interface.
MakeValue(bool * ok)73   void MakeValue(bool* ok) {
74     *ok = !IsModule();
75     if (*ok) Chase()->flags_ |= VALUE;
76   }
77 
78   // Determine this interface to be an immutable interface.
MakeConst(bool * ok)79   void MakeConst(bool* ok) {
80     *ok = !IsModule() && (IsConst() || !IsFrozen());
81     if (*ok) Chase()->flags_ |= VALUE + CONST;
82   }
83 
84   // Determine this interface to be a module interface.
MakeModule(bool * ok)85   void MakeModule(bool* ok) {
86     *ok = !IsValue();
87     if (*ok) Chase()->flags_ |= MODULE;
88   }
89 
90   // Do not allow any further refinements, directly or through unification.
Freeze(bool * ok)91   void Freeze(bool* ok) {
92     *ok = IsValue() || IsModule();
93     if (*ok) Chase()->flags_ |= FROZEN;
94   }
95 
96   // Assign an index.
Allocate(int index)97   void Allocate(int index) {
98     DCHECK(IsModule() && IsFrozen() && Chase()->index_ == -1);
99     Chase()->index_ = index;
100   }
101 
102   // ---------------------------------------------------------------------------
103   // Accessors.
104 
105   // Check whether this is still a fully undetermined type.
IsUnknown()106   bool IsUnknown() { return Chase()->flags_ == NONE; }
107 
108   // Check whether this is a value type.
IsValue()109   bool IsValue() { return Chase()->flags_ & VALUE; }
110 
111   // Check whether this is a constant type.
IsConst()112   bool IsConst() { return Chase()->flags_ & CONST; }
113 
114   // Check whether this is a module type.
IsModule()115   bool IsModule() { return Chase()->flags_ & MODULE; }
116 
117   // Check whether this is closed (i.e. fully determined).
IsFrozen()118   bool IsFrozen() { return Chase()->flags_ & FROZEN; }
119 
IsUnified(Interface * that)120   bool IsUnified(Interface* that) {
121     return Chase() == that->Chase()
122         || (this->IsValue() == that->IsValue() &&
123             this->IsConst() == that->IsConst());
124   }
125 
Length()126   int Length() {
127     DCHECK(IsModule() && IsFrozen());
128     ZoneHashMap* exports = Chase()->exports_;
129     return exports ? exports->occupancy() : 0;
130   }
131 
132   // The context slot in the hosting global context pointing to this module.
Index()133   int Index() {
134     DCHECK(IsModule() && IsFrozen());
135     return Chase()->index_;
136   }
137 
138   // Look up an exported name. Returns NULL if not (yet) defined.
139   Interface* Lookup(Handle<String> name, Zone* zone);
140 
141   // ---------------------------------------------------------------------------
142   // Iterators.
143 
144   // Use like:
145   //   for (auto it = interface->iterator(); !it.done(); it.Advance()) {
146   //     ... it.name() ... it.interface() ...
147   //   }
148   class Iterator {
149    public:
done()150     bool done() const { return entry_ == NULL; }
name()151     const AstRawString* name() const {
152       DCHECK(!done());
153       return static_cast<const AstRawString*>(entry_->key);
154     }
interface()155     Interface* interface() const {
156       DCHECK(!done());
157       return static_cast<Interface*>(entry_->value);
158     }
Advance()159     void Advance() { entry_ = exports_->Next(entry_); }
160 
161    private:
162     friend class Interface;
Iterator(const ZoneHashMap * exports)163     explicit Iterator(const ZoneHashMap* exports)
164         : exports_(exports), entry_(exports ? exports->Start() : NULL) {}
165 
166     const ZoneHashMap* exports_;
167     ZoneHashMap::Entry* entry_;
168   };
169 
iterator()170   Iterator iterator() const { return Iterator(this->exports_); }
171 
172   // ---------------------------------------------------------------------------
173   // Debugging.
174 #ifdef DEBUG
175   void Print(int n = 0);  // n = indentation; n < 0 => don't print recursively
176 #endif
177 
178   // ---------------------------------------------------------------------------
179   // Implementation.
180  private:
181   enum Flags {    // All flags are monotonic
182     NONE = 0,
183     VALUE = 1,    // This type describes a value
184     CONST = 2,    // This type describes a constant
185     MODULE = 4,   // This type describes a module
186     FROZEN = 8    // This type is fully determined
187   };
188 
189   int flags_;
190   Interface* forward_;     // Unification link
191   ZoneHashMap* exports_;   // Module exports and their types (allocated lazily)
192   int index_;
193 
Interface(int flags)194   explicit Interface(int flags)
195     : flags_(flags),
196       forward_(NULL),
197       exports_(NULL),
198       index_(-1) {
199 #ifdef DEBUG
200     if (FLAG_print_interface_details)
201       PrintF("# Creating %p\n", static_cast<void*>(this));
202 #endif
203   }
204 
Chase()205   Interface* Chase() {
206     Interface* result = this;
207     while (result->forward_ != NULL) result = result->forward_;
208     if (result != this) forward_ = result;  // On-the-fly path compression.
209     return result;
210   }
211 
212   void DoAdd(const void* name, uint32_t hash, Interface* interface, Zone* zone,
213              bool* ok);
214   void DoUnify(Interface* that, bool* ok, Zone* zone);
215 };
216 
217 } }  // namespace v8::internal
218 
219 #endif  // V8_INTERFACE_H_
220