Move JavaScriptCore to Source
[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 "Identifier.h"
26 #include "JSGlobalObject.h"
27 #include "JSObject.h"
28 #include "PropertySlot.h"
29 #include <stdio.h>
30 #include <wtf/Assertions.h>
31
32 // Bug #26843: Work around Metrowerks compiler bug
33 #if COMPILER(WINSCW)
34 #define JSC_CONST_HASHTABLE
35 #else
36 #define JSC_CONST_HASHTABLE const
37 #endif
38
39 namespace JSC {
40     // Hash table generated by the create_hash_table script.
41     struct HashTableValue {
42         const char* key; // property name
43         unsigned char attributes; // JSObject attributes
44         intptr_t value1;
45         intptr_t value2;
46 #if ENABLE(JIT)
47         ThunkGenerator generator;
48 #endif
49     };
50
51     // FIXME: There is no reason this get function can't be simpler.
52     // ie. typedef JSValue (*GetFunction)(ExecState*, JSObject* baseObject)
53     typedef PropertySlot::GetValueFunc GetFunction;
54     typedef void (*PutFunction)(ExecState*, JSObject* baseObject, JSValue value);
55
56     class HashEntry : public FastAllocBase {
57     public:
58         void initialize(StringImpl* key, unsigned char attributes, intptr_t v1, intptr_t v2
59 #if ENABLE(JIT)
60                         , ThunkGenerator generator = 0
61 #endif
62                         )
63         {
64             m_key = key;
65             m_attributes = attributes;
66             m_u.store.value1 = v1;
67             m_u.store.value2 = v2;
68 #if ENABLE(JIT)
69             m_u.function.generator = generator;
70 #endif
71             m_next = 0;
72         }
73
74         void setKey(StringImpl* key) { m_key = key; }
75         StringImpl* key() const { return m_key; }
76
77         unsigned char attributes() const { return m_attributes; }
78
79 #if ENABLE(JIT) && ENABLE(JIT_OPTIMIZE_NATIVE_CALL)
80         ThunkGenerator generator() const { ASSERT(m_attributes & Function); return m_u.function.generator; }
81 #endif
82         NativeFunction function() const { ASSERT(m_attributes & Function); return m_u.function.functionValue; }
83         unsigned char functionLength() const { ASSERT(m_attributes & Function); return static_cast<unsigned char>(m_u.function.length); }
84
85         GetFunction propertyGetter() const { ASSERT(!(m_attributes & Function)); return m_u.property.get; }
86         PutFunction propertyPutter() const { ASSERT(!(m_attributes & Function)); return m_u.property.put; }
87
88         intptr_t lexerValue() const { ASSERT(!m_attributes); return m_u.lexer.value; }
89
90         void setNext(HashEntry *next) { m_next = next; }
91         HashEntry* next() const { return m_next; }
92
93     private:
94         StringImpl* m_key;
95         unsigned char m_attributes; // JSObject attributes
96
97         union {
98             struct {
99                 intptr_t value1;
100                 intptr_t value2;
101             } store;
102             struct {
103                 NativeFunction functionValue;
104                 intptr_t length; // number of arguments for function
105 #if ENABLE(JIT)
106                 ThunkGenerator generator;
107 #endif
108             } function;
109             struct {
110                 GetFunction get;
111                 PutFunction put;
112             } property;
113             struct {
114                 intptr_t value;
115                 intptr_t unused;
116             } lexer;
117         } m_u;
118
119         HashEntry* m_next;
120     };
121
122     struct HashTable {
123
124         int compactSize;
125         int compactHashSizeMask;
126
127         const HashTableValue* values; // Fixed values generated by script.
128         mutable const HashEntry* table; // Table allocated at runtime.
129
130         ALWAYS_INLINE void initializeIfNeeded(JSGlobalData* globalData) const
131         {
132             if (!table)
133                 createTable(globalData);
134         }
135
136         ALWAYS_INLINE void initializeIfNeeded(ExecState* exec) const
137         {
138             if (!table)
139                 createTable(&exec->globalData());
140         }
141
142         void deleteTable() const;
143
144         // Find an entry in the table, and return the entry.
145         ALWAYS_INLINE const HashEntry* entry(JSGlobalData* globalData, const Identifier& identifier) const
146         {
147             initializeIfNeeded(globalData);
148             return entry(identifier);
149         }
150
151         ALWAYS_INLINE const HashEntry* entry(ExecState* exec, const Identifier& identifier) const
152         {
153             initializeIfNeeded(exec);
154             return entry(identifier);
155         }
156
157     private:
158         ALWAYS_INLINE const HashEntry* entry(const Identifier& identifier) const
159         {
160             ASSERT(table);
161
162             const HashEntry* entry = &table[identifier.impl()->existingHash() & compactHashSizeMask];
163
164             if (!entry->key())
165                 return 0;
166
167             do {
168                 if (entry->key() == identifier.impl())
169                     return entry;
170                 entry = entry->next();
171             } while (entry);
172
173             return 0;
174         }
175
176         // Convert the hash table keys to identifiers.
177         void createTable(JSGlobalData*) const;
178     };
179
180     void setUpStaticFunctionSlot(ExecState*, const HashEntry*, JSObject* thisObject, const Identifier& propertyName, PropertySlot&);
181
182     /**
183      * This method does it all (looking in the hashtable, checking for function
184      * overrides, creating the function or retrieving from cache, calling
185      * getValueProperty in case of a non-function property, forwarding to parent if
186      * unknown property).
187      */
188     template <class ThisImp, class ParentImp>
189     inline bool getStaticPropertySlot(ExecState* exec, const HashTable* table, ThisImp* thisObj, const Identifier& propertyName, PropertySlot& slot)
190     {
191         const HashEntry* entry = table->entry(exec, propertyName);
192
193         if (!entry) // not found, forward to parent
194             return thisObj->ParentImp::getOwnPropertySlot(exec, propertyName, slot);
195
196         if (entry->attributes() & Function)
197             setUpStaticFunctionSlot(exec, entry, thisObj, propertyName, slot);
198         else
199             slot.setCacheableCustom(thisObj, entry->propertyGetter());
200
201         return true;
202     }
203
204     template <class ThisImp, class ParentImp>
205     inline bool getStaticPropertyDescriptor(ExecState* exec, const HashTable* table, ThisImp* thisObj, const Identifier& propertyName, PropertyDescriptor& descriptor)
206     {
207         const HashEntry* entry = table->entry(exec, propertyName);
208         
209         if (!entry) // not found, forward to parent
210             return thisObj->ParentImp::getOwnPropertyDescriptor(exec, propertyName, descriptor);
211  
212         PropertySlot slot;
213         if (entry->attributes() & Function)
214             setUpStaticFunctionSlot(exec, entry, thisObj, propertyName, slot);
215         else
216             slot.setCustom(thisObj, entry->propertyGetter());
217
218         descriptor.setDescriptor(slot.getValue(exec, propertyName), entry->attributes());
219         return true;
220     }
221
222     /**
223      * Simplified version of getStaticPropertySlot in case there are only functions.
224      * Using this instead of getStaticPropertySlot allows 'this' to avoid implementing
225      * a dummy getValueProperty.
226      */
227     template <class ParentImp>
228     inline bool getStaticFunctionSlot(ExecState* exec, const HashTable* table, JSObject* thisObj, const Identifier& propertyName, PropertySlot& slot)
229     {
230         if (static_cast<ParentImp*>(thisObj)->ParentImp::getOwnPropertySlot(exec, propertyName, slot))
231             return true;
232
233         const HashEntry* entry = table->entry(exec, propertyName);
234         if (!entry)
235             return false;
236
237         setUpStaticFunctionSlot(exec, entry, thisObj, propertyName, slot);
238         return true;
239     }
240     
241     /**
242      * Simplified version of getStaticPropertyDescriptor in case there are only functions.
243      * Using this instead of getStaticPropertyDescriptor allows 'this' to avoid implementing
244      * a dummy getValueProperty.
245      */
246     template <class ParentImp>
247     inline bool getStaticFunctionDescriptor(ExecState* exec, const HashTable* table, JSObject* thisObj, const Identifier& propertyName, PropertyDescriptor& descriptor)
248     {
249         if (static_cast<ParentImp*>(thisObj)->ParentImp::getOwnPropertyDescriptor(exec, propertyName, descriptor))
250             return true;
251         
252         const HashEntry* entry = table->entry(exec, propertyName);
253         if (!entry)
254             return false;
255         
256         PropertySlot slot;
257         setUpStaticFunctionSlot(exec, entry, thisObj, propertyName, slot);
258         descriptor.setDescriptor(slot.getValue(exec, propertyName), entry->attributes());
259         return true;
260     }
261
262     /**
263      * Simplified version of getStaticPropertySlot in case there are no functions, only "values".
264      * Using this instead of getStaticPropertySlot removes the need for a FuncImp class.
265      */
266     template <class ThisImp, class ParentImp>
267     inline bool getStaticValueSlot(ExecState* exec, const HashTable* table, ThisImp* thisObj, const Identifier& propertyName, PropertySlot& slot)
268     {
269         const HashEntry* entry = table->entry(exec, propertyName);
270
271         if (!entry) // not found, forward to parent
272             return thisObj->ParentImp::getOwnPropertySlot(exec, propertyName, slot);
273
274         ASSERT(!(entry->attributes() & Function));
275
276         slot.setCacheableCustom(thisObj, entry->propertyGetter());
277         return true;
278     }
279
280     /**
281      * Simplified version of getStaticPropertyDescriptor in case there are no functions, only "values".
282      * Using this instead of getStaticPropertyDescriptor removes the need for a FuncImp class.
283      */
284     template <class ThisImp, class ParentImp>
285     inline bool getStaticValueDescriptor(ExecState* exec, const HashTable* table, ThisImp* thisObj, const Identifier& propertyName, PropertyDescriptor& descriptor)
286     {
287         const HashEntry* entry = table->entry(exec, propertyName);
288         
289         if (!entry) // not found, forward to parent
290             return thisObj->ParentImp::getOwnPropertyDescriptor(exec, propertyName, descriptor);
291         
292         ASSERT(!(entry->attributes() & Function));
293         PropertySlot slot;
294         slot.setCustom(thisObj, entry->propertyGetter());
295         descriptor.setDescriptor(slot.getValue(exec, propertyName), entry->attributes());
296         return true;
297     }
298
299     /**
300      * This one is for "put".
301      * It looks up a hash entry for the property to be set.  If an entry
302      * is found it sets the value and returns true, else it returns false.
303      */
304     template <class ThisImp>
305     inline bool lookupPut(ExecState* exec, const Identifier& propertyName, JSValue value, const HashTable* table, ThisImp* thisObj)
306     {
307         const HashEntry* entry = table->entry(exec, propertyName);
308
309         if (!entry)
310             return false;
311
312         if (entry->attributes() & Function) { // function: put as override property
313             if (LIKELY(value.isCell()))
314                 thisObj->putDirectFunction(propertyName, value.asCell());
315             else
316                 thisObj->putDirect(propertyName, value);
317         } else if (!(entry->attributes() & ReadOnly))
318             entry->propertyPutter()(exec, thisObj, value);
319
320         return true;
321     }
322
323     /**
324      * This one is for "put".
325      * It calls lookupPut<ThisImp>() to set the value.  If that call
326      * returns false (meaning no entry in the hash table was found),
327      * then it calls put() on the ParentImp class.
328      */
329     template <class ThisImp, class ParentImp>
330     inline void lookupPut(ExecState* exec, const Identifier& propertyName, JSValue value, const HashTable* table, ThisImp* thisObj, PutPropertySlot& slot)
331     {
332         if (!lookupPut<ThisImp>(exec, propertyName, value, table, thisObj))
333             thisObj->ParentImp::put(exec, propertyName, value, slot); // not found: forward to parent
334     }
335
336 } // namespace JSC
337
338 #endif // Lookup_h