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