Add support for private names
[WebKit-https.git] / Source / JavaScriptCore / runtime / Lookup.h
1 /*
2  *  Copyright (C) 1999-2000 Harri Porten (porten@kde.org)
3  *  Copyright (C) 2003, 2006, 2007, 2008, 2009 Apple Inc. All rights reserved.
4  *
5  *  This library is free software; you can redistribute it and/or
6  *  modify it under the terms of the GNU Lesser General Public
7  *  License as published by the Free Software Foundation; either
8  *  version 2 of the License, or (at your option) any later version.
9  *
10  *  This library is distributed in the hope that it will be useful,
11  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  *  Lesser General Public License for more details.
14  *
15  *  You should have received a copy of the GNU Lesser General Public
16  *  License along with this library; if not, write to the Free Software
17  *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
18  *
19  */
20
21 #ifndef Lookup_h
22 #define Lookup_h
23
24 #include "CallFrame.h"
25 #include "Intrinsic.h"
26 #include "Identifier.h"
27 #include "JSGlobalObject.h"
28 #include "PropertySlot.h"
29 #include <stdio.h>
30 #include <wtf/Assertions.h>
31
32 namespace JSC {
33     // Hash table generated by the create_hash_table script.
34     struct HashTableValue {
35         const char* key; // property name
36         unsigned char attributes; // JSObject attributes
37         intptr_t value1;
38         intptr_t value2;
39         Intrinsic intrinsic;
40     };
41
42     // FIXME: There is no reason this get function can't be simpler.
43     // ie. typedef JSValue (*GetFunction)(ExecState*, JSObject* baseObject)
44     typedef PropertySlot::GetValueFunc GetFunction;
45     typedef void (*PutFunction)(ExecState*, JSObject* baseObject, JSValue value);
46
47     class HashEntry {
48         WTF_MAKE_FAST_ALLOCATED;
49     public:
50         void initialize(StringImpl* key, unsigned char attributes, intptr_t v1, intptr_t v2, Intrinsic intrinsic)
51         {
52             m_key = key;
53             m_attributes = attributes;
54             m_u.store.value1 = v1;
55             m_u.store.value2 = v2;
56             m_u.function.intrinsic = intrinsic;
57             m_next = 0;
58         }
59
60         void setKey(StringImpl* key) { m_key = key; }
61         StringImpl* key() const { return m_key; }
62
63         unsigned char attributes() const { return m_attributes; }
64
65         Intrinsic intrinsic() const
66         {
67             ASSERT(m_attributes & Function);
68             return m_u.function.intrinsic;
69         }
70
71         NativeFunction function() const { ASSERT(m_attributes & Function); return m_u.function.functionValue; }
72         unsigned char functionLength() const { ASSERT(m_attributes & Function); return static_cast<unsigned char>(m_u.function.length); }
73
74         GetFunction propertyGetter() const { ASSERT(!(m_attributes & Function)); return m_u.property.get; }
75         PutFunction propertyPutter() const { ASSERT(!(m_attributes & Function)); return m_u.property.put; }
76
77         intptr_t lexerValue() const { ASSERT(!m_attributes); return m_u.lexer.value; }
78
79         void setNext(HashEntry *next) { m_next = next; }
80         HashEntry* next() const { return m_next; }
81
82     private:
83         StringImpl* m_key;
84         unsigned char m_attributes; // JSObject attributes
85
86         union {
87             struct {
88                 intptr_t value1;
89                 intptr_t value2;
90             } store;
91             struct {
92                 NativeFunction functionValue;
93                 intptr_t length; // number of arguments for function
94                 Intrinsic intrinsic;
95             } function;
96             struct {
97                 GetFunction get;
98                 PutFunction put;
99             } property;
100             struct {
101                 intptr_t value;
102                 intptr_t unused;
103             } lexer;
104         } m_u;
105
106         HashEntry* m_next;
107     };
108
109     struct HashTable {
110
111         int compactSize;
112         int compactHashSizeMask;
113
114         const HashTableValue* values; // Fixed values generated by script.
115         mutable const HashEntry* table; // Table allocated at runtime.
116
117         ALWAYS_INLINE void initializeIfNeeded(JSGlobalData* globalData) const
118         {
119             if (!table)
120                 createTable(globalData);
121         }
122
123         ALWAYS_INLINE void initializeIfNeeded(ExecState* exec) const
124         {
125             if (!table)
126                 createTable(&exec->globalData());
127         }
128
129         JS_EXPORT_PRIVATE void deleteTable() const;
130
131         // Find an entry in the table, and return the entry.
132         ALWAYS_INLINE const HashEntry* entry(JSGlobalData* globalData, PropertyName identifier) const
133         {
134             initializeIfNeeded(globalData);
135             return entry(identifier);
136         }
137
138         ALWAYS_INLINE const HashEntry* entry(ExecState* exec, PropertyName identifier) const
139         {
140             initializeIfNeeded(exec);
141             return entry(identifier);
142         }
143
144         class ConstIterator {
145         public:
146             ConstIterator(const HashTable* table, int position)
147                 : m_table(table)
148                 , m_position(position)
149             {
150                 skipInvalidKeys();
151             }
152
153             const HashEntry* operator->()
154             {
155                 return &m_table->table[m_position];
156             }
157
158             const HashEntry* operator*()
159             {
160                 return &m_table->table[m_position];
161             }
162
163             bool operator!=(const ConstIterator& other)
164             {
165                 ASSERT(m_table == other.m_table);
166                 return m_position != other.m_position;
167             }
168             
169             ConstIterator& operator++()
170             {
171                 ASSERT(m_position < m_table->compactSize);
172                 ++m_position;
173                 skipInvalidKeys();
174                 return *this;
175             }
176
177         private:
178             void skipInvalidKeys()
179             {
180                 ASSERT(m_position <= m_table->compactSize);
181                 while (m_position < m_table->compactSize && !m_table->table[m_position].key())
182                     ++m_position;
183                 ASSERT(m_position <= m_table->compactSize);
184             }
185             
186             const HashTable* m_table;
187             int m_position;
188         };
189
190         ConstIterator begin(JSGlobalData& globalData) const
191         {
192             initializeIfNeeded(&globalData);
193             return ConstIterator(this, 0);
194         }
195         ConstIterator end(JSGlobalData& globalData) const
196         {
197             initializeIfNeeded(&globalData);
198             return ConstIterator(this, compactSize);
199         }
200
201     private:
202         ALWAYS_INLINE const HashEntry* entry(PropertyName propertyName) const
203         {
204             StringImpl* impl = propertyName.publicName();
205             if (!impl)
206                 return 0;
207         
208             ASSERT(table);
209
210             const HashEntry* entry = &table[impl->existingHash() & compactHashSizeMask];
211
212             if (!entry->key())
213                 return 0;
214
215             do {
216                 if (entry->key() == impl)
217                     return entry;
218                 entry = entry->next();
219             } while (entry);
220
221             return 0;
222         }
223
224         // Convert the hash table keys to identifiers.
225         JS_EXPORT_PRIVATE void createTable(JSGlobalData*) const;
226     };
227
228     JS_EXPORT_PRIVATE bool setUpStaticFunctionSlot(ExecState*, const HashEntry*, JSObject* thisObject, PropertyName, PropertySlot&);
229
230     /**
231      * This method does it all (looking in the hashtable, checking for function
232      * overrides, creating the function or retrieving from cache, calling
233      * getValueProperty in case of a non-function property, forwarding to parent if
234      * unknown property).
235      */
236     template <class ThisImp, class ParentImp>
237     inline bool getStaticPropertySlot(ExecState* exec, const HashTable* table, ThisImp* thisObj, PropertyName propertyName, PropertySlot& slot)
238     {
239         const HashEntry* entry = table->entry(exec, propertyName);
240
241         if (!entry) // not found, forward to parent
242             return ParentImp::getOwnPropertySlot(thisObj, exec, propertyName, slot);
243
244         if (entry->attributes() & Function)
245             return setUpStaticFunctionSlot(exec, entry, thisObj, propertyName, slot);
246
247         slot.setCacheableCustom(thisObj, entry->propertyGetter());
248         return true;
249     }
250
251     template <class ThisImp, class ParentImp>
252     inline bool getStaticPropertyDescriptor(ExecState* exec, const HashTable* table, ThisImp* thisObj, PropertyName propertyName, PropertyDescriptor& descriptor)
253     {
254         const HashEntry* entry = table->entry(exec, propertyName);
255         
256         if (!entry) // not found, forward to parent
257             return ParentImp::getOwnPropertyDescriptor(thisObj, exec, propertyName, descriptor);
258  
259         PropertySlot slot;
260         if (entry->attributes() & Function) {
261             bool present = setUpStaticFunctionSlot(exec, entry, thisObj, propertyName, slot);
262             if (present)
263                 descriptor.setDescriptor(slot.getValue(exec, propertyName), entry->attributes());
264             return present;
265         }
266
267         slot.setCustom(thisObj, entry->propertyGetter());
268         descriptor.setDescriptor(slot.getValue(exec, propertyName), entry->attributes());
269         return true;
270     }
271
272     /**
273      * Simplified version of getStaticPropertySlot in case there are only functions.
274      * Using this instead of getStaticPropertySlot allows 'this' to avoid implementing
275      * a dummy getValueProperty.
276      */
277     template <class ParentImp>
278     inline bool getStaticFunctionSlot(ExecState* exec, const HashTable* table, JSObject* thisObj, PropertyName propertyName, PropertySlot& slot)
279     {
280         if (ParentImp::getOwnPropertySlot(thisObj, exec, propertyName, slot))
281             return true;
282
283         const HashEntry* entry = table->entry(exec, propertyName);
284         if (!entry)
285             return false;
286
287         return setUpStaticFunctionSlot(exec, entry, thisObj, propertyName, slot);
288     }
289     
290     /**
291      * Simplified version of getStaticPropertyDescriptor in case there are only functions.
292      * Using this instead of getStaticPropertyDescriptor allows 'this' to avoid implementing
293      * a dummy getValueProperty.
294      */
295     template <class ParentImp>
296     inline bool getStaticFunctionDescriptor(ExecState* exec, const HashTable* table, JSObject* thisObj, PropertyName propertyName, PropertyDescriptor& descriptor)
297     {
298         if (ParentImp::getOwnPropertyDescriptor(static_cast<ParentImp*>(thisObj), exec, propertyName, descriptor))
299             return true;
300         
301         const HashEntry* entry = table->entry(exec, propertyName);
302         if (!entry)
303             return false;
304         
305         PropertySlot slot;
306         bool present = setUpStaticFunctionSlot(exec, entry, thisObj, propertyName, slot);
307         if (present)
308             descriptor.setDescriptor(slot.getValue(exec, propertyName), entry->attributes());
309         return present;
310     }
311
312     /**
313      * Simplified version of getStaticPropertySlot in case there are no functions, only "values".
314      * Using this instead of getStaticPropertySlot removes the need for a FuncImp class.
315      */
316     template <class ThisImp, class ParentImp>
317     inline bool getStaticValueSlot(ExecState* exec, const HashTable* table, ThisImp* thisObj, PropertyName propertyName, PropertySlot& slot)
318     {
319         const HashEntry* entry = table->entry(exec, propertyName);
320
321         if (!entry) // not found, forward to parent
322             return ParentImp::getOwnPropertySlot(thisObj, exec, propertyName, slot);
323
324         ASSERT(!(entry->attributes() & Function));
325
326         slot.setCacheableCustom(thisObj, entry->propertyGetter());
327         return true;
328     }
329
330     /**
331      * Simplified version of getStaticPropertyDescriptor in case there are no functions, only "values".
332      * Using this instead of getStaticPropertyDescriptor removes the need for a FuncImp class.
333      */
334     template <class ThisImp, class ParentImp>
335     inline bool getStaticValueDescriptor(ExecState* exec, const HashTable* table, ThisImp* thisObj, PropertyName propertyName, PropertyDescriptor& descriptor)
336     {
337         const HashEntry* entry = table->entry(exec, propertyName);
338         
339         if (!entry) // not found, forward to parent
340             return ParentImp::getOwnPropertyDescriptor(thisObj, exec, propertyName, descriptor);
341         
342         ASSERT(!(entry->attributes() & Function));
343         PropertySlot slot;
344         slot.setCustom(thisObj, entry->propertyGetter());
345         descriptor.setDescriptor(slot.getValue(exec, propertyName), entry->attributes());
346         return true;
347     }
348
349     /**
350      * This one is for "put".
351      * It looks up a hash entry for the property to be set.  If an entry
352      * is found it sets the value and returns true, else it returns false.
353      */
354     template <class ThisImp>
355     inline bool lookupPut(ExecState* exec, PropertyName propertyName, JSValue value, const HashTable* table, ThisImp* thisObj, bool shouldThrow = false)
356     {
357         const HashEntry* entry = table->entry(exec, propertyName);
358         
359         if (!entry)
360             return false;
361
362         // If this is a function put it as an override property.
363         if (entry->attributes() & Function)
364             thisObj->putDirect(exec->globalData(), propertyName, value);
365         else if (!(entry->attributes() & ReadOnly))
366             entry->propertyPutter()(exec, thisObj, value);
367         else if (shouldThrow)
368             throwTypeError(exec, StrictModeReadonlyPropertyWriteError);
369
370         return true;
371     }
372
373     /**
374      * This one is for "put".
375      * It calls lookupPut<ThisImp>() to set the value.  If that call
376      * returns false (meaning no entry in the hash table was found),
377      * then it calls put() on the ParentImp class.
378      */
379     template <class ThisImp, class ParentImp>
380     inline void lookupPut(ExecState* exec, PropertyName propertyName, JSValue value, const HashTable* table, ThisImp* thisObj, PutPropertySlot& slot)
381     {
382         if (!lookupPut<ThisImp>(exec, propertyName, value, table, thisObj, slot.isStrictMode()))
383             ParentImp::put(thisObj, exec, propertyName, value, slot); // not found: forward to parent
384     }
385
386 } // namespace JSC
387
388 #endif // Lookup_h