~ubuntu-branches/ubuntu/maverick/webkit/maverick

« back to all changes in this revision

Viewing changes to JavaScriptCore/kjs/lookup.h

  • Committer: Bazaar Package Importer
  • Author(s): Mike Hommey
  • Date: 2007-08-19 15:54:12 UTC
  • Revision ID: james.westby@ubuntu.com-20070819155412-uxxg1h9plpghmtbi
Tags: upstream-0~svn25144
ImportĀ upstreamĀ versionĀ 0~svn25144

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
// -*- c-basic-offset: 2 -*-
 
2
/*
 
3
 *  This file is part of the KDE libraries
 
4
 *  Copyright (C) 1999-2000 Harri Porten (porten@kde.org)
 
5
 *  Copyright (C) 2003 Apple Computer, Inc.
 
6
 *
 
7
 *  This library is free software; you can redistribute it and/or
 
8
 *  modify it under the terms of the GNU Lesser General Public
 
9
 *  License as published by the Free Software Foundation; either
 
10
 *  version 2 of the License, or (at your option) any later version.
 
11
 *
 
12
 *  This library is distributed in the hope that it will be useful,
 
13
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 
14
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 
15
 *  Lesser General Public License for more details.
 
16
 *
 
17
 *  You should have received a copy of the GNU Lesser General Public
 
18
 *  License along with this library; if not, write to the Free Software
 
19
 *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 
20
 *
 
21
 */
 
22
 
 
23
#ifndef _KJSLOOKUP_H_
 
24
#define _KJSLOOKUP_H_
 
25
 
 
26
#include "interpreter.h"
 
27
#include "identifier.h"
 
28
#include "object.h"
 
29
#include <stdio.h>
 
30
 
 
31
namespace KJS {
 
32
 
 
33
  class FunctionPrototype;
 
34
 
 
35
  /**
 
36
   * An entry in a hash table.
 
37
   */
 
38
  struct HashEntry {
 
39
    /**
 
40
     * s is the key (e.g. a property name)
 
41
     */
 
42
    const char* s;
 
43
 
 
44
    /**
 
45
     * value is the result value (usually an enum value)
 
46
     */
 
47
    int value;
 
48
    /**
 
49
     * attr is a set for flags (e.g. the property flags, see object.h)
 
50
     */
 
51
    short int attr;
 
52
    /**
 
53
     * params is another number. For property hashtables, it is used to
 
54
     * denote the number of argument of the function
 
55
     */
 
56
    short int params;
 
57
    /**
 
58
     * next is the pointer to the next entry for the same hash value
 
59
     */
 
60
    const HashEntry* next;
 
61
  };
 
62
 
 
63
  /**
 
64
   * A hash table
 
65
   * Usually the hashtable is generated by the create_hash_table script, from a .table file.
 
66
   *
 
67
   * The implementation uses an array of entries, "size" is the total size of that array.
 
68
   * The entries between 0 and hashSize-1 are the entry points
 
69
   * for each hash value, and the entries between hashSize and size-1
 
70
   * are the overflow entries for the hash values that need one.
 
71
   * The "next" pointer of the entry links entry points to overflow entries,
 
72
   * and links overflow entries between them.
 
73
   */
 
74
  struct HashTable {
 
75
    /**
 
76
     * type is a version number. Currently always 2
 
77
     */
 
78
    int type;
 
79
    /**
 
80
     * size is the total number of entries in the hashtable, including the null entries,
 
81
     * i.e. the size of the "entries" array.
 
82
     * Used to iterate over all entries in the table
 
83
     */
 
84
    int size;
 
85
    /**
 
86
     * pointer to the array of entries
 
87
     * Mind that some entries in the array are null (0,0,0,0).
 
88
     */
 
89
    const HashEntry* entries;
 
90
    /**
 
91
     * the maximum value for the hash. Always smaller than size.
 
92
     */
 
93
    int hashSize;
 
94
  };
 
95
 
 
96
  /**
 
97
   * @short Fast keyword lookup.
 
98
   */
 
99
  class Lookup {
 
100
  public:
 
101
    /**
 
102
     * Find an entry in the table, and return its value (i.e. the value field of HashEntry)
 
103
     */
 
104
    static int find(const struct HashTable*, const Identifier&);
 
105
    static int find(const struct HashTable*, const UChar*, unsigned int len);
 
106
 
 
107
 
 
108
    /**
 
109
     * Find an entry in the table, and return the entry
 
110
     * This variant gives access to the other attributes of the entry,
 
111
     * especially the attr field.
 
112
     */
 
113
    static const HashEntry* findEntry(const struct HashTable*, const Identifier&);
 
114
 
 
115
  };
 
116
 
 
117
  class ExecState;
 
118
  class UString;
 
119
  /**
 
120
   * @internal
 
121
   * Helper for getStaticFunctionSlot and getStaticPropertySlot
 
122
   */
 
123
  template <class FuncImp>
 
124
  inline JSValue* staticFunctionGetter(ExecState* exec, JSObject*, const Identifier& propertyName, const PropertySlot& slot)
 
125
  {
 
126
      // Look for cached value in dynamic map of properties (in JSObject)
 
127
      JSObject* thisObj = slot.slotBase();
 
128
      JSValue* cachedVal = thisObj->getDirect(propertyName);
 
129
      if (cachedVal)
 
130
        return cachedVal;
 
131
 
 
132
      const HashEntry* entry = slot.staticEntry();
 
133
      JSValue* val = new FuncImp(exec, entry->value, entry->params, propertyName);
 
134
      thisObj->putDirect(propertyName, val, entry->attr);
 
135
      return val;
 
136
  }
 
137
 
 
138
  /**
 
139
   * @internal
 
140
   * Helper for getStaticValueSlot and getStaticPropertySlot
 
141
   */
 
142
  template <class ThisImp>
 
143
  inline JSValue* staticValueGetter(ExecState* exec, JSObject*, const Identifier&, const PropertySlot& slot)
 
144
  {
 
145
      ThisImp* thisObj = static_cast<ThisImp*>(slot.slotBase());
 
146
      const HashEntry* entry = slot.staticEntry();
 
147
      return thisObj->getValueProperty(exec, entry->value);
 
148
  }
 
149
 
 
150
  /**
 
151
   * Helper method for property lookups
 
152
   *
 
153
   * This method does it all (looking in the hashtable, checking for function
 
154
   * overrides, creating the function or retrieving from cache, calling
 
155
   * getValueProperty in case of a non-function property, forwarding to parent if
 
156
   * unknown property).
 
157
   *
 
158
   * Template arguments:
 
159
   * @param FuncImp the class which implements this object's functions
 
160
   * @param ThisImp the class of "this". It must implement the getValueProperty(exec,token) method,
 
161
   * for non-function properties.
 
162
   * @param ParentImp the class of the parent, to propagate the lookup.
 
163
   *
 
164
   * Method arguments:
 
165
   * @param exec execution state, as usual
 
166
   * @param propertyName the property we're looking for
 
167
   * @param table the static hashtable for this class
 
168
   * @param thisObj "this"
 
169
   */
 
170
  template <class FuncImp, class ThisImp, class ParentImp>
 
171
  inline bool getStaticPropertySlot(ExecState* exec, const HashTable* table, 
 
172
                                    ThisImp* thisObj, const Identifier& propertyName, PropertySlot& slot)
 
173
  {
 
174
    const HashEntry* entry = Lookup::findEntry(table, propertyName);
 
175
 
 
176
    if (!entry) // not found, forward to parent
 
177
      return thisObj->ParentImp::getOwnPropertySlot(exec, propertyName, slot);
 
178
 
 
179
    if (entry->attr & Function)
 
180
      slot.setStaticEntry(thisObj, entry, staticFunctionGetter<FuncImp>);
 
181
    else
 
182
      slot.setStaticEntry(thisObj, entry, staticValueGetter<ThisImp>);
 
183
 
 
184
    return true;
 
185
  }
 
186
 
 
187
  /**
 
188
   * Simplified version of getStaticPropertySlot in case there are only functions.
 
189
   * Using this instead of getStaticPropertySlot allows 'this' to avoid implementing
 
190
   * a dummy getValueProperty.
 
191
   */
 
192
  template <class FuncImp, class ParentImp>
 
193
  inline bool getStaticFunctionSlot(ExecState* exec, const HashTable* table,
 
194
                                    JSObject* thisObj, const Identifier& propertyName, PropertySlot& slot)
 
195
  {
 
196
    const HashEntry* entry = Lookup::findEntry(table, propertyName);
 
197
 
 
198
    if (!entry) // not found, forward to parent
 
199
      return static_cast<ParentImp*>(thisObj)->ParentImp::getOwnPropertySlot(exec, propertyName, slot);
 
200
 
 
201
    assert(entry->attr & Function);
 
202
 
 
203
    slot.setStaticEntry(thisObj, entry, staticFunctionGetter<FuncImp>);
 
204
    return true;
 
205
  }
 
206
 
 
207
  /**
 
208
   * Simplified version of getStaticPropertySlot in case there are no functions, only "values".
 
209
   * Using this instead of getStaticPropertySlot removes the need for a FuncImp class.
 
210
   */
 
211
  template <class ThisImp, class ParentImp>
 
212
  inline bool getStaticValueSlot(ExecState* exec, const HashTable* table,
 
213
                                 ThisImp* thisObj, const Identifier& propertyName, PropertySlot& slot)
 
214
  {
 
215
    const HashEntry* entry = Lookup::findEntry(table, propertyName);
 
216
 
 
217
    if (!entry) // not found, forward to parent
 
218
      return thisObj->ParentImp::getOwnPropertySlot(exec, propertyName, slot);
 
219
 
 
220
    assert(!(entry->attr & Function));
 
221
 
 
222
    slot.setStaticEntry(thisObj, entry, staticValueGetter<ThisImp>);
 
223
    return true;
 
224
  }
 
225
 
 
226
  /**
 
227
   * This one is for "put".
 
228
   * It looks up a hash entry for the property to be set.  If an entry
 
229
   * is found it sets the value and returns true, else it returns false.
 
230
   */
 
231
  template <class ThisImp>
 
232
  inline bool lookupPut(ExecState* exec, const Identifier& propertyName,
 
233
                        JSValue* value, int attr,
 
234
                        const HashTable* table, ThisImp* thisObj)
 
235
  {
 
236
    const HashEntry* entry = Lookup::findEntry(table, propertyName);
 
237
 
 
238
    if (!entry)
 
239
      return false;
 
240
 
 
241
    if (entry->attr & Function) // function: put as override property
 
242
      thisObj->JSObject::put(exec, propertyName, value, attr);
 
243
    else if (entry->attr & ReadOnly) // readonly! Can't put!
 
244
#ifdef KJS_VERBOSE
 
245
      fprintf(stderr,"WARNING: Attempt to change value of readonly property '%s'\n",propertyName.ascii());
 
246
#else
 
247
      ; // do nothing
 
248
#endif
 
249
    else
 
250
      thisObj->putValueProperty(exec, entry->value, value, attr);
 
251
 
 
252
    return true;
 
253
  }
 
254
 
 
255
  /**
 
256
   * This one is for "put".
 
257
   * It calls lookupPut<ThisImp>() to set the value.  If that call
 
258
   * returns false (meaning no entry in the hash table was found),
 
259
   * then it calls put() on the ParentImp class.
 
260
   */
 
261
  template <class ThisImp, class ParentImp>
 
262
  inline void lookupPut(ExecState* exec, const Identifier& propertyName,
 
263
                        JSValue* value, int attr,
 
264
                        const HashTable* table, ThisImp* thisObj)
 
265
  {
 
266
    if (!lookupPut<ThisImp>(exec, propertyName, value, attr, table, thisObj))
 
267
      thisObj->ParentImp::put(exec, propertyName, value, attr); // not found: forward to parent
 
268
  }
 
269
 
 
270
  /**
 
271
   * This template method retrieves or create an object that is unique
 
272
   * (for a given interpreter) The first time this is called (for a given
 
273
   * property name), the Object will be constructed, and set as a property
 
274
   * of the interpreter's global object. Later calls will simply retrieve
 
275
   * that cached object. Note that the object constructor must take 1 argument, exec.
 
276
   */
 
277
  template <class ClassCtor>
 
278
  inline JSObject* cacheGlobalObject(ExecState* exec, const Identifier& propertyName)
 
279
  {
 
280
    JSObject* globalObject = static_cast<JSObject*>(exec->lexicalInterpreter()->globalObject());
 
281
    JSValue* obj = globalObject->getDirect(propertyName);
 
282
    if (obj) {
 
283
      assert(obj->isObject());
 
284
      return static_cast<JSObject* >(obj);
 
285
    }
 
286
    JSObject* newObject = new ClassCtor(exec);
 
287
    globalObject->put(exec, propertyName, newObject, Internal | DontEnum);
 
288
    return newObject;
 
289
  }
 
290
 
 
291
} // namespace
 
292
 
 
293
/**
 
294
 * Helpers to define prototype objects (each of which simply implements
 
295
 * the functions for a type of objects).
 
296
 * Sorry for this not being very readable, but it actually saves much copy-n-paste.
 
297
 * ParentPrototype is not our base class, it's the object we use as fallback.
 
298
 * The reason for this is that there should only be ONE DOMNode.hasAttributes (e.g.),
 
299
 * not one in each derived class. So we link the (unique) prototypes between them.
 
300
 *
 
301
 * Using those macros is very simple: define the hashtable (e.g. "DOMNodePrototypeTable"), then
 
302
 * KJS_DEFINE_PROTOTYPE(DOMNodePrototype)
 
303
 * KJS_IMPLEMENT_PROTOFUNC(DOMNodePrototypeFunction)
 
304
 * KJS_IMPLEMENT_PROTOTYPE("DOMNode", DOMNodePrototype, DOMNodePrototypeFunction)
 
305
 * and use DOMNodePrototype::self(exec) as prototype in the DOMNode constructor.
 
306
 * If the prototype has a "parent prototype", e.g. DOMElementPrototype falls back on DOMNodePrototype,
 
307
 * then the first line will use KJS_DEFINE_PROTOTYPE_WITH_PROTOTYPE, with DOMNodePrototype as the second argument.
 
308
 */
 
309
 
 
310
// These macros assume that a prototype's only properties are functions
 
311
#define KJS_DEFINE_PROTOTYPE(ClassPrototype) \
 
312
  class ClassPrototype : public KJS::JSObject { \
 
313
  public: \
 
314
    static KJS::JSObject* self(KJS::ExecState* exec); \
 
315
    virtual const KJS::ClassInfo* classInfo() const { return &info; } \
 
316
    static const KJS::ClassInfo info; \
 
317
    bool getOwnPropertySlot(KJS::ExecState* , const KJS::Identifier&, KJS::PropertySlot&); \
 
318
    ClassPrototype(KJS::ExecState* exec) \
 
319
      : KJS::JSObject(exec->lexicalInterpreter()->builtinObjectPrototype()) { } \
 
320
    \
 
321
  };
 
322
 
 
323
#define KJS_DEFINE_PROTOTYPE_WITH_PROTOTYPE(ClassPrototype, ClassPrototypePrototype) \
 
324
    class ClassPrototype : public KJS::JSObject { \
 
325
    public: \
 
326
        static KJS::JSObject* self(KJS::ExecState* exec); \
 
327
        virtual const KJS::ClassInfo* classInfo() const { return &info; } \
 
328
        static const KJS::ClassInfo info; \
 
329
        bool getOwnPropertySlot(KJS::ExecState*, const KJS::Identifier&, KJS::PropertySlot&); \
 
330
        ClassPrototype(KJS::ExecState* exec) \
 
331
            : KJS::JSObject(ClassPrototypePrototype::self(exec)) { } \
 
332
    \
 
333
    };
 
334
 
 
335
#define KJS_IMPLEMENT_PROTOTYPE(ClassName, ClassPrototype, ClassFunction) \
 
336
    const ClassInfo ClassPrototype::info = { ClassName"Prototype", 0, &ClassPrototype##Table, 0 }; \
 
337
    JSObject* ClassPrototype::self(ExecState* exec) \
 
338
    { \
 
339
        return KJS::cacheGlobalObject<ClassPrototype>(exec, "[[" ClassName ".prototype]]"); \
 
340
    } \
 
341
    bool ClassPrototype::getOwnPropertySlot(ExecState* exec, const Identifier& propertyName, PropertySlot& slot) \
 
342
    { \
 
343
      return getStaticFunctionSlot<ClassFunction, JSObject>(exec, &ClassPrototype##Table, this, propertyName, slot); \
 
344
    }
 
345
 
 
346
#define KJS_IMPLEMENT_PROTOTYPE_FUNCTION(ClassFunction) \
 
347
  class ClassFunction : public InternalFunctionImp { \
 
348
  public: \
 
349
    ClassFunction(ExecState* exec, int i, int len, const Identifier& name) \
 
350
      : InternalFunctionImp(static_cast<FunctionPrototype*>(exec->lexicalInterpreter()->builtinFunctionPrototype()), name) \
 
351
      , id(i) \
 
352
    { \
 
353
       put(exec, exec->propertyNames().length, jsNumber(len), DontDelete|ReadOnly|DontEnum); \
 
354
    } \
 
355
    /* Macro user needs to implement the callAsFunction function. */ \
 
356
    virtual JSValue* callAsFunction(ExecState* exec, JSObject* thisObj, const List& args); \
 
357
  private: \
 
358
    int id; \
 
359
  };
 
360
 
 
361
#endif