diff options
Diffstat (limited to 'Source/JavaScriptCore/runtime/JSGlobalObject.h')
-rw-r--r-- | Source/JavaScriptCore/runtime/JSGlobalObject.h | 484 |
1 files changed, 484 insertions, 0 deletions
diff --git a/Source/JavaScriptCore/runtime/JSGlobalObject.h b/Source/JavaScriptCore/runtime/JSGlobalObject.h new file mode 100644 index 0000000..a22b0aa --- /dev/null +++ b/Source/JavaScriptCore/runtime/JSGlobalObject.h @@ -0,0 +1,484 @@ +/* + * Copyright (C) 2007 Eric Seidel <eric@webkit.org> + * Copyright (C) 2007, 2008, 2009 Apple Inc. All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + * + */ + +#ifndef JSGlobalObject_h +#define JSGlobalObject_h + +#include "JSArray.h" +#include "JSGlobalData.h" +#include "JSVariableObject.h" +#include "JSWeakObjectMapRefInternal.h" +#include "NativeFunctionWrapper.h" +#include "NumberPrototype.h" +#include "StringPrototype.h" +#include <wtf/HashSet.h> +#include <wtf/OwnPtr.h> +#include <wtf/RandomNumber.h> + +namespace JSC { + + class ArrayPrototype; + class BooleanPrototype; + class DatePrototype; + class Debugger; + class ErrorConstructor; + class FunctionPrototype; + class GlobalCodeBlock; + class GlobalEvalFunction; + class NativeErrorConstructor; + class ProgramCodeBlock; + class PrototypeFunction; + class RegExpConstructor; + class RegExpPrototype; + class RegisterFile; + + struct ActivationStackNode; + struct HashTable; + + typedef Vector<ExecState*, 16> ExecStateStack; + + class JSGlobalObject : public JSVariableObject { + protected: + using JSVariableObject::JSVariableObjectData; + typedef HashSet<RefPtr<OpaqueJSWeakObjectMap> > WeakMapSet; + + struct JSGlobalObjectData : public JSVariableObjectData { + // We use an explicit destructor function pointer instead of a + // virtual destructor because we want to avoid adding a vtable + // pointer to this struct. Adding a vtable pointer would force the + // compiler to emit costly pointer fixup code when casting from + // JSVariableObjectData* to JSGlobalObjectData*. + typedef void (*Destructor)(void*); + + JSGlobalObjectData(Destructor destructor) + : JSVariableObjectData(&symbolTable, 0) + , destructor(destructor) + , registerArraySize(0) + , globalScopeChain(NoScopeChain()) + , regExpConstructor(0) + , errorConstructor(0) + , evalErrorConstructor(0) + , rangeErrorConstructor(0) + , referenceErrorConstructor(0) + , syntaxErrorConstructor(0) + , typeErrorConstructor(0) + , URIErrorConstructor(0) + , evalFunction(0) + , callFunction(0) + , applyFunction(0) + , objectPrototype(0) + , functionPrototype(0) + , arrayPrototype(0) + , booleanPrototype(0) + , stringPrototype(0) + , numberPrototype(0) + , datePrototype(0) + , regExpPrototype(0) + , methodCallDummy(0) + , weakRandom(static_cast<unsigned>(randomNumber() * (std::numeric_limits<unsigned>::max() + 1.0))) + { + } + + Destructor destructor; + + size_t registerArraySize; + + JSGlobalObject* next; + JSGlobalObject* prev; + + Debugger* debugger; + + ScopeChain globalScopeChain; + Register globalCallFrame[RegisterFile::CallFrameHeaderSize]; + + RegExpConstructor* regExpConstructor; + ErrorConstructor* errorConstructor; + NativeErrorConstructor* evalErrorConstructor; + NativeErrorConstructor* rangeErrorConstructor; + NativeErrorConstructor* referenceErrorConstructor; + NativeErrorConstructor* syntaxErrorConstructor; + NativeErrorConstructor* typeErrorConstructor; + NativeErrorConstructor* URIErrorConstructor; + + GlobalEvalFunction* evalFunction; + NativeFunctionWrapper* callFunction; + NativeFunctionWrapper* applyFunction; + + ObjectPrototype* objectPrototype; + FunctionPrototype* functionPrototype; + ArrayPrototype* arrayPrototype; + BooleanPrototype* booleanPrototype; + StringPrototype* stringPrototype; + NumberPrototype* numberPrototype; + DatePrototype* datePrototype; + RegExpPrototype* regExpPrototype; + + JSObject* methodCallDummy; + + RefPtr<Structure> argumentsStructure; + RefPtr<Structure> arrayStructure; + RefPtr<Structure> booleanObjectStructure; + RefPtr<Structure> callbackConstructorStructure; + RefPtr<Structure> callbackFunctionStructure; + RefPtr<Structure> callbackObjectStructure; + RefPtr<Structure> dateStructure; + RefPtr<Structure> emptyObjectStructure; + RefPtr<Structure> errorStructure; + RefPtr<Structure> functionStructure; + RefPtr<Structure> numberObjectStructure; + RefPtr<Structure> prototypeFunctionStructure; + RefPtr<Structure> regExpMatchesArrayStructure; + RefPtr<Structure> regExpStructure; + RefPtr<Structure> stringObjectStructure; + RefPtr<Structure> internalFunctionStructure; + + SymbolTable symbolTable; + unsigned profileGroup; + + RefPtr<JSGlobalData> globalData; + + HashSet<GlobalCodeBlock*> codeBlocks; + WeakMapSet weakMaps; + WeakRandom weakRandom; + }; + + public: + void* operator new(size_t, JSGlobalData*); + + explicit JSGlobalObject() + : JSVariableObject(JSGlobalObject::createStructure(jsNull()), new JSGlobalObjectData(destroyJSGlobalObjectData)) + { + COMPILE_ASSERT(JSGlobalObject::AnonymousSlotCount == 1, JSGlobalObject_has_only_a_single_slot); + putAnonymousValue(0, this); + init(this); + } + + explicit JSGlobalObject(NonNullPassRefPtr<Structure> structure) + : JSVariableObject(structure, new JSGlobalObjectData(destroyJSGlobalObjectData)) + { + COMPILE_ASSERT(JSGlobalObject::AnonymousSlotCount == 1, JSGlobalObject_has_only_a_single_slot); + putAnonymousValue(0, this); + init(this); + } + + protected: + JSGlobalObject(NonNullPassRefPtr<Structure> structure, JSGlobalObjectData* data, JSObject* thisValue) + : JSVariableObject(structure, data) + { + COMPILE_ASSERT(JSGlobalObject::AnonymousSlotCount == 1, JSGlobalObject_has_only_a_single_slot); + putAnonymousValue(0, this); + init(thisValue); + } + + public: + virtual ~JSGlobalObject(); + + virtual void markChildren(MarkStack&); + + virtual bool getOwnPropertySlot(ExecState*, const Identifier&, PropertySlot&); + virtual bool getOwnPropertyDescriptor(ExecState*, const Identifier&, PropertyDescriptor&); + virtual bool hasOwnPropertyForWrite(ExecState*, const Identifier&); + virtual void put(ExecState*, const Identifier&, JSValue, PutPropertySlot&); + virtual void putWithAttributes(ExecState*, const Identifier& propertyName, JSValue value, unsigned attributes); + + virtual void defineGetter(ExecState*, const Identifier& propertyName, JSObject* getterFunc, unsigned attributes); + virtual void defineSetter(ExecState*, const Identifier& propertyName, JSObject* setterFunc, unsigned attributes); + + // Linked list of all global objects that use the same JSGlobalData. + JSGlobalObject*& head() { return d()->globalData->head; } + JSGlobalObject* next() { return d()->next; } + + // The following accessors return pristine values, even if a script + // replaces the global object's associated property. + + RegExpConstructor* regExpConstructor() const { return d()->regExpConstructor; } + + ErrorConstructor* errorConstructor() const { return d()->errorConstructor; } + NativeErrorConstructor* evalErrorConstructor() const { return d()->evalErrorConstructor; } + NativeErrorConstructor* rangeErrorConstructor() const { return d()->rangeErrorConstructor; } + NativeErrorConstructor* referenceErrorConstructor() const { return d()->referenceErrorConstructor; } + NativeErrorConstructor* syntaxErrorConstructor() const { return d()->syntaxErrorConstructor; } + NativeErrorConstructor* typeErrorConstructor() const { return d()->typeErrorConstructor; } + NativeErrorConstructor* URIErrorConstructor() const { return d()->URIErrorConstructor; } + + GlobalEvalFunction* evalFunction() const { return d()->evalFunction; } + + ObjectPrototype* objectPrototype() const { return d()->objectPrototype; } + FunctionPrototype* functionPrototype() const { return d()->functionPrototype; } + ArrayPrototype* arrayPrototype() const { return d()->arrayPrototype; } + BooleanPrototype* booleanPrototype() const { return d()->booleanPrototype; } + StringPrototype* stringPrototype() const { return d()->stringPrototype; } + NumberPrototype* numberPrototype() const { return d()->numberPrototype; } + DatePrototype* datePrototype() const { return d()->datePrototype; } + RegExpPrototype* regExpPrototype() const { return d()->regExpPrototype; } + + JSObject* methodCallDummy() const { return d()->methodCallDummy; } + + Structure* argumentsStructure() const { return d()->argumentsStructure.get(); } + Structure* arrayStructure() const { return d()->arrayStructure.get(); } + Structure* booleanObjectStructure() const { return d()->booleanObjectStructure.get(); } + Structure* callbackConstructorStructure() const { return d()->callbackConstructorStructure.get(); } + Structure* callbackFunctionStructure() const { return d()->callbackFunctionStructure.get(); } + Structure* callbackObjectStructure() const { return d()->callbackObjectStructure.get(); } + Structure* dateStructure() const { return d()->dateStructure.get(); } + Structure* emptyObjectStructure() const { return d()->emptyObjectStructure.get(); } + Structure* errorStructure() const { return d()->errorStructure.get(); } + Structure* functionStructure() const { return d()->functionStructure.get(); } + Structure* numberObjectStructure() const { return d()->numberObjectStructure.get(); } + Structure* prototypeFunctionStructure() const { return d()->prototypeFunctionStructure.get(); } + Structure* internalFunctionStructure() const { return d()->internalFunctionStructure.get(); } + Structure* regExpMatchesArrayStructure() const { return d()->regExpMatchesArrayStructure.get(); } + Structure* regExpStructure() const { return d()->regExpStructure.get(); } + Structure* stringObjectStructure() const { return d()->stringObjectStructure.get(); } + + void setProfileGroup(unsigned value) { d()->profileGroup = value; } + unsigned profileGroup() const { return d()->profileGroup; } + + Debugger* debugger() const { return d()->debugger; } + void setDebugger(Debugger* debugger) { d()->debugger = debugger; } + + virtual bool supportsProfiling() const { return false; } + virtual bool supportsRichSourceInfo() const { return true; } + + ScopeChain& globalScopeChain() { return d()->globalScopeChain; } + + virtual bool isGlobalObject() const { return true; } + + virtual ExecState* globalExec(); + + virtual bool shouldInterruptScript() const { return true; } + + virtual bool allowsAccessFrom(const JSGlobalObject*) const { return true; } + + virtual bool isDynamicScope(bool& requiresDynamicChecks) const; + + HashSet<GlobalCodeBlock*>& codeBlocks() { return d()->codeBlocks; } + + void copyGlobalsFrom(RegisterFile&); + void copyGlobalsTo(RegisterFile&); + + void resetPrototype(JSValue prototype); + + JSGlobalData& globalData() const { return *d()->globalData.get(); } + JSGlobalObjectData* d() const { return static_cast<JSGlobalObjectData*>(JSVariableObject::d); } + + static PassRefPtr<Structure> createStructure(JSValue prototype) + { + return Structure::create(prototype, TypeInfo(ObjectType, StructureFlags), AnonymousSlotCount); + } + + void registerWeakMap(OpaqueJSWeakObjectMap* map) + { + d()->weakMaps.add(map); + } + + void deregisterWeakMap(OpaqueJSWeakObjectMap* map) + { + d()->weakMaps.remove(map); + } + + double weakRandomNumber() { return d()->weakRandom.get(); } + protected: + + static const unsigned AnonymousSlotCount = JSVariableObject::AnonymousSlotCount + 1; + static const unsigned StructureFlags = OverridesGetOwnPropertySlot | OverridesMarkChildren | OverridesGetPropertyNames | JSVariableObject::StructureFlags; + + struct GlobalPropertyInfo { + GlobalPropertyInfo(const Identifier& i, JSValue v, unsigned a) + : identifier(i) + , value(v) + , attributes(a) + { + } + + const Identifier identifier; + JSValue value; + unsigned attributes; + }; + void addStaticGlobals(GlobalPropertyInfo*, int count); + + private: + static void destroyJSGlobalObjectData(void*); + + // FIXME: Fold reset into init. + void init(JSObject* thisValue); + void reset(JSValue prototype); + + void setRegisters(Register* registers, Register* registerArray, size_t count); + + void* operator new(size_t); // can only be allocated with JSGlobalData + }; + + JSGlobalObject* asGlobalObject(JSValue); + + inline JSGlobalObject* asGlobalObject(JSValue value) + { + ASSERT(asObject(value)->isGlobalObject()); + return static_cast<JSGlobalObject*>(asObject(value)); + } + + inline void JSGlobalObject::setRegisters(Register* registers, Register* registerArray, size_t count) + { + JSVariableObject::setRegisters(registers, registerArray); + d()->registerArraySize = count; + } + + inline void JSGlobalObject::addStaticGlobals(GlobalPropertyInfo* globals, int count) + { + size_t oldSize = d()->registerArraySize; + size_t newSize = oldSize + count; + Register* registerArray = new Register[newSize]; + if (d()->registerArray) + memcpy(registerArray + count, d()->registerArray.get(), oldSize * sizeof(Register)); + setRegisters(registerArray + newSize, registerArray, newSize); + + for (int i = 0, index = -static_cast<int>(oldSize) - 1; i < count; ++i, --index) { + GlobalPropertyInfo& global = globals[i]; + ASSERT(global.attributes & DontDelete); + SymbolTableEntry newEntry(index, global.attributes); + symbolTable().add(global.identifier.impl(), newEntry); + registerAt(index) = global.value; + } + } + + inline bool JSGlobalObject::getOwnPropertySlot(ExecState* exec, const Identifier& propertyName, PropertySlot& slot) + { + if (JSVariableObject::getOwnPropertySlot(exec, propertyName, slot)) + return true; + return symbolTableGet(propertyName, slot); + } + + inline bool JSGlobalObject::getOwnPropertyDescriptor(ExecState* exec, const Identifier& propertyName, PropertyDescriptor& descriptor) + { + if (symbolTableGet(propertyName, descriptor)) + return true; + return JSVariableObject::getOwnPropertyDescriptor(exec, propertyName, descriptor); + } + + inline bool JSGlobalObject::hasOwnPropertyForWrite(ExecState* exec, const Identifier& propertyName) + { + PropertySlot slot; + if (JSVariableObject::getOwnPropertySlot(exec, propertyName, slot)) + return true; + bool slotIsWriteable; + return symbolTableGet(propertyName, slot, slotIsWriteable); + } + + inline JSValue Structure::prototypeForLookup(ExecState* exec) const + { + if (typeInfo().type() == ObjectType) + return m_prototype; + + ASSERT(typeInfo().type() == StringType); + return exec->lexicalGlobalObject()->stringPrototype(); + } + + inline StructureChain* Structure::prototypeChain(ExecState* exec) const + { + // We cache our prototype chain so our clients can share it. + if (!isValid(exec, m_cachedPrototypeChain.get())) { + JSValue prototype = prototypeForLookup(exec); + m_cachedPrototypeChain = StructureChain::create(prototype.isNull() ? 0 : asObject(prototype)->structure()); + } + return m_cachedPrototypeChain.get(); + } + + inline bool Structure::isValid(ExecState* exec, StructureChain* cachedPrototypeChain) const + { + if (!cachedPrototypeChain) + return false; + + JSValue prototype = prototypeForLookup(exec); + RefPtr<Structure>* cachedStructure = cachedPrototypeChain->head(); + while(*cachedStructure && !prototype.isNull()) { + if (asObject(prototype)->structure() != *cachedStructure) + return false; + ++cachedStructure; + prototype = asObject(prototype)->prototype(); + } + return prototype.isNull() && !*cachedStructure; + } + + inline JSGlobalObject* ExecState::dynamicGlobalObject() + { + if (this == lexicalGlobalObject()->globalExec()) + return lexicalGlobalObject(); + + // For any ExecState that's not a globalExec, the + // dynamic global object must be set since code is running + ASSERT(globalData().dynamicGlobalObject); + return globalData().dynamicGlobalObject; + } + + inline JSObject* constructEmptyObject(ExecState* exec) + { + return new (exec) JSObject(exec->lexicalGlobalObject()->emptyObjectStructure()); + } + + inline JSObject* constructEmptyObject(ExecState* exec, JSGlobalObject* globalObject) + { + return new (exec) JSObject(globalObject->emptyObjectStructure()); + } + + inline JSArray* constructEmptyArray(ExecState* exec) + { + return new (exec) JSArray(exec->lexicalGlobalObject()->arrayStructure()); + } + + inline JSArray* constructEmptyArray(ExecState* exec, JSGlobalObject* globalObject) + { + return new (exec) JSArray(globalObject->arrayStructure()); + } + + inline JSArray* constructEmptyArray(ExecState* exec, unsigned initialLength) + { + return new (exec) JSArray(exec->lexicalGlobalObject()->arrayStructure(), initialLength, CreateInitialized); + } + + inline JSArray* constructArray(ExecState* exec, JSValue singleItemValue) + { + MarkedArgumentBuffer values; + values.append(singleItemValue); + return new (exec) JSArray(exec->lexicalGlobalObject()->arrayStructure(), values); + } + + inline JSArray* constructArray(ExecState* exec, const ArgList& values) + { + return new (exec) JSArray(exec->lexicalGlobalObject()->arrayStructure(), values); + } + + class DynamicGlobalObjectScope : public Noncopyable { + public: + DynamicGlobalObjectScope(CallFrame* callFrame, JSGlobalObject* dynamicGlobalObject); + + ~DynamicGlobalObjectScope() + { + m_dynamicGlobalObjectSlot = m_savedDynamicGlobalObject; + } + + private: + JSGlobalObject*& m_dynamicGlobalObjectSlot; + JSGlobalObject* m_savedDynamicGlobalObject; + }; + +} // namespace JSC + +#endif // JSGlobalObject_h |