X-Git-Url: https://git.saurik.com/apple/javascriptcore.git/blobdiff_plain/4e4e5a6f2694187498445a6ac6f1634ce8141119..2656c66b5b30d5597e842a751c7f19ad6c2fe31a:/runtime/JSGlobalObject.h diff --git a/runtime/JSGlobalObject.h b/runtime/JSGlobalObject.h index 6b9429a..7bdcb72 100644 --- a/runtime/JSGlobalObject.h +++ b/runtime/JSGlobalObject.h @@ -1,6 +1,6 @@ /* * Copyright (C) 2007 Eric Seidel - * Copyright (C) 2007, 2008, 2009 Apple Inc. All rights reserved. + * Copyright (C) 2007, 2008, 2009, 2014 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 @@ -22,472 +22,664 @@ #ifndef JSGlobalObject_h #define JSGlobalObject_h +#include "ArrayAllocationProfile.h" +#include "ConstantMode.h" #include "JSArray.h" -#include "JSGlobalData.h" -#include "JSVariableObject.h" +#include "JSArrayBufferPrototype.h" +#include "JSClassRef.h" +#include "JSProxy.h" +#include "JSSegmentedVariableObject.h" #include "JSWeakObjectMapRefInternal.h" -#include "NativeFunctionWrapper.h" #include "NumberPrototype.h" +#include "SpecialPointer.h" #include "StringPrototype.h" +#include "StructureChain.h" +#include "StructureRareDataInlines.h" +#include "VM.h" +#include "Watchpoint.h" +#include +#include #include #include +#include #include +struct OpaqueJSClass; +struct OpaqueJSClassContextData; + +namespace Inspector { +class JSGlobalObjectInspectorController; +} + 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 ExecStateStack; +class ArrayPrototype; +class BooleanPrototype; +class ConsoleClient; +class Debugger; +class ErrorConstructor; +class ErrorPrototype; +class EvalCodeBlock; +class EvalExecutable; +class FunctionCodeBlock; +class FunctionExecutable; +class FunctionPrototype; +class GetterSetter; +class GlobalCodeBlock; +class InputCursor; +class JSGlobalObjectDebuggable; +class JSPromiseConstructor; +class JSPromisePrototype; +class JSStack; +class LLIntOffsetsExtractor; +class Microtask; +class NativeErrorConstructor; +class ObjectConstructor; +class ProgramCodeBlock; +class ProgramExecutable; +class RegExpConstructor; +class RegExpPrototype; +class SourceCode; +struct ActivationStackNode; +struct HashTable; + +#define DEFINE_STANDARD_BUILTIN(macro, upperName, lowerName) macro(upperName, lowerName, lowerName, JS ## upperName, upperName) - class JSGlobalObject : public JSVariableObject { - protected: - using JSVariableObject::JSVariableObjectData; - typedef HashSet > 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(randomNumber() * (std::numeric_limits::max() + 1.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 argumentsStructure; - RefPtr arrayStructure; - RefPtr booleanObjectStructure; - RefPtr callbackConstructorStructure; - RefPtr callbackFunctionStructure; - RefPtr callbackObjectStructure; - RefPtr dateStructure; - RefPtr emptyObjectStructure; - RefPtr errorStructure; - RefPtr functionStructure; - RefPtr numberObjectStructure; - RefPtr prototypeFunctionStructure; - RefPtr regExpMatchesArrayStructure; - RefPtr regExpStructure; - RefPtr stringObjectStructure; - - SymbolTable symbolTable; - unsigned profileGroup; - - RefPtr globalData; - - HashSet codeBlocks; - WeakMapSet weakMaps; - WeakRandom weakRandom; - }; - - public: - void* operator new(size_t, JSGlobalData*); - - explicit JSGlobalObject() - : JSVariableObject(JSGlobalObject::createStructure(jsNull()), new JSGlobalObjectData(destroyJSGlobalObjectData)) - { - init(this); - } +#define FOR_EACH_SIMPLE_BUILTIN_TYPE_WITH_CONSTRUCTOR(macro) \ + macro(Set, set, set, JSSet, Set) \ + macro(Map, map, map, JSMap, Map) \ + macro(Date, date, date, DateInstance, Date) \ + macro(String, string, stringObject, StringObject, String) \ + macro(Boolean, boolean, booleanObject, BooleanObject, Boolean) \ + macro(Number, number, numberObject, NumberObject, Number) \ + macro(Error, error, error, ErrorInstance, Error) \ + macro(JSArrayBuffer, arrayBuffer, arrayBuffer, JSArrayBuffer, ArrayBuffer) \ + DEFINE_STANDARD_BUILTIN(macro, WeakMap, weakMap) \ - protected: - JSGlobalObject(NonNullPassRefPtr structure, JSGlobalObjectData* data, JSObject* thisValue) - : JSVariableObject(structure, data) - { - init(thisValue); - } +#define FOR_EACH_SIMPLE_BUILTIN_TYPE(macro) \ + FOR_EACH_SIMPLE_BUILTIN_TYPE_WITH_CONSTRUCTOR(macro) \ + DEFINE_STANDARD_BUILTIN(macro, ArrayIterator, arrayIterator) \ + DEFINE_STANDARD_BUILTIN(macro, ArgumentsIterator, argumentsIterator) \ + DEFINE_STANDARD_BUILTIN(macro, MapIterator, mapIterator) \ + DEFINE_STANDARD_BUILTIN(macro, SetIterator, setIterator) \ - 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; } +#define DECLARE_SIMPLE_BUILTIN_TYPE(capitalName, lowerName, properName, instanceType, jsName) \ + class JS ## capitalName; \ + class capitalName ## Prototype; \ + class capitalName ## Constructor; - virtual ExecState* globalExec(); +FOR_EACH_SIMPLE_BUILTIN_TYPE(DECLARE_SIMPLE_BUILTIN_TYPE) - virtual bool shouldInterruptScriptBeforeTimeout() const { return false; } - virtual bool shouldInterruptScript() const { return true; } +#undef DECLARE_SIMPLE_BUILTIN_TYPE - virtual bool allowsAccessFrom(const JSGlobalObject*) const { return true; } +typedef Vector ExecStateStack; - virtual bool isDynamicScope(bool& requiresDynamicChecks) const; +struct GlobalObjectMethodTable { + typedef bool (*AllowsAccessFromFunctionPtr)(const JSGlobalObject*, ExecState*); + AllowsAccessFromFunctionPtr allowsAccessFrom; - HashSet& codeBlocks() { return d()->codeBlocks; } + typedef bool (*SupportsProfilingFunctionPtr)(const JSGlobalObject*); + SupportsProfilingFunctionPtr supportsProfiling; - void copyGlobalsFrom(RegisterFile&); - void copyGlobalsTo(RegisterFile&); - - void resetPrototype(JSValue prototype); + typedef bool (*SupportsRichSourceInfoFunctionPtr)(const JSGlobalObject*); + SupportsRichSourceInfoFunctionPtr supportsRichSourceInfo; - JSGlobalData* globalData() { return d()->globalData.get(); } - JSGlobalObjectData* d() const { return static_cast(JSVariableObject::d); } + typedef bool (*ShouldInterruptScriptFunctionPtr)(const JSGlobalObject*); + ShouldInterruptScriptFunctionPtr shouldInterruptScript; - static PassRefPtr createStructure(JSValue prototype) - { - return Structure::create(prototype, TypeInfo(ObjectType, StructureFlags), AnonymousSlotCount); - } + typedef bool (*JavaScriptExperimentsEnabledFunctionPtr)(const JSGlobalObject*); + JavaScriptExperimentsEnabledFunctionPtr javaScriptExperimentsEnabled; - void registerWeakMap(OpaqueJSWeakObjectMap* map) - { - d()->weakMaps.add(map); - } + typedef void (*QueueTaskToEventLoopFunctionPtr)(const JSGlobalObject*, PassRefPtr); + QueueTaskToEventLoopFunctionPtr queueTaskToEventLoop; + + typedef bool (*ShouldInterruptScriptBeforeTimeoutPtr)(const JSGlobalObject*); + ShouldInterruptScriptBeforeTimeoutPtr shouldInterruptScriptBeforeTimeout; +}; - void deregisterWeakMap(OpaqueJSWeakObjectMap* map) +class JSGlobalObject : public JSSegmentedVariableObject { +private: + typedef HashSet> WeakMapSet; + typedef HashMap> OpaqueJSClassDataMap; + + struct JSGlobalObjectRareData { + JSGlobalObjectRareData() + : profileGroup(0) { - d()->weakMaps.remove(map); } - double weakRandomNumber() { return d()->weakRandom.get(); } - protected: + WeakMapSet weakMaps; + unsigned profileGroup; + + OpaqueJSClassDataMap opaqueJSClassData; + }; - static const unsigned StructureFlags = OverridesGetOwnPropertySlot | OverridesMarkChildren | OverridesGetPropertyNames | JSVariableObject::StructureFlags; +protected: + Register m_globalCallFrame[JSStack::CallFrameHeaderSize]; + + WriteBarrier m_globalThis; + + WriteBarrier m_regExpConstructor; + WriteBarrier m_errorConstructor; + WriteBarrier m_evalErrorConstructor; + WriteBarrier m_rangeErrorConstructor; + WriteBarrier m_referenceErrorConstructor; + WriteBarrier m_syntaxErrorConstructor; + WriteBarrier m_typeErrorConstructor; + WriteBarrier m_URIErrorConstructor; +#if ENABLE(PROMISES) + WriteBarrier m_promiseConstructor; +#endif + WriteBarrier m_objectConstructor; + + WriteBarrier m_evalFunction; + WriteBarrier m_callFunction; + WriteBarrier m_applyFunction; + WriteBarrier m_throwTypeErrorGetterSetter; + + WriteBarrier m_objectPrototype; + WriteBarrier m_functionPrototype; + WriteBarrier m_arrayPrototype; + WriteBarrier m_regExpPrototype; +#if ENABLE(PROMISES) + WriteBarrier m_promisePrototype; +#endif - struct GlobalPropertyInfo { - GlobalPropertyInfo(const Identifier& i, JSValue v, unsigned a) - : identifier(i) - , value(v) - , attributes(a) - { - } + WriteBarrier m_withScopeStructure; + WriteBarrier m_strictEvalActivationStructure; + WriteBarrier m_activationStructure; + WriteBarrier m_nameScopeStructure; + WriteBarrier m_argumentsStructure; + + // Lists the actual structures used for having these particular indexing shapes. + WriteBarrier m_originalArrayStructureForIndexingShape[NumberOfIndexingShapes]; + // Lists the structures we should use during allocation for these particular indexing shapes. + WriteBarrier m_arrayStructureForIndexingShapeDuringAllocation[NumberOfIndexingShapes]; + + WriteBarrier m_callbackConstructorStructure; + WriteBarrier m_callbackFunctionStructure; + WriteBarrier m_callbackObjectStructure; +#if JSC_OBJC_API_ENABLED + WriteBarrier m_objcCallbackFunctionStructure; + WriteBarrier m_objcWrapperObjectStructure; +#endif + WriteBarrier m_nullPrototypeObjectStructure; + WriteBarrier m_functionStructure; + WriteBarrier m_boundFunctionStructure; + WriteBarrier m_namedFunctionStructure; + PropertyOffset m_functionNameOffset; + WriteBarrier m_privateNameStructure; + WriteBarrier m_regExpMatchesArrayStructure; + WriteBarrier m_regExpStructure; + WriteBarrier m_consoleStructure; + WriteBarrier m_internalFunctionStructure; + + WriteBarrier m_iteratorResultStructure; - const Identifier identifier; - JSValue value; - unsigned attributes; - }; - void addStaticGlobals(GlobalPropertyInfo*, int count); +#if ENABLE(PROMISES) + WriteBarrier m_promiseStructure; +#endif // ENABLE(PROMISES) - private: - static void destroyJSGlobalObjectData(void*); +#define DEFINE_STORAGE_FOR_SIMPLE_TYPE(capitalName, lowerName, properName, instanceType, jsName) \ + WriteBarrier m_ ## lowerName ## Prototype; \ + WriteBarrier m_ ## properName ## Structure; - // FIXME: Fold reset into init. - void init(JSObject* thisValue); - void reset(JSValue prototype); + FOR_EACH_SIMPLE_BUILTIN_TYPE(DEFINE_STORAGE_FOR_SIMPLE_TYPE) - void setRegisters(Register* registers, Register* registerArray, size_t count); +#undef DEFINE_STORAGE_FOR_SIMPLE_TYPE - void* operator new(size_t); // can only be allocated with JSGlobalData + struct TypedArrayData { + WriteBarrier prototype; + WriteBarrier structure; }; + + std::array m_typedArrays; + + void* m_specialPointers[Special::TableSize]; // Special pointers used by the LLInt and JIT. + + String m_name; + + Debugger* m_debugger; + + VM& m_vm; + +#if ENABLE(WEB_REPLAY) + RefPtr m_inputCursor; +#endif + +#if ENABLE(REMOTE_INSPECTOR) + std::unique_ptr m_inspectorController; + std::unique_ptr m_inspectorDebuggable; +#endif + + RefPtr m_masqueradesAsUndefinedWatchpoint; + RefPtr m_havingABadTimeWatchpoint; + RefPtr m_varInjectionWatchpoint; + + OwnPtr m_rareData; + + WeakRandom m_weakRandom; + + bool m_evalEnabled; + String m_evalDisabledErrorMessage; + bool m_experimentsEnabled; + ConsoleClient* m_consoleClient; - JSGlobalObject* asGlobalObject(JSValue); + static JS_EXPORTDATA const GlobalObjectMethodTable s_globalObjectMethodTable; + const GlobalObjectMethodTable* m_globalObjectMethodTable; - inline JSGlobalObject* asGlobalObject(JSValue value) + void createRareDataIfNeeded() { - ASSERT(asObject(value)->isGlobalObject()); - return static_cast(asObject(value)); + if (m_rareData) + return; + m_rareData = adoptPtr(new JSGlobalObjectRareData); } + +public: + typedef JSSegmentedVariableObject Base; - inline void JSGlobalObject::setRegisters(Register* registers, Register* registerArray, size_t count) + static JSGlobalObject* create(VM& vm, Structure* structure) { - JSVariableObject::setRegisters(registers, registerArray); - d()->registerArraySize = count; + JSGlobalObject* globalObject = new (NotNull, allocateCell(vm.heap)) JSGlobalObject(vm, structure); + globalObject->finishCreation(vm); + vm.heap.addFinalizer(globalObject, destroy); + return globalObject; } - inline void JSGlobalObject::addStaticGlobals(GlobalPropertyInfo* globals, int count) + DECLARE_EXPORT_INFO; + + bool hasDebugger() const { return m_debugger; } + bool hasProfiler() const { return globalObjectMethodTable()->supportsProfiling(this); } + +protected: + JS_EXPORT_PRIVATE explicit JSGlobalObject(VM&, Structure*, const GlobalObjectMethodTable* = 0); + + void finishCreation(VM& vm) { - 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(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; - } + Base::finishCreation(vm); + structure()->setGlobalObject(vm, this); + m_experimentsEnabled = m_globalObjectMethodTable->javaScriptExperimentsEnabled(this); + init(); + setGlobalThis(vm, JSProxy::create(vm, JSProxy::createStructure(vm, this, prototype(), PureForwardingProxyType), this)); } - inline bool JSGlobalObject::getOwnPropertySlot(ExecState* exec, const Identifier& propertyName, PropertySlot& slot) + void finishCreation(VM& vm, JSObject* thisValue) { - if (JSVariableObject::getOwnPropertySlot(exec, propertyName, slot)) - return true; - return symbolTableGet(propertyName, slot); + Base::finishCreation(vm); + structure()->setGlobalObject(vm, this); + m_experimentsEnabled = m_globalObjectMethodTable->javaScriptExperimentsEnabled(this); + init(); + setGlobalThis(vm, thisValue); } - inline bool JSGlobalObject::getOwnPropertyDescriptor(ExecState* exec, const Identifier& propertyName, PropertyDescriptor& descriptor) + struct NewGlobalVar { + int registerNumber; + VariableWatchpointSet* set; + }; + NewGlobalVar addGlobalVar(const Identifier&, ConstantMode); + +public: + JS_EXPORT_PRIVATE ~JSGlobalObject(); + JS_EXPORT_PRIVATE static void destroy(JSCell*); + // We don't need a destructor because we use a finalizer instead. + static const bool needsDestruction = false; + + JS_EXPORT_PRIVATE static void visitChildren(JSCell*, SlotVisitor&); + + JS_EXPORT_PRIVATE static bool getOwnPropertySlot(JSObject*, ExecState*, PropertyName, PropertySlot&); + bool hasOwnPropertyForWrite(ExecState*, PropertyName); + JS_EXPORT_PRIVATE static void put(JSCell*, ExecState*, PropertyName, JSValue, PutPropertySlot&); + + JS_EXPORT_PRIVATE static void defineGetter(JSObject*, ExecState*, PropertyName, JSObject* getterFunc, unsigned attributes); + JS_EXPORT_PRIVATE static void defineSetter(JSObject*, ExecState*, PropertyName, JSObject* setterFunc, unsigned attributes); + JS_EXPORT_PRIVATE static bool defineOwnProperty(JSObject*, ExecState*, PropertyName, const PropertyDescriptor&, bool shouldThrow); + + // We use this in the code generator as we perform symbol table + // lookups prior to initializing the properties + bool symbolTableHasProperty(PropertyName); + + void addVar(ExecState* exec, const Identifier& propertyName) { - if (symbolTableGet(propertyName, descriptor)) - return true; - return JSVariableObject::getOwnPropertyDescriptor(exec, propertyName, descriptor); + if (!hasProperty(exec, propertyName)) + addGlobalVar(propertyName, IsVariable); } - - inline bool JSGlobalObject::hasOwnPropertyForWrite(ExecState* exec, const Identifier& propertyName) + void addConst(ExecState* exec, const Identifier& propertyName) { - PropertySlot slot; - if (JSVariableObject::getOwnPropertySlot(exec, propertyName, slot)) - return true; - bool slotIsWriteable; - return symbolTableGet(propertyName, slot, slotIsWriteable); + if (!hasProperty(exec, propertyName)) + addGlobalVar(propertyName, IsConstant); } + void addFunction(ExecState*, const Identifier&, JSValue); + + // The following accessors return pristine values, even if a script + // replaces the global object's associated property. + + RegExpConstructor* regExpConstructor() const { return m_regExpConstructor.get(); } + + ErrorConstructor* errorConstructor() const { return m_errorConstructor.get(); } + ObjectConstructor* objectConstructor() const { return m_objectConstructor.get(); } + NativeErrorConstructor* evalErrorConstructor() const { return m_evalErrorConstructor.get(); } + NativeErrorConstructor* rangeErrorConstructor() const { return m_rangeErrorConstructor.get(); } + NativeErrorConstructor* referenceErrorConstructor() const { return m_referenceErrorConstructor.get(); } + NativeErrorConstructor* syntaxErrorConstructor() const { return m_syntaxErrorConstructor.get(); } + NativeErrorConstructor* typeErrorConstructor() const { return m_typeErrorConstructor.get(); } + NativeErrorConstructor* URIErrorConstructor() const { return m_URIErrorConstructor.get(); } +#if ENABLE(PROMISES) + JSPromiseConstructor* promiseConstructor() const { return m_promiseConstructor.get(); } +#endif - inline JSValue Structure::prototypeForLookup(ExecState* exec) const + JSFunction* evalFunction() const { return m_evalFunction.get(); } + JSFunction* callFunction() const { return m_callFunction.get(); } + JSFunction* applyFunction() const { return m_applyFunction.get(); } + GetterSetter* throwTypeErrorGetterSetter(VM& vm) { - 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 + if (!m_throwTypeErrorGetterSetter) + createThrowTypeError(vm); + return m_throwTypeErrorGetterSetter.get(); } - inline StructureChain* Structure::prototypeChain(ExecState* exec) const + ObjectPrototype* objectPrototype() const { return m_objectPrototype.get(); } + FunctionPrototype* functionPrototype() const { return m_functionPrototype.get(); } + ArrayPrototype* arrayPrototype() const { return m_arrayPrototype.get(); } + BooleanPrototype* booleanPrototype() const { return m_booleanPrototype.get(); } + StringPrototype* stringPrototype() const { return m_stringPrototype.get(); } + NumberPrototype* numberPrototype() const { return m_numberPrototype.get(); } + DatePrototype* datePrototype() const { return m_datePrototype.get(); } + RegExpPrototype* regExpPrototype() const { return m_regExpPrototype.get(); } + ErrorPrototype* errorPrototype() const { return m_errorPrototype.get(); } +#if ENABLE(PROMISES) + JSPromisePrototype* promisePrototype() const { return m_promisePrototype.get(); } +#endif + + Structure* withScopeStructure() const { return m_withScopeStructure.get(); } + Structure* strictEvalActivationStructure() const { return m_strictEvalActivationStructure.get(); } + Structure* activationStructure() const { return m_activationStructure.get(); } + Structure* nameScopeStructure() const { return m_nameScopeStructure.get(); } + Structure* argumentsStructure() const { return m_argumentsStructure.get(); } + Structure* originalArrayStructureForIndexingType(IndexingType indexingType) 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(); + ASSERT(indexingType & IsArray); + return m_originalArrayStructureForIndexingShape[(indexingType & IndexingShapeMask) >> IndexingShapeShift].get(); + } + Structure* arrayStructureForIndexingTypeDuringAllocation(IndexingType indexingType) const + { + ASSERT(indexingType & IsArray); + return m_arrayStructureForIndexingShapeDuringAllocation[(indexingType & IndexingShapeMask) >> IndexingShapeShift].get(); + } + Structure* arrayStructureForProfileDuringAllocation(ArrayAllocationProfile* profile) const + { + return arrayStructureForIndexingTypeDuringAllocation(ArrayAllocationProfile::selectIndexingTypeFor(profile)); + } + + bool isOriginalArrayStructure(Structure* structure) + { + return originalArrayStructureForIndexingType(structure->indexingType() | IsArray) == structure; } + + Structure* booleanObjectStructure() const { return m_booleanObjectStructure.get(); } + Structure* callbackConstructorStructure() const { return m_callbackConstructorStructure.get(); } + Structure* callbackFunctionStructure() const { return m_callbackFunctionStructure.get(); } + Structure* callbackObjectStructure() const { return m_callbackObjectStructure.get(); } +#if JSC_OBJC_API_ENABLED + Structure* objcCallbackFunctionStructure() const { return m_objcCallbackFunctionStructure.get(); } + Structure* objcWrapperObjectStructure() const { return m_objcWrapperObjectStructure.get(); } +#endif + Structure* dateStructure() const { return m_dateStructure.get(); } + Structure* nullPrototypeObjectStructure() const { return m_nullPrototypeObjectStructure.get(); } + Structure* errorStructure() const { return m_errorStructure.get(); } + Structure* functionStructure() const { return m_functionStructure.get(); } + Structure* boundFunctionStructure() const { return m_boundFunctionStructure.get(); } + Structure* namedFunctionStructure() const { return m_namedFunctionStructure.get(); } + PropertyOffset functionNameOffset() const { return m_functionNameOffset; } + Structure* numberObjectStructure() const { return m_numberObjectStructure.get(); } + Structure* privateNameStructure() const { return m_privateNameStructure.get(); } + Structure* internalFunctionStructure() const { return m_internalFunctionStructure.get(); } + Structure* mapStructure() const { return m_mapStructure.get(); } + Structure* regExpMatchesArrayStructure() const { return m_regExpMatchesArrayStructure.get(); } + Structure* regExpStructure() const { return m_regExpStructure.get(); } + Structure* setStructure() const { return m_setStructure.get(); } + Structure* stringObjectStructure() const { return m_stringObjectStructure.get(); } + Structure* iteratorResultStructure() const { return m_iteratorResultStructure.get(); } + static ptrdiff_t iteratorResultStructureOffset() { return OBJECT_OFFSETOF(JSGlobalObject, m_iteratorResultStructure); } + +#if ENABLE(PROMISES) + Structure* promiseStructure() const { return m_promiseStructure.get(); } +#endif // ENABLE(PROMISES) + + JS_EXPORT_PRIVATE void setRemoteDebuggingEnabled(bool); + JS_EXPORT_PRIVATE bool remoteDebuggingEnabled() const; + +#if ENABLE(WEB_REPLAY) + JS_EXPORT_PRIVATE void setInputCursor(PassRefPtr); + InputCursor& inputCursor() const { return *m_inputCursor; } +#endif + +#if ENABLE(REMOTE_INSPECTOR) + Inspector::JSGlobalObjectInspectorController& inspectorController() const { return *m_inspectorController.get(); } + JSGlobalObjectDebuggable& inspectorDebuggable() { return *m_inspectorDebuggable.get(); } +#endif + + JS_EXPORT_PRIVATE void setConsoleClient(ConsoleClient* consoleClient) { m_consoleClient = consoleClient; } + ConsoleClient* consoleClient() const { return m_consoleClient; } + + void setName(const String&); + const String& name() const { return m_name; } + + JSArrayBufferPrototype* arrayBufferPrototype() const { return m_arrayBufferPrototype.get(); } + +#define DEFINE_ACCESSORS_FOR_SIMPLE_TYPE(capitalName, lowerName, properName, instanceType, jsName) \ + Structure* properName ## Structure() { return m_ ## properName ## Structure.get(); } + + FOR_EACH_SIMPLE_BUILTIN_TYPE(DEFINE_ACCESSORS_FOR_SIMPLE_TYPE) + +#undef DEFINE_ACCESSORS_FOR_SIMPLE_TYPE - inline bool Structure::isValid(ExecState* exec, StructureChain* cachedPrototypeChain) const + Structure* typedArrayStructure(TypedArrayType type) const { - if (!cachedPrototypeChain) + return m_typedArrays[toIndex(type)].structure.get(); + } + bool isOriginalTypedArrayStructure(Structure* structure) + { + TypedArrayType type = structure->classInfo()->typedArrayStorageType; + if (type == NotTypedArray) return false; - - JSValue prototype = prototypeForLookup(exec); - RefPtr* cachedStructure = cachedPrototypeChain->head(); - while(*cachedStructure && !prototype.isNull()) { - if (asObject(prototype)->structure() != *cachedStructure) - return false; - ++cachedStructure; - prototype = asObject(prototype)->prototype(); - } - return prototype.isNull() && !*cachedStructure; + return typedArrayStructure(type) == structure; } - inline JSGlobalObject* ExecState::dynamicGlobalObject() + void* actualPointerFor(Special::Pointer pointer) { - 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; + ASSERT(pointer < Special::TableSize); + return m_specialPointers[pointer]; } - inline JSObject* constructEmptyObject(ExecState* exec) + WatchpointSet* masqueradesAsUndefinedWatchpoint() { return m_masqueradesAsUndefinedWatchpoint.get(); } + WatchpointSet* havingABadTimeWatchpoint() { return m_havingABadTimeWatchpoint.get(); } + WatchpointSet* varInjectionWatchpoint() { return m_varInjectionWatchpoint.get(); } + + bool isHavingABadTime() const { - return new (exec) JSObject(exec->lexicalGlobalObject()->emptyObjectStructure()); + return m_havingABadTimeWatchpoint->hasBeenInvalidated(); } - - inline JSObject* constructEmptyObject(ExecState* exec, JSGlobalObject* globalObject) - { - return new (exec) JSObject(globalObject->emptyObjectStructure()); + + void haveABadTime(VM&); + + bool objectPrototypeIsSane(); + bool arrayPrototypeChainIsSane(); + bool stringPrototypeChainIsSane(); + + void setProfileGroup(unsigned value) { createRareDataIfNeeded(); m_rareData->profileGroup = value; } + unsigned profileGroup() const + { + if (!m_rareData) + return 0; + return m_rareData->profileGroup; } - inline JSArray* constructEmptyArray(ExecState* exec) + Debugger* debugger() const { return m_debugger; } + void setDebugger(Debugger* debugger) { m_debugger = debugger; } + + const GlobalObjectMethodTable* globalObjectMethodTable() const { return m_globalObjectMethodTable; } + + static bool allowsAccessFrom(const JSGlobalObject*, ExecState*) { return true; } + static bool supportsProfiling(const JSGlobalObject*) { return false; } + static bool supportsRichSourceInfo(const JSGlobalObject*) { return true; } + + JS_EXPORT_PRIVATE ExecState* globalExec(); + + static bool shouldInterruptScript(const JSGlobalObject*) { return true; } + static bool shouldInterruptScriptBeforeTimeout(const JSGlobalObject*) { return false; } + static bool javaScriptExperimentsEnabled(const JSGlobalObject*) { return false; } + + void queueMicrotask(PassRefPtr); + + bool evalEnabled() const { return m_evalEnabled; } + const String& evalDisabledErrorMessage() const { return m_evalDisabledErrorMessage; } + void setEvalEnabled(bool enabled, const String& errorMessage = String()) { - return new (exec) JSArray(exec->lexicalGlobalObject()->arrayStructure()); + m_evalEnabled = enabled; + m_evalDisabledErrorMessage = errorMessage; } - - inline JSArray* constructEmptyArray(ExecState* exec, JSGlobalObject* globalObject) + + void resetPrototype(VM&, JSValue prototype); + + VM& vm() const { return m_vm; } + JSObject* globalThis() const; + + static Structure* createStructure(VM& vm, JSValue prototype) { - return new (exec) JSArray(globalObject->arrayStructure()); + return Structure::create(vm, 0, prototype, TypeInfo(GlobalObjectType, StructureFlags), info()); } - inline JSArray* constructEmptyArray(ExecState* exec, unsigned initialLength) + void registerWeakMap(OpaqueJSWeakObjectMap* map) { - return new (exec) JSArray(exec->lexicalGlobalObject()->arrayStructure(), initialLength); + createRareDataIfNeeded(); + m_rareData->weakMaps.add(map); } - inline JSArray* constructArray(ExecState* exec, JSValue singleItemValue) + void unregisterWeakMap(OpaqueJSWeakObjectMap* map) { - MarkedArgumentBuffer values; - values.append(singleItemValue); - return new (exec) JSArray(exec->lexicalGlobalObject()->arrayStructure(), values); + if (m_rareData) + m_rareData->weakMaps.remove(map); } - inline JSArray* constructArray(ExecState* exec, const ArgList& values) + OpaqueJSClassDataMap& opaqueJSClassData() { - return new (exec) JSArray(exec->lexicalGlobalObject()->arrayStructure(), values); + createRareDataIfNeeded(); + return m_rareData->opaqueJSClassData; } - 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; + double weakRandomNumber() { return m_weakRandom.get(); } + unsigned weakRandomInteger() { return m_weakRandom.getUint32(); } - // Reset the date cache between JS invocations to force the VM - // to observe time zone changes. - callFrame->globalData().resetDateCache(); - } - } + UnlinkedProgramCodeBlock* createProgramCodeBlock(CallFrame*, ProgramExecutable*, JSObject** exception); + UnlinkedEvalCodeBlock* createEvalCodeBlock(CallFrame*, EvalExecutable*); + +protected: + + static const unsigned StructureFlags = OverridesGetOwnPropertySlot | OverridesVisitChildren | OverridesGetPropertyNames | Base::StructureFlags; - ~DynamicGlobalObjectScope() + struct GlobalPropertyInfo { + GlobalPropertyInfo(const Identifier& i, JSValue v, unsigned a) + : identifier(i) + , value(v) + , attributes(a) { - m_dynamicGlobalObjectSlot = m_savedDynamicGlobalObject; } - private: - JSGlobalObject*& m_dynamicGlobalObjectSlot; - JSGlobalObject* m_savedDynamicGlobalObject; + const Identifier identifier; + JSValue value; + unsigned attributes; }; + JS_EXPORT_PRIVATE void addStaticGlobals(GlobalPropertyInfo*, int count); + + JS_EXPORT_PRIVATE static JSC::JSValue toThis(JSC::JSCell*, JSC::ExecState*, ECMAMode); + +private: + friend class LLIntOffsetsExtractor; + + JS_EXPORT_PRIVATE void setGlobalThis(VM&, JSObject* globalThis); + + // FIXME: Fold reset into init. + JS_EXPORT_PRIVATE void init(); + void reset(JSValue prototype); + + void createThrowTypeError(VM&); + + JS_EXPORT_PRIVATE static void clearRareData(JSCell*); +}; + +JSGlobalObject* asGlobalObject(JSValue); + +inline JSGlobalObject* asGlobalObject(JSValue value) +{ + ASSERT(asObject(value)->isGlobalObject()); + return jsCast(asObject(value)); +} + +inline bool JSGlobalObject::hasOwnPropertyForWrite(ExecState* exec, PropertyName propertyName) +{ + PropertySlot slot(this); + if (Base::getOwnPropertySlot(this, exec, propertyName, slot)) + return true; + bool slotIsWriteable; + return symbolTableGet(this, propertyName, slot, slotIsWriteable); +} + +inline bool JSGlobalObject::symbolTableHasProperty(PropertyName propertyName) +{ + SymbolTableEntry entry = symbolTable()->inlineGet(propertyName.uid()); + return !entry.isNull(); +} + +inline JSArray* constructEmptyArray(ExecState* exec, ArrayAllocationProfile* profile, JSGlobalObject* globalObject, unsigned initialLength = 0) +{ + return ArrayAllocationProfile::updateLastAllocationFor(profile, JSArray::create(exec->vm(), initialLength >= MIN_SPARSE_ARRAY_INDEX ? globalObject->arrayStructureForIndexingTypeDuringAllocation(ArrayWithArrayStorage) : globalObject->arrayStructureForProfileDuringAllocation(profile), initialLength)); +} + +inline JSArray* constructEmptyArray(ExecState* exec, ArrayAllocationProfile* profile, unsigned initialLength = 0) +{ + return constructEmptyArray(exec, profile, exec->lexicalGlobalObject(), initialLength); +} + +inline JSArray* constructArray(ExecState* exec, ArrayAllocationProfile* profile, JSGlobalObject* globalObject, const ArgList& values) +{ + return ArrayAllocationProfile::updateLastAllocationFor(profile, constructArray(exec, globalObject->arrayStructureForProfileDuringAllocation(profile), values)); +} + +inline JSArray* constructArray(ExecState* exec, ArrayAllocationProfile* profile, const ArgList& values) +{ + return constructArray(exec, profile, exec->lexicalGlobalObject(), values); +} + +inline JSArray* constructArray(ExecState* exec, ArrayAllocationProfile* profile, JSGlobalObject* globalObject, const JSValue* values, unsigned length) +{ + return ArrayAllocationProfile::updateLastAllocationFor(profile, constructArray(exec, globalObject->arrayStructureForProfileDuringAllocation(profile), values, length)); +} + +inline JSArray* constructArray(ExecState* exec, ArrayAllocationProfile* profile, const JSValue* values, unsigned length) +{ + return constructArray(exec, profile, exec->lexicalGlobalObject(), values, length); +} + +inline JSArray* constructArrayNegativeIndexed(ExecState* exec, ArrayAllocationProfile* profile, JSGlobalObject* globalObject, const JSValue* values, unsigned length) +{ + return ArrayAllocationProfile::updateLastAllocationFor(profile, constructArrayNegativeIndexed(exec, globalObject->arrayStructureForProfileDuringAllocation(profile), values, length)); +} + +inline JSArray* constructArrayNegativeIndexed(ExecState* exec, ArrayAllocationProfile* profile, const JSValue* values, unsigned length) +{ + return constructArrayNegativeIndexed(exec, profile, exec->lexicalGlobalObject(), values, length); +} + +inline JSObject* JSScope::globalThis() +{ + return globalObject()->globalThis(); +} + +inline JSObject* JSGlobalObject::globalThis() const +{ + return m_globalThis.get(); +} } // namespace JSC