Home | History | Annotate | Download | only in runtime
      1 /*
      2  *  Copyright (C) 2007 Eric Seidel <eric (at) 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 
    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 
    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:
    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 
    172         RegExpConstructor* regExpConstructor() const { return m_regExpConstructor.get(); }
    173 
    174         ErrorConstructor* errorConstructor() const { return m_errorConstructor.get(); }
    175         NativeErrorConstructor* evalErrorConstructor() const { return m_evalErrorConstructor.get(); }
    176         NativeErrorConstructor* rangeErrorConstructor() const { return m_rangeErrorConstructor.get(); }
    177         NativeErrorConstructor* referenceErrorConstructor() const { return m_referenceErrorConstructor.get(); }
    178         NativeErrorConstructor* syntaxErrorConstructor() const { return m_syntaxErrorConstructor.get(); }
    179         NativeErrorConstructor* typeErrorConstructor() const { return m_typeErrorConstructor.get(); }
    180         NativeErrorConstructor* URIErrorConstructor() const { return m_URIErrorConstructor.get(); }
    181 
    182         JSFunction* evalFunction() const { return m_evalFunction.get(); }
    183         JSFunction* callFunction() const { return m_callFunction.get(); }
    184         JSFunction* applyFunction() const { return m_applyFunction.get(); }
    185 
    186         ObjectPrototype* objectPrototype() const { return m_objectPrototype.get(); }
    187         FunctionPrototype* functionPrototype() const { return m_functionPrototype.get(); }
    188         ArrayPrototype* arrayPrototype() const { return m_arrayPrototype.get(); }
    189         BooleanPrototype* booleanPrototype() const { return m_booleanPrototype.get(); }
    190         StringPrototype* stringPrototype() const { return m_stringPrototype.get(); }
    191         NumberPrototype* numberPrototype() const { return m_numberPrototype.get(); }
    192         DatePrototype* datePrototype() const { return m_datePrototype.get(); }
    193         RegExpPrototype* regExpPrototype() const { return m_regExpPrototype.get(); }
    194 
    195         JSObject* methodCallDummy() const { return m_methodCallDummy.get(); }
    196 
    197         Structure* argumentsStructure() const { return m_argumentsStructure.get(); }
    198         Structure* arrayStructure() const { return m_arrayStructure.get(); }
    199         Structure* booleanObjectStructure() const { return m_booleanObjectStructure.get(); }
    200         Structure* callbackConstructorStructure() const { return m_callbackConstructorStructure.get(); }
    201         Structure* callbackFunctionStructure() const { return m_callbackFunctionStructure.get(); }
    202         Structure* callbackObjectStructure() const { return m_callbackObjectStructure.get(); }
    203         Structure* dateStructure() const { return m_dateStructure.get(); }
    204         Structure* emptyObjectStructure() const { return m_emptyObjectStructure.get(); }
    205         Structure* errorStructure() const { return m_errorStructure.get(); }
    206         Structure* functionStructure() const { return m_functionStructure.get(); }
    207         Structure* numberObjectStructure() const { return m_numberObjectStructure.get(); }
    208         Structure* internalFunctionStructure() const { return m_internalFunctionStructure.get(); }
    209         Structure* regExpMatchesArrayStructure() const { return m_regExpMatchesArrayStructure.get(); }
    210         Structure* regExpStructure() const { return m_regExpStructure.get(); }
    211         Structure* stringObjectStructure() const { return m_stringObjectStructure.get(); }
    212 
    213         void setProfileGroup(unsigned value) { m_profileGroup = value; }
    214         unsigned profileGroup() const { return m_profileGroup; }
    215 
    216         Debugger* debugger() const { return m_debugger; }
    217         void setDebugger(Debugger* debugger) { m_debugger = debugger; }
    218 
    219         virtual bool supportsProfiling() const { return false; }
    220         virtual bool supportsRichSourceInfo() const { return true; }
    221 
    222         ScopeChainNode* globalScopeChain() { return m_globalScopeChain.get(); }
    223 
    224         virtual bool isGlobalObject() const { return true; }
    225 
    226         virtual ExecState* globalExec();
    227 
    228         virtual bool shouldInterruptScript() const { return true; }
    229 
    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 
    240         JSGlobalData& globalData() const { return *m_globalData.get(); }
    241 
    242         static Structure* createStructure(JSGlobalData& globalData, JSValue prototype)
    243         {
    244             return Structure::create(globalData, prototype, TypeInfo(ObjectType, StructureFlags), AnonymousSlotCount, &s_info);
    245         }
    246 
    247         void registerWeakMap(OpaqueJSWeakObjectMap* map)
    248         {
    249             m_weakMaps.add(map);
    250         }
    251 
    252         void deregisterWeakMap(OpaqueJSWeakObjectMap* map)
    253         {
    254             m_weakMaps.remove(map);
    255         }
    256 
    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 {
    264             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 
    289     inline JSGlobalObject* asGlobalObject(JSValue value)
    290     {
    291         ASSERT(asObject(value)->isGlobalObject());
    292         return static_cast<JSGlobalObject*>(asObject(value));
    293     }
    294 
    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 
    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 
    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 
    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 
    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 
    346     inline bool JSGlobalObject::symbolTableHasProperty(const Identifier& propertyName)
    347     {
    348         SymbolTableEntry entry = symbolTable().inlineGet(propertyName.impl());
    349         return !entry.isNull();
    350     }
    351 
    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 
    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 
    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 
    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 
    398     inline JSObject* constructEmptyObject(ExecState* exec, JSGlobalObject* globalObject)
    399     {
    400         return constructEmptyObject(exec, globalObject->emptyObjectStructure());
    401     }
    402 
    403     inline JSObject* constructEmptyObject(ExecState* exec)
    404     {
    405         return constructEmptyObject(exec, exec->lexicalGlobalObject());
    406     }
    407 
    408     inline JSArray* constructEmptyArray(ExecState* exec)
    409     {
    410         return new (exec) JSArray(exec->globalData(), exec->lexicalGlobalObject()->arrayStructure());
    411     }
    412 
    413     inline JSArray* constructEmptyArray(ExecState* exec, JSGlobalObject* globalObject)
    414     {
    415         return new (exec) JSArray(exec->globalData(), globalObject->arrayStructure());
    416     }
    417 
    418     inline JSArray* constructEmptyArray(ExecState* exec, unsigned initialLength)
    419     {
    420         return new (exec) JSArray(exec->globalData(), exec->lexicalGlobalObject()->arrayStructure(), initialLength, CreateInitialized);
    421     }
    422 
    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 
    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 
    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