JavaScriptCore: Mark all exported symbols in the header file automatically.
[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, const Identifier& identifier) const
133         {
134             initializeIfNeeded(globalData);
135             return entry(identifier);
136         }
137
138         ALWAYS_INLINE const HashEntry* entry(ExecState* exec, const Identifier& 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(const Identifier& identifier) const
203         {
204             ASSERT(table);
205
206             const HashEntry* entry = &table[identifier.impl()->existingHash() & compactHashSizeMask];
207
208             if (!entry->key())
209                 return 0;
210
211             do {
212                 if (entry->key() == identifier.impl())
213                     return entry;
214                 entry = entry->next();
215             } while (entry);
216
217             return 0;
218         }
219
220         // Convert the hash table keys to identifiers.
221         JS_EXPORT_PRIVATE void createTable(JSGlobalData*) const;
222     };
223
224     JS_EXPORT_PRIVATE bool setUpStaticFunctionSlot(ExecState*, const HashEntry*, JSObject* thisObject, const Identifier& propertyName, PropertySlot&);
225
226     /**
227      * This method does it all (looking in the hashtable, checking for function
228      * overrides, creating the function or retrieving from cache, calling
229      * getValueProperty in case of a non-function property, forwarding to parent if
230      * unknown property).
231      */
232     template <class ThisImp, class ParentImp>
233     inline bool getStaticPropertySlot(ExecState* exec, const HashTable* table, ThisImp* thisObj, const Identifier& propertyName, PropertySlot& slot)
234     {
235         const HashEntry* entry = table->entry(exec, propertyName);
236
237         if (!entry) // not found, forward to parent
238             return ParentImp::getOwnPropertySlot(thisObj, exec, propertyName, slot);
239
240         if (entry->attributes() & Function)
241             return setUpStaticFunctionSlot(exec, entry, thisObj, propertyName, slot);
242
243         slot.setCacheableCustom(thisObj, entry->propertyGetter());
244         return true;
245     }
246
247     template <class ThisImp, class ParentImp>
248     inline bool getStaticPropertyDescriptor(ExecState* exec, const HashTable* table, ThisImp* thisObj, const Identifier& propertyName, PropertyDescriptor& descriptor)
249     {
250         const HashEntry* entry = table->entry(exec, propertyName);
251         
252         if (!entry) // not found, forward to parent
253             return ParentImp::getOwnPropertyDescriptor(thisObj, exec, propertyName, descriptor);
254  
255         PropertySlot slot;
256         if (entry->attributes() & Function) {
257             bool present = setUpStaticFunctionSlot(exec, entry, thisObj, propertyName, slot);
258             if (present)
259                 descriptor.setDescriptor(slot.getValue(exec, propertyName), entry->attributes());
260             return present;
261         }
262
263         slot.setCustom(thisObj, entry->propertyGetter());
264         descriptor.setDescriptor(slot.getValue(exec, propertyName), entry->attributes());
265         return true;
266     }
267
268     /**
269      * Simplified version of getStaticPropertySlot in case there are only functions.
270      * Using this instead of getStaticPropertySlot allows 'this' to avoid implementing
271      * a dummy getValueProperty.
272      */
273     template <class ParentImp>
274     inline bool getStaticFunctionSlot(ExecState* exec, const HashTable* table, JSObject* thisObj, const Identifier& propertyName, PropertySlot& slot)
275     {
276         if (ParentImp::getOwnPropertySlot(thisObj, exec, propertyName, slot))
277             return true;
278
279         const HashEntry* entry = table->entry(exec, propertyName);
280         if (!entry)
281             return false;
282
283         return setUpStaticFunctionSlot(exec, entry, thisObj, propertyName, slot);
284     }
285     
286     /**
287      * Simplified version of getStaticPropertyDescriptor in case there are only functions.
288      * Using this instead of getStaticPropertyDescriptor allows 'this' to avoid implementing
289      * a dummy getValueProperty.
290      */
291     template <class ParentImp>
292     inline bool getStaticFunctionDescriptor(ExecState* exec, const HashTable* table, JSObject* thisObj, const Identifier& propertyName, PropertyDescriptor& descriptor)
293     {
294         if (ParentImp::getOwnPropertyDescriptor(static_cast<ParentImp*>(thisObj), exec, propertyName, descriptor))
295             return true;
296         
297         const HashEntry* entry = table->entry(exec, propertyName);
298         if (!entry)
299             return false;
300         
301         PropertySlot slot;
302         bool present = setUpStaticFunctionSlot(exec, entry, thisObj, propertyName, slot);
303         if (present)
304             descriptor.setDescriptor(slot.getValue(exec, propertyName), entry->attributes());
305         return present;
306     }
307
308     /**
309      * Simplified version of getStaticPropertySlot in case there are no functions, only "values".
310      * Using this instead of getStaticPropertySlot removes the need for a FuncImp class.
311      */
312     template <class ThisImp, class ParentImp>
313     inline bool getStaticValueSlot(ExecState* exec, const HashTable* table, ThisImp* thisObj, const Identifier& propertyName, PropertySlot& slot)
314     {
315         const HashEntry* entry = table->entry(exec, propertyName);
316
317         if (!entry) // not found, forward to parent
318             return ParentImp::getOwnPropertySlot(thisObj, exec, propertyName, slot);
319
320         ASSERT(!(entry->attributes() & Function));
321
322         slot.setCacheableCustom(thisObj, entry->propertyGetter());
323         return true;
324     }
325
326     /**
327      * Simplified version of getStaticPropertyDescriptor in case there are no functions, only "values".
328      * Using this instead of getStaticPropertyDescriptor removes the need for a FuncImp class.
329      */
330     template <class ThisImp, class ParentImp>
331     inline bool getStaticValueDescriptor(ExecState* exec, const HashTable* table, ThisImp* thisObj, const Identifier& propertyName, PropertyDescriptor& descriptor)
332     {
333         const HashEntry* entry = table->entry(exec, propertyName);
334         
335         if (!entry) // not found, forward to parent
336             return ParentImp::getOwnPropertyDescriptor(thisObj, exec, propertyName, descriptor);
337         
338         ASSERT(!(entry->attributes() & Function));
339         PropertySlot slot;
340         slot.setCustom(thisObj, entry->propertyGetter());
341         descriptor.setDescriptor(slot.getValue(exec, propertyName), entry->attributes());
342         return true;
343     }
344
345     /**
346      * This one is for "put".
347      * It looks up a hash entry for the property to be set.  If an entry
348      * is found it sets the value and returns true, else it returns false.
349      */
350     template <class ThisImp>
351     inline bool lookupPut(ExecState* exec, const Identifier& propertyName, JSValue value, const HashTable* table, ThisImp* thisObj, bool shouldThrow = false)
352     {
353         const HashEntry* entry = table->entry(exec, propertyName);
354         
355         if (!entry)
356             return false;
357
358         // If this is a function put it as an override property.
359         if (entry->attributes() & Function)
360             thisObj->putDirect(exec->globalData(), propertyName, value);
361         else if (!(entry->attributes() & ReadOnly))
362             entry->propertyPutter()(exec, thisObj, value);
363         else if (shouldThrow)
364             throwTypeError(exec, StrictModeReadonlyPropertyWriteError);
365
366         return true;
367     }
368
369     /**
370      * This one is for "put".
371      * It calls lookupPut<ThisImp>() to set the value.  If that call
372      * returns false (meaning no entry in the hash table was found),
373      * then it calls put() on the ParentImp class.
374      */
375     template <class ThisImp, class ParentImp>
376     inline void lookupPut(ExecState* exec, const Identifier& propertyName, JSValue value, const HashTable* table, ThisImp* thisObj, PutPropertySlot& slot)
377     {
378         if (!lookupPut<ThisImp>(exec, propertyName, value, table, thisObj, slot.isStrictMode()))
379             ParentImp::put(thisObj, exec, propertyName, value, slot); // not found: forward to parent
380     }
381
382 } // namespace JSC
383
384 #endif // Lookup_h