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