michael@0: /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- michael@0: * vim: set ts=8 sts=4 et sw=4 tw=99: michael@0: * This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: #ifndef vm_GlobalObject_h michael@0: #define vm_GlobalObject_h michael@0: michael@0: #include "jsarray.h" michael@0: #include "jsbool.h" michael@0: #include "jsexn.h" michael@0: #include "jsfun.h" michael@0: #include "jsnum.h" michael@0: michael@0: #include "builtin/RegExp.h" michael@0: #include "js/Vector.h" michael@0: #include "vm/ArrayBufferObject.h" michael@0: #include "vm/ErrorObject.h" michael@0: michael@0: extern JSObject * michael@0: js_InitObjectClass(JSContext *cx, js::HandleObject obj); michael@0: michael@0: extern JSObject * michael@0: js_InitFunctionClass(JSContext *cx, js::HandleObject obj); michael@0: michael@0: extern JSObject * michael@0: js_InitTypedArrayClasses(JSContext *cx, js::HandleObject obj); michael@0: michael@0: extern JSObject * michael@0: js_InitSharedArrayBufferClass(JSContext *cx, js::HandleObject obj); michael@0: michael@0: namespace js { michael@0: michael@0: class Debugger; michael@0: class TypedObjectModuleObject; michael@0: michael@0: /* michael@0: * Global object slots are reserved as follows: michael@0: * michael@0: * [0, APPLICATION_SLOTS) michael@0: * Pre-reserved slots in all global objects set aside for the embedding's michael@0: * use. As with all reserved slots these start out as UndefinedValue() and michael@0: * are traced for GC purposes. Apart from that the engine never touches michael@0: * these slots, so the embedding can do whatever it wants with them. michael@0: * [APPLICATION_SLOTS, APPLICATION_SLOTS + JSProto_LIMIT) michael@0: * Stores the original value of the constructor for the corresponding michael@0: * JSProtoKey. michael@0: * [APPLICATION_SLOTS + JSProto_LIMIT, APPLICATION_SLOTS + 2 * JSProto_LIMIT) michael@0: * Stores the prototype, if any, for the constructor for the corresponding michael@0: * JSProtoKey offset from JSProto_LIMIT. michael@0: * [APPLICATION_SLOTS + 2 * JSProto_LIMIT, APPLICATION_SLOTS + 3 * JSProto_LIMIT) michael@0: * Stores the current value of the global property named for the JSProtoKey michael@0: * for the corresponding JSProtoKey offset from 2 * JSProto_LIMIT. michael@0: * [APPLICATION_SLOTS + 3 * JSProto_LIMIT, RESERVED_SLOTS) michael@0: * Various one-off values: ES5 13.2.3's [[ThrowTypeError]], RegExp statics, michael@0: * the original eval for this global object (implementing |var eval = michael@0: * otherWindow.eval; eval(...)| as an indirect eval), a bit indicating michael@0: * whether this object has been cleared (see JS_ClearScope), and a cache for michael@0: * whether eval is allowed (per the global's Content Security Policy). michael@0: * michael@0: * The first two JSProto_LIMIT-sized ranges are necessary to implement michael@0: * js::FindClassObject, and spec language speaking in terms of "the original michael@0: * Array prototype object", or "as if by the expression new Array()" referring michael@0: * to the original Array constructor. The third range stores the (writable and michael@0: * even deletable) Object, Array, &c. properties (although a slot won't be used michael@0: * again if its property is deleted and readded). michael@0: */ michael@0: class GlobalObject : public JSObject michael@0: { michael@0: /* Count of slots set aside for application use. */ michael@0: static const unsigned APPLICATION_SLOTS = 3; michael@0: michael@0: /* michael@0: * Count of slots to store built-in constructors, prototypes, and initial michael@0: * visible properties for the constructors. michael@0: */ michael@0: static const unsigned STANDARD_CLASS_SLOTS = JSProto_LIMIT * 3; michael@0: michael@0: /* Various function values needed by the engine. */ michael@0: static const unsigned EVAL = APPLICATION_SLOTS + STANDARD_CLASS_SLOTS; michael@0: static const unsigned CREATE_DATAVIEW_FOR_THIS = EVAL + 1; michael@0: static const unsigned THROWTYPEERROR = CREATE_DATAVIEW_FOR_THIS + 1; michael@0: static const unsigned PROTO_GETTER = THROWTYPEERROR + 1; michael@0: michael@0: /* michael@0: * Instances of the internal createArrayFromBuffer function used by the michael@0: * typed array code, one per typed array element type. michael@0: */ michael@0: static const unsigned FROM_BUFFER_UINT8 = PROTO_GETTER + 1; michael@0: static const unsigned FROM_BUFFER_INT8 = FROM_BUFFER_UINT8 + 1; michael@0: static const unsigned FROM_BUFFER_UINT16 = FROM_BUFFER_INT8 + 1; michael@0: static const unsigned FROM_BUFFER_INT16 = FROM_BUFFER_UINT16 + 1; michael@0: static const unsigned FROM_BUFFER_UINT32 = FROM_BUFFER_INT16 + 1; michael@0: static const unsigned FROM_BUFFER_INT32 = FROM_BUFFER_UINT32 + 1; michael@0: static const unsigned FROM_BUFFER_FLOAT32 = FROM_BUFFER_INT32 + 1; michael@0: static const unsigned FROM_BUFFER_FLOAT64 = FROM_BUFFER_FLOAT32 + 1; michael@0: static const unsigned FROM_BUFFER_UINT8CLAMPED = FROM_BUFFER_FLOAT64 + 1; michael@0: michael@0: /* One-off properties stored after slots for built-ins. */ michael@0: static const unsigned ARRAY_ITERATOR_PROTO = FROM_BUFFER_UINT8CLAMPED + 1; michael@0: static const unsigned STRING_ITERATOR_PROTO = ARRAY_ITERATOR_PROTO + 1; michael@0: static const unsigned LEGACY_GENERATOR_OBJECT_PROTO = STRING_ITERATOR_PROTO + 1; michael@0: static const unsigned STAR_GENERATOR_OBJECT_PROTO = LEGACY_GENERATOR_OBJECT_PROTO + 1; michael@0: static const unsigned MAP_ITERATOR_PROTO = STAR_GENERATOR_OBJECT_PROTO + 1; michael@0: static const unsigned SET_ITERATOR_PROTO = MAP_ITERATOR_PROTO + 1; michael@0: static const unsigned COLLATOR_PROTO = SET_ITERATOR_PROTO + 1; michael@0: static const unsigned NUMBER_FORMAT_PROTO = COLLATOR_PROTO + 1; michael@0: static const unsigned DATE_TIME_FORMAT_PROTO = NUMBER_FORMAT_PROTO + 1; michael@0: static const unsigned REGEXP_STATICS = DATE_TIME_FORMAT_PROTO + 1; michael@0: static const unsigned WARNED_WATCH_DEPRECATED = REGEXP_STATICS + 1; michael@0: static const unsigned WARNED_PROTO_SETTING_SLOW = WARNED_WATCH_DEPRECATED + 1; michael@0: static const unsigned RUNTIME_CODEGEN_ENABLED = WARNED_PROTO_SETTING_SLOW + 1; michael@0: static const unsigned DEBUGGERS = RUNTIME_CODEGEN_ENABLED + 1; michael@0: static const unsigned INTRINSICS = DEBUGGERS + 1; michael@0: static const unsigned FLOAT32X4_TYPE_DESCR = INTRINSICS + 1; michael@0: static const unsigned INT32X4_TYPE_DESCR = FLOAT32X4_TYPE_DESCR + 1; michael@0: static const unsigned FOR_OF_PIC_CHAIN = INT32X4_TYPE_DESCR + 1; michael@0: michael@0: /* Total reserved-slot count for global objects. */ michael@0: static const unsigned RESERVED_SLOTS = FOR_OF_PIC_CHAIN + 1; michael@0: michael@0: /* michael@0: * The slot count must be in the public API for JSCLASS_GLOBAL_FLAGS, and michael@0: * we won't expose GlobalObject, so just assert that the two values are michael@0: * synchronized. michael@0: */ michael@0: static_assert(JSCLASS_GLOBAL_SLOT_COUNT == RESERVED_SLOTS, michael@0: "global object slot counts are inconsistent"); michael@0: michael@0: /* Initialize the Function and Object classes. Must only be called once! */ michael@0: JSObject * michael@0: initFunctionAndObjectClasses(JSContext *cx); michael@0: michael@0: void setThrowTypeError(JSFunction *fun) { michael@0: JS_ASSERT(getSlotRef(THROWTYPEERROR).isUndefined()); michael@0: setSlot(THROWTYPEERROR, ObjectValue(*fun)); michael@0: } michael@0: michael@0: void setOriginalEval(JSObject *evalobj) { michael@0: JS_ASSERT(getSlotRef(EVAL).isUndefined()); michael@0: setSlot(EVAL, ObjectValue(*evalobj)); michael@0: } michael@0: michael@0: void setProtoGetter(JSFunction *protoGetter) { michael@0: JS_ASSERT(getSlotRef(PROTO_GETTER).isUndefined()); michael@0: setSlot(PROTO_GETTER, ObjectValue(*protoGetter)); michael@0: } michael@0: michael@0: void setIntrinsicsHolder(JSObject *obj) { michael@0: JS_ASSERT(getSlotRef(INTRINSICS).isUndefined()); michael@0: setSlot(INTRINSICS, ObjectValue(*obj)); michael@0: } michael@0: michael@0: // Emit the specified warning if the given slot in |obj|'s global isn't michael@0: // true, then set the slot to true. Thus calling this method warns once michael@0: // for each global object it's called on, and every other call does michael@0: // nothing. michael@0: static bool michael@0: warnOnceAbout(JSContext *cx, HandleObject obj, uint32_t slot, unsigned errorNumber); michael@0: michael@0: public: michael@0: Value getConstructor(JSProtoKey key) const { michael@0: JS_ASSERT(key <= JSProto_LIMIT); michael@0: return getSlot(APPLICATION_SLOTS + key); michael@0: } michael@0: static bool ensureConstructor(JSContext *cx, Handle global, JSProtoKey key); michael@0: static bool resolveConstructor(JSContext *cx, Handle global, JSProtoKey key); michael@0: static bool initBuiltinConstructor(JSContext *cx, Handle global, michael@0: JSProtoKey key, HandleObject ctor, HandleObject proto); michael@0: michael@0: void setConstructor(JSProtoKey key, const Value &v) { michael@0: JS_ASSERT(key <= JSProto_LIMIT); michael@0: setSlot(APPLICATION_SLOTS + key, v); michael@0: } michael@0: michael@0: Value getPrototype(JSProtoKey key) const { michael@0: JS_ASSERT(key <= JSProto_LIMIT); michael@0: return getSlot(APPLICATION_SLOTS + JSProto_LIMIT + key); michael@0: } michael@0: michael@0: void setPrototype(JSProtoKey key, const Value &value) { michael@0: JS_ASSERT(key <= JSProto_LIMIT); michael@0: setSlot(APPLICATION_SLOTS + JSProto_LIMIT + key, value); michael@0: } michael@0: michael@0: static uint32_t constructorPropertySlot(JSProtoKey key) { michael@0: JS_ASSERT(key <= JSProto_LIMIT); michael@0: return APPLICATION_SLOTS + JSProto_LIMIT * 2 + key; michael@0: } michael@0: michael@0: Value getConstructorPropertySlot(JSProtoKey key) { michael@0: return getSlot(constructorPropertySlot(key)); michael@0: } michael@0: michael@0: void setConstructorPropertySlot(JSProtoKey key, const Value &ctor) { michael@0: setSlot(constructorPropertySlot(key), ctor); michael@0: } michael@0: michael@0: bool classIsInitialized(JSProtoKey key) const { michael@0: bool inited = !getConstructor(key).isUndefined(); michael@0: JS_ASSERT(inited == !getPrototype(key).isUndefined()); michael@0: return inited; michael@0: } michael@0: michael@0: bool functionObjectClassesInitialized() const { michael@0: bool inited = classIsInitialized(JSProto_Function); michael@0: JS_ASSERT(inited == classIsInitialized(JSProto_Object)); michael@0: return inited; michael@0: } michael@0: michael@0: /* michael@0: * Lazy standard classes need a way to indicate they have been initialized. michael@0: * Otherwise, when we delete them, we might accidentally recreate them via michael@0: * a lazy initialization. We use the presence of an object in the michael@0: * getConstructor(key) reserved slot to indicate that they've been michael@0: * initialized. michael@0: * michael@0: * Note: A few builtin objects, like JSON and Math, are not constructors, michael@0: * so getConstructor is a bit of a misnomer. michael@0: */ michael@0: bool isStandardClassResolved(JSProtoKey key) const { michael@0: // If the constructor is undefined, then it hasn't been initialized. michael@0: MOZ_ASSERT(getConstructor(key).isUndefined() || michael@0: getConstructor(key).isObject()); michael@0: return !getConstructor(key).isUndefined(); michael@0: } michael@0: michael@0: bool isStandardClassResolved(const js::Class *clasp) const { michael@0: JSProtoKey key = JSCLASS_CACHED_PROTO_KEY(clasp); michael@0: return isStandardClassResolved(key); michael@0: } michael@0: michael@0: private: michael@0: void setDetailsForKey(JSProtoKey key, JSObject *ctor, JSObject *proto) { michael@0: JS_ASSERT(getConstructor(key).isUndefined()); michael@0: JS_ASSERT(getPrototype(key).isUndefined()); michael@0: JS_ASSERT(getConstructorPropertySlot(key).isUndefined()); michael@0: setConstructor(key, ObjectValue(*ctor)); michael@0: setPrototype(key, ObjectValue(*proto)); michael@0: setConstructorPropertySlot(key, ObjectValue(*ctor)); michael@0: } michael@0: michael@0: void setObjectClassDetails(JSFunction *ctor, JSObject *proto) { michael@0: setDetailsForKey(JSProto_Object, ctor, proto); michael@0: } michael@0: michael@0: void setFunctionClassDetails(JSFunction *ctor, JSObject *proto) { michael@0: setDetailsForKey(JSProto_Function, ctor, proto); michael@0: } michael@0: michael@0: bool arrayClassInitialized() const { michael@0: return classIsInitialized(JSProto_Array); michael@0: } michael@0: michael@0: bool booleanClassInitialized() const { michael@0: return classIsInitialized(JSProto_Boolean); michael@0: } michael@0: bool numberClassInitialized() const { michael@0: return classIsInitialized(JSProto_Number); michael@0: } michael@0: bool stringClassInitialized() const { michael@0: return classIsInitialized(JSProto_String); michael@0: } michael@0: bool regexpClassInitialized() const { michael@0: return classIsInitialized(JSProto_RegExp); michael@0: } michael@0: bool arrayBufferClassInitialized() const { michael@0: return classIsInitialized(JSProto_ArrayBuffer); michael@0: } michael@0: bool sharedArrayBufferClassInitialized() const { michael@0: return classIsInitialized(JSProto_SharedArrayBuffer); michael@0: } michael@0: bool errorClassesInitialized() const { michael@0: return classIsInitialized(JSProto_Error); michael@0: } michael@0: bool dataViewClassInitialized() const { michael@0: return classIsInitialized(JSProto_DataView); michael@0: } michael@0: bool typedArrayClassesInitialized() const { michael@0: // This alias exists only for clarity: in reality all the typed array michael@0: // classes constitute a (semi-)coherent whole. michael@0: return classIsInitialized(JSProto_DataView); michael@0: } michael@0: michael@0: Value createArrayFromBufferHelper(uint32_t slot) const { michael@0: JS_ASSERT(typedArrayClassesInitialized()); michael@0: JS_ASSERT(FROM_BUFFER_UINT8 <= slot && slot <= FROM_BUFFER_UINT8CLAMPED); michael@0: return getSlot(slot); michael@0: } michael@0: michael@0: void setCreateArrayFromBufferHelper(uint32_t slot, Handle fun) { michael@0: JS_ASSERT(getSlotRef(slot).isUndefined()); michael@0: setSlot(slot, ObjectValue(*fun)); michael@0: } michael@0: michael@0: public: michael@0: /* XXX Privatize me! */ michael@0: void setCreateDataViewForThis(Handle fun) { michael@0: JS_ASSERT(getSlotRef(CREATE_DATAVIEW_FOR_THIS).isUndefined()); michael@0: setSlot(CREATE_DATAVIEW_FOR_THIS, ObjectValue(*fun)); michael@0: } michael@0: michael@0: template michael@0: inline void setCreateArrayFromBuffer(Handle fun); michael@0: michael@0: public: michael@0: static GlobalObject *create(JSContext *cx, const Class *clasp); michael@0: michael@0: /* michael@0: * Create a constructor function with the specified name and length using michael@0: * ctor, a method which creates objects with the given class. michael@0: */ michael@0: JSFunction * michael@0: createConstructor(JSContext *cx, JSNative ctor, JSAtom *name, unsigned length, michael@0: gc::AllocKind kind = JSFunction::FinalizeKind); michael@0: michael@0: /* michael@0: * Create an object to serve as [[Prototype]] for instances of the given michael@0: * class, using |Object.prototype| as its [[Prototype]]. Users creating michael@0: * prototype objects with particular internal structure (e.g. reserved michael@0: * slots guaranteed to contain values of particular types) must immediately michael@0: * complete the minimal initialization to make the returned object safe to michael@0: * touch. michael@0: */ michael@0: JSObject *createBlankPrototype(JSContext *cx, const js::Class *clasp); michael@0: michael@0: /* michael@0: * Identical to createBlankPrototype, but uses proto as the [[Prototype]] michael@0: * of the returned blank prototype. michael@0: */ michael@0: JSObject *createBlankPrototypeInheriting(JSContext *cx, const js::Class *clasp, JSObject &proto); michael@0: michael@0: JSObject *getOrCreateObjectPrototype(JSContext *cx) { michael@0: if (functionObjectClassesInitialized()) michael@0: return &getPrototype(JSProto_Object).toObject(); michael@0: Rooted self(cx, this); michael@0: if (!initFunctionAndObjectClasses(cx)) michael@0: return nullptr; michael@0: return &self->getPrototype(JSProto_Object).toObject(); michael@0: } michael@0: michael@0: JSObject *getOrCreateFunctionPrototype(JSContext *cx) { michael@0: if (functionObjectClassesInitialized()) michael@0: return &getPrototype(JSProto_Function).toObject(); michael@0: Rooted self(cx, this); michael@0: if (!initFunctionAndObjectClasses(cx)) michael@0: return nullptr; michael@0: return &self->getPrototype(JSProto_Function).toObject(); michael@0: } michael@0: michael@0: static JSObject *getOrCreateArrayPrototype(JSContext *cx, Handle global) { michael@0: if (!ensureConstructor(cx, global, JSProto_Array)) michael@0: return nullptr; michael@0: return &global->getPrototype(JSProto_Array).toObject(); michael@0: } michael@0: michael@0: JSObject *maybeGetArrayPrototype() { michael@0: if (arrayClassInitialized()) michael@0: return &getPrototype(JSProto_Array).toObject(); michael@0: return nullptr; michael@0: } michael@0: michael@0: static JSObject *getOrCreateBooleanPrototype(JSContext *cx, Handle global) { michael@0: if (!ensureConstructor(cx, global, JSProto_Boolean)) michael@0: return nullptr; michael@0: return &global->getPrototype(JSProto_Boolean).toObject(); michael@0: } michael@0: michael@0: static JSObject *getOrCreateNumberPrototype(JSContext *cx, Handle global) { michael@0: if (!ensureConstructor(cx, global, JSProto_Number)) michael@0: return nullptr; michael@0: return &global->getPrototype(JSProto_Number).toObject(); michael@0: } michael@0: michael@0: static JSObject *getOrCreateStringPrototype(JSContext *cx, Handle global) { michael@0: if (!ensureConstructor(cx, global, JSProto_String)) michael@0: return nullptr; michael@0: return &global->getPrototype(JSProto_String).toObject(); michael@0: } michael@0: michael@0: static JSObject *getOrCreateRegExpPrototype(JSContext *cx, Handle global) { michael@0: if (!ensureConstructor(cx, global, JSProto_RegExp)) michael@0: return nullptr; michael@0: return &global->getPrototype(JSProto_RegExp).toObject(); michael@0: } michael@0: michael@0: JSObject *maybeGetRegExpPrototype() { michael@0: if (regexpClassInitialized()) michael@0: return &getPrototype(JSProto_RegExp).toObject(); michael@0: return nullptr; michael@0: } michael@0: michael@0: static JSObject *getOrCreateArrayBufferPrototype(JSContext *cx, Handle global) { michael@0: if (!ensureConstructor(cx, global, JSProto_ArrayBuffer)) michael@0: return nullptr; michael@0: return &global->getPrototype(JSProto_ArrayBuffer).toObject(); michael@0: } michael@0: michael@0: JSObject *getOrCreateSharedArrayBufferPrototype(JSContext *cx, Handle global) { michael@0: if (!ensureConstructor(cx, global, JSProto_SharedArrayBuffer)) michael@0: return nullptr; michael@0: return &global->getPrototype(JSProto_SharedArrayBuffer).toObject(); michael@0: } michael@0: michael@0: static JSObject *getOrCreateCustomErrorPrototype(JSContext *cx, michael@0: Handle global, michael@0: JSExnType exnType) michael@0: { michael@0: JSProtoKey key = GetExceptionProtoKey(exnType); michael@0: if (!ensureConstructor(cx, global, key)) michael@0: return nullptr; michael@0: return &global->getPrototype(key).toObject(); michael@0: } michael@0: michael@0: JSObject *getOrCreateIntlObject(JSContext *cx) { michael@0: return getOrCreateObject(cx, APPLICATION_SLOTS + JSProto_Intl, initIntlObject); michael@0: } michael@0: michael@0: JSObject *getOrCreateTypedObjectModule(JSContext *cx) { michael@0: return getOrCreateObject(cx, APPLICATION_SLOTS + JSProto_TypedObject, initTypedObjectModule); michael@0: } michael@0: michael@0: void setFloat32x4TypeDescr(JSObject &obj) { michael@0: JS_ASSERT(getSlotRef(FLOAT32X4_TYPE_DESCR).isUndefined()); michael@0: setSlot(FLOAT32X4_TYPE_DESCR, ObjectValue(obj)); michael@0: } michael@0: michael@0: JSObject &float32x4TypeDescr() { michael@0: JS_ASSERT(getSlotRef(FLOAT32X4_TYPE_DESCR).isObject()); michael@0: return getSlotRef(FLOAT32X4_TYPE_DESCR).toObject(); michael@0: } michael@0: michael@0: void setInt32x4TypeDescr(JSObject &obj) { michael@0: JS_ASSERT(getSlotRef(INT32X4_TYPE_DESCR).isUndefined()); michael@0: setSlot(INT32X4_TYPE_DESCR, ObjectValue(obj)); michael@0: } michael@0: michael@0: JSObject &int32x4TypeDescr() { michael@0: JS_ASSERT(getSlotRef(INT32X4_TYPE_DESCR).isObject()); michael@0: return getSlotRef(INT32X4_TYPE_DESCR).toObject(); michael@0: } michael@0: michael@0: TypedObjectModuleObject &getTypedObjectModule() const; michael@0: michael@0: JSObject *getIteratorPrototype() { michael@0: return &getPrototype(JSProto_Iterator).toObject(); michael@0: } michael@0: michael@0: JSObject *getOrCreateCollatorPrototype(JSContext *cx) { michael@0: return getOrCreateObject(cx, COLLATOR_PROTO, initCollatorProto); michael@0: } michael@0: michael@0: JSObject *getOrCreateNumberFormatPrototype(JSContext *cx) { michael@0: return getOrCreateObject(cx, NUMBER_FORMAT_PROTO, initNumberFormatProto); michael@0: } michael@0: michael@0: JSObject *getOrCreateDateTimeFormatPrototype(JSContext *cx) { michael@0: return getOrCreateObject(cx, DATE_TIME_FORMAT_PROTO, initDateTimeFormatProto); michael@0: } michael@0: michael@0: private: michael@0: typedef bool (*ObjectInitOp)(JSContext *cx, Handle global); michael@0: michael@0: JSObject *getOrCreateObject(JSContext *cx, unsigned slot, ObjectInitOp init) { michael@0: Value v = getSlotRef(slot); michael@0: if (v.isObject()) michael@0: return &v.toObject(); michael@0: Rooted self(cx, this); michael@0: if (!init(cx, self)) michael@0: return nullptr; michael@0: return &self->getSlot(slot).toObject(); michael@0: } michael@0: michael@0: public: michael@0: static JSObject *getOrCreateIteratorPrototype(JSContext *cx, michael@0: Handle global) michael@0: { michael@0: if (!ensureConstructor(cx, global, JSProto_Iterator)) michael@0: return nullptr; michael@0: return &global->getSlot(APPLICATION_SLOTS + JSProto_LIMIT + JSProto_Iterator).toObject(); michael@0: } michael@0: michael@0: static JSObject *getOrCreateArrayIteratorPrototype(JSContext *cx, michael@0: Handle global) michael@0: { michael@0: if (!ensureConstructor(cx, global, JSProto_Iterator)) michael@0: return nullptr; michael@0: return &global->getSlot(ARRAY_ITERATOR_PROTO).toObject(); michael@0: } michael@0: michael@0: static JSObject *getOrCreateStringIteratorPrototype(JSContext *cx, michael@0: Handle global) michael@0: { michael@0: if (!ensureConstructor(cx, global, JSProto_Iterator)) michael@0: return nullptr; michael@0: return &global->getSlot(STRING_ITERATOR_PROTO).toObject(); michael@0: } michael@0: michael@0: static JSObject *getOrCreateLegacyGeneratorObjectPrototype(JSContext *cx, michael@0: Handle global) michael@0: { michael@0: if (!ensureConstructor(cx, global, JSProto_Iterator)) michael@0: return nullptr; michael@0: return &global->getSlot(LEGACY_GENERATOR_OBJECT_PROTO).toObject(); michael@0: } michael@0: michael@0: static JSObject *getOrCreateStarGeneratorObjectPrototype(JSContext *cx, michael@0: Handle global) michael@0: { michael@0: if (!ensureConstructor(cx, global, JSProto_Iterator)) michael@0: return nullptr; michael@0: return &global->getSlot(STAR_GENERATOR_OBJECT_PROTO).toObject(); michael@0: } michael@0: michael@0: static JSObject *getOrCreateStarGeneratorFunctionPrototype(JSContext *cx, michael@0: Handle global) michael@0: { michael@0: if (!ensureConstructor(cx, global, JSProto_Iterator)) michael@0: return nullptr; michael@0: return &global->getSlot(APPLICATION_SLOTS + JSProto_LIMIT + JSProto_GeneratorFunction).toObject(); michael@0: } michael@0: michael@0: static JSObject *getOrCreateStarGeneratorFunction(JSContext *cx, michael@0: Handle global) michael@0: { michael@0: if (!ensureConstructor(cx, global, JSProto_Iterator)) michael@0: return nullptr; michael@0: return &global->getSlot(APPLICATION_SLOTS + JSProto_GeneratorFunction).toObject(); michael@0: } michael@0: michael@0: static JSObject *getOrCreateMapIteratorPrototype(JSContext *cx, michael@0: Handle global) michael@0: { michael@0: return global->getOrCreateObject(cx, MAP_ITERATOR_PROTO, initMapIteratorProto); michael@0: } michael@0: michael@0: static JSObject *getOrCreateSetIteratorPrototype(JSContext *cx, michael@0: Handle global) michael@0: { michael@0: return global->getOrCreateObject(cx, SET_ITERATOR_PROTO, initSetIteratorProto); michael@0: } michael@0: michael@0: JSObject *getOrCreateDataViewPrototype(JSContext *cx) { michael@0: Rooted self(cx, this); michael@0: if (!ensureConstructor(cx, self, JSProto_DataView)) michael@0: return nullptr; michael@0: return &self->getPrototype(JSProto_DataView).toObject(); michael@0: } michael@0: michael@0: JSObject *intrinsicsHolder() { michael@0: JS_ASSERT(!getSlot(INTRINSICS).isUndefined()); michael@0: return &getSlot(INTRINSICS).toObject(); michael@0: } michael@0: michael@0: bool maybeGetIntrinsicValue(jsid id, Value *vp) { michael@0: JSObject *holder = intrinsicsHolder(); michael@0: michael@0: if (Shape *shape = holder->nativeLookupPure(id)) { michael@0: *vp = holder->getSlot(shape->slot()); michael@0: return true; michael@0: } michael@0: return false; michael@0: } michael@0: bool maybeGetIntrinsicValue(PropertyName *name, Value *vp) { michael@0: return maybeGetIntrinsicValue(NameToId(name), vp); michael@0: } michael@0: michael@0: static bool getIntrinsicValue(JSContext *cx, Handle global, michael@0: HandlePropertyName name, MutableHandleValue value) michael@0: { michael@0: if (global->maybeGetIntrinsicValue(name, value.address())) michael@0: return true; michael@0: if (!cx->runtime()->cloneSelfHostedValue(cx, name, value)) michael@0: return false; michael@0: RootedId id(cx, NameToId(name)); michael@0: return global->addIntrinsicValue(cx, id, value); michael@0: } michael@0: michael@0: bool addIntrinsicValue(JSContext *cx, HandleId id, HandleValue value); michael@0: michael@0: bool setIntrinsicValue(JSContext *cx, PropertyName *name, HandleValue value) { michael@0: #ifdef DEBUG michael@0: RootedObject self(cx, this); michael@0: JS_ASSERT(cx->runtime()->isSelfHostingGlobal(self)); michael@0: #endif michael@0: RootedObject holder(cx, intrinsicsHolder()); michael@0: RootedValue valCopy(cx, value); michael@0: return JSObject::setProperty(cx, holder, holder, name, &valCopy, false); michael@0: } michael@0: michael@0: bool getSelfHostedFunction(JSContext *cx, HandleAtom selfHostedName, HandleAtom name, michael@0: unsigned nargs, MutableHandleValue funVal); michael@0: michael@0: RegExpStatics *getRegExpStatics() const { michael@0: JSObject &resObj = getSlot(REGEXP_STATICS).toObject(); michael@0: return static_cast(resObj.getPrivate(/* nfixed = */ 1)); michael@0: } michael@0: michael@0: JSObject *getThrowTypeError() const { michael@0: JS_ASSERT(functionObjectClassesInitialized()); michael@0: return &getSlot(THROWTYPEERROR).toObject(); michael@0: } michael@0: michael@0: Value createDataViewForThis() const { michael@0: JS_ASSERT(dataViewClassInitialized()); michael@0: return getSlot(CREATE_DATAVIEW_FOR_THIS); michael@0: } michael@0: michael@0: template michael@0: inline Value createArrayFromBuffer() const; michael@0: michael@0: Value protoGetter() const { michael@0: JS_ASSERT(functionObjectClassesInitialized()); michael@0: return getSlot(PROTO_GETTER); michael@0: } michael@0: michael@0: static bool isRuntimeCodeGenEnabled(JSContext *cx, Handle global); michael@0: michael@0: // Warn about use of the deprecated watch/unwatch functions in the global michael@0: // in which |obj| was created, if no prior warning was given. michael@0: static bool warnOnceAboutWatch(JSContext *cx, HandleObject obj) { michael@0: // Temporarily disabled until we've provided a watch/unwatch workaround for michael@0: // debuggers like Firebug (bug 934669). michael@0: //return warnOnceAbout(cx, obj, WARNED_WATCH_DEPRECATED, JSMSG_OBJECT_WATCH_DEPRECATED); michael@0: return true; michael@0: } michael@0: michael@0: // Warn about use of the given __proto__ setter to attempt to mutate an michael@0: // object's [[Prototype]], if no prior warning was given. michael@0: static bool warnOnceAboutPrototypeMutation(JSContext *cx, HandleObject protoSetter) { michael@0: return warnOnceAbout(cx, protoSetter, WARNED_PROTO_SETTING_SLOW, JSMSG_PROTO_SETTING_SLOW); michael@0: } michael@0: michael@0: static bool getOrCreateEval(JSContext *cx, Handle global, michael@0: MutableHandleObject eval); michael@0: michael@0: // Infallibly test whether the given value is the eval function for this global. michael@0: bool valueIsEval(Value val); michael@0: michael@0: // Implemented in jsiter.cpp. michael@0: static bool initIteratorClasses(JSContext *cx, Handle global); michael@0: michael@0: // Implemented in builtin/MapObject.cpp. michael@0: static bool initMapIteratorProto(JSContext *cx, Handle global); michael@0: static bool initSetIteratorProto(JSContext *cx, Handle global); michael@0: michael@0: // Implemented in Intl.cpp. michael@0: static bool initIntlObject(JSContext *cx, Handle global); michael@0: static bool initCollatorProto(JSContext *cx, Handle global); michael@0: static bool initNumberFormatProto(JSContext *cx, Handle global); michael@0: static bool initDateTimeFormatProto(JSContext *cx, Handle global); michael@0: michael@0: // Implemented in builtin/TypedObject.cpp michael@0: static bool initTypedObjectModule(JSContext *cx, Handle global); michael@0: michael@0: static bool initStandardClasses(JSContext *cx, Handle global); michael@0: michael@0: typedef js::Vector DebuggerVector; michael@0: michael@0: /* michael@0: * The collection of Debugger objects debugging this global. If this global michael@0: * is not a debuggee, this returns either nullptr or an empty vector. michael@0: */ michael@0: DebuggerVector *getDebuggers(); michael@0: michael@0: /* michael@0: * The same, but create the empty vector if one does not already michael@0: * exist. Returns nullptr only on OOM. michael@0: */ michael@0: static DebuggerVector *getOrCreateDebuggers(JSContext *cx, Handle global); michael@0: michael@0: inline JSObject *getForOfPICObject() { michael@0: Value forOfPIC = getReservedSlot(FOR_OF_PIC_CHAIN); michael@0: if (forOfPIC.isUndefined()) michael@0: return nullptr; michael@0: return &forOfPIC.toObject(); michael@0: } michael@0: static JSObject *getOrCreateForOfPICObject(JSContext *cx, Handle global); michael@0: michael@0: static bool addDebugger(JSContext *cx, Handle global, Debugger *dbg); michael@0: }; michael@0: michael@0: template<> michael@0: inline void michael@0: GlobalObject::setCreateArrayFromBuffer(Handle fun) michael@0: { michael@0: setCreateArrayFromBufferHelper(FROM_BUFFER_UINT8, fun); michael@0: } michael@0: michael@0: template<> michael@0: inline void michael@0: GlobalObject::setCreateArrayFromBuffer(Handle fun) michael@0: { michael@0: setCreateArrayFromBufferHelper(FROM_BUFFER_INT8, fun); michael@0: } michael@0: michael@0: template<> michael@0: inline void michael@0: GlobalObject::setCreateArrayFromBuffer(Handle fun) michael@0: { michael@0: setCreateArrayFromBufferHelper(FROM_BUFFER_UINT16, fun); michael@0: } michael@0: michael@0: template<> michael@0: inline void michael@0: GlobalObject::setCreateArrayFromBuffer(Handle fun) michael@0: { michael@0: setCreateArrayFromBufferHelper(FROM_BUFFER_INT16, fun); michael@0: } michael@0: michael@0: template<> michael@0: inline void michael@0: GlobalObject::setCreateArrayFromBuffer(Handle fun) michael@0: { michael@0: setCreateArrayFromBufferHelper(FROM_BUFFER_UINT32, fun); michael@0: } michael@0: michael@0: template<> michael@0: inline void michael@0: GlobalObject::setCreateArrayFromBuffer(Handle fun) michael@0: { michael@0: setCreateArrayFromBufferHelper(FROM_BUFFER_INT32, fun); michael@0: } michael@0: michael@0: template<> michael@0: inline void michael@0: GlobalObject::setCreateArrayFromBuffer(Handle fun) michael@0: { michael@0: setCreateArrayFromBufferHelper(FROM_BUFFER_FLOAT32, fun); michael@0: } michael@0: michael@0: template<> michael@0: inline void michael@0: GlobalObject::setCreateArrayFromBuffer(Handle fun) michael@0: { michael@0: setCreateArrayFromBufferHelper(FROM_BUFFER_FLOAT64, fun); michael@0: } michael@0: michael@0: template<> michael@0: inline void michael@0: GlobalObject::setCreateArrayFromBuffer(Handle fun) michael@0: { michael@0: setCreateArrayFromBufferHelper(FROM_BUFFER_UINT8CLAMPED, fun); michael@0: } michael@0: michael@0: template<> michael@0: inline Value michael@0: GlobalObject::createArrayFromBuffer() const michael@0: { michael@0: return createArrayFromBufferHelper(FROM_BUFFER_UINT8); michael@0: } michael@0: michael@0: template<> michael@0: inline Value michael@0: GlobalObject::createArrayFromBuffer() const michael@0: { michael@0: return createArrayFromBufferHelper(FROM_BUFFER_INT8); michael@0: } michael@0: michael@0: template<> michael@0: inline Value michael@0: GlobalObject::createArrayFromBuffer() const michael@0: { michael@0: return createArrayFromBufferHelper(FROM_BUFFER_UINT16); michael@0: } michael@0: michael@0: template<> michael@0: inline Value michael@0: GlobalObject::createArrayFromBuffer() const michael@0: { michael@0: return createArrayFromBufferHelper(FROM_BUFFER_INT16); michael@0: } michael@0: michael@0: template<> michael@0: inline Value michael@0: GlobalObject::createArrayFromBuffer() const michael@0: { michael@0: return createArrayFromBufferHelper(FROM_BUFFER_UINT32); michael@0: } michael@0: michael@0: template<> michael@0: inline Value michael@0: GlobalObject::createArrayFromBuffer() const michael@0: { michael@0: return createArrayFromBufferHelper(FROM_BUFFER_INT32); michael@0: } michael@0: michael@0: template<> michael@0: inline Value michael@0: GlobalObject::createArrayFromBuffer() const michael@0: { michael@0: return createArrayFromBufferHelper(FROM_BUFFER_FLOAT32); michael@0: } michael@0: michael@0: template<> michael@0: inline Value michael@0: GlobalObject::createArrayFromBuffer() const michael@0: { michael@0: return createArrayFromBufferHelper(FROM_BUFFER_FLOAT64); michael@0: } michael@0: michael@0: template<> michael@0: inline Value michael@0: GlobalObject::createArrayFromBuffer() const michael@0: { michael@0: return createArrayFromBufferHelper(FROM_BUFFER_UINT8CLAMPED); michael@0: } michael@0: michael@0: /* michael@0: * Define ctor.prototype = proto as non-enumerable, non-configurable, and michael@0: * non-writable; define proto.constructor = ctor as non-enumerable but michael@0: * configurable and writable. michael@0: */ michael@0: extern bool michael@0: LinkConstructorAndPrototype(JSContext *cx, JSObject *ctor, JSObject *proto); michael@0: michael@0: /* michael@0: * Define properties, then functions, on the object, then brand for tracing michael@0: * benefits. michael@0: */ michael@0: extern bool michael@0: DefinePropertiesAndBrand(JSContext *cx, JSObject *obj, michael@0: const JSPropertySpec *ps, const JSFunctionSpec *fs); michael@0: michael@0: typedef HashSet, SystemAllocPolicy> GlobalObjectSet; michael@0: michael@0: /* michael@0: * Convenience templates to generic constructor and prototype creation functions michael@0: * for ClassSpecs. michael@0: */ michael@0: michael@0: template michael@0: JSObject * michael@0: GenericCreateConstructor(JSContext *cx, JSProtoKey key) michael@0: { michael@0: JSAtom *atom = AtomStateOffsetToName(cx->names(), atomOffset); michael@0: return cx->global()->createConstructor(cx, ctor, atom, length); michael@0: } michael@0: michael@0: template michael@0: JSObject * michael@0: GenericCreatePrototype(JSContext *cx, JSProtoKey key) michael@0: { michael@0: return cx->global()->createBlankPrototype(cx, clasp); michael@0: } michael@0: michael@0: } // namespace js michael@0: michael@0: template<> michael@0: inline bool michael@0: JSObject::is() const michael@0: { michael@0: return !!(getClass()->flags & JSCLASS_IS_GLOBAL); michael@0: } michael@0: michael@0: #endif /* vm_GlobalObject_h */