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