Changeset View
Changeset View
Standalone View
Standalone View
libraries/source/spidermonkey/include-win32-debug/js/Class.h
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- | /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- | ||||
* vim: set ts=8 sts=4 et sw=4 tw=99: | * vim: set ts=8 sts=4 et sw=4 tw=99: | ||||
* This Source Code Form is subject to the terms of the Mozilla Public | * This Source Code Form is subject to the terms of the Mozilla Public | ||||
* License, v. 2.0. If a copy of the MPL was not distributed with this | * License, v. 2.0. If a copy of the MPL was not distributed with this | ||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */ | * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ | ||||
/* JSClass definition and its component types, plus related interfaces. */ | /* JSClass definition and its component types, plus related interfaces. */ | ||||
#ifndef js_Class_h | #ifndef js_Class_h | ||||
#define js_Class_h | #define js_Class_h | ||||
#include "mozilla/DebugOnly.h" | |||||
#include "jstypes.h" | #include "jstypes.h" | ||||
#include "js/CallArgs.h" | #include "js/CallArgs.h" | ||||
#include "js/Id.h" | #include "js/Id.h" | ||||
#include "js/TypeDecls.h" | #include "js/TypeDecls.h" | ||||
/* | /* | ||||
* A JSClass acts as a vtable for JS objects that allows JSAPI clients to | * A JSClass acts as a vtable for JS objects that allows JSAPI clients to | ||||
Show All 15 Lines | |||||
// This is equal to JSFunction::class_. Use it in places where you don't want | // This is equal to JSFunction::class_. Use it in places where you don't want | ||||
// to #include jsfun.h. | // to #include jsfun.h. | ||||
extern JS_FRIEND_DATA(const js::Class* const) FunctionClassPtr; | extern JS_FRIEND_DATA(const js::Class* const) FunctionClassPtr; | ||||
} // namespace js | } // namespace js | ||||
namespace JS { | namespace JS { | ||||
template <typename T> | class AutoIdVector; | ||||
class AutoVectorRooter; | |||||
typedef AutoVectorRooter<jsid> AutoIdVector; | |||||
/** | /** | ||||
* The answer to a successful query as to whether an object is an Array per | * The answer to a successful query as to whether an object is an Array per | ||||
* ES6's internal |IsArray| operation (as exposed by |Array.isArray|). | * ES6's internal |IsArray| operation (as exposed by |Array.isArray|). | ||||
*/ | */ | ||||
enum class IsArrayAnswer | enum class IsArrayAnswer | ||||
{ | { | ||||
Array, | Array, | ||||
▲ Show 20 Lines • Show All 276 Lines • ▼ Show 20 Lines | |||||
(* JSFunToStringOp)(JSContext* cx, JS::HandleObject obj, unsigned indent); | (* JSFunToStringOp)(JSContext* cx, JS::HandleObject obj, unsigned indent); | ||||
/** | /** | ||||
* Resolve a lazy property named by id in obj by defining it directly in obj. | * Resolve a lazy property named by id in obj by defining it directly in obj. | ||||
* Lazy properties are those reflected from some peer native property space | * Lazy properties are those reflected from some peer native property space | ||||
* (e.g., the DOM attributes for a given node reflected as obj) on demand. | * (e.g., the DOM attributes for a given node reflected as obj) on demand. | ||||
* | * | ||||
* JS looks for a property in an object, and if not found, tries to resolve | * JS looks for a property in an object, and if not found, tries to resolve | ||||
* the given id. *resolvedp should be set to true iff the property was | * the given id. *resolvedp should be set to true iff the property was defined | ||||
* was defined on |obj|. | * on |obj|. | ||||
*/ | */ | ||||
typedef bool | typedef bool | ||||
(* JSResolveOp)(JSContext* cx, JS::HandleObject obj, JS::HandleId id, | (* JSResolveOp)(JSContext* cx, JS::HandleObject obj, JS::HandleId id, | ||||
bool* resolvedp); | bool* resolvedp); | ||||
/** | /** | ||||
* A class with a resolve hook can optionally have a mayResolve hook. This hook | * A class with a resolve hook can optionally have a mayResolve hook. This hook | ||||
* must have no side effects and must return true for a given id if the resolve | * must have no side effects and must return true for a given id if the resolve | ||||
Show All 13 Lines | |||||
* from other live objects or from GC roots. Obviously, finalizers must never | * from other live objects or from GC roots. Obviously, finalizers must never | ||||
* store a reference to obj. | * store a reference to obj. | ||||
*/ | */ | ||||
typedef void | typedef void | ||||
(* JSFinalizeOp)(JSFreeOp* fop, JSObject* obj); | (* JSFinalizeOp)(JSFreeOp* fop, JSObject* obj); | ||||
/** Finalizes external strings created by JS_NewExternalString. */ | /** Finalizes external strings created by JS_NewExternalString. */ | ||||
struct JSStringFinalizer { | struct JSStringFinalizer { | ||||
void (*finalize)(const JSStringFinalizer* fin, char16_t* chars); | void (*finalize)(JS::Zone* zone, const JSStringFinalizer* fin, char16_t* chars); | ||||
}; | }; | ||||
/** | /** | ||||
* Check whether v is an instance of obj. Return false on error or exception, | * Check whether v is an instance of obj. Return false on error or exception, | ||||
* true on success with true in *bp if v is an instance of obj, false in | * true on success with true in *bp if v is an instance of obj, false in | ||||
* *bp otherwise. | * *bp otherwise. | ||||
*/ | */ | ||||
typedef bool | typedef bool | ||||
(* JSHasInstanceOp)(JSContext* cx, JS::HandleObject obj, JS::MutableHandleValue vp, | (* JSHasInstanceOp)(JSContext* cx, JS::HandleObject obj, JS::MutableHandleValue vp, | ||||
bool* bp); | bool* bp); | ||||
/** | /** | ||||
* Function type for trace operation of the class called to enumerate all | * Function type for trace operation of the class called to enumerate all | ||||
* traceable things reachable from obj's private data structure. For each such | * traceable things reachable from obj's private data structure. For each such | ||||
* thing, a trace implementation must call one of the JS_Call*Tracer variants | * thing, a trace implementation must call JS::TraceEdge on the thing's | ||||
* on the thing. | * location. | ||||
* | * | ||||
* JSTraceOp implementation can assume that no other threads mutates object | * JSTraceOp implementation can assume that no other threads mutates object | ||||
* state. It must not change state of the object or corresponding native | * state. It must not change state of the object or corresponding native | ||||
* structures. The only exception for this rule is the case when the embedding | * structures. The only exception for this rule is the case when the embedding | ||||
* needs a tight integration with GC. In that case the embedding can check if | * needs a tight integration with GC. In that case the embedding can check if | ||||
* the traversal is a part of the marking phase through calling | * the traversal is a part of the marking phase through calling | ||||
* JS_IsGCMarkingTracer and apply a special code like emptying caches or | * JS_IsGCMarkingTracer and apply a special code like emptying caches or | ||||
* marking its native structures. | * marking its native structures. | ||||
Show All 11 Lines | |||||
namespace js { | namespace js { | ||||
typedef bool | typedef bool | ||||
(* LookupPropertyOp)(JSContext* cx, JS::HandleObject obj, JS::HandleId id, | (* LookupPropertyOp)(JSContext* cx, JS::HandleObject obj, JS::HandleId id, | ||||
JS::MutableHandleObject objp, JS::MutableHandle<Shape*> propp); | JS::MutableHandleObject objp, JS::MutableHandle<Shape*> propp); | ||||
typedef bool | typedef bool | ||||
(* DefinePropertyOp)(JSContext* cx, JS::HandleObject obj, JS::HandleId id, | (* DefinePropertyOp)(JSContext* cx, JS::HandleObject obj, JS::HandleId id, | ||||
JS::Handle<JSPropertyDescriptor> desc, | JS::Handle<JS::PropertyDescriptor> desc, | ||||
JS::ObjectOpResult& result); | JS::ObjectOpResult& result); | ||||
typedef bool | typedef bool | ||||
(* HasPropertyOp)(JSContext* cx, JS::HandleObject obj, JS::HandleId id, bool* foundp); | (* HasPropertyOp)(JSContext* cx, JS::HandleObject obj, JS::HandleId id, bool* foundp); | ||||
typedef bool | typedef bool | ||||
(* GetPropertyOp)(JSContext* cx, JS::HandleObject obj, JS::HandleValue receiver, JS::HandleId id, | (* GetPropertyOp)(JSContext* cx, JS::HandleObject obj, JS::HandleValue receiver, JS::HandleId id, | ||||
JS::MutableHandleValue vp); | JS::MutableHandleValue vp); | ||||
typedef bool | typedef bool | ||||
(* SetPropertyOp)(JSContext* cx, JS::HandleObject obj, JS::HandleId id, JS::HandleValue v, | (* SetPropertyOp)(JSContext* cx, JS::HandleObject obj, JS::HandleId id, JS::HandleValue v, | ||||
JS::HandleValue receiver, JS::ObjectOpResult& result); | JS::HandleValue receiver, JS::ObjectOpResult& result); | ||||
typedef bool | typedef bool | ||||
(* GetOwnPropertyOp)(JSContext* cx, JS::HandleObject obj, JS::HandleId id, | (* GetOwnPropertyOp)(JSContext* cx, JS::HandleObject obj, JS::HandleId id, | ||||
JS::MutableHandle<JSPropertyDescriptor> desc); | JS::MutableHandle<JS::PropertyDescriptor> desc); | ||||
typedef bool | typedef bool | ||||
(* DeletePropertyOp)(JSContext* cx, JS::HandleObject obj, JS::HandleId id, | (* DeletePropertyOp)(JSContext* cx, JS::HandleObject obj, JS::HandleId id, | ||||
JS::ObjectOpResult& result); | JS::ObjectOpResult& result); | ||||
typedef bool | typedef bool | ||||
(* WatchOp)(JSContext* cx, JS::HandleObject obj, JS::HandleId id, JS::HandleObject callable); | (* WatchOp)(JSContext* cx, JS::HandleObject obj, JS::HandleId id, JS::HandleObject callable); | ||||
typedef bool | typedef bool | ||||
Show All 12 Lines | public: | ||||
}; | }; | ||||
private: | private: | ||||
// Only one of these is used. | // Only one of these is used. | ||||
JS::RootedObject resObj_; | JS::RootedObject resObj_; | ||||
JS::Value* vp_; | JS::Value* vp_; | ||||
uint32_t index_; | uint32_t index_; | ||||
mozilla::DebugOnly<uint32_t> length_; | #ifdef DEBUG | ||||
uint32_t length_; | |||||
#endif | |||||
GetBehavior getBehavior_; | GetBehavior getBehavior_; | ||||
public: | public: | ||||
ElementAdder(JSContext* cx, JSObject* obj, uint32_t length, GetBehavior behavior) | ElementAdder(JSContext* cx, JSObject* obj, uint32_t length, GetBehavior behavior) | ||||
: resObj_(cx, obj), vp_(nullptr), index_(0), length_(length), getBehavior_(behavior) | : resObj_(cx, obj), vp_(nullptr), index_(0), | ||||
#ifdef DEBUG | |||||
length_(length), | |||||
#endif | |||||
getBehavior_(behavior) | |||||
{} | {} | ||||
ElementAdder(JSContext* cx, JS::Value* vp, uint32_t length, GetBehavior behavior) | ElementAdder(JSContext* cx, JS::Value* vp, uint32_t length, GetBehavior behavior) | ||||
: resObj_(cx), vp_(vp), index_(0), length_(length), getBehavior_(behavior) | : resObj_(cx), vp_(vp), index_(0), | ||||
#ifdef DEBUG | |||||
length_(length), | |||||
#endif | |||||
getBehavior_(behavior) | |||||
{} | {} | ||||
GetBehavior getBehavior() const { return getBehavior_; } | GetBehavior getBehavior() const { return getBehavior_; } | ||||
bool append(JSContext* cx, JS::HandleValue v); | bool append(JSContext* cx, JS::HandleValue v); | ||||
void appendHole(); | void appendHole(); | ||||
}; | }; | ||||
typedef bool | typedef bool | ||||
(* GetElementsOp)(JSContext* cx, JS::HandleObject obj, uint32_t begin, uint32_t end, | (* GetElementsOp)(JSContext* cx, JS::HandleObject obj, uint32_t begin, uint32_t end, | ||||
ElementAdder* adder); | ElementAdder* adder); | ||||
typedef void | typedef void | ||||
(* FinalizeOp)(FreeOp* fop, JSObject* obj); | (* FinalizeOp)(FreeOp* fop, JSObject* obj); | ||||
#define JS_CLASS_MEMBERS(FinalizeOpType) \ | // The special treatment of |finalize| and |trace| is necessary because if we | ||||
// assign either of those hooks to a local variable and then call it -- as is | |||||
// done with the other hooks -- the GC hazard analysis gets confused. | |||||
#define JS_CLASS_MEMBERS(ClassOpsType, FreeOpType) \ | |||||
const char* name; \ | const char* name; \ | ||||
uint32_t flags; \ | uint32_t flags; \ | ||||
const ClassOpsType* cOps; \ | |||||
\ | |||||
JSAddPropertyOp getAddProperty() const { return cOps ? cOps->addProperty : nullptr; } \ | |||||
JSDeletePropertyOp getDelProperty() const { return cOps ? cOps->delProperty : nullptr; } \ | |||||
JSGetterOp getGetProperty() const { return cOps ? cOps->getProperty : nullptr; } \ | |||||
JSSetterOp getSetProperty() const { return cOps ? cOps->setProperty : nullptr; } \ | |||||
JSEnumerateOp getEnumerate() const { return cOps ? cOps->enumerate : nullptr; } \ | |||||
JSResolveOp getResolve() const { return cOps ? cOps->resolve : nullptr; } \ | |||||
JSMayResolveOp getMayResolve() const { return cOps ? cOps->mayResolve : nullptr; } \ | |||||
JSNative getCall() const { return cOps ? cOps->call : nullptr; } \ | |||||
JSHasInstanceOp getHasInstance() const { return cOps ? cOps->hasInstance : nullptr; } \ | |||||
JSNative getConstruct() const { return cOps ? cOps->construct : nullptr; } \ | |||||
\ | |||||
bool hasFinalize() const { return cOps && cOps->finalize; } \ | |||||
bool hasTrace() const { return cOps && cOps->trace; } \ | |||||
\ | \ | ||||
/* Function pointer members (may be null). */ \ | bool isTrace(JSTraceOp trace) const { return cOps && cOps->trace == trace; } \ | ||||
JSAddPropertyOp addProperty; \ | \ | ||||
JSDeletePropertyOp delProperty; \ | void doFinalize(FreeOpType* fop, JSObject* obj) const { \ | ||||
JSGetterOp getProperty; \ | MOZ_ASSERT(cOps && cOps->finalize); \ | ||||
JSSetterOp setProperty; \ | cOps->finalize(fop, obj); \ | ||||
JSEnumerateOp enumerate; \ | } \ | ||||
JSResolveOp resolve; \ | void doTrace(JSTracer* trc, JSObject* obj) const { \ | ||||
JSMayResolveOp mayResolve; \ | MOZ_ASSERT(cOps && cOps->trace); \ | ||||
FinalizeOpType finalize; \ | cOps->trace(trc, obj); \ | ||||
JSNative call; \ | } | ||||
JSHasInstanceOp hasInstance; \ | |||||
JSNative construct; \ | struct ClassOps | ||||
JSTraceOp trace | { | ||||
/* Function pointer members (may be null). */ | |||||
JSAddPropertyOp addProperty; | |||||
JSDeletePropertyOp delProperty; | |||||
JSGetterOp getProperty; | |||||
JSSetterOp setProperty; | |||||
JSEnumerateOp enumerate; | |||||
JSResolveOp resolve; | |||||
JSMayResolveOp mayResolve; | |||||
FinalizeOp finalize; | |||||
JSNative call; | |||||
JSHasInstanceOp hasInstance; | |||||
JSNative construct; | |||||
JSTraceOp trace; | |||||
}; | |||||
/** Callback for the creation of constructor and prototype objects. */ | /** Callback for the creation of constructor and prototype objects. */ | ||||
typedef JSObject* (*ClassObjectCreationOp)(JSContext* cx, JSProtoKey key); | typedef JSObject* (*ClassObjectCreationOp)(JSContext* cx, JSProtoKey key); | ||||
/** Callback for custom post-processing after class initialization via ClassSpec. */ | /** Callback for custom post-processing after class initialization via ClassSpec. */ | ||||
typedef bool (*FinishClassInitOp)(JSContext* cx, JS::HandleObject ctor, | typedef bool (*FinishClassInitOp)(JSContext* cx, JS::HandleObject ctor, | ||||
JS::HandleObject proto); | JS::HandleObject proto); | ||||
const size_t JSCLASS_CACHED_PROTO_WIDTH = 6; | const size_t JSCLASS_CACHED_PROTO_WIDTH = 6; | ||||
struct ClassSpec | struct ClassSpec | ||||
{ | { | ||||
// All properties except flags should be accessed through accessor. | // All properties except flags should be accessed through accessor. | ||||
ClassObjectCreationOp createConstructor_; | ClassObjectCreationOp createConstructor_; | ||||
ClassObjectCreationOp createPrototype_; | ClassObjectCreationOp createPrototype_; | ||||
const JSFunctionSpec* constructorFunctions_; | const JSFunctionSpec* constructorFunctions_; | ||||
const JSPropertySpec* constructorProperties_; | const JSPropertySpec* constructorProperties_; | ||||
const JSFunctionSpec* prototypeFunctions_; | const JSFunctionSpec* prototypeFunctions_; | ||||
const JSPropertySpec* prototypeProperties_; | const JSPropertySpec* prototypeProperties_; | ||||
FinishClassInitOp finishInit_; | FinishClassInitOp finishInit_; | ||||
uintptr_t flags; | uintptr_t flags; | ||||
static const size_t ParentKeyWidth = JSCLASS_CACHED_PROTO_WIDTH; | static const size_t ProtoKeyWidth = JSCLASS_CACHED_PROTO_WIDTH; | ||||
static const uintptr_t ParentKeyMask = (1 << ParentKeyWidth) - 1; | static const uintptr_t ProtoKeyMask = (1 << ProtoKeyWidth) - 1; | ||||
static const uintptr_t DontDefineConstructor = 1 << ParentKeyWidth; | static const uintptr_t DontDefineConstructor = 1 << ProtoKeyWidth; | ||||
static const uintptr_t IsDelegated = 1 << (ParentKeyWidth + 1); | static const uintptr_t IsDelegated = 1 << (ProtoKeyWidth + 1); | ||||
bool defined() const { return !!createConstructor_; } | bool defined() const { return !!createConstructor_; } | ||||
bool delegated() const { | bool delegated() const { | ||||
return (flags & IsDelegated); | return (flags & IsDelegated); | ||||
} | } | ||||
bool dependent() const { | // The ProtoKey this class inherits from. | ||||
JSProtoKey inheritanceProtoKey() const { | |||||
MOZ_ASSERT(defined()); | MOZ_ASSERT(defined()); | ||||
return (flags & ParentKeyMask); | |||||
} | |||||
JSProtoKey parentKey() const { | |||||
static_assert(JSProto_Null == 0, "zeroed key must be null"); | static_assert(JSProto_Null == 0, "zeroed key must be null"); | ||||
return JSProtoKey(flags & ParentKeyMask); | |||||
// Default: Inherit from Object. | |||||
if (!(flags & ProtoKeyMask)) | |||||
return JSProto_Object; | |||||
return JSProtoKey(flags & ProtoKeyMask); | |||||
} | } | ||||
bool shouldDefineConstructor() const { | bool shouldDefineConstructor() const { | ||||
MOZ_ASSERT(defined()); | MOZ_ASSERT(defined()); | ||||
return !(flags & DontDefineConstructor); | return !(flags & DontDefineConstructor); | ||||
} | } | ||||
const ClassSpec* delegatedClassSpec() const { | const ClassSpec* delegatedClassSpec() const { | ||||
Show All 36 Lines | FinishClassInitOp finishInitHook() const { | ||||
return delegatedClassSpec()->finishInitHook(); | return delegatedClassSpec()->finishInitHook(); | ||||
return finishInit_; | return finishInit_; | ||||
} | } | ||||
}; | }; | ||||
struct ClassExtension | struct ClassExtension | ||||
{ | { | ||||
/** | /** | ||||
* isWrappedNative is true only if the class is an XPCWrappedNative. | |||||
* WeakMaps use this to override the wrapper disposal optimization. | |||||
*/ | |||||
bool isWrappedNative; | |||||
/** | |||||
* If an object is used as a key in a weakmap, it may be desirable for the | * If an object is used as a key in a weakmap, it may be desirable for the | ||||
* garbage collector to keep that object around longer than it otherwise | * garbage collector to keep that object around longer than it otherwise | ||||
* would. A common case is when the key is a wrapper around an object in | * would. A common case is when the key is a wrapper around an object in | ||||
* another compartment, and we want to avoid collecting the wrapper (and | * another compartment, and we want to avoid collecting the wrapper (and | ||||
* removing the weakmap entry) as long as the wrapped object is alive. In | * removing the weakmap entry) as long as the wrapped object is alive. In | ||||
* that case, the wrapped object is returned by the wrapper's | * that case, the wrapped object is returned by the wrapper's | ||||
* weakmapKeyDelegateOp hook. As long as the wrapper is used as a weakmap | * weakmapKeyDelegateOp hook. As long as the wrapper is used as a weakmap | ||||
* key, it will not be collected (and remain in the weakmap) until the | * key, it will not be collected (and remain in the weakmap) until the | ||||
Show All 14 Lines | struct ClassExtension | ||||
*/ | */ | ||||
JSObjectMovedOp objectMovedOp; | JSObjectMovedOp objectMovedOp; | ||||
}; | }; | ||||
inline ClassObjectCreationOp DELEGATED_CLASSSPEC(const ClassSpec* spec) { | inline ClassObjectCreationOp DELEGATED_CLASSSPEC(const ClassSpec* spec) { | ||||
return reinterpret_cast<ClassObjectCreationOp>(const_cast<ClassSpec*>(spec)); | return reinterpret_cast<ClassObjectCreationOp>(const_cast<ClassSpec*>(spec)); | ||||
} | } | ||||
#define JS_NULL_CLASS_SPEC {nullptr,nullptr,nullptr,nullptr,nullptr,nullptr} | #define JS_NULL_CLASS_SPEC nullptr | ||||
#define JS_NULL_CLASS_EXT {false,nullptr} | #define JS_NULL_CLASS_EXT nullptr | ||||
struct ObjectOps | struct ObjectOps | ||||
{ | { | ||||
LookupPropertyOp lookupProperty; | LookupPropertyOp lookupProperty; | ||||
DefinePropertyOp defineProperty; | DefinePropertyOp defineProperty; | ||||
HasPropertyOp hasProperty; | HasPropertyOp hasProperty; | ||||
GetPropertyOp getProperty; | GetPropertyOp getProperty; | ||||
SetPropertyOp setProperty; | SetPropertyOp setProperty; | ||||
GetOwnPropertyOp getOwnPropertyDescriptor; | GetOwnPropertyOp getOwnPropertyDescriptor; | ||||
DeletePropertyOp deleteProperty; | DeletePropertyOp deleteProperty; | ||||
WatchOp watch; | WatchOp watch; | ||||
UnwatchOp unwatch; | UnwatchOp unwatch; | ||||
GetElementsOp getElements; | GetElementsOp getElements; | ||||
JSNewEnumerateOp enumerate; | JSNewEnumerateOp enumerate; | ||||
JSFunToStringOp funToString; | JSFunToStringOp funToString; | ||||
}; | }; | ||||
#define JS_NULL_OBJECT_OPS \ | #define JS_NULL_OBJECT_OPS nullptr | ||||
{nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, \ | |||||
nullptr, nullptr, nullptr, nullptr} | |||||
} // namespace js | } // namespace js | ||||
// Classes, objects, and properties. | // Classes, objects, and properties. | ||||
typedef void (*JSClassInternal)(); | typedef void (*JSClassInternal)(); | ||||
struct JSClassOps | |||||
{ | |||||
/* Function pointer members (may be null). */ | |||||
JSAddPropertyOp addProperty; | |||||
JSDeletePropertyOp delProperty; | |||||
JSGetterOp getProperty; | |||||
JSSetterOp setProperty; | |||||
JSEnumerateOp enumerate; | |||||
JSResolveOp resolve; | |||||
JSMayResolveOp mayResolve; | |||||
JSFinalizeOp finalize; | |||||
JSNative call; | |||||
JSHasInstanceOp hasInstance; | |||||
JSNative construct; | |||||
JSTraceOp trace; | |||||
}; | |||||
#define JS_NULL_CLASS_OPS nullptr | |||||
struct JSClass { | struct JSClass { | ||||
JS_CLASS_MEMBERS(JSFinalizeOp); | JS_CLASS_MEMBERS(JSClassOps, JSFreeOp); | ||||
void* reserved[23]; | void* reserved[3]; | ||||
}; | }; | ||||
#define JSCLASS_HAS_PRIVATE (1<<0) // objects have private slot | #define JSCLASS_HAS_PRIVATE (1<<0) // objects have private slot | ||||
#define JSCLASS_DELAY_METADATA_CALLBACK (1<<1) // class's initialization code | #define JSCLASS_DELAY_METADATA_BUILDER (1<<1) // class's initialization code | ||||
// will call | // will call | ||||
// SetNewObjectMetadata itself | // SetNewObjectMetadata itself | ||||
#define JSCLASS_IS_WRAPPED_NATIVE (1<<2) // class is an XPCWrappedNative. | |||||
// WeakMaps use this to override | |||||
// the wrapper disposal | |||||
// mechanism. | |||||
#define JSCLASS_PRIVATE_IS_NSISUPPORTS (1<<3) // private is (nsISupports*) | #define JSCLASS_PRIVATE_IS_NSISUPPORTS (1<<3) // private is (nsISupports*) | ||||
#define JSCLASS_IS_DOMJSCLASS (1<<4) // objects are DOM | #define JSCLASS_IS_DOMJSCLASS (1<<4) // objects are DOM | ||||
// Bit 5 is unused. | #define JSCLASS_HAS_XRAYED_CONSTRUCTOR (1<<5) // if wrapped by an xray | ||||
// wrapper, the builtin | |||||
// class's constructor won't | |||||
// be unwrapped and invoked. | |||||
// Instead, the constructor is | |||||
// resolved in the caller's | |||||
// compartment and invoked | |||||
// with a wrapped newTarget. | |||||
// The constructor has to | |||||
// detect and handle this | |||||
// situation. | |||||
// See PromiseConstructor for | |||||
// details. | |||||
#define JSCLASS_EMULATES_UNDEFINED (1<<6) // objects of this class act | #define JSCLASS_EMULATES_UNDEFINED (1<<6) // objects of this class act | ||||
// like the value undefined, | // like the value undefined, | ||||
// in some contexts | // in some contexts | ||||
#define JSCLASS_USERBIT1 (1<<7) // Reserved for embeddings. | #define JSCLASS_USERBIT1 (1<<7) // Reserved for embeddings. | ||||
// To reserve slots fetched and stored via JS_Get/SetReservedSlot, bitwise-or | // To reserve slots fetched and stored via JS_Get/SetReservedSlot, bitwise-or | ||||
// JSCLASS_HAS_RESERVED_SLOTS(n) into the initializer for JSClass.flags, where | // JSCLASS_HAS_RESERVED_SLOTS(n) into the initializer for JSClass.flags, where | ||||
// n is a constant in [1, 255]. Reserved slots are indexed from 0 to n-1. | // n is a constant in [1, 255]. Reserved slots are indexed from 0 to n-1. | ||||
Show All 18 Lines | |||||
#define JSCLASS_SKIP_NURSERY_FINALIZE (1<<(JSCLASS_HIGH_FLAGS_SHIFT+5)) | #define JSCLASS_SKIP_NURSERY_FINALIZE (1<<(JSCLASS_HIGH_FLAGS_SHIFT+5)) | ||||
// Reserved for embeddings. | // Reserved for embeddings. | ||||
#define JSCLASS_USERBIT2 (1<<(JSCLASS_HIGH_FLAGS_SHIFT+6)) | #define JSCLASS_USERBIT2 (1<<(JSCLASS_HIGH_FLAGS_SHIFT+6)) | ||||
#define JSCLASS_USERBIT3 (1<<(JSCLASS_HIGH_FLAGS_SHIFT+7)) | #define JSCLASS_USERBIT3 (1<<(JSCLASS_HIGH_FLAGS_SHIFT+7)) | ||||
#define JSCLASS_BACKGROUND_FINALIZE (1<<(JSCLASS_HIGH_FLAGS_SHIFT+8)) | #define JSCLASS_BACKGROUND_FINALIZE (1<<(JSCLASS_HIGH_FLAGS_SHIFT+8)) | ||||
#define JSCLASS_FOREGROUND_FINALIZE (1<<(JSCLASS_HIGH_FLAGS_SHIFT+9)) | |||||
// Bits 26 through 31 are reserved for the CACHED_PROTO_KEY mechanism, see | // Bits 26 through 31 are reserved for the CACHED_PROTO_KEY mechanism, see | ||||
// below. | // below. | ||||
// ECMA-262 requires that most constructors used internally create objects | // ECMA-262 requires that most constructors used internally create objects | ||||
// with "the original Foo.prototype value" as their [[Prototype]] (__proto__) | // with "the original Foo.prototype value" as their [[Prototype]] (__proto__) | ||||
// member initial value. The "original ... value" verbiage is there because | // member initial value. The "original ... value" verbiage is there because | ||||
// in ECMA-262, global properties naming class objects are read/write and | // in ECMA-262, global properties naming class objects are read/write and | ||||
// deleteable, for the most part. | // deleteable, for the most part. | ||||
// | // | ||||
// Implementing this efficiently requires that global objects have classes | // Implementing this efficiently requires that global objects have classes | ||||
// with the following flags. Failure to use JSCLASS_GLOBAL_FLAGS was | // with the following flags. Failure to use JSCLASS_GLOBAL_FLAGS was | ||||
// previously allowed, but is now an ES5 violation and thus unsupported. | // previously allowed, but is now an ES5 violation and thus unsupported. | ||||
// | // | ||||
// JSCLASS_GLOBAL_APPLICATION_SLOTS is the number of slots reserved at | // JSCLASS_GLOBAL_APPLICATION_SLOTS is the number of slots reserved at | ||||
// the beginning of every global object's slots for use by the | // the beginning of every global object's slots for use by the | ||||
// application. | // application. | ||||
#define JSCLASS_GLOBAL_APPLICATION_SLOTS 5 | #define JSCLASS_GLOBAL_APPLICATION_SLOTS 5 | ||||
#define JSCLASS_GLOBAL_SLOT_COUNT \ | #define JSCLASS_GLOBAL_SLOT_COUNT \ | ||||
(JSCLASS_GLOBAL_APPLICATION_SLOTS + JSProto_LIMIT * 3 + 36) | (JSCLASS_GLOBAL_APPLICATION_SLOTS + JSProto_LIMIT * 2 + 39) | ||||
#define JSCLASS_GLOBAL_FLAGS_WITH_SLOTS(n) \ | #define JSCLASS_GLOBAL_FLAGS_WITH_SLOTS(n) \ | ||||
(JSCLASS_IS_GLOBAL | JSCLASS_HAS_RESERVED_SLOTS(JSCLASS_GLOBAL_SLOT_COUNT + (n))) | (JSCLASS_IS_GLOBAL | JSCLASS_HAS_RESERVED_SLOTS(JSCLASS_GLOBAL_SLOT_COUNT + (n))) | ||||
#define JSCLASS_GLOBAL_FLAGS \ | #define JSCLASS_GLOBAL_FLAGS \ | ||||
JSCLASS_GLOBAL_FLAGS_WITH_SLOTS(0) | JSCLASS_GLOBAL_FLAGS_WITH_SLOTS(0) | ||||
#define JSCLASS_HAS_GLOBAL_FLAG_AND_SLOTS(clasp) \ | #define JSCLASS_HAS_GLOBAL_FLAG_AND_SLOTS(clasp) \ | ||||
(((clasp)->flags & JSCLASS_IS_GLOBAL) \ | (((clasp)->flags & JSCLASS_IS_GLOBAL) \ | ||||
&& JSCLASS_RESERVED_SLOTS(clasp) >= JSCLASS_GLOBAL_SLOT_COUNT) | && JSCLASS_RESERVED_SLOTS(clasp) >= JSCLASS_GLOBAL_SLOT_COUNT) | ||||
Show All 9 Lines | |||||
// Initializer for unused members of statically initialized JSClass structs. | // Initializer for unused members of statically initialized JSClass structs. | ||||
#define JSCLASS_NO_INTERNAL_MEMBERS {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0} | #define JSCLASS_NO_INTERNAL_MEMBERS {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0} | ||||
#define JSCLASS_NO_OPTIONAL_MEMBERS 0,0,0,0,0,JSCLASS_NO_INTERNAL_MEMBERS | #define JSCLASS_NO_OPTIONAL_MEMBERS 0,0,0,0,0,JSCLASS_NO_INTERNAL_MEMBERS | ||||
namespace js { | namespace js { | ||||
struct Class | struct Class | ||||
{ | { | ||||
JS_CLASS_MEMBERS(FinalizeOp); | JS_CLASS_MEMBERS(js::ClassOps, FreeOp); | ||||
ClassSpec spec; | const ClassSpec* spec; | ||||
ClassExtension ext; | const ClassExtension* ext; | ||||
ObjectOps ops; | const ObjectOps* oOps; | ||||
/* | /* | ||||
* Objects of this class aren't native objects. They don't have Shapes that | * Objects of this class aren't native objects. They don't have Shapes that | ||||
* describe their properties and layout. Classes using this flag must | * describe their properties and layout. Classes using this flag must | ||||
* provide their own property behavior, either by being proxy classes (do | * provide their own property behavior, either by being proxy classes (do | ||||
* this) or by overriding all the ObjectOps except getElements, watch and | * this) or by overriding all the ObjectOps except getElements, watch and | ||||
* unwatch (don't do this). | * unwatch (don't do this). | ||||
*/ | */ | ||||
Show All 12 Lines | struct Class | ||||
} | } | ||||
bool isJSFunction() const { | bool isJSFunction() const { | ||||
return this == js::FunctionClassPtr; | return this == js::FunctionClassPtr; | ||||
} | } | ||||
bool nonProxyCallable() const { | bool nonProxyCallable() const { | ||||
MOZ_ASSERT(!isProxy()); | MOZ_ASSERT(!isProxy()); | ||||
return isJSFunction() || call; | return isJSFunction() || getCall(); | ||||
} | } | ||||
bool isProxy() const { | bool isProxy() const { | ||||
return flags & JSCLASS_IS_PROXY; | return flags & JSCLASS_IS_PROXY; | ||||
} | } | ||||
bool isDOMClass() const { | bool isDOMClass() const { | ||||
return flags & JSCLASS_IS_DOMJSCLASS; | return flags & JSCLASS_IS_DOMJSCLASS; | ||||
} | } | ||||
bool shouldDelayMetadataCallback() const { | bool shouldDelayMetadataBuilder() const { | ||||
return flags & JSCLASS_DELAY_METADATA_CALLBACK; | return flags & JSCLASS_DELAY_METADATA_BUILDER; | ||||
} | |||||
bool isWrappedNative() const { | |||||
return flags & JSCLASS_IS_WRAPPED_NATIVE; | |||||
} | } | ||||
static size_t offsetOfFlags() { return offsetof(Class, flags); } | static size_t offsetOfFlags() { return offsetof(Class, flags); } | ||||
}; | |||||
bool specDefined() const { return spec ? spec->defined() : false; } | |||||
JSProtoKey specInheritanceProtoKey() | |||||
const { return spec ? spec->inheritanceProtoKey() : JSProto_Null; } | |||||
bool specShouldDefineConstructor() | |||||
const { return spec ? spec->shouldDefineConstructor() : true; } | |||||
ClassObjectCreationOp specCreateConstructorHook() | |||||
const { return spec ? spec->createConstructorHook() : nullptr; } | |||||
ClassObjectCreationOp specCreatePrototypeHook() | |||||
const { return spec ? spec->createPrototypeHook() : nullptr; } | |||||
const JSFunctionSpec* specConstructorFunctions() | |||||
const { return spec ? spec->constructorFunctions() : nullptr; } | |||||
const JSPropertySpec* specConstructorProperties() | |||||
const { return spec ? spec->constructorProperties() : nullptr; } | |||||
const JSFunctionSpec* specPrototypeFunctions() | |||||
const { return spec ? spec->prototypeFunctions() : nullptr; } | |||||
const JSPropertySpec* specPrototypeProperties() | |||||
const { return spec ? spec->prototypeProperties() : nullptr; } | |||||
FinishClassInitOp specFinishInitHook() | |||||
const { return spec ? spec->finishInitHook() : nullptr; } | |||||
JSWeakmapKeyDelegateOp extWeakmapKeyDelegateOp() | |||||
const { return ext ? ext->weakmapKeyDelegateOp : nullptr; } | |||||
JSObjectMovedOp extObjectMovedOp() | |||||
const { return ext ? ext->objectMovedOp : nullptr; } | |||||
LookupPropertyOp getOpsLookupProperty() const { return oOps ? oOps->lookupProperty : nullptr; } | |||||
DefinePropertyOp getOpsDefineProperty() const { return oOps ? oOps->defineProperty : nullptr; } | |||||
HasPropertyOp getOpsHasProperty() const { return oOps ? oOps->hasProperty : nullptr; } | |||||
GetPropertyOp getOpsGetProperty() const { return oOps ? oOps->getProperty : nullptr; } | |||||
SetPropertyOp getOpsSetProperty() const { return oOps ? oOps->setProperty : nullptr; } | |||||
GetOwnPropertyOp getOpsGetOwnPropertyDescriptor() | |||||
const { return oOps ? oOps->getOwnPropertyDescriptor | |||||
: nullptr; } | |||||
DeletePropertyOp getOpsDeleteProperty() const { return oOps ? oOps->deleteProperty : nullptr; } | |||||
WatchOp getOpsWatch() const { return oOps ? oOps->watch : nullptr; } | |||||
UnwatchOp getOpsUnwatch() const { return oOps ? oOps->unwatch : nullptr; } | |||||
GetElementsOp getOpsGetElements() const { return oOps ? oOps->getElements : nullptr; } | |||||
JSNewEnumerateOp getOpsEnumerate() const { return oOps ? oOps->enumerate : nullptr; } | |||||
JSFunToStringOp getOpsFunToString() const { return oOps ? oOps->funToString : nullptr; } | |||||
}; | |||||
static_assert(offsetof(JSClassOps, addProperty) == offsetof(ClassOps, addProperty), | |||||
"ClassOps and JSClassOps must be consistent"); | |||||
static_assert(offsetof(JSClassOps, delProperty) == offsetof(ClassOps, delProperty), | |||||
"ClassOps and JSClassOps must be consistent"); | |||||
static_assert(offsetof(JSClassOps, getProperty) == offsetof(ClassOps, getProperty), | |||||
"ClassOps and JSClassOps must be consistent"); | |||||
static_assert(offsetof(JSClassOps, setProperty) == offsetof(ClassOps, setProperty), | |||||
"ClassOps and JSClassOps must be consistent"); | |||||
static_assert(offsetof(JSClassOps, enumerate) == offsetof(ClassOps, enumerate), | |||||
"ClassOps and JSClassOps must be consistent"); | |||||
static_assert(offsetof(JSClassOps, resolve) == offsetof(ClassOps, resolve), | |||||
"ClassOps and JSClassOps must be consistent"); | |||||
static_assert(offsetof(JSClassOps, mayResolve) == offsetof(ClassOps, mayResolve), | |||||
"ClassOps and JSClassOps must be consistent"); | |||||
static_assert(offsetof(JSClassOps, finalize) == offsetof(ClassOps, finalize), | |||||
"ClassOps and JSClassOps must be consistent"); | |||||
static_assert(offsetof(JSClassOps, call) == offsetof(ClassOps, call), | |||||
"ClassOps and JSClassOps must be consistent"); | |||||
static_assert(offsetof(JSClassOps, construct) == offsetof(ClassOps, construct), | |||||
"ClassOps and JSClassOps must be consistent"); | |||||
static_assert(offsetof(JSClassOps, hasInstance) == offsetof(ClassOps, hasInstance), | |||||
"ClassOps and JSClassOps must be consistent"); | |||||
static_assert(offsetof(JSClassOps, trace) == offsetof(ClassOps, trace), | |||||
"ClassOps and JSClassOps must be consistent"); | |||||
static_assert(sizeof(JSClassOps) == sizeof(ClassOps), | |||||
"ClassOps and JSClassOps must be consistent"); | |||||
static_assert(offsetof(JSClass, name) == offsetof(Class, name), | static_assert(offsetof(JSClass, name) == offsetof(Class, name), | ||||
"Class and JSClass must be consistent"); | "Class and JSClass must be consistent"); | ||||
static_assert(offsetof(JSClass, flags) == offsetof(Class, flags), | static_assert(offsetof(JSClass, flags) == offsetof(Class, flags), | ||||
"Class and JSClass must be consistent"); | "Class and JSClass must be consistent"); | ||||
static_assert(offsetof(JSClass, addProperty) == offsetof(Class, addProperty), | static_assert(offsetof(JSClass, cOps) == offsetof(Class, cOps), | ||||
"Class and JSClass must be consistent"); | |||||
static_assert(offsetof(JSClass, delProperty) == offsetof(Class, delProperty), | |||||
"Class and JSClass must be consistent"); | |||||
static_assert(offsetof(JSClass, getProperty) == offsetof(Class, getProperty), | |||||
"Class and JSClass must be consistent"); | |||||
static_assert(offsetof(JSClass, setProperty) == offsetof(Class, setProperty), | |||||
"Class and JSClass must be consistent"); | |||||
static_assert(offsetof(JSClass, enumerate) == offsetof(Class, enumerate), | |||||
"Class and JSClass must be consistent"); | |||||
static_assert(offsetof(JSClass, resolve) == offsetof(Class, resolve), | |||||
"Class and JSClass must be consistent"); | |||||
static_assert(offsetof(JSClass, mayResolve) == offsetof(Class, mayResolve), | |||||
"Class and JSClass must be consistent"); | |||||
static_assert(offsetof(JSClass, finalize) == offsetof(Class, finalize), | |||||
"Class and JSClass must be consistent"); | |||||
static_assert(offsetof(JSClass, call) == offsetof(Class, call), | |||||
"Class and JSClass must be consistent"); | |||||
static_assert(offsetof(JSClass, construct) == offsetof(Class, construct), | |||||
"Class and JSClass must be consistent"); | |||||
static_assert(offsetof(JSClass, hasInstance) == offsetof(Class, hasInstance), | |||||
"Class and JSClass must be consistent"); | |||||
static_assert(offsetof(JSClass, trace) == offsetof(Class, trace), | |||||
"Class and JSClass must be consistent"); | "Class and JSClass must be consistent"); | ||||
static_assert(sizeof(JSClass) == sizeof(Class), | static_assert(sizeof(JSClass) == sizeof(Class), | ||||
"Class and JSClass must be consistent"); | "Class and JSClass must be consistent"); | ||||
static MOZ_ALWAYS_INLINE const JSClass* | static MOZ_ALWAYS_INLINE const JSClass* | ||||
Jsvalify(const Class* c) | Jsvalify(const Class* c) | ||||
{ | { | ||||
return (const JSClass*)c; | return (const JSClass*)c; | ||||
} | } | ||||
static MOZ_ALWAYS_INLINE const Class* | static MOZ_ALWAYS_INLINE const Class* | ||||
Valueify(const JSClass* c) | Valueify(const JSClass* c) | ||||
{ | { | ||||
return (const Class*)c; | return (const Class*)c; | ||||
} | } | ||||
/** | /** | ||||
* Enumeration describing possible values of the [[Class]] internal property | * Enumeration describing possible values of the [[Class]] internal property | ||||
* value of objects. | * value of objects. | ||||
*/ | */ | ||||
enum ESClassValue { | enum class ESClass { | ||||
ESClass_Object, ESClass_Array, ESClass_Number, ESClass_String, | Object, | ||||
ESClass_Boolean, ESClass_RegExp, ESClass_ArrayBuffer, ESClass_SharedArrayBuffer, | Array, | ||||
ESClass_Date, ESClass_Set, ESClass_Map, | Number, | ||||
String, | |||||
Boolean, | |||||
RegExp, | |||||
ArrayBuffer, | |||||
SharedArrayBuffer, | |||||
Date, | |||||
Set, | |||||
Map, | |||||
Promise, | |||||
MapIterator, | |||||
SetIterator, | |||||
Arguments, | |||||
Error, | |||||
/** None of the above. */ | /** None of the above. */ | ||||
ESClass_Other | Other | ||||
}; | }; | ||||
/* Fills |vp| with the unboxed value for boxed types, or undefined otherwise. */ | /* Fills |vp| with the unboxed value for boxed types, or undefined otherwise. */ | ||||
inline bool | bool | ||||
Unbox(JSContext* cx, JS::HandleObject obj, JS::MutableHandleValue vp); | Unbox(JSContext* cx, JS::HandleObject obj, JS::MutableHandleValue vp); | ||||
#ifdef DEBUG | #ifdef DEBUG | ||||
JS_FRIEND_API(bool) | JS_FRIEND_API(bool) | ||||
HasObjectMovedOp(JSObject* obj); | HasObjectMovedOp(JSObject* obj); | ||||
#endif | #endif | ||||
} /* namespace js */ | } /* namespace js */ | ||||
#endif /* js_Class_h */ | #endif /* js_Class_h */ |
Wildfire Games · Phabricator