2011-01-27 Oliver Hunt <oliver@apple.com>
[WebKit-https.git] / Source / JavaScriptCore / runtime / JSGlobalObject.h
1 /*
2  *  Copyright (C) 2007 Eric Seidel <eric@webkit.org>
3  *  Copyright (C) 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 Library 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  *  Library General Public License for more details.
14  *
15  *  You should have received a copy of the GNU Library General Public License
16  *  along with this library; see the file COPYING.LIB.  If not, write to
17  *  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18  *  Boston, MA 02110-1301, USA.
19  *
20  */
21
22 #ifndef JSGlobalObject_h
23 #define JSGlobalObject_h
24
25 #include "JSArray.h"
26 #include "JSGlobalData.h"
27 #include "JSVariableObject.h"
28 #include "JSWeakObjectMapRefInternal.h"
29 #include "NativeFunctionWrapper.h"
30 #include "NumberPrototype.h"
31 #include "StringPrototype.h"
32 #include <wtf/HashSet.h>
33 #include <wtf/OwnPtr.h>
34 #include <wtf/RandomNumber.h>
35
36 namespace JSC {
37
38     class ArrayPrototype;
39     class BooleanPrototype;
40     class DatePrototype;
41     class Debugger;
42     class ErrorConstructor;
43     class FunctionPrototype;
44     class GlobalCodeBlock;
45     class GlobalEvalFunction;
46     class NativeErrorConstructor;
47     class ProgramCodeBlock;
48     class PrototypeFunction;
49     class RegExpConstructor;
50     class RegExpPrototype;
51     class RegisterFile;
52
53     struct ActivationStackNode;
54     struct HashTable;
55
56     typedef Vector<ExecState*, 16> ExecStateStack;
57     
58     class JSGlobalObject : public JSVariableObject {
59     protected:
60         using JSVariableObject::JSVariableObjectData;
61         typedef HashSet<RefPtr<OpaqueJSWeakObjectMap> > WeakMapSet;
62
63         struct JSGlobalObjectData : public JSVariableObjectData {
64             // We use an explicit destructor function pointer instead of a
65             // virtual destructor because we want to avoid adding a vtable
66             // pointer to this struct. Adding a vtable pointer would force the
67             // compiler to emit costly pointer fixup code when casting from
68             // JSVariableObjectData* to JSGlobalObjectData*.
69             typedef void (*Destructor)(void*);
70
71             JSGlobalObjectData(Destructor destructor)
72                 : JSVariableObjectData(&symbolTable, 0)
73                 , destructor(destructor)
74                 , registerArraySize(0)
75                 , globalScopeChain(NoScopeChain())
76                 , weakRandom(static_cast<unsigned>(randomNumber() * (std::numeric_limits<unsigned>::max() + 1.0)))
77             {
78             }
79             
80             Destructor destructor;
81             
82             size_t registerArraySize;
83
84             JSGlobalObject* next;
85             JSGlobalObject* prev;
86
87             Debugger* debugger;
88             
89             ScopeChain globalScopeChain;
90             Register globalCallFrame[RegisterFile::CallFrameHeaderSize];
91
92             WriteBarrier<RegExpConstructor> regExpConstructor;
93             WriteBarrier<ErrorConstructor> errorConstructor;
94             WriteBarrier<NativeErrorConstructor> evalErrorConstructor;
95             WriteBarrier<NativeErrorConstructor> rangeErrorConstructor;
96             WriteBarrier<NativeErrorConstructor> referenceErrorConstructor;
97             WriteBarrier<NativeErrorConstructor> syntaxErrorConstructor;
98             WriteBarrier<NativeErrorConstructor> typeErrorConstructor;
99             WriteBarrier<NativeErrorConstructor> URIErrorConstructor;
100
101             WriteBarrier<GlobalEvalFunction> evalFunction;
102             WriteBarrier<NativeFunctionWrapper> callFunction;
103             WriteBarrier<NativeFunctionWrapper> applyFunction;
104
105             WriteBarrier<ObjectPrototype> objectPrototype;
106             WriteBarrier<FunctionPrototype> functionPrototype;
107             WriteBarrier<ArrayPrototype> arrayPrototype;
108             WriteBarrier<BooleanPrototype> booleanPrototype;
109             WriteBarrier<StringPrototype> stringPrototype;
110             WriteBarrier<NumberPrototype> numberPrototype;
111             WriteBarrier<DatePrototype> datePrototype;
112             WriteBarrier<RegExpPrototype> regExpPrototype;
113
114             WriteBarrier<JSObject> methodCallDummy;
115
116             RefPtr<Structure> argumentsStructure;
117             RefPtr<Structure> arrayStructure;
118             RefPtr<Structure> booleanObjectStructure;
119             RefPtr<Structure> callbackConstructorStructure;
120             RefPtr<Structure> callbackFunctionStructure;
121             RefPtr<Structure> callbackObjectStructure;
122             RefPtr<Structure> dateStructure;
123             RefPtr<Structure> emptyObjectStructure;
124             RefPtr<Structure> errorStructure;
125             RefPtr<Structure> functionStructure;
126             RefPtr<Structure> numberObjectStructure;
127             RefPtr<Structure> prototypeFunctionStructure;
128             RefPtr<Structure> regExpMatchesArrayStructure;
129             RefPtr<Structure> regExpStructure;
130             RefPtr<Structure> stringObjectStructure;
131             RefPtr<Structure> internalFunctionStructure;
132
133             SymbolTable symbolTable;
134             unsigned profileGroup;
135
136             RefPtr<JSGlobalData> globalData;
137
138             HashSet<GlobalCodeBlock*> codeBlocks;
139             WeakMapSet weakMaps;
140             WeakRandom weakRandom;
141         };
142
143     public:
144         void* operator new(size_t, JSGlobalData*);
145         
146         explicit JSGlobalObject()
147             : JSVariableObject(JSGlobalObject::createStructure(jsNull()), new JSGlobalObjectData(destroyJSGlobalObjectData))
148         {
149             COMPILE_ASSERT(JSGlobalObject::AnonymousSlotCount == 1, JSGlobalObject_has_only_a_single_slot);
150             putAnonymousValue(0, this);
151             init(this);
152         }
153         
154         explicit JSGlobalObject(NonNullPassRefPtr<Structure> structure)
155             : JSVariableObject(structure, new JSGlobalObjectData(destroyJSGlobalObjectData))
156         {
157             COMPILE_ASSERT(JSGlobalObject::AnonymousSlotCount == 1, JSGlobalObject_has_only_a_single_slot);
158             putAnonymousValue(0, this);
159             init(this);
160         }
161
162     protected:
163         JSGlobalObject(NonNullPassRefPtr<Structure> structure, JSGlobalObjectData* data, JSObject* thisValue)
164             : JSVariableObject(structure, data)
165         {
166             COMPILE_ASSERT(JSGlobalObject::AnonymousSlotCount == 1, JSGlobalObject_has_only_a_single_slot);
167             putAnonymousValue(0, this);
168             init(thisValue);
169         }
170
171     public:
172         virtual ~JSGlobalObject();
173
174         virtual void markChildren(MarkStack&);
175
176         virtual bool getOwnPropertySlot(ExecState*, const Identifier&, PropertySlot&);
177         virtual bool getOwnPropertyDescriptor(ExecState*, const Identifier&, PropertyDescriptor&);
178         virtual bool hasOwnPropertyForWrite(ExecState*, const Identifier&);
179         virtual void put(ExecState*, const Identifier&, JSValue, PutPropertySlot&);
180         virtual void putWithAttributes(ExecState*, const Identifier& propertyName, JSValue value, unsigned attributes);
181
182         virtual void defineGetter(ExecState*, const Identifier& propertyName, JSObject* getterFunc, unsigned attributes);
183         virtual void defineSetter(ExecState*, const Identifier& propertyName, JSObject* setterFunc, unsigned attributes);
184
185         // Linked list of all global objects that use the same JSGlobalData.
186         JSGlobalObject*& head() { return d()->globalData->head; }
187         JSGlobalObject* next() { return d()->next; }
188
189         // The following accessors return pristine values, even if a script 
190         // replaces the global object's associated property.
191
192         RegExpConstructor* regExpConstructor() const { return d()->regExpConstructor.get(); }
193
194         ErrorConstructor* errorConstructor() const { return d()->errorConstructor.get(); }
195         NativeErrorConstructor* evalErrorConstructor() const { return d()->evalErrorConstructor.get(); }
196         NativeErrorConstructor* rangeErrorConstructor() const { return d()->rangeErrorConstructor.get(); }
197         NativeErrorConstructor* referenceErrorConstructor() const { return d()->referenceErrorConstructor.get(); }
198         NativeErrorConstructor* syntaxErrorConstructor() const { return d()->syntaxErrorConstructor.get(); }
199         NativeErrorConstructor* typeErrorConstructor() const { return d()->typeErrorConstructor.get(); }
200         NativeErrorConstructor* URIErrorConstructor() const { return d()->URIErrorConstructor.get(); }
201
202         GlobalEvalFunction* evalFunction() const { return d()->evalFunction.get(); }
203
204         ObjectPrototype* objectPrototype() const { return d()->objectPrototype.get(); }
205         FunctionPrototype* functionPrototype() const { return d()->functionPrototype.get(); }
206         ArrayPrototype* arrayPrototype() const { return d()->arrayPrototype.get(); }
207         BooleanPrototype* booleanPrototype() const { return d()->booleanPrototype.get(); }
208         StringPrototype* stringPrototype() const { return d()->stringPrototype.get(); }
209         NumberPrototype* numberPrototype() const { return d()->numberPrototype.get(); }
210         DatePrototype* datePrototype() const { return d()->datePrototype.get(); }
211         RegExpPrototype* regExpPrototype() const { return d()->regExpPrototype.get(); }
212
213         JSObject* methodCallDummy() const { return d()->methodCallDummy.get(); }
214
215         Structure* argumentsStructure() const { return d()->argumentsStructure.get(); }
216         Structure* arrayStructure() const { return d()->arrayStructure.get(); }
217         Structure* booleanObjectStructure() const { return d()->booleanObjectStructure.get(); }
218         Structure* callbackConstructorStructure() const { return d()->callbackConstructorStructure.get(); }
219         Structure* callbackFunctionStructure() const { return d()->callbackFunctionStructure.get(); }
220         Structure* callbackObjectStructure() const { return d()->callbackObjectStructure.get(); }
221         Structure* dateStructure() const { return d()->dateStructure.get(); }
222         Structure* emptyObjectStructure() const { return d()->emptyObjectStructure.get(); }
223         Structure* errorStructure() const { return d()->errorStructure.get(); }
224         Structure* functionStructure() const { return d()->functionStructure.get(); }
225         Structure* numberObjectStructure() const { return d()->numberObjectStructure.get(); }
226         Structure* prototypeFunctionStructure() const { return d()->prototypeFunctionStructure.get(); }
227         Structure* internalFunctionStructure() const { return d()->internalFunctionStructure.get(); }
228         Structure* regExpMatchesArrayStructure() const { return d()->regExpMatchesArrayStructure.get(); }
229         Structure* regExpStructure() const { return d()->regExpStructure.get(); }
230         Structure* stringObjectStructure() const { return d()->stringObjectStructure.get(); }
231
232         void setProfileGroup(unsigned value) { d()->profileGroup = value; }
233         unsigned profileGroup() const { return d()->profileGroup; }
234
235         Debugger* debugger() const { return d()->debugger; }
236         void setDebugger(Debugger* debugger) { d()->debugger = debugger; }
237
238         virtual bool supportsProfiling() const { return false; }
239         virtual bool supportsRichSourceInfo() const { return true; }
240
241         ScopeChain& globalScopeChain() { return d()->globalScopeChain; }
242
243         virtual bool isGlobalObject() const { return true; }
244
245         virtual ExecState* globalExec();
246
247         virtual bool shouldInterruptScript() const { return true; }
248
249         virtual bool allowsAccessFrom(const JSGlobalObject*) const { return true; }
250
251         virtual bool isDynamicScope(bool& requiresDynamicChecks) const;
252
253         HashSet<GlobalCodeBlock*>& codeBlocks() { return d()->codeBlocks; }
254
255         void copyGlobalsFrom(RegisterFile&);
256         void copyGlobalsTo(RegisterFile&);
257         
258         void resetPrototype(JSValue prototype);
259
260         JSGlobalData& globalData() const { return *d()->globalData.get(); }
261         JSGlobalObjectData* d() const { return static_cast<JSGlobalObjectData*>(JSVariableObject::d); }
262
263         static PassRefPtr<Structure> createStructure(JSValue prototype)
264         {
265             return Structure::create(prototype, TypeInfo(ObjectType, StructureFlags), AnonymousSlotCount);
266         }
267
268         void registerWeakMap(OpaqueJSWeakObjectMap* map)
269         {
270             d()->weakMaps.add(map);
271         }
272
273         void deregisterWeakMap(OpaqueJSWeakObjectMap* map)
274         {
275             d()->weakMaps.remove(map);
276         }
277
278         double weakRandomNumber() { return d()->weakRandom.get(); }
279     protected:
280
281         static const unsigned AnonymousSlotCount = JSVariableObject::AnonymousSlotCount + 1;
282         static const unsigned StructureFlags = OverridesGetOwnPropertySlot | OverridesMarkChildren | OverridesGetPropertyNames | JSVariableObject::StructureFlags;
283
284         struct GlobalPropertyInfo {
285             GlobalPropertyInfo(const Identifier& i, JSValue v, unsigned a)
286                 : identifier(i)
287                 , value(v)
288                 , attributes(a)
289             {
290             }
291
292             const Identifier identifier;
293             JSValue value;
294             unsigned attributes;
295         };
296         void addStaticGlobals(GlobalPropertyInfo*, int count);
297
298     private:
299         static void destroyJSGlobalObjectData(void*);
300
301         // FIXME: Fold reset into init.
302         void init(JSObject* thisValue);
303         void reset(JSValue prototype);
304
305         void setRegisters(Register* registers, Register* registerArray, size_t count);
306
307         void* operator new(size_t); // can only be allocated with JSGlobalData
308     };
309
310     JSGlobalObject* asGlobalObject(JSValue);
311
312     inline JSGlobalObject* asGlobalObject(JSValue value)
313     {
314         ASSERT(asObject(value)->isGlobalObject());
315         return static_cast<JSGlobalObject*>(asObject(value));
316     }
317
318     inline void JSGlobalObject::setRegisters(Register* registers, Register* registerArray, size_t count)
319     {
320         JSVariableObject::setRegisters(registers, registerArray);
321         d()->registerArraySize = count;
322     }
323
324     inline void JSGlobalObject::addStaticGlobals(GlobalPropertyInfo* globals, int count)
325     {
326         size_t oldSize = d()->registerArraySize;
327         size_t newSize = oldSize + count;
328         Register* registerArray = new Register[newSize];
329         if (d()->registerArray)
330             memcpy(registerArray + count, d()->registerArray.get(), oldSize * sizeof(Register));
331         setRegisters(registerArray + newSize, registerArray, newSize);
332
333         for (int i = 0, index = -static_cast<int>(oldSize) - 1; i < count; ++i, --index) {
334             GlobalPropertyInfo& global = globals[i];
335             ASSERT(global.attributes & DontDelete);
336             SymbolTableEntry newEntry(index, global.attributes);
337             symbolTable().add(global.identifier.impl(), newEntry);
338             registerAt(index) = global.value;
339         }
340     }
341
342     inline bool JSGlobalObject::getOwnPropertySlot(ExecState* exec, const Identifier& propertyName, PropertySlot& slot)
343     {
344         if (JSVariableObject::getOwnPropertySlot(exec, propertyName, slot))
345             return true;
346         return symbolTableGet(propertyName, slot);
347     }
348
349     inline bool JSGlobalObject::getOwnPropertyDescriptor(ExecState* exec, const Identifier& propertyName, PropertyDescriptor& descriptor)
350     {
351         if (symbolTableGet(propertyName, descriptor))
352             return true;
353         return JSVariableObject::getOwnPropertyDescriptor(exec, propertyName, descriptor);
354     }
355
356     inline bool JSGlobalObject::hasOwnPropertyForWrite(ExecState* exec, const Identifier& propertyName)
357     {
358         PropertySlot slot;
359         if (JSVariableObject::getOwnPropertySlot(exec, propertyName, slot))
360             return true;
361         bool slotIsWriteable;
362         return symbolTableGet(propertyName, slot, slotIsWriteable);
363     }
364
365     inline JSValue Structure::prototypeForLookup(ExecState* exec) const
366     {
367         if (typeInfo().type() == ObjectType)
368             return m_prototype.get();
369
370         ASSERT(typeInfo().type() == StringType);
371         return exec->lexicalGlobalObject()->stringPrototype();
372     }
373
374     inline StructureChain* Structure::prototypeChain(ExecState* exec) const
375     {
376         // We cache our prototype chain so our clients can share it.
377         if (!isValid(exec, m_cachedPrototypeChain.get())) {
378             JSValue prototype = prototypeForLookup(exec);
379             m_cachedPrototypeChain = StructureChain::create(prototype.isNull() ? 0 : asObject(prototype)->structure());
380         }
381         return m_cachedPrototypeChain.get();
382     }
383
384     inline bool Structure::isValid(ExecState* exec, StructureChain* cachedPrototypeChain) const
385     {
386         if (!cachedPrototypeChain)
387             return false;
388
389         JSValue prototype = prototypeForLookup(exec);
390         RefPtr<Structure>* cachedStructure = cachedPrototypeChain->head();
391         while(*cachedStructure && !prototype.isNull()) {
392             if (asObject(prototype)->structure() != *cachedStructure)
393                 return false;
394             ++cachedStructure;
395             prototype = asObject(prototype)->prototype();
396         }
397         return prototype.isNull() && !*cachedStructure;
398     }
399
400     inline JSGlobalObject* ExecState::dynamicGlobalObject()
401     {
402         if (this == lexicalGlobalObject()->globalExec())
403             return lexicalGlobalObject();
404
405         // For any ExecState that's not a globalExec, the 
406         // dynamic global object must be set since code is running
407         ASSERT(globalData().dynamicGlobalObject);
408         return globalData().dynamicGlobalObject;
409     }
410
411     inline JSObject* constructEmptyObject(ExecState* exec)
412     {
413         return new (exec) JSObject(exec->lexicalGlobalObject()->emptyObjectStructure());
414     }
415     
416     inline JSObject* constructEmptyObject(ExecState* exec, JSGlobalObject* globalObject)
417     {
418         return new (exec) JSObject(globalObject->emptyObjectStructure());
419     }
420
421     inline JSArray* constructEmptyArray(ExecState* exec)
422     {
423         return new (exec) JSArray(exec->lexicalGlobalObject()->arrayStructure());
424     }
425     
426     inline JSArray* constructEmptyArray(ExecState* exec, JSGlobalObject* globalObject)
427     {
428         return new (exec) JSArray(globalObject->arrayStructure());
429     }
430
431     inline JSArray* constructEmptyArray(ExecState* exec, unsigned initialLength)
432     {
433         return new (exec) JSArray(exec->lexicalGlobalObject()->arrayStructure(), initialLength, CreateInitialized);
434     }
435
436     inline JSArray* constructArray(ExecState* exec, JSValue singleItemValue)
437     {
438         MarkedArgumentBuffer values;
439         values.append(singleItemValue);
440         return new (exec) JSArray(exec->globalData(), exec->lexicalGlobalObject()->arrayStructure(), values);
441     }
442
443     inline JSArray* constructArray(ExecState* exec, const ArgList& values)
444     {
445         return new (exec) JSArray(exec->globalData(), exec->lexicalGlobalObject()->arrayStructure(), values);
446     }
447
448     class DynamicGlobalObjectScope {
449         WTF_MAKE_NONCOPYABLE(DynamicGlobalObjectScope);
450     public:
451         DynamicGlobalObjectScope(CallFrame* callFrame, JSGlobalObject* dynamicGlobalObject);
452
453         ~DynamicGlobalObjectScope()
454         {
455             m_dynamicGlobalObjectSlot = m_savedDynamicGlobalObject;
456         }
457
458     private:
459         JSGlobalObject*& m_dynamicGlobalObjectSlot;
460         JSGlobalObject* m_savedDynamicGlobalObject;
461     };
462
463 } // namespace JSC
464
465 #endif // JSGlobalObject_h