702ebfd9ae8c5712acfdd0de225766dbaae8816e
[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 "JSGlobalThis.h"
28 #include "JSSegmentedVariableObject.h"
29 #include "JSWeakObjectMapRefInternal.h"
30 #include "NumberPrototype.h"
31 #include "StringPrototype.h"
32 #include "StructureChain.h"
33 #include <wtf/HashSet.h>
34 #include <wtf/OwnPtr.h>
35 #include <wtf/RandomNumber.h>
36
37 namespace JSC {
38
39     class ArrayPrototype;
40     class BooleanPrototype;
41     class DatePrototype;
42     class Debugger;
43     class ErrorConstructor;
44     class ErrorPrototype;
45     class FunctionPrototype;
46     class GetterSetter;
47     class GlobalCodeBlock;
48     class LLIntOffsetsExtractor;
49     class NativeErrorConstructor;
50     class ProgramCodeBlock;
51     class RegExpConstructor;
52     class RegExpPrototype;
53     class RegisterFile;
54
55     struct ActivationStackNode;
56     struct HashTable;
57
58     typedef Vector<ExecState*, 16> ExecStateStack;
59     
60     struct GlobalObjectMethodTable {
61         typedef bool (*AllowsAccessFromFunctionPtr)(const JSGlobalObject*, ExecState*);
62         AllowsAccessFromFunctionPtr allowsAccessFrom;
63
64         typedef bool (*SupportsProfilingFunctionPtr)(const JSGlobalObject*); 
65         SupportsProfilingFunctionPtr supportsProfiling;
66
67         typedef bool (*SupportsRichSourceInfoFunctionPtr)(const JSGlobalObject*);
68         SupportsRichSourceInfoFunctionPtr supportsRichSourceInfo;
69
70         typedef bool (*ShouldInterruptScriptFunctionPtr)(const JSGlobalObject*);
71         ShouldInterruptScriptFunctionPtr shouldInterruptScript;
72
73         typedef bool (*JavaScriptExperimentsEnabledFunctionPtr)(const JSGlobalObject*);
74         JavaScriptExperimentsEnabledFunctionPtr javaScriptExperimentsEnabled;
75     };
76
77     class JSGlobalObject : public JSSegmentedVariableObject {
78     private:
79         typedef HashSet<RefPtr<OpaqueJSWeakObjectMap> > WeakMapSet;
80
81         struct JSGlobalObjectRareData {
82             JSGlobalObjectRareData()
83                 : profileGroup(0)
84             {
85             }
86
87             WeakMapSet weakMaps;
88             unsigned profileGroup;
89         };
90
91     protected:
92
93         Register m_globalCallFrame[RegisterFile::CallFrameHeaderSize];
94
95         WriteBarrier<ScopeChainNode> m_globalScopeChain;
96         WriteBarrier<JSObject> m_methodCallDummy;
97
98         WriteBarrier<RegExpConstructor> m_regExpConstructor;
99         WriteBarrier<ErrorConstructor> m_errorConstructor;
100         WriteBarrier<NativeErrorConstructor> m_evalErrorConstructor;
101         WriteBarrier<NativeErrorConstructor> m_rangeErrorConstructor;
102         WriteBarrier<NativeErrorConstructor> m_referenceErrorConstructor;
103         WriteBarrier<NativeErrorConstructor> m_syntaxErrorConstructor;
104         WriteBarrier<NativeErrorConstructor> m_typeErrorConstructor;
105         WriteBarrier<NativeErrorConstructor> m_URIErrorConstructor;
106
107         WriteBarrier<JSFunction> m_evalFunction;
108         WriteBarrier<JSFunction> m_callFunction;
109         WriteBarrier<JSFunction> m_applyFunction;
110         WriteBarrier<GetterSetter> m_throwTypeErrorGetterSetter;
111
112         WriteBarrier<ObjectPrototype> m_objectPrototype;
113         WriteBarrier<FunctionPrototype> m_functionPrototype;
114         WriteBarrier<ArrayPrototype> m_arrayPrototype;
115         WriteBarrier<BooleanPrototype> m_booleanPrototype;
116         WriteBarrier<StringPrototype> m_stringPrototype;
117         WriteBarrier<NumberPrototype> m_numberPrototype;
118         WriteBarrier<DatePrototype> m_datePrototype;
119         WriteBarrier<RegExpPrototype> m_regExpPrototype;
120         WriteBarrier<ErrorPrototype> m_errorPrototype;
121
122         WriteBarrier<Structure> m_argumentsStructure;
123         WriteBarrier<Structure> m_arrayStructure;
124         WriteBarrier<Structure> m_booleanObjectStructure;
125         WriteBarrier<Structure> m_callbackConstructorStructure;
126         WriteBarrier<Structure> m_callbackFunctionStructure;
127         WriteBarrier<Structure> m_callbackObjectStructure;
128         WriteBarrier<Structure> m_dateStructure;
129         WriteBarrier<Structure> m_emptyObjectStructure;
130         WriteBarrier<Structure> m_nullPrototypeObjectStructure;
131         WriteBarrier<Structure> m_errorStructure;
132         WriteBarrier<Structure> m_functionStructure;
133         WriteBarrier<Structure> m_boundFunctionStructure;
134         WriteBarrier<Structure> m_namedFunctionStructure;
135         size_t m_functionNameOffset;
136         WriteBarrier<Structure> m_numberObjectStructure;
137         WriteBarrier<Structure> m_privateNameStructure;
138         WriteBarrier<Structure> m_regExpMatchesArrayStructure;
139         WriteBarrier<Structure> m_regExpStructure;
140         WriteBarrier<Structure> m_stringObjectStructure;
141         WriteBarrier<Structure> m_internalFunctionStructure;
142
143         Debugger* m_debugger;
144
145         OwnPtr<JSGlobalObjectRareData> m_rareData;
146
147         WeakRandom m_weakRandom;
148
149         SymbolTable m_symbolTable;
150
151         bool m_evalEnabled;
152         bool m_experimentsEnabled;
153
154         static JS_EXPORTDATA const GlobalObjectMethodTable s_globalObjectMethodTable;
155         const GlobalObjectMethodTable* m_globalObjectMethodTable;
156
157         void createRareDataIfNeeded()
158         {
159             if (m_rareData)
160                 return;
161             m_rareData = adoptPtr(new JSGlobalObjectRareData);
162             Heap::heap(this)->addFinalizer(this, clearRareData);
163         }
164         
165     public:
166         typedef JSSegmentedVariableObject Base;
167
168         static JSGlobalObject* create(JSGlobalData& globalData, Structure* structure)
169         {
170             JSGlobalObject* globalObject = new (NotNull, allocateCell<JSGlobalObject>(globalData.heap)) JSGlobalObject(globalData, structure);
171             globalObject->finishCreation(globalData);
172             return globalObject;
173         }
174
175         static JS_EXPORTDATA const ClassInfo s_info;
176
177     protected:
178         explicit JSGlobalObject(JSGlobalData& globalData, Structure* structure, const GlobalObjectMethodTable* globalObjectMethodTable = 0)
179             : JSSegmentedVariableObject(globalData, structure, &m_symbolTable)
180             , m_globalScopeChain()
181             , m_weakRandom(static_cast<unsigned>(randomNumber() * (std::numeric_limits<unsigned>::max() + 1.0)))
182             , m_evalEnabled(true)
183             , m_globalObjectMethodTable(globalObjectMethodTable ? globalObjectMethodTable : &s_globalObjectMethodTable)
184         {
185         }
186
187         void finishCreation(JSGlobalData& globalData)
188         {
189             Base::finishCreation(globalData);
190             structure()->setGlobalObject(globalData, this);
191             m_experimentsEnabled = m_globalObjectMethodTable->javaScriptExperimentsEnabled(this);
192             init(this);
193         }
194
195         void finishCreation(JSGlobalData& globalData, JSGlobalThis* thisValue)
196         {
197             Base::finishCreation(globalData);
198             structure()->setGlobalObject(globalData, this);
199             m_experimentsEnabled = m_globalObjectMethodTable->javaScriptExperimentsEnabled(this);
200             init(thisValue);
201         }
202
203     public:
204         JS_EXPORT_PRIVATE ~JSGlobalObject();
205         JS_EXPORT_PRIVATE static void destroy(JSCell*);
206
207         JS_EXPORT_PRIVATE static void visitChildren(JSCell*, SlotVisitor&);
208
209         JS_EXPORT_PRIVATE static bool getOwnPropertySlot(JSCell*, ExecState*, PropertyName, PropertySlot&);
210         JS_EXPORT_PRIVATE static bool getOwnPropertyDescriptor(JSObject*, ExecState*, PropertyName, PropertyDescriptor&);
211         bool hasOwnPropertyForWrite(ExecState*, PropertyName);
212         JS_EXPORT_PRIVATE static void put(JSCell*, ExecState*, PropertyName, JSValue, PutPropertySlot&);
213
214         JS_EXPORT_PRIVATE static void putDirectVirtual(JSObject*, ExecState*, PropertyName, JSValue, unsigned attributes);
215
216         JS_EXPORT_PRIVATE static void defineGetter(JSObject*, ExecState*, PropertyName, JSObject* getterFunc, unsigned attributes);
217         JS_EXPORT_PRIVATE static void defineSetter(JSObject*, ExecState*, PropertyName, JSObject* setterFunc, unsigned attributes);
218         JS_EXPORT_PRIVATE static bool defineOwnProperty(JSObject*, ExecState*, PropertyName, PropertyDescriptor&, bool shouldThrow);
219
220         // We use this in the code generator as we perform symbol table
221         // lookups prior to initializing the properties
222         bool symbolTableHasProperty(PropertyName);
223
224         // The following accessors return pristine values, even if a script 
225         // replaces the global object's associated property.
226
227         RegExpConstructor* regExpConstructor() const { return m_regExpConstructor.get(); }
228
229         ErrorConstructor* errorConstructor() const { return m_errorConstructor.get(); }
230         NativeErrorConstructor* evalErrorConstructor() const { return m_evalErrorConstructor.get(); }
231         NativeErrorConstructor* rangeErrorConstructor() const { return m_rangeErrorConstructor.get(); }
232         NativeErrorConstructor* referenceErrorConstructor() const { return m_referenceErrorConstructor.get(); }
233         NativeErrorConstructor* syntaxErrorConstructor() const { return m_syntaxErrorConstructor.get(); }
234         NativeErrorConstructor* typeErrorConstructor() const { return m_typeErrorConstructor.get(); }
235         NativeErrorConstructor* URIErrorConstructor() const { return m_URIErrorConstructor.get(); }
236
237         JSFunction* evalFunction() const { return m_evalFunction.get(); }
238         JSFunction* callFunction() const { return m_callFunction.get(); }
239         JSFunction* applyFunction() const { return m_applyFunction.get(); }
240         GetterSetter* throwTypeErrorGetterSetter(ExecState* exec)
241         {
242             if (!m_throwTypeErrorGetterSetter)
243                 createThrowTypeError(exec);
244             return m_throwTypeErrorGetterSetter.get();
245         }
246
247         ObjectPrototype* objectPrototype() const { return m_objectPrototype.get(); }
248         FunctionPrototype* functionPrototype() const { return m_functionPrototype.get(); }
249         ArrayPrototype* arrayPrototype() const { return m_arrayPrototype.get(); }
250         BooleanPrototype* booleanPrototype() const { return m_booleanPrototype.get(); }
251         StringPrototype* stringPrototype() const { return m_stringPrototype.get(); }
252         NumberPrototype* numberPrototype() const { return m_numberPrototype.get(); }
253         DatePrototype* datePrototype() const { return m_datePrototype.get(); }
254         RegExpPrototype* regExpPrototype() const { return m_regExpPrototype.get(); }
255         ErrorPrototype* errorPrototype() const { return m_errorPrototype.get(); }
256
257         JSObject* methodCallDummy() const { return m_methodCallDummy.get(); }
258
259         Structure* argumentsStructure() const { return m_argumentsStructure.get(); }
260         Structure* arrayStructure() const { return m_arrayStructure.get(); }
261         Structure* booleanObjectStructure() const { return m_booleanObjectStructure.get(); }
262         Structure* callbackConstructorStructure() const { return m_callbackConstructorStructure.get(); }
263         Structure* callbackFunctionStructure() const { return m_callbackFunctionStructure.get(); }
264         Structure* callbackObjectStructure() const { return m_callbackObjectStructure.get(); }
265         Structure* dateStructure() const { return m_dateStructure.get(); }
266         Structure* emptyObjectStructure() const { return m_emptyObjectStructure.get(); }
267         Structure* nullPrototypeObjectStructure() const { return m_nullPrototypeObjectStructure.get(); }
268         Structure* errorStructure() const { return m_errorStructure.get(); }
269         Structure* functionStructure() const { return m_functionStructure.get(); }
270         Structure* boundFunctionStructure() const { return m_boundFunctionStructure.get(); }
271         Structure* namedFunctionStructure() const { return m_namedFunctionStructure.get(); }
272         size_t functionNameOffset() const { return m_functionNameOffset; }
273         Structure* numberObjectStructure() const { return m_numberObjectStructure.get(); }
274         Structure* privateNameStructure() const { return m_privateNameStructure.get(); }
275         Structure* internalFunctionStructure() const { return m_internalFunctionStructure.get(); }
276         Structure* regExpMatchesArrayStructure() const { return m_regExpMatchesArrayStructure.get(); }
277         Structure* regExpStructure() const { return m_regExpStructure.get(); }
278         Structure* stringObjectStructure() const { return m_stringObjectStructure.get(); }
279
280         void setProfileGroup(unsigned value) { createRareDataIfNeeded(); m_rareData->profileGroup = value; }
281         unsigned profileGroup() const
282         { 
283             if (!m_rareData)
284                 return 0;
285             return m_rareData->profileGroup;
286         }
287
288         Debugger* debugger() const { return m_debugger; }
289         void setDebugger(Debugger* debugger) { m_debugger = debugger; }
290
291         const GlobalObjectMethodTable* globalObjectMethodTable() const { return m_globalObjectMethodTable; }
292
293         static bool allowsAccessFrom(const JSGlobalObject*, ExecState*) { return true; }
294         static bool supportsProfiling(const JSGlobalObject*) { return false; }
295         static bool supportsRichSourceInfo(const JSGlobalObject*) { return true; }
296
297         ScopeChainNode* globalScopeChain() { return m_globalScopeChain.get(); }
298
299         JS_EXPORT_PRIVATE ExecState* globalExec();
300
301         static bool shouldInterruptScript(const JSGlobalObject*) { return true; }
302         static bool javaScriptExperimentsEnabled(const JSGlobalObject*) { return false; }
303
304         bool isDynamicScope(bool& requiresDynamicChecks) const;
305
306         void setEvalEnabled(bool enabled) { m_evalEnabled = enabled; }
307         bool evalEnabled() { return m_evalEnabled; }
308
309         void resetPrototype(JSGlobalData&, JSValue prototype);
310
311         JSGlobalData& globalData() const { return *Heap::heap(this)->globalData(); }
312
313         static Structure* createStructure(JSGlobalData& globalData, JSValue prototype)
314         {
315             return Structure::create(globalData, 0, prototype, TypeInfo(GlobalObjectType, StructureFlags), &s_info);
316         }
317
318         void registerWeakMap(OpaqueJSWeakObjectMap* map)
319         {
320             createRareDataIfNeeded();
321             m_rareData->weakMaps.add(map);
322         }
323
324         void unregisterWeakMap(OpaqueJSWeakObjectMap* map)
325         {
326             if (m_rareData)
327                 m_rareData->weakMaps.remove(map);
328         }
329
330         double weakRandomNumber() { return m_weakRandom.get(); }
331     protected:
332
333         static const unsigned StructureFlags = OverridesGetOwnPropertySlot | OverridesVisitChildren | OverridesGetPropertyNames | JSSegmentedVariableObject::StructureFlags;
334
335         struct GlobalPropertyInfo {
336             GlobalPropertyInfo(const Identifier& i, JSValue v, unsigned a)
337                 : identifier(i)
338                 , value(v)
339                 , attributes(a)
340             {
341             }
342
343             const Identifier identifier;
344             JSValue value;
345             unsigned attributes;
346         };
347         JS_EXPORT_PRIVATE void addStaticGlobals(GlobalPropertyInfo*, int count);
348
349     private:
350         friend class LLIntOffsetsExtractor;
351         
352         // FIXME: Fold reset into init.
353         JS_EXPORT_PRIVATE void init(JSObject* thisValue);
354         void reset(JSValue prototype);
355
356         void createThrowTypeError(ExecState*);
357
358         JS_EXPORT_PRIVATE static void clearRareData(JSCell*);
359     };
360
361     JSGlobalObject* asGlobalObject(JSValue);
362
363     inline JSGlobalObject* asGlobalObject(JSValue value)
364     {
365         ASSERT(asObject(value)->isGlobalObject());
366         return jsCast<JSGlobalObject*>(asObject(value));
367     }
368
369     inline bool JSGlobalObject::hasOwnPropertyForWrite(ExecState* exec, PropertyName propertyName)
370     {
371         PropertySlot slot;
372         if (JSSegmentedVariableObject::getOwnPropertySlot(this, exec, propertyName, slot))
373             return true;
374         bool slotIsWriteable;
375         return symbolTableGet(this, propertyName, slot, slotIsWriteable);
376     }
377
378     inline bool JSGlobalObject::symbolTableHasProperty(PropertyName propertyName)
379     {
380         SymbolTableEntry entry = symbolTable().inlineGet(propertyName.publicName());
381         return !entry.isNull();
382     }
383
384     inline JSValue Structure::prototypeForLookup(ExecState* exec) const
385     {
386         if (isObject())
387             return m_prototype.get();
388
389         ASSERT(typeInfo().type() == StringType);
390         return exec->lexicalGlobalObject()->stringPrototype();
391     }
392
393     inline StructureChain* Structure::prototypeChain(ExecState* exec) const
394     {
395         // We cache our prototype chain so our clients can share it.
396         if (!isValid(exec, m_cachedPrototypeChain.get())) {
397             JSValue prototype = prototypeForLookup(exec);
398             m_cachedPrototypeChain.set(exec->globalData(), this, StructureChain::create(exec->globalData(), prototype.isNull() ? 0 : asObject(prototype)->structure()));
399         }
400         return m_cachedPrototypeChain.get();
401     }
402
403     inline bool Structure::isValid(ExecState* exec, StructureChain* cachedPrototypeChain) const
404     {
405         if (!cachedPrototypeChain)
406             return false;
407
408         JSValue prototype = prototypeForLookup(exec);
409         WriteBarrier<Structure>* cachedStructure = cachedPrototypeChain->head();
410         while(*cachedStructure && !prototype.isNull()) {
411             if (asObject(prototype)->structure() != cachedStructure->get())
412                 return false;
413             ++cachedStructure;
414             prototype = asObject(prototype)->prototype();
415         }
416         return prototype.isNull() && !*cachedStructure;
417     }
418
419     inline JSGlobalObject* ExecState::dynamicGlobalObject()
420     {
421         if (this == lexicalGlobalObject()->globalExec())
422             return lexicalGlobalObject();
423
424         // For any ExecState that's not a globalExec, the 
425         // dynamic global object must be set since code is running
426         ASSERT(globalData().dynamicGlobalObject);
427         return globalData().dynamicGlobalObject;
428     }
429
430     inline JSObject* constructEmptyObject(ExecState* exec, JSGlobalObject* globalObject)
431     {
432         return constructEmptyObject(exec, globalObject->emptyObjectStructure());
433     }
434
435     inline JSObject* constructEmptyObject(ExecState* exec)
436     {
437         return constructEmptyObject(exec, exec->lexicalGlobalObject());
438     }
439
440     inline JSArray* constructEmptyArray(ExecState* exec, JSGlobalObject* globalObject, unsigned initialLength = 0)
441     {
442         return JSArray::create(exec->globalData(), globalObject->arrayStructure(), initialLength);
443     }
444
445     inline JSArray* constructEmptyArray(ExecState* exec, unsigned initialLength = 0)
446     {
447         return constructEmptyArray(exec, exec->lexicalGlobalObject(), initialLength);
448     }
449
450     inline JSArray* constructArray(ExecState* exec, JSGlobalObject* globalObject, const ArgList& values)
451     {
452         JSGlobalData& globalData = exec->globalData();
453         unsigned length = values.size();
454         JSArray* array = JSArray::tryCreateUninitialized(globalData, globalObject->arrayStructure(), length);
455
456         // FIXME: we should probably throw an out of memory error here, but
457         // when making this change we should check that all clients of this
458         // function will correctly handle an exception being thrown from here.
459         if (!array)
460             CRASH();
461
462         for (unsigned i = 0; i < length; ++i)
463             array->initializeIndex(globalData, i, values.at(i));
464         array->completeInitialization(length);
465         return array;
466     }
467
468     inline JSArray* constructArray(ExecState* exec, const ArgList& values)
469     {
470         return constructArray(exec, exec->lexicalGlobalObject(), values);
471     }
472
473     inline JSArray* constructArray(ExecState* exec, JSGlobalObject* globalObject, const JSValue* values, unsigned length)
474     {
475         JSGlobalData& globalData = exec->globalData();
476         JSArray* array = JSArray::tryCreateUninitialized(globalData, globalObject->arrayStructure(), length);
477
478         // FIXME: we should probably throw an out of memory error here, but
479         // when making this change we should check that all clients of this
480         // function will correctly handle an exception being thrown from here.
481         if (!array)
482             CRASH();
483
484         for (unsigned i = 0; i < length; ++i)
485             array->initializeIndex(globalData, i, values[i]);
486         array->completeInitialization(length);
487         return array;
488     }
489
490     inline JSArray* constructArray(ExecState* exec, const JSValue* values, unsigned length)
491     {
492         return constructArray(exec, exec->lexicalGlobalObject(), values, length);
493     }
494
495     class DynamicGlobalObjectScope {
496         WTF_MAKE_NONCOPYABLE(DynamicGlobalObjectScope);
497     public:
498         JS_EXPORT_PRIVATE DynamicGlobalObjectScope(JSGlobalData&, JSGlobalObject*);
499
500         ~DynamicGlobalObjectScope()
501         {
502             m_dynamicGlobalObjectSlot = m_savedDynamicGlobalObject;
503         }
504
505     private:
506         JSGlobalObject*& m_dynamicGlobalObjectSlot;
507         JSGlobalObject* m_savedDynamicGlobalObject;
508     };
509
510     inline bool JSGlobalObject::isDynamicScope(bool&) const
511     {
512         return true;
513     }
514
515 } // namespace JSC
516
517 #endif // JSGlobalObject_h