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