JavaScriptCore/runtime/JSGlobalObject.h
changeset 0 4f2f89ce4247
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/JavaScriptCore/runtime/JSGlobalObject.h	Fri Sep 17 09:02:29 2010 +0300
@@ -0,0 +1,502 @@
+/*
+ *  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>
+
+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)
+            {
+            }
+            
+            Destructor destructor;
+            
+            size_t registerArraySize;
+
+            JSGlobalObject* next;
+            JSGlobalObject* prev;
+
+            Debugger* debugger;
+            
+            ScopeChain globalScopeChain;
+            Register globalCallFrame[RegisterFile::CallFrameHeaderSize];
+
+            int recursion;
+
+            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;
+
+            SymbolTable symbolTable;
+            unsigned profileGroup;
+
+            RefPtr<JSGlobalData> globalData;
+
+            HashSet<GlobalCodeBlock*> codeBlocks;
+            WeakMapSet weakMaps;
+        };
+
+    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* 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; }
+        
+        int recursion() { return d()->recursion; }
+        void incRecursion() { ++d()->recursion; }
+        void decRecursion() { --d()->recursion; }
+        
+        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() { 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);
+        }
+
+    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.ustring().rep(), 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;
+
+#if USE(JSVALUE32)
+        if (typeInfo().type() == StringType)
+            return exec->lexicalGlobalObject()->stringPrototype();
+
+        ASSERT(typeInfo().type() == NumberType);
+        return exec->lexicalGlobalObject()->numberPrototype();
+#else
+        ASSERT(typeInfo().type() == StringType);
+        return exec->lexicalGlobalObject()->stringPrototype();
+#endif
+    }
+
+    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) 
+            : m_dynamicGlobalObjectSlot(callFrame->globalData().dynamicGlobalObject)
+            , m_savedDynamicGlobalObject(m_dynamicGlobalObjectSlot)
+        {
+            if (!m_dynamicGlobalObjectSlot) {
+                m_dynamicGlobalObjectSlot = dynamicGlobalObject;
+
+                // Reset the date cache between JS invocations to force the VM
+                // to observe time zone changes.
+                callFrame->globalData().resetDateCache();
+            }
+        }
+
+        ~DynamicGlobalObjectScope()
+        {
+            m_dynamicGlobalObjectSlot = m_savedDynamicGlobalObject;
+        }
+
+    private:
+        JSGlobalObject*& m_dynamicGlobalObjectSlot;
+        JSGlobalObject* m_savedDynamicGlobalObject;
+    };
+
+} // namespace JSC
+
+#endif // JSGlobalObject_h