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