• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 "NumberPrototype.h"
30 #include "StringPrototype.h"
31 #include "StructureChain.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 NativeErrorConstructor;
46     class ProgramCodeBlock;
47     class RegExpConstructor;
48     class RegExpPrototype;
49     class RegisterFile;
50 
51     struct ActivationStackNode;
52     struct HashTable;
53 
54     typedef Vector<ExecState*, 16> ExecStateStack;
55 
56     class JSGlobalObject : public JSVariableObject {
57     protected:
58         typedef HashSet<RefPtr<OpaqueJSWeakObjectMap> > WeakMapSet;
59 
60         RefPtr<JSGlobalData> m_globalData;
61 
62         size_t m_registerArraySize;
63         Register m_globalCallFrame[RegisterFile::CallFrameHeaderSize];
64 
65         WriteBarrier<ScopeChainNode> m_globalScopeChain;
66         WriteBarrier<JSObject> m_methodCallDummy;
67 
68         WriteBarrier<RegExpConstructor> m_regExpConstructor;
69         WriteBarrier<ErrorConstructor> m_errorConstructor;
70         WriteBarrier<NativeErrorConstructor> m_evalErrorConstructor;
71         WriteBarrier<NativeErrorConstructor> m_rangeErrorConstructor;
72         WriteBarrier<NativeErrorConstructor> m_referenceErrorConstructor;
73         WriteBarrier<NativeErrorConstructor> m_syntaxErrorConstructor;
74         WriteBarrier<NativeErrorConstructor> m_typeErrorConstructor;
75         WriteBarrier<NativeErrorConstructor> m_URIErrorConstructor;
76 
77         WriteBarrier<JSFunction> m_evalFunction;
78         WriteBarrier<JSFunction> m_callFunction;
79         WriteBarrier<JSFunction> m_applyFunction;
80 
81         WriteBarrier<ObjectPrototype> m_objectPrototype;
82         WriteBarrier<FunctionPrototype> m_functionPrototype;
83         WriteBarrier<ArrayPrototype> m_arrayPrototype;
84         WriteBarrier<BooleanPrototype> m_booleanPrototype;
85         WriteBarrier<StringPrototype> m_stringPrototype;
86         WriteBarrier<NumberPrototype> m_numberPrototype;
87         WriteBarrier<DatePrototype> m_datePrototype;
88         WriteBarrier<RegExpPrototype> m_regExpPrototype;
89 
90         WriteBarrier<Structure> m_argumentsStructure;
91         WriteBarrier<Structure> m_arrayStructure;
92         WriteBarrier<Structure> m_booleanObjectStructure;
93         WriteBarrier<Structure> m_callbackConstructorStructure;
94         WriteBarrier<Structure> m_callbackFunctionStructure;
95         WriteBarrier<Structure> m_callbackObjectStructure;
96         WriteBarrier<Structure> m_dateStructure;
97         WriteBarrier<Structure> m_emptyObjectStructure;
98         WriteBarrier<Structure> m_errorStructure;
99         WriteBarrier<Structure> m_functionStructure;
100         WriteBarrier<Structure> m_numberObjectStructure;
101         WriteBarrier<Structure> m_regExpMatchesArrayStructure;
102         WriteBarrier<Structure> m_regExpStructure;
103         WriteBarrier<Structure> m_stringObjectStructure;
104         WriteBarrier<Structure> m_internalFunctionStructure;
105 
106         unsigned m_profileGroup;
107         Debugger* m_debugger;
108 
109         WeakMapSet m_weakMaps;
110         WeakRandom m_weakRandom;
111 
112         SymbolTable m_symbolTable;
113 
114     public:
115         void* operator new(size_t, JSGlobalData*);
116 
JSGlobalObject(JSGlobalData & globalData)117         explicit JSGlobalObject(JSGlobalData& globalData)
118             : JSVariableObject(globalData, JSGlobalObject::createStructure(globalData, jsNull()), &m_symbolTable, 0)
119             , m_registerArraySize(0)
120             , m_globalScopeChain()
121             , m_weakRandom(static_cast<unsigned>(randomNumber() * (std::numeric_limits<unsigned>::max() + 1.0)))
122         {
123             COMPILE_ASSERT(JSGlobalObject::AnonymousSlotCount == 1, JSGlobalObject_has_only_a_single_slot);
124             putThisToAnonymousValue(0);
125             init(this);
126         }
127 
JSGlobalObject(JSGlobalData & globalData,Structure * structure)128         explicit JSGlobalObject(JSGlobalData& globalData, Structure* structure)
129             : JSVariableObject(globalData, structure, &m_symbolTable, 0)
130             , m_registerArraySize(0)
131             , m_globalScopeChain()
132             , m_weakRandom(static_cast<unsigned>(randomNumber() * (std::numeric_limits<unsigned>::max() + 1.0)))
133         {
134             COMPILE_ASSERT(JSGlobalObject::AnonymousSlotCount == 1, JSGlobalObject_has_only_a_single_slot);
135             putThisToAnonymousValue(0);
136             init(this);
137         }
138 
139     protected:
JSGlobalObject(JSGlobalData & globalData,Structure * structure,JSObject * thisValue)140         JSGlobalObject(JSGlobalData& globalData, Structure* structure, JSObject* thisValue)
141             : JSVariableObject(globalData, structure, &m_symbolTable, 0)
142             , m_registerArraySize(0)
143             , m_globalScopeChain()
144             , m_weakRandom(static_cast<unsigned>(randomNumber() * (std::numeric_limits<unsigned>::max() + 1.0)))
145         {
146             COMPILE_ASSERT(JSGlobalObject::AnonymousSlotCount == 1, JSGlobalObject_has_only_a_single_slot);
147             putThisToAnonymousValue(0);
148             init(thisValue);
149         }
150 
151     public:
152         virtual ~JSGlobalObject();
153 
154         virtual void markChildren(MarkStack&);
155 
156         virtual bool getOwnPropertySlot(ExecState*, const Identifier&, PropertySlot&);
157         virtual bool getOwnPropertyDescriptor(ExecState*, const Identifier&, PropertyDescriptor&);
158         virtual bool hasOwnPropertyForWrite(ExecState*, const Identifier&);
159         virtual void put(ExecState*, const Identifier&, JSValue, PutPropertySlot&);
160         virtual void putWithAttributes(ExecState*, const Identifier& propertyName, JSValue value, unsigned attributes);
161 
162         virtual void defineGetter(ExecState*, const Identifier& propertyName, JSObject* getterFunc, unsigned attributes);
163         virtual void defineSetter(ExecState*, const Identifier& propertyName, JSObject* setterFunc, unsigned attributes);
164 
165         // We use this in the code generator as we perform symbol table
166         // lookups prior to initializing the properties
167         bool symbolTableHasProperty(const Identifier& propertyName);
168 
169         // The following accessors return pristine values, even if a script
170         // replaces the global object's associated property.
171 
regExpConstructor()172         RegExpConstructor* regExpConstructor() const { return m_regExpConstructor.get(); }
173 
errorConstructor()174         ErrorConstructor* errorConstructor() const { return m_errorConstructor.get(); }
evalErrorConstructor()175         NativeErrorConstructor* evalErrorConstructor() const { return m_evalErrorConstructor.get(); }
rangeErrorConstructor()176         NativeErrorConstructor* rangeErrorConstructor() const { return m_rangeErrorConstructor.get(); }
referenceErrorConstructor()177         NativeErrorConstructor* referenceErrorConstructor() const { return m_referenceErrorConstructor.get(); }
syntaxErrorConstructor()178         NativeErrorConstructor* syntaxErrorConstructor() const { return m_syntaxErrorConstructor.get(); }
typeErrorConstructor()179         NativeErrorConstructor* typeErrorConstructor() const { return m_typeErrorConstructor.get(); }
URIErrorConstructor()180         NativeErrorConstructor* URIErrorConstructor() const { return m_URIErrorConstructor.get(); }
181 
evalFunction()182         JSFunction* evalFunction() const { return m_evalFunction.get(); }
callFunction()183         JSFunction* callFunction() const { return m_callFunction.get(); }
applyFunction()184         JSFunction* applyFunction() const { return m_applyFunction.get(); }
185 
objectPrototype()186         ObjectPrototype* objectPrototype() const { return m_objectPrototype.get(); }
functionPrototype()187         FunctionPrototype* functionPrototype() const { return m_functionPrototype.get(); }
arrayPrototype()188         ArrayPrototype* arrayPrototype() const { return m_arrayPrototype.get(); }
booleanPrototype()189         BooleanPrototype* booleanPrototype() const { return m_booleanPrototype.get(); }
stringPrototype()190         StringPrototype* stringPrototype() const { return m_stringPrototype.get(); }
numberPrototype()191         NumberPrototype* numberPrototype() const { return m_numberPrototype.get(); }
datePrototype()192         DatePrototype* datePrototype() const { return m_datePrototype.get(); }
regExpPrototype()193         RegExpPrototype* regExpPrototype() const { return m_regExpPrototype.get(); }
194 
methodCallDummy()195         JSObject* methodCallDummy() const { return m_methodCallDummy.get(); }
196 
argumentsStructure()197         Structure* argumentsStructure() const { return m_argumentsStructure.get(); }
arrayStructure()198         Structure* arrayStructure() const { return m_arrayStructure.get(); }
booleanObjectStructure()199         Structure* booleanObjectStructure() const { return m_booleanObjectStructure.get(); }
callbackConstructorStructure()200         Structure* callbackConstructorStructure() const { return m_callbackConstructorStructure.get(); }
callbackFunctionStructure()201         Structure* callbackFunctionStructure() const { return m_callbackFunctionStructure.get(); }
callbackObjectStructure()202         Structure* callbackObjectStructure() const { return m_callbackObjectStructure.get(); }
dateStructure()203         Structure* dateStructure() const { return m_dateStructure.get(); }
emptyObjectStructure()204         Structure* emptyObjectStructure() const { return m_emptyObjectStructure.get(); }
errorStructure()205         Structure* errorStructure() const { return m_errorStructure.get(); }
functionStructure()206         Structure* functionStructure() const { return m_functionStructure.get(); }
numberObjectStructure()207         Structure* numberObjectStructure() const { return m_numberObjectStructure.get(); }
internalFunctionStructure()208         Structure* internalFunctionStructure() const { return m_internalFunctionStructure.get(); }
regExpMatchesArrayStructure()209         Structure* regExpMatchesArrayStructure() const { return m_regExpMatchesArrayStructure.get(); }
regExpStructure()210         Structure* regExpStructure() const { return m_regExpStructure.get(); }
stringObjectStructure()211         Structure* stringObjectStructure() const { return m_stringObjectStructure.get(); }
212 
setProfileGroup(unsigned value)213         void setProfileGroup(unsigned value) { m_profileGroup = value; }
profileGroup()214         unsigned profileGroup() const { return m_profileGroup; }
215 
debugger()216         Debugger* debugger() const { return m_debugger; }
setDebugger(Debugger * debugger)217         void setDebugger(Debugger* debugger) { m_debugger = debugger; }
218 
supportsProfiling()219         virtual bool supportsProfiling() const { return false; }
supportsRichSourceInfo()220         virtual bool supportsRichSourceInfo() const { return true; }
221 
globalScopeChain()222         ScopeChainNode* globalScopeChain() { return m_globalScopeChain.get(); }
223 
isGlobalObject()224         virtual bool isGlobalObject() const { return true; }
225 
226         virtual ExecState* globalExec();
227 
shouldInterruptScript()228         virtual bool shouldInterruptScript() const { return true; }
229 
allowsAccessFrom(const JSGlobalObject *)230         virtual bool allowsAccessFrom(const JSGlobalObject*) const { return true; }
231 
232         virtual bool isDynamicScope(bool& requiresDynamicChecks) const;
233 
234         void copyGlobalsFrom(RegisterFile&);
235         void copyGlobalsTo(RegisterFile&);
236         void resizeRegisters(int oldSize, int newSize);
237 
238         void resetPrototype(JSGlobalData&, JSValue prototype);
239 
globalData()240         JSGlobalData& globalData() const { return *m_globalData.get(); }
241 
createStructure(JSGlobalData & globalData,JSValue prototype)242         static Structure* createStructure(JSGlobalData& globalData, JSValue prototype)
243         {
244             return Structure::create(globalData, prototype, TypeInfo(ObjectType, StructureFlags), AnonymousSlotCount, &s_info);
245         }
246 
registerWeakMap(OpaqueJSWeakObjectMap * map)247         void registerWeakMap(OpaqueJSWeakObjectMap* map)
248         {
249             m_weakMaps.add(map);
250         }
251 
deregisterWeakMap(OpaqueJSWeakObjectMap * map)252         void deregisterWeakMap(OpaqueJSWeakObjectMap* map)
253         {
254             m_weakMaps.remove(map);
255         }
256 
weakRandomNumber()257         double weakRandomNumber() { return m_weakRandom.get(); }
258     protected:
259 
260         static const unsigned AnonymousSlotCount = JSVariableObject::AnonymousSlotCount + 1;
261         static const unsigned StructureFlags = OverridesGetOwnPropertySlot | OverridesMarkChildren | OverridesGetPropertyNames | JSVariableObject::StructureFlags;
262 
263         struct GlobalPropertyInfo {
GlobalPropertyInfoGlobalPropertyInfo264             GlobalPropertyInfo(const Identifier& i, JSValue v, unsigned a)
265                 : identifier(i)
266                 , value(v)
267                 , attributes(a)
268             {
269             }
270 
271             const Identifier identifier;
272             JSValue value;
273             unsigned attributes;
274         };
275         void addStaticGlobals(GlobalPropertyInfo*, int count);
276 
277     private:
278         // FIXME: Fold reset into init.
279         void init(JSObject* thisValue);
280         void reset(JSValue prototype);
281 
282         void setRegisters(WriteBarrier<Unknown>* registers, PassOwnArrayPtr<WriteBarrier<Unknown> > registerArray, size_t count);
283 
284         void* operator new(size_t); // can only be allocated with JSGlobalData
285     };
286 
287     JSGlobalObject* asGlobalObject(JSValue);
288 
asGlobalObject(JSValue value)289     inline JSGlobalObject* asGlobalObject(JSValue value)
290     {
291         ASSERT(asObject(value)->isGlobalObject());
292         return static_cast<JSGlobalObject*>(asObject(value));
293     }
294 
setRegisters(WriteBarrier<Unknown> * registers,PassOwnArrayPtr<WriteBarrier<Unknown>> registerArray,size_t count)295     inline void JSGlobalObject::setRegisters(WriteBarrier<Unknown>* registers, PassOwnArrayPtr<WriteBarrier<Unknown> > registerArray, size_t count)
296     {
297         JSVariableObject::setRegisters(registers, registerArray);
298         m_registerArraySize = count;
299     }
300 
addStaticGlobals(GlobalPropertyInfo * globals,int count)301     inline void JSGlobalObject::addStaticGlobals(GlobalPropertyInfo* globals, int count)
302     {
303         size_t oldSize = m_registerArraySize;
304         size_t newSize = oldSize + count;
305         OwnArrayPtr<WriteBarrier<Unknown> > registerArray = adoptArrayPtr(new WriteBarrier<Unknown>[newSize]);
306         if (m_registerArray) {
307             // memcpy is safe here as we're copying barriers we already own from the existing array
308             memcpy(registerArray.get() + count, m_registerArray.get(), oldSize * sizeof(Register));
309         }
310 
311         WriteBarrier<Unknown>* registers = registerArray.get() + newSize;
312         setRegisters(registers, registerArray.release(), newSize);
313 
314         for (int i = 0, index = -static_cast<int>(oldSize) - 1; i < count; ++i, --index) {
315             GlobalPropertyInfo& global = globals[i];
316             ASSERT(global.attributes & DontDelete);
317             SymbolTableEntry newEntry(index, global.attributes);
318             symbolTable().add(global.identifier.impl(), newEntry);
319             registerAt(index).set(globalData(), this, global.value);
320         }
321     }
322 
getOwnPropertySlot(ExecState * exec,const Identifier & propertyName,PropertySlot & slot)323     inline bool JSGlobalObject::getOwnPropertySlot(ExecState* exec, const Identifier& propertyName, PropertySlot& slot)
324     {
325         if (JSVariableObject::getOwnPropertySlot(exec, propertyName, slot))
326             return true;
327         return symbolTableGet(propertyName, slot);
328     }
329 
getOwnPropertyDescriptor(ExecState * exec,const Identifier & propertyName,PropertyDescriptor & descriptor)330     inline bool JSGlobalObject::getOwnPropertyDescriptor(ExecState* exec, const Identifier& propertyName, PropertyDescriptor& descriptor)
331     {
332         if (symbolTableGet(propertyName, descriptor))
333             return true;
334         return JSVariableObject::getOwnPropertyDescriptor(exec, propertyName, descriptor);
335     }
336 
hasOwnPropertyForWrite(ExecState * exec,const Identifier & propertyName)337     inline bool JSGlobalObject::hasOwnPropertyForWrite(ExecState* exec, const Identifier& propertyName)
338     {
339         PropertySlot slot;
340         if (JSVariableObject::getOwnPropertySlot(exec, propertyName, slot))
341             return true;
342         bool slotIsWriteable;
343         return symbolTableGet(propertyName, slot, slotIsWriteable);
344     }
345 
symbolTableHasProperty(const Identifier & propertyName)346     inline bool JSGlobalObject::symbolTableHasProperty(const Identifier& propertyName)
347     {
348         SymbolTableEntry entry = symbolTable().inlineGet(propertyName.impl());
349         return !entry.isNull();
350     }
351 
prototypeForLookup(ExecState * exec)352     inline JSValue Structure::prototypeForLookup(ExecState* exec) const
353     {
354         if (typeInfo().type() == ObjectType)
355             return m_prototype.get();
356 
357         ASSERT(typeInfo().type() == StringType);
358         return exec->lexicalGlobalObject()->stringPrototype();
359     }
360 
prototypeChain(ExecState * exec)361     inline StructureChain* Structure::prototypeChain(ExecState* exec) const
362     {
363         // We cache our prototype chain so our clients can share it.
364         if (!isValid(exec, m_cachedPrototypeChain.get())) {
365             JSValue prototype = prototypeForLookup(exec);
366             m_cachedPrototypeChain.set(exec->globalData(), this, StructureChain::create(exec->globalData(), prototype.isNull() ? 0 : asObject(prototype)->structure()));
367         }
368         return m_cachedPrototypeChain.get();
369     }
370 
isValid(ExecState * exec,StructureChain * cachedPrototypeChain)371     inline bool Structure::isValid(ExecState* exec, StructureChain* cachedPrototypeChain) const
372     {
373         if (!cachedPrototypeChain)
374             return false;
375 
376         JSValue prototype = prototypeForLookup(exec);
377         WriteBarrier<Structure>* cachedStructure = cachedPrototypeChain->head();
378         while(*cachedStructure && !prototype.isNull()) {
379             if (asObject(prototype)->structure() != cachedStructure->get())
380                 return false;
381             ++cachedStructure;
382             prototype = asObject(prototype)->prototype();
383         }
384         return prototype.isNull() && !*cachedStructure;
385     }
386 
dynamicGlobalObject()387     inline JSGlobalObject* ExecState::dynamicGlobalObject()
388     {
389         if (this == lexicalGlobalObject()->globalExec())
390             return lexicalGlobalObject();
391 
392         // For any ExecState that's not a globalExec, the
393         // dynamic global object must be set since code is running
394         ASSERT(globalData().dynamicGlobalObject);
395         return globalData().dynamicGlobalObject;
396     }
397 
constructEmptyObject(ExecState * exec,JSGlobalObject * globalObject)398     inline JSObject* constructEmptyObject(ExecState* exec, JSGlobalObject* globalObject)
399     {
400         return constructEmptyObject(exec, globalObject->emptyObjectStructure());
401     }
402 
constructEmptyObject(ExecState * exec)403     inline JSObject* constructEmptyObject(ExecState* exec)
404     {
405         return constructEmptyObject(exec, exec->lexicalGlobalObject());
406     }
407 
constructEmptyArray(ExecState * exec)408     inline JSArray* constructEmptyArray(ExecState* exec)
409     {
410         return new (exec) JSArray(exec->globalData(), exec->lexicalGlobalObject()->arrayStructure());
411     }
412 
constructEmptyArray(ExecState * exec,JSGlobalObject * globalObject)413     inline JSArray* constructEmptyArray(ExecState* exec, JSGlobalObject* globalObject)
414     {
415         return new (exec) JSArray(exec->globalData(), globalObject->arrayStructure());
416     }
417 
constructEmptyArray(ExecState * exec,unsigned initialLength)418     inline JSArray* constructEmptyArray(ExecState* exec, unsigned initialLength)
419     {
420         return new (exec) JSArray(exec->globalData(), exec->lexicalGlobalObject()->arrayStructure(), initialLength, CreateInitialized);
421     }
422 
constructArray(ExecState * exec,JSValue singleItemValue)423     inline JSArray* constructArray(ExecState* exec, JSValue singleItemValue)
424     {
425         MarkedArgumentBuffer values;
426         values.append(singleItemValue);
427         return new (exec) JSArray(exec->globalData(), exec->lexicalGlobalObject()->arrayStructure(), values);
428     }
429 
constructArray(ExecState * exec,const ArgList & values)430     inline JSArray* constructArray(ExecState* exec, const ArgList& values)
431     {
432         return new (exec) JSArray(exec->globalData(), exec->lexicalGlobalObject()->arrayStructure(), values);
433     }
434 
435     class DynamicGlobalObjectScope {
436         WTF_MAKE_NONCOPYABLE(DynamicGlobalObjectScope);
437     public:
438         DynamicGlobalObjectScope(JSGlobalData&, JSGlobalObject*);
439 
~DynamicGlobalObjectScope()440         ~DynamicGlobalObjectScope()
441         {
442             m_dynamicGlobalObjectSlot = m_savedDynamicGlobalObject;
443         }
444 
445     private:
446         JSGlobalObject*& m_dynamicGlobalObjectSlot;
447         JSGlobalObject* m_savedDynamicGlobalObject;
448     };
449 
450 } // namespace JSC
451 
452 #endif // JSGlobalObject_h
453