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