diff options
author | Martok <martok@martoks-place.de> | 2023-01-27 19:32:21 +0100 |
---|---|---|
committer | Martok <martok@martoks-place.de> | 2023-02-01 00:02:44 +0100 |
commit | e3c44ebafa1295585628385d4a74c5dc8d8583fd (patch) | |
tree | e74f73b65fe77743d96f310e8400ce263f7c1e73 /js/src/builtin/Promise.h | |
parent | c9764f76ec95c2003bc6197d90cff0da819b211f (diff) | |
download | uxp-e3c44ebafa1295585628385d4a74c5dc8d8583fd.tar.gz |
Issue #2089 - Add cache for Promise property lookups
Based-on: m-c 1475678/11
Diffstat (limited to 'js/src/builtin/Promise.h')
-rw-r--r-- | js/src/builtin/Promise.h | 136 |
1 files changed, 136 insertions, 0 deletions
diff --git a/js/src/builtin/Promise.h b/js/src/builtin/Promise.h index 1fe9b060ad..3d6dbe0e62 100644 --- a/js/src/builtin/Promise.h +++ b/js/src/builtin/Promise.h @@ -181,6 +181,142 @@ AsyncGeneratorEnqueue(JSContext* cx, HandleValue asyncGenVal, CompletionKind com bool AsyncFromSyncIteratorMethod(JSContext* cx, CallArgs& args, CompletionKind completionKind); +class MOZ_NON_TEMPORARY_CLASS PromiseLookup final +{ + /* + * A PromiseLookup holds the following: + * + * Promise's shape (promiseConstructorShape_) + * To ensure that Promise has not been modified. + * + * Promise.prototype's shape (promiseProtoShape_) + * To ensure that Promise.prototype has not been modified. + * + * Promise's shape for the @@species getter. (promiseSpeciesShape_) + * To quickly retrieve the @@species getter for Promise. + * + * Promise's slot number for resolve (promiseResolveSlot_) + * To quickly retrieve the Promise.resolve function. + * + * Promise.prototype's slot number for constructor (promiseProtoConstructorSlot_) + * To quickly retrieve the Promise.prototype.constructor property. + * + * Promise.prototype's slot number for then (promiseProtoThenSlot_) + * To quickly retrieve the Promise.prototype.then function. + * + * MOZ_INIT_OUTSIDE_CTOR fields below are set in |initialize()|. The + * constructor only initializes a |state_| field, that defines whether the + * other fields are accessible. + */ + + // Shape of matching Promise object. + MOZ_INIT_OUTSIDE_CTOR Shape* promiseConstructorShape_; + +#ifdef DEBUG + // Accessor Shape containing the @@species property. + // See isPromiseStateStillSane() for why this field is debug-only. + MOZ_INIT_OUTSIDE_CTOR Shape* promiseSpeciesShape_; +#endif + + // Shape of matching Promise.prototype object. + MOZ_INIT_OUTSIDE_CTOR Shape* promiseProtoShape_; + + // Slots Promise.resolve, Promise.prototype.constructor, and + // Promise.prototype.then. + MOZ_INIT_OUTSIDE_CTOR uint32_t promiseResolveSlot_; + MOZ_INIT_OUTSIDE_CTOR uint32_t promiseProtoConstructorSlot_; + MOZ_INIT_OUTSIDE_CTOR uint32_t promiseProtoThenSlot_; + + enum class State : uint8_t { + // Flags marking the lazy initialization of the above fields. + Uninitialized, + Initialized, + + // The disabled flag is set when we don't want to try optimizing + // anymore because core objects were changed. + Disabled + }; + + State state_ = State::Uninitialized; + + // Initialize the internal fields. + // + // The cache is successfully initialized iff + // 1. Promise and Promise.prototype classes are initialized. + // 2. Promise.prototype.constructor is equal to Promise. + // 3. Promise.prototype.then is the original `then` function. + // 4. Promise[@@species] is the original @@species getter. + // 5. Promise.resolve is the original `resolve` function. + void initialize(JSContext* cx); + + // Reset the cache. + void reset(); + + // Check if the global promise-related objects have not been messed with + // in a way that would disable this cache. + bool isPromiseStateStillSane(JSContext* cx); + + // Flags to control whether or not ensureInitialized() is allowed to + // reinitialize the cache when the Promise state is no longer sane. + enum class Reinitialize : bool { + Allowed, + Disallowed + }; + + // Return true if the lookup cache is properly initialized for usage. + bool ensureInitialized(JSContext* cx, Reinitialize reinitialize); + + // Return true if the prototype of the given Promise object is + // Promise.prototype and the object doesn't shadow properties from + // Promise.prototype. + bool hasDefaultProtoAndNoShadowedProperties(JSContext* cx, PromiseObject* promise); + + // Return true if the given Promise object uses the default @@species, + // "constructor", and "then" properties. + bool isDefaultInstance(JSContext* cx, PromiseObject* promise, Reinitialize reinitialize); + + // Return the built-in Promise constructor or null if not yet initialized. + static JSFunction* getPromiseConstructor(JSContext* cx); + + // Return the built-in Promise prototype or null if not yet initialized. + static NativeObject* getPromisePrototype(JSContext* cx); + + // Return true if the slot contains the given native. + static bool isDataPropertyNative(JSContext* cx, NativeObject* obj, uint32_t slot, + JSNative native); + + // Return true if the accessor shape contains the given native. + static bool isAccessorPropertyNative(JSContext* cx, Shape* shape, JSNative native); + + public: + /** Construct a |PromiseSpeciesLookup| in the uninitialized state. */ + PromiseLookup() { + reset(); + } + + // Return true if the Promise constructor and Promise.prototype still use + // the default built-in functions. + bool isDefaultPromiseState(JSContext* cx); + + // Return true if the given Promise object uses the default @@species, + // "constructor", and "then" properties. + bool isDefaultInstance(JSContext* cx, PromiseObject* promise) { + return isDefaultInstance(cx, promise, Reinitialize::Allowed); + } + + // Return true if the given Promise object uses the default @@species, + // "constructor", and "then" properties. + bool isDefaultInstanceWhenPromiseStateIsSane(JSContext* cx, PromiseObject* promise) { + return isDefaultInstance(cx, promise, Reinitialize::Disallowed); + } + + // Purge the cache and all info associated with it. + void purge() { + if (state_ == State::Initialized) + reset(); + } +}; + /** * A PromiseTask represents a task that can be dispatched to a helper thread * (via StartPromiseTask), executed (by implementing PromiseTask::execute()), |