2 * Copyright (C) 2007 Eric Seidel <eric@webkit.org>
3 * Copyright (C) 2007, 2008, 2009 Apple Inc. All rights reserved.
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.
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.
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.
22 #ifndef JSGlobalObject_h
23 #define JSGlobalObject_h
26 #include "JSGlobalData.h"
27 #include "JSVariableObject.h"
28 #include "JSWeakObjectMapRefInternal.h"
29 #include "NativeFunctionWrapper.h"
30 #include "NumberPrototype.h"
31 #include "StringPrototype.h"
32 #include <wtf/HashSet.h>
33 #include <wtf/OwnPtr.h>
34 #include <wtf/RandomNumber.h>
39 class BooleanPrototype;
42 class ErrorConstructor;
43 class FunctionPrototype;
44 class GlobalCodeBlock;
45 class GlobalEvalFunction;
46 class NativeErrorConstructor;
47 class ProgramCodeBlock;
48 class PrototypeFunction;
49 class RegExpConstructor;
50 class RegExpPrototype;
53 struct ActivationStackNode;
56 typedef Vector<ExecState*, 16> ExecStateStack;
58 class JSGlobalObject : public JSVariableObject {
60 using JSVariableObject::JSVariableObjectData;
61 typedef HashSet<RefPtr<OpaqueJSWeakObjectMap> > WeakMapSet;
63 struct JSGlobalObjectData : public JSVariableObjectData {
64 // We use an explicit destructor function pointer instead of a
65 // virtual destructor because we want to avoid adding a vtable
66 // pointer to this struct. Adding a vtable pointer would force the
67 // compiler to emit costly pointer fixup code when casting from
68 // JSVariableObjectData* to JSGlobalObjectData*.
69 typedef void (*Destructor)(void*);
71 JSGlobalObjectData(Destructor destructor)
72 : JSVariableObjectData(&symbolTable, 0)
73 , destructor(destructor)
74 , registerArraySize(0)
75 , globalScopeChain(NoScopeChain())
76 , regExpConstructor(0)
78 , evalErrorConstructor(0)
79 , rangeErrorConstructor(0)
80 , referenceErrorConstructor(0)
81 , syntaxErrorConstructor(0)
82 , typeErrorConstructor(0)
83 , URIErrorConstructor(0)
88 , functionPrototype(0)
96 , weakRandom(static_cast<unsigned>(randomNumber() * (std::numeric_limits<unsigned>::max() + 1.0)))
100 Destructor destructor;
102 size_t registerArraySize;
104 JSGlobalObject* next;
105 JSGlobalObject* prev;
109 ScopeChain globalScopeChain;
110 Register globalCallFrame[RegisterFile::CallFrameHeaderSize];
112 RegExpConstructor* regExpConstructor;
113 ErrorConstructor* errorConstructor;
114 NativeErrorConstructor* evalErrorConstructor;
115 NativeErrorConstructor* rangeErrorConstructor;
116 NativeErrorConstructor* referenceErrorConstructor;
117 NativeErrorConstructor* syntaxErrorConstructor;
118 NativeErrorConstructor* typeErrorConstructor;
119 NativeErrorConstructor* URIErrorConstructor;
121 GlobalEvalFunction* evalFunction;
122 NativeFunctionWrapper* callFunction;
123 NativeFunctionWrapper* applyFunction;
125 ObjectPrototype* objectPrototype;
126 FunctionPrototype* functionPrototype;
127 ArrayPrototype* arrayPrototype;
128 BooleanPrototype* booleanPrototype;
129 StringPrototype* stringPrototype;
130 NumberPrototype* numberPrototype;
131 DatePrototype* datePrototype;
132 RegExpPrototype* regExpPrototype;
134 JSObject* methodCallDummy;
136 RefPtr<Structure> argumentsStructure;
137 RefPtr<Structure> arrayStructure;
138 RefPtr<Structure> booleanObjectStructure;
139 RefPtr<Structure> callbackConstructorStructure;
140 RefPtr<Structure> callbackFunctionStructure;
141 RefPtr<Structure> callbackObjectStructure;
142 RefPtr<Structure> dateStructure;
143 RefPtr<Structure> emptyObjectStructure;
144 RefPtr<Structure> errorStructure;
145 RefPtr<Structure> functionStructure;
146 RefPtr<Structure> numberObjectStructure;
147 RefPtr<Structure> prototypeFunctionStructure;
148 RefPtr<Structure> regExpMatchesArrayStructure;
149 RefPtr<Structure> regExpStructure;
150 RefPtr<Structure> stringObjectStructure;
151 RefPtr<Structure> internalFunctionStructure;
153 SymbolTable symbolTable;
154 unsigned profileGroup;
156 RefPtr<JSGlobalData> globalData;
158 HashSet<GlobalCodeBlock*> codeBlocks;
160 WeakRandom weakRandom;
164 void* operator new(size_t, JSGlobalData*);
166 explicit JSGlobalObject()
167 : JSVariableObject(JSGlobalObject::createStructure(jsNull()), new JSGlobalObjectData(destroyJSGlobalObjectData))
169 COMPILE_ASSERT(JSGlobalObject::AnonymousSlotCount == 1, JSGlobalObject_has_only_a_single_slot);
170 putAnonymousValue(0, this);
174 explicit JSGlobalObject(NonNullPassRefPtr<Structure> structure)
175 : JSVariableObject(structure, new JSGlobalObjectData(destroyJSGlobalObjectData))
177 COMPILE_ASSERT(JSGlobalObject::AnonymousSlotCount == 1, JSGlobalObject_has_only_a_single_slot);
178 putAnonymousValue(0, this);
183 JSGlobalObject(NonNullPassRefPtr<Structure> structure, JSGlobalObjectData* data, JSObject* thisValue)
184 : JSVariableObject(structure, data)
186 COMPILE_ASSERT(JSGlobalObject::AnonymousSlotCount == 1, JSGlobalObject_has_only_a_single_slot);
187 putAnonymousValue(0, this);
192 virtual ~JSGlobalObject();
194 virtual void markChildren(MarkStack&);
196 virtual bool getOwnPropertySlot(ExecState*, const Identifier&, PropertySlot&);
197 virtual bool getOwnPropertyDescriptor(ExecState*, const Identifier&, PropertyDescriptor&);
198 virtual bool hasOwnPropertyForWrite(ExecState*, const Identifier&);
199 virtual void put(ExecState*, const Identifier&, JSValue, PutPropertySlot&);
200 virtual void putWithAttributes(ExecState*, const Identifier& propertyName, JSValue value, unsigned attributes);
202 virtual void defineGetter(ExecState*, const Identifier& propertyName, JSObject* getterFunc, unsigned attributes);
203 virtual void defineSetter(ExecState*, const Identifier& propertyName, JSObject* setterFunc, unsigned attributes);
205 // Linked list of all global objects that use the same JSGlobalData.
206 JSGlobalObject*& head() { return d()->globalData->head; }
207 JSGlobalObject* next() { return d()->next; }
209 // The following accessors return pristine values, even if a script
210 // replaces the global object's associated property.
212 RegExpConstructor* regExpConstructor() const { return d()->regExpConstructor; }
214 ErrorConstructor* errorConstructor() const { return d()->errorConstructor; }
215 NativeErrorConstructor* evalErrorConstructor() const { return d()->evalErrorConstructor; }
216 NativeErrorConstructor* rangeErrorConstructor() const { return d()->rangeErrorConstructor; }
217 NativeErrorConstructor* referenceErrorConstructor() const { return d()->referenceErrorConstructor; }
218 NativeErrorConstructor* syntaxErrorConstructor() const { return d()->syntaxErrorConstructor; }
219 NativeErrorConstructor* typeErrorConstructor() const { return d()->typeErrorConstructor; }
220 NativeErrorConstructor* URIErrorConstructor() const { return d()->URIErrorConstructor; }
222 GlobalEvalFunction* evalFunction() const { return d()->evalFunction; }
224 ObjectPrototype* objectPrototype() const { return d()->objectPrototype; }
225 FunctionPrototype* functionPrototype() const { return d()->functionPrototype; }
226 ArrayPrototype* arrayPrototype() const { return d()->arrayPrototype; }
227 BooleanPrototype* booleanPrototype() const { return d()->booleanPrototype; }
228 StringPrototype* stringPrototype() const { return d()->stringPrototype; }
229 NumberPrototype* numberPrototype() const { return d()->numberPrototype; }
230 DatePrototype* datePrototype() const { return d()->datePrototype; }
231 RegExpPrototype* regExpPrototype() const { return d()->regExpPrototype; }
233 JSObject* methodCallDummy() const { return d()->methodCallDummy; }
235 Structure* argumentsStructure() const { return d()->argumentsStructure.get(); }
236 Structure* arrayStructure() const { return d()->arrayStructure.get(); }
237 Structure* booleanObjectStructure() const { return d()->booleanObjectStructure.get(); }
238 Structure* callbackConstructorStructure() const { return d()->callbackConstructorStructure.get(); }
239 Structure* callbackFunctionStructure() const { return d()->callbackFunctionStructure.get(); }
240 Structure* callbackObjectStructure() const { return d()->callbackObjectStructure.get(); }
241 Structure* dateStructure() const { return d()->dateStructure.get(); }
242 Structure* emptyObjectStructure() const { return d()->emptyObjectStructure.get(); }
243 Structure* errorStructure() const { return d()->errorStructure.get(); }
244 Structure* functionStructure() const { return d()->functionStructure.get(); }
245 Structure* numberObjectStructure() const { return d()->numberObjectStructure.get(); }
246 Structure* prototypeFunctionStructure() const { return d()->prototypeFunctionStructure.get(); }
247 Structure* internalFunctionStructure() const { return d()->internalFunctionStructure.get(); }
248 Structure* regExpMatchesArrayStructure() const { return d()->regExpMatchesArrayStructure.get(); }
249 Structure* regExpStructure() const { return d()->regExpStructure.get(); }
250 Structure* stringObjectStructure() const { return d()->stringObjectStructure.get(); }
252 void setProfileGroup(unsigned value) { d()->profileGroup = value; }
253 unsigned profileGroup() const { return d()->profileGroup; }
255 Debugger* debugger() const { return d()->debugger; }
256 void setDebugger(Debugger* debugger) { d()->debugger = debugger; }
258 virtual bool supportsProfiling() const { return false; }
259 virtual bool supportsRichSourceInfo() const { return true; }
261 ScopeChain& globalScopeChain() { return d()->globalScopeChain; }
263 virtual bool isGlobalObject() const { return true; }
265 virtual ExecState* globalExec();
267 virtual bool shouldInterruptScript() const { return true; }
269 virtual bool allowsAccessFrom(const JSGlobalObject*) const { return true; }
271 virtual bool isDynamicScope(bool& requiresDynamicChecks) const;
273 HashSet<GlobalCodeBlock*>& codeBlocks() { return d()->codeBlocks; }
275 void copyGlobalsFrom(RegisterFile&);
276 void copyGlobalsTo(RegisterFile&);
278 void resetPrototype(JSValue prototype);
280 JSGlobalData& globalData() const { return *d()->globalData.get(); }
281 JSGlobalObjectData* d() const { return static_cast<JSGlobalObjectData*>(JSVariableObject::d); }
283 static PassRefPtr<Structure> createStructure(JSValue prototype)
285 return Structure::create(prototype, TypeInfo(ObjectType, StructureFlags), AnonymousSlotCount);
288 void registerWeakMap(OpaqueJSWeakObjectMap* map)
290 d()->weakMaps.add(map);
293 void deregisterWeakMap(OpaqueJSWeakObjectMap* map)
295 d()->weakMaps.remove(map);
298 double weakRandomNumber() { return d()->weakRandom.get(); }
301 static const unsigned AnonymousSlotCount = JSVariableObject::AnonymousSlotCount + 1;
302 static const unsigned StructureFlags = OverridesGetOwnPropertySlot | OverridesMarkChildren | OverridesGetPropertyNames | JSVariableObject::StructureFlags;
304 struct GlobalPropertyInfo {
305 GlobalPropertyInfo(const Identifier& i, JSValue v, unsigned a)
312 const Identifier identifier;
316 void addStaticGlobals(GlobalPropertyInfo*, int count);
319 static void destroyJSGlobalObjectData(void*);
321 // FIXME: Fold reset into init.
322 void init(JSObject* thisValue);
323 void reset(JSValue prototype);
325 void setRegisters(Register* registers, Register* registerArray, size_t count);
327 void* operator new(size_t); // can only be allocated with JSGlobalData
330 JSGlobalObject* asGlobalObject(JSValue);
332 inline JSGlobalObject* asGlobalObject(JSValue value)
334 ASSERT(asObject(value)->isGlobalObject());
335 return static_cast<JSGlobalObject*>(asObject(value));
338 inline void JSGlobalObject::setRegisters(Register* registers, Register* registerArray, size_t count)
340 JSVariableObject::setRegisters(registers, registerArray);
341 d()->registerArraySize = count;
344 inline void JSGlobalObject::addStaticGlobals(GlobalPropertyInfo* globals, int count)
346 size_t oldSize = d()->registerArraySize;
347 size_t newSize = oldSize + count;
348 Register* registerArray = new Register[newSize];
349 if (d()->registerArray)
350 memcpy(registerArray + count, d()->registerArray.get(), oldSize * sizeof(Register));
351 setRegisters(registerArray + newSize, registerArray, newSize);
353 for (int i = 0, index = -static_cast<int>(oldSize) - 1; i < count; ++i, --index) {
354 GlobalPropertyInfo& global = globals[i];
355 ASSERT(global.attributes & DontDelete);
356 SymbolTableEntry newEntry(index, global.attributes);
357 symbolTable().add(global.identifier.impl(), newEntry);
358 registerAt(index) = global.value;
362 inline bool JSGlobalObject::getOwnPropertySlot(ExecState* exec, const Identifier& propertyName, PropertySlot& slot)
364 if (JSVariableObject::getOwnPropertySlot(exec, propertyName, slot))
366 return symbolTableGet(propertyName, slot);
369 inline bool JSGlobalObject::getOwnPropertyDescriptor(ExecState* exec, const Identifier& propertyName, PropertyDescriptor& descriptor)
371 if (symbolTableGet(propertyName, descriptor))
373 return JSVariableObject::getOwnPropertyDescriptor(exec, propertyName, descriptor);
376 inline bool JSGlobalObject::hasOwnPropertyForWrite(ExecState* exec, const Identifier& propertyName)
379 if (JSVariableObject::getOwnPropertySlot(exec, propertyName, slot))
381 bool slotIsWriteable;
382 return symbolTableGet(propertyName, slot, slotIsWriteable);
385 inline JSValue Structure::prototypeForLookup(ExecState* exec) const
387 if (typeInfo().type() == ObjectType)
390 ASSERT(typeInfo().type() == StringType);
391 return exec->lexicalGlobalObject()->stringPrototype();
394 inline StructureChain* Structure::prototypeChain(ExecState* exec) const
396 // We cache our prototype chain so our clients can share it.
397 if (!isValid(exec, m_cachedPrototypeChain.get())) {
398 JSValue prototype = prototypeForLookup(exec);
399 m_cachedPrototypeChain = StructureChain::create(prototype.isNull() ? 0 : asObject(prototype)->structure());
401 return m_cachedPrototypeChain.get();
404 inline bool Structure::isValid(ExecState* exec, StructureChain* cachedPrototypeChain) const
406 if (!cachedPrototypeChain)
409 JSValue prototype = prototypeForLookup(exec);
410 RefPtr<Structure>* cachedStructure = cachedPrototypeChain->head();
411 while(*cachedStructure && !prototype.isNull()) {
412 if (asObject(prototype)->structure() != *cachedStructure)
415 prototype = asObject(prototype)->prototype();
417 return prototype.isNull() && !*cachedStructure;
420 inline JSGlobalObject* ExecState::dynamicGlobalObject()
422 if (this == lexicalGlobalObject()->globalExec())
423 return lexicalGlobalObject();
425 // For any ExecState that's not a globalExec, the
426 // dynamic global object must be set since code is running
427 ASSERT(globalData().dynamicGlobalObject);
428 return globalData().dynamicGlobalObject;
431 inline JSObject* constructEmptyObject(ExecState* exec)
433 return new (exec) JSObject(exec->lexicalGlobalObject()->emptyObjectStructure());
436 inline JSObject* constructEmptyObject(ExecState* exec, JSGlobalObject* globalObject)
438 return new (exec) JSObject(globalObject->emptyObjectStructure());
441 inline JSArray* constructEmptyArray(ExecState* exec)
443 return new (exec) JSArray(exec->lexicalGlobalObject()->arrayStructure());
446 inline JSArray* constructEmptyArray(ExecState* exec, JSGlobalObject* globalObject)
448 return new (exec) JSArray(globalObject->arrayStructure());
451 inline JSArray* constructEmptyArray(ExecState* exec, unsigned initialLength)
453 return new (exec) JSArray(exec->lexicalGlobalObject()->arrayStructure(), initialLength, CreateInitialized);
456 inline JSArray* constructArray(ExecState* exec, JSValue singleItemValue)
458 MarkedArgumentBuffer values;
459 values.append(singleItemValue);
460 return new (exec) JSArray(exec->lexicalGlobalObject()->arrayStructure(), values);
463 inline JSArray* constructArray(ExecState* exec, const ArgList& values)
465 return new (exec) JSArray(exec->lexicalGlobalObject()->arrayStructure(), values);
468 class DynamicGlobalObjectScope {
469 WTF_MAKE_NONCOPYABLE(DynamicGlobalObjectScope);
471 DynamicGlobalObjectScope(CallFrame* callFrame, JSGlobalObject* dynamicGlobalObject);
473 ~DynamicGlobalObjectScope()
475 m_dynamicGlobalObjectSlot = m_savedDynamicGlobalObject;
479 JSGlobalObject*& m_dynamicGlobalObjectSlot;
480 JSGlobalObject* m_savedDynamicGlobalObject;
485 #endif // JSGlobalObject_h