24bc2f88b71c23f5ce0aa09a9f1fedfa9533f580
[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                 , regExpConstructor(0)
77                 , errorConstructor(0)
78                 , evalErrorConstructor(0)
79                 , rangeErrorConstructor(0)
80                 , referenceErrorConstructor(0)
81                 , syntaxErrorConstructor(0)
82                 , typeErrorConstructor(0)
83                 , URIErrorConstructor(0)
84                 , evalFunction(0)
85                 , callFunction(0)
86                 , applyFunction(0)
87                 , objectPrototype(0)
88                 , functionPrototype(0)
89                 , arrayPrototype(0)
90                 , booleanPrototype(0)
91                 , stringPrototype(0)
92                 , numberPrototype(0)
93                 , datePrototype(0)
94                 , regExpPrototype(0)
95                 , methodCallDummy(0)
96                 , weakRandom(static_cast<unsigned>(randomNumber() * (std::numeric_limits<unsigned>::max() + 1.0)))
97             {
98             }
99             
100             Destructor destructor;
101             
102             size_t registerArraySize;
103
104             JSGlobalObject* next;
105             JSGlobalObject* prev;
106
107             Debugger* debugger;
108             
109             ScopeChain globalScopeChain;
110             Register globalCallFrame[RegisterFile::CallFrameHeaderSize];
111
112             RegExpConstructor* regExpConstructor;
113             ErrorConstructor* errorConstructor;
114             NativeErrorConstructor* evalErrorConstructor;
115             NativeErrorConstructor* rangeErrorConstructor;
116             NativeErrorConstructor* referenceErrorConstructor;
117             NativeErrorConstructor* syntaxErrorConstructor;
118             NativeErrorConstructor* typeErrorConstructor;
119             NativeErrorConstructor* URIErrorConstructor;
120
121             GlobalEvalFunction* evalFunction;
122             NativeFunctionWrapper* callFunction;
123             NativeFunctionWrapper* applyFunction;
124
125             ObjectPrototype* objectPrototype;
126             FunctionPrototype* functionPrototype;
127             ArrayPrototype* arrayPrototype;
128             BooleanPrototype* booleanPrototype;
129             StringPrototype* stringPrototype;
130             NumberPrototype* numberPrototype;
131             DatePrototype* datePrototype;
132             RegExpPrototype* regExpPrototype;
133
134             JSObject* methodCallDummy;
135
136             RefPtr<Structure> argumentsStructure;
137             RefPtr<Structure> arrayStructure;
138             RefPtr<Structure> booleanObjectStructure;
139             RefPtr<Structure> callbackConstructorStructure;
140             RefPtr<Structure> callbackFunctionStructure;
141             RefPtr<Structure> callbackObjectStructure;
142             RefPtr<Structure> dateStructure;
143             RefPtr<Structure> emptyObjectStructure;
144             RefPtr<Structure> errorStructure;
145             RefPtr<Structure> functionStructure;
146             RefPtr<Structure> numberObjectStructure;
147             RefPtr<Structure> prototypeFunctionStructure;
148             RefPtr<Structure> regExpMatchesArrayStructure;
149             RefPtr<Structure> regExpStructure;
150             RefPtr<Structure> stringObjectStructure;
151             RefPtr<Structure> internalFunctionStructure;
152
153             SymbolTable symbolTable;
154             unsigned profileGroup;
155
156             RefPtr<JSGlobalData> globalData;
157
158             HashSet<GlobalCodeBlock*> codeBlocks;
159             WeakMapSet weakMaps;
160             WeakRandom weakRandom;
161         };
162
163     public:
164         void* operator new(size_t, JSGlobalData*);
165         
166         explicit JSGlobalObject()
167             : JSVariableObject(JSGlobalObject::createStructure(jsNull()), new JSGlobalObjectData(destroyJSGlobalObjectData))
168         {
169             COMPILE_ASSERT(JSGlobalObject::AnonymousSlotCount == 1, JSGlobalObject_has_only_a_single_slot);
170             putAnonymousValue(0, this);
171             init(this);
172         }
173         
174         explicit JSGlobalObject(NonNullPassRefPtr<Structure> structure)
175             : JSVariableObject(structure, new JSGlobalObjectData(destroyJSGlobalObjectData))
176         {
177             COMPILE_ASSERT(JSGlobalObject::AnonymousSlotCount == 1, JSGlobalObject_has_only_a_single_slot);
178             putAnonymousValue(0, this);
179             init(this);
180         }
181
182     protected:
183         JSGlobalObject(NonNullPassRefPtr<Structure> structure, JSGlobalObjectData* data, JSObject* thisValue)
184             : JSVariableObject(structure, data)
185         {
186             COMPILE_ASSERT(JSGlobalObject::AnonymousSlotCount == 1, JSGlobalObject_has_only_a_single_slot);
187             putAnonymousValue(0, this);
188             init(thisValue);
189         }
190
191     public:
192         virtual ~JSGlobalObject();
193
194         virtual void markChildren(MarkStack&);
195
196         virtual bool getOwnPropertySlot(ExecState*, const Identifier&, PropertySlot&);
197         virtual bool getOwnPropertyDescriptor(ExecState*, const Identifier&, PropertyDescriptor&);
198         virtual bool hasOwnPropertyForWrite(ExecState*, const Identifier&);
199         virtual void put(ExecState*, const Identifier&, JSValue, PutPropertySlot&);
200         virtual void putWithAttributes(ExecState*, const Identifier& propertyName, JSValue value, unsigned attributes);
201
202         virtual void defineGetter(ExecState*, const Identifier& propertyName, JSObject* getterFunc, unsigned attributes);
203         virtual void defineSetter(ExecState*, const Identifier& propertyName, JSObject* setterFunc, unsigned attributes);
204
205         // Linked list of all global objects that use the same JSGlobalData.
206         JSGlobalObject*& head() { return d()->globalData->head; }
207         JSGlobalObject* next() { return d()->next; }
208
209         // The following accessors return pristine values, even if a script 
210         // replaces the global object's associated property.
211
212         RegExpConstructor* regExpConstructor() const { return d()->regExpConstructor; }
213
214         ErrorConstructor* errorConstructor() const { return d()->errorConstructor; }
215         NativeErrorConstructor* evalErrorConstructor() const { return d()->evalErrorConstructor; }
216         NativeErrorConstructor* rangeErrorConstructor() const { return d()->rangeErrorConstructor; }
217         NativeErrorConstructor* referenceErrorConstructor() const { return d()->referenceErrorConstructor; }
218         NativeErrorConstructor* syntaxErrorConstructor() const { return d()->syntaxErrorConstructor; }
219         NativeErrorConstructor* typeErrorConstructor() const { return d()->typeErrorConstructor; }
220         NativeErrorConstructor* URIErrorConstructor() const { return d()->URIErrorConstructor; }
221
222         GlobalEvalFunction* evalFunction() const { return d()->evalFunction; }
223
224         ObjectPrototype* objectPrototype() const { return d()->objectPrototype; }
225         FunctionPrototype* functionPrototype() const { return d()->functionPrototype; }
226         ArrayPrototype* arrayPrototype() const { return d()->arrayPrototype; }
227         BooleanPrototype* booleanPrototype() const { return d()->booleanPrototype; }
228         StringPrototype* stringPrototype() const { return d()->stringPrototype; }
229         NumberPrototype* numberPrototype() const { return d()->numberPrototype; }
230         DatePrototype* datePrototype() const { return d()->datePrototype; }
231         RegExpPrototype* regExpPrototype() const { return d()->regExpPrototype; }
232
233         JSObject* methodCallDummy() const { return d()->methodCallDummy; }
234
235         Structure* argumentsStructure() const { return d()->argumentsStructure.get(); }
236         Structure* arrayStructure() const { return d()->arrayStructure.get(); }
237         Structure* booleanObjectStructure() const { return d()->booleanObjectStructure.get(); }
238         Structure* callbackConstructorStructure() const { return d()->callbackConstructorStructure.get(); }
239         Structure* callbackFunctionStructure() const { return d()->callbackFunctionStructure.get(); }
240         Structure* callbackObjectStructure() const { return d()->callbackObjectStructure.get(); }
241         Structure* dateStructure() const { return d()->dateStructure.get(); }
242         Structure* emptyObjectStructure() const { return d()->emptyObjectStructure.get(); }
243         Structure* errorStructure() const { return d()->errorStructure.get(); }
244         Structure* functionStructure() const { return d()->functionStructure.get(); }
245         Structure* numberObjectStructure() const { return d()->numberObjectStructure.get(); }
246         Structure* prototypeFunctionStructure() const { return d()->prototypeFunctionStructure.get(); }
247         Structure* internalFunctionStructure() const { return d()->internalFunctionStructure.get(); }
248         Structure* regExpMatchesArrayStructure() const { return d()->regExpMatchesArrayStructure.get(); }
249         Structure* regExpStructure() const { return d()->regExpStructure.get(); }
250         Structure* stringObjectStructure() const { return d()->stringObjectStructure.get(); }
251
252         void setProfileGroup(unsigned value) { d()->profileGroup = value; }
253         unsigned profileGroup() const { return d()->profileGroup; }
254
255         Debugger* debugger() const { return d()->debugger; }
256         void setDebugger(Debugger* debugger) { d()->debugger = debugger; }
257
258         virtual bool supportsProfiling() const { return false; }
259         virtual bool supportsRichSourceInfo() const { return true; }
260
261         ScopeChain& globalScopeChain() { return d()->globalScopeChain; }
262
263         virtual bool isGlobalObject() const { return true; }
264
265         virtual ExecState* globalExec();
266
267         virtual bool shouldInterruptScript() const { return true; }
268
269         virtual bool allowsAccessFrom(const JSGlobalObject*) const { return true; }
270
271         virtual bool isDynamicScope(bool& requiresDynamicChecks) const;
272
273         HashSet<GlobalCodeBlock*>& codeBlocks() { return d()->codeBlocks; }
274
275         void copyGlobalsFrom(RegisterFile&);
276         void copyGlobalsTo(RegisterFile&);
277         
278         void resetPrototype(JSValue prototype);
279
280         JSGlobalData& globalData() const { return *d()->globalData.get(); }
281         JSGlobalObjectData* d() const { return static_cast<JSGlobalObjectData*>(JSVariableObject::d); }
282
283         static PassRefPtr<Structure> createStructure(JSValue prototype)
284         {
285             return Structure::create(prototype, TypeInfo(ObjectType, StructureFlags), AnonymousSlotCount);
286         }
287
288         void registerWeakMap(OpaqueJSWeakObjectMap* map)
289         {
290             d()->weakMaps.add(map);
291         }
292
293         void deregisterWeakMap(OpaqueJSWeakObjectMap* map)
294         {
295             d()->weakMaps.remove(map);
296         }
297
298         double weakRandomNumber() { return d()->weakRandom.get(); }
299     protected:
300
301         static const unsigned AnonymousSlotCount = JSVariableObject::AnonymousSlotCount + 1;
302         static const unsigned StructureFlags = OverridesGetOwnPropertySlot | OverridesMarkChildren | OverridesGetPropertyNames | JSVariableObject::StructureFlags;
303
304         struct GlobalPropertyInfo {
305             GlobalPropertyInfo(const Identifier& i, JSValue v, unsigned a)
306                 : identifier(i)
307                 , value(v)
308                 , attributes(a)
309             {
310             }
311
312             const Identifier identifier;
313             JSValue value;
314             unsigned attributes;
315         };
316         void addStaticGlobals(GlobalPropertyInfo*, int count);
317
318     private:
319         static void destroyJSGlobalObjectData(void*);
320
321         // FIXME: Fold reset into init.
322         void init(JSObject* thisValue);
323         void reset(JSValue prototype);
324
325         void setRegisters(Register* registers, Register* registerArray, size_t count);
326
327         void* operator new(size_t); // can only be allocated with JSGlobalData
328     };
329
330     JSGlobalObject* asGlobalObject(JSValue);
331
332     inline JSGlobalObject* asGlobalObject(JSValue value)
333     {
334         ASSERT(asObject(value)->isGlobalObject());
335         return static_cast<JSGlobalObject*>(asObject(value));
336     }
337
338     inline void JSGlobalObject::setRegisters(Register* registers, Register* registerArray, size_t count)
339     {
340         JSVariableObject::setRegisters(registers, registerArray);
341         d()->registerArraySize = count;
342     }
343
344     inline void JSGlobalObject::addStaticGlobals(GlobalPropertyInfo* globals, int count)
345     {
346         size_t oldSize = d()->registerArraySize;
347         size_t newSize = oldSize + count;
348         Register* registerArray = new Register[newSize];
349         if (d()->registerArray)
350             memcpy(registerArray + count, d()->registerArray.get(), oldSize * sizeof(Register));
351         setRegisters(registerArray + newSize, registerArray, newSize);
352
353         for (int i = 0, index = -static_cast<int>(oldSize) - 1; i < count; ++i, --index) {
354             GlobalPropertyInfo& global = globals[i];
355             ASSERT(global.attributes & DontDelete);
356             SymbolTableEntry newEntry(index, global.attributes);
357             symbolTable().add(global.identifier.impl(), newEntry);
358             registerAt(index) = global.value;
359         }
360     }
361
362     inline bool JSGlobalObject::getOwnPropertySlot(ExecState* exec, const Identifier& propertyName, PropertySlot& slot)
363     {
364         if (JSVariableObject::getOwnPropertySlot(exec, propertyName, slot))
365             return true;
366         return symbolTableGet(propertyName, slot);
367     }
368
369     inline bool JSGlobalObject::getOwnPropertyDescriptor(ExecState* exec, const Identifier& propertyName, PropertyDescriptor& descriptor)
370     {
371         if (symbolTableGet(propertyName, descriptor))
372             return true;
373         return JSVariableObject::getOwnPropertyDescriptor(exec, propertyName, descriptor);
374     }
375
376     inline bool JSGlobalObject::hasOwnPropertyForWrite(ExecState* exec, const Identifier& propertyName)
377     {
378         PropertySlot slot;
379         if (JSVariableObject::getOwnPropertySlot(exec, propertyName, slot))
380             return true;
381         bool slotIsWriteable;
382         return symbolTableGet(propertyName, slot, slotIsWriteable);
383     }
384
385     inline JSValue Structure::prototypeForLookup(ExecState* exec) const
386     {
387         if (typeInfo().type() == ObjectType)
388             return m_prototype;
389
390         ASSERT(typeInfo().type() == StringType);
391         return exec->lexicalGlobalObject()->stringPrototype();
392     }
393
394     inline StructureChain* Structure::prototypeChain(ExecState* exec) const
395     {
396         // We cache our prototype chain so our clients can share it.
397         if (!isValid(exec, m_cachedPrototypeChain.get())) {
398             JSValue prototype = prototypeForLookup(exec);
399             m_cachedPrototypeChain = StructureChain::create(prototype.isNull() ? 0 : asObject(prototype)->structure());
400         }
401         return m_cachedPrototypeChain.get();
402     }
403
404     inline bool Structure::isValid(ExecState* exec, StructureChain* cachedPrototypeChain) const
405     {
406         if (!cachedPrototypeChain)
407             return false;
408
409         JSValue prototype = prototypeForLookup(exec);
410         RefPtr<Structure>* cachedStructure = cachedPrototypeChain->head();
411         while(*cachedStructure && !prototype.isNull()) {
412             if (asObject(prototype)->structure() != *cachedStructure)
413                 return false;
414             ++cachedStructure;
415             prototype = asObject(prototype)->prototype();
416         }
417         return prototype.isNull() && !*cachedStructure;
418     }
419
420     inline JSGlobalObject* ExecState::dynamicGlobalObject()
421     {
422         if (this == lexicalGlobalObject()->globalExec())
423             return lexicalGlobalObject();
424
425         // For any ExecState that's not a globalExec, the 
426         // dynamic global object must be set since code is running
427         ASSERT(globalData().dynamicGlobalObject);
428         return globalData().dynamicGlobalObject;
429     }
430
431     inline JSObject* constructEmptyObject(ExecState* exec)
432     {
433         return new (exec) JSObject(exec->lexicalGlobalObject()->emptyObjectStructure());
434     }
435     
436     inline JSObject* constructEmptyObject(ExecState* exec, JSGlobalObject* globalObject)
437     {
438         return new (exec) JSObject(globalObject->emptyObjectStructure());
439     }
440
441     inline JSArray* constructEmptyArray(ExecState* exec)
442     {
443         return new (exec) JSArray(exec->lexicalGlobalObject()->arrayStructure());
444     }
445     
446     inline JSArray* constructEmptyArray(ExecState* exec, JSGlobalObject* globalObject)
447     {
448         return new (exec) JSArray(globalObject->arrayStructure());
449     }
450
451     inline JSArray* constructEmptyArray(ExecState* exec, unsigned initialLength)
452     {
453         return new (exec) JSArray(exec->lexicalGlobalObject()->arrayStructure(), initialLength, CreateInitialized);
454     }
455
456     inline JSArray* constructArray(ExecState* exec, JSValue singleItemValue)
457     {
458         MarkedArgumentBuffer values;
459         values.append(singleItemValue);
460         return new (exec) JSArray(exec->lexicalGlobalObject()->arrayStructure(), values);
461     }
462
463     inline JSArray* constructArray(ExecState* exec, const ArgList& values)
464     {
465         return new (exec) JSArray(exec->lexicalGlobalObject()->arrayStructure(), values);
466     }
467
468     class DynamicGlobalObjectScope {
469         WTF_MAKE_NONCOPYABLE(DynamicGlobalObjectScope);
470     public:
471         DynamicGlobalObjectScope(CallFrame* callFrame, JSGlobalObject* dynamicGlobalObject);
472
473         ~DynamicGlobalObjectScope()
474         {
475             m_dynamicGlobalObjectSlot = m_savedDynamicGlobalObject;
476         }
477
478     private:
479         JSGlobalObject*& m_dynamicGlobalObjectSlot;
480         JSGlobalObject* m_savedDynamicGlobalObject;
481     };
482
483 } // namespace JSC
484
485 #endif // JSGlobalObject_h