1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- 2 * vim: set ts=8 sts=2 et sw=2 tw=80: 3 * This Source Code Form is subject to the terms of the Mozilla Public 4 * License, v. 2.0. If a copy of the MPL was not distributed with this 5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 6 7 #ifndef vm_PromiseLookup_h 8 #define vm_PromiseLookup_h 9 10 #include "mozilla/Attributes.h" // MOZ_NON_TEMPORARY_CLASS, MOZ_INIT_OUTSIDE_CTOR 11 12 #include <stdint.h> // uint8_t, uint32_t 13 14 #include "js/CallArgs.h" // JSNative 15 16 struct JS_PUBLIC_API JSContext; 17 18 class JSFunction; 19 20 namespace js { 21 22 class NativeObject; 23 class PromiseObject; 24 class Shape; 25 26 class MOZ_NON_TEMPORARY_CLASS PromiseLookup final { 27 // clang-format off 28 /* 29 * A PromiseLookup holds the following: 30 * 31 * Promise's shape (promiseConstructorShape_) 32 * To ensure that Promise has not been modified. 33 * 34 * Promise.prototype's shape (promiseProtoShape_) 35 * To ensure that Promise.prototype has not been modified. 36 * 37 * Promise's slot number for the @@species getter 38 * (promiseSpeciesGetterSlot_) 39 * To quickly retrieve the @@species getter for Promise. 40 * 41 * Promise's slot number for resolve (promiseResolveSlot_) 42 * To quickly retrieve the Promise.resolve function. 43 * 44 * Promise.prototype's slot number for constructor (promiseProtoConstructorSlot_) 45 * To quickly retrieve the Promise.prototype.constructor property. 46 * 47 * Promise.prototype's slot number for then (promiseProtoThenSlot_) 48 * To quickly retrieve the Promise.prototype.then function. 49 * 50 * MOZ_INIT_OUTSIDE_CTOR fields below are set in |initialize()|. The 51 * constructor only initializes a |state_| field, that defines whether the 52 * other fields are accessible. 53 */ 54 // clang-format on 55 56 // Shape of matching Promise object. 57 MOZ_INIT_OUTSIDE_CTOR Shape* promiseConstructorShape_; 58 59 // Shape of matching Promise.prototype object. 60 MOZ_INIT_OUTSIDE_CTOR Shape* promiseProtoShape_; 61 62 // Slot number for the @@species property on the Promise constructor. 63 MOZ_INIT_OUTSIDE_CTOR uint32_t promiseSpeciesGetterSlot_; 64 65 // Slots Promise.resolve, Promise.prototype.constructor, and 66 // Promise.prototype.then. 67 MOZ_INIT_OUTSIDE_CTOR uint32_t promiseResolveSlot_; 68 MOZ_INIT_OUTSIDE_CTOR uint32_t promiseProtoConstructorSlot_; 69 MOZ_INIT_OUTSIDE_CTOR uint32_t promiseProtoThenSlot_; 70 71 enum class State : uint8_t { 72 // Flags marking the lazy initialization of the above fields. 73 Uninitialized, 74 Initialized, 75 76 // The disabled flag is set when we don't want to try optimizing 77 // anymore because core objects were changed. 78 Disabled 79 }; 80 81 State state_ = State::Uninitialized; 82 83 // Initialize the internal fields. 84 // 85 // The cache is successfully initialized iff 86 // 1. Promise and Promise.prototype classes are initialized. 87 // 2. Promise.prototype.constructor is equal to Promise. 88 // 3. Promise.prototype.then is the original `then` function. 89 // 4. Promise[@@species] is the original @@species getter. 90 // 5. Promise.resolve is the original `resolve` function. 91 void initialize(JSContext* cx); 92 93 // Reset the cache. 94 void reset(); 95 96 // Check if the global promise-related objects have not been messed with 97 // in a way that would disable this cache. 98 bool isPromiseStateStillSane(JSContext* cx); 99 100 // Flags to control whether or not ensureInitialized() is allowed to 101 // reinitialize the cache when the Promise state is no longer sane. 102 enum class Reinitialize : bool { Allowed, Disallowed }; 103 104 // Return true if the lookup cache is properly initialized for usage. 105 bool ensureInitialized(JSContext* cx, Reinitialize reinitialize); 106 107 // Return true if the prototype of the given Promise object is 108 // Promise.prototype and the object doesn't shadow properties from 109 // Promise.prototype. 110 bool hasDefaultProtoAndNoShadowedProperties(JSContext* cx, 111 PromiseObject* promise); 112 113 // Return true if the given Promise object uses the default @@species, 114 // "constructor", and "then" properties. 115 bool isDefaultInstance(JSContext* cx, PromiseObject* promise, 116 Reinitialize reinitialize); 117 118 // Return the built-in Promise constructor or null if not yet initialized. 119 static JSFunction* getPromiseConstructor(JSContext* cx); 120 121 // Return the built-in Promise prototype or null if not yet initialized. 122 static NativeObject* getPromisePrototype(JSContext* cx); 123 124 // Return true if the slot contains the given native. 125 static bool isDataPropertyNative(JSContext* cx, NativeObject* obj, 126 uint32_t slot, JSNative native); 127 128 // Return true if the accessor shape contains the given native. 129 static bool isAccessorPropertyNative(JSContext* cx, NativeObject* holder, 130 uint32_t getterSlot, JSNative native); 131 132 public: 133 /** Construct a |PromiseSpeciesLookup| in the uninitialized state. */ PromiseLookup()134 PromiseLookup() { reset(); } 135 136 // Return true if the Promise constructor and Promise.prototype still use 137 // the default built-in functions. 138 bool isDefaultPromiseState(JSContext* cx); 139 140 // Return true if the given Promise object uses the default @@species, 141 // "constructor", and "then" properties. isDefaultInstance(JSContext * cx,PromiseObject * promise)142 bool isDefaultInstance(JSContext* cx, PromiseObject* promise) { 143 return isDefaultInstance(cx, promise, Reinitialize::Allowed); 144 } 145 146 // Return true if the given Promise object uses the default @@species, 147 // "constructor", and "then" properties. isDefaultInstanceWhenPromiseStateIsSane(JSContext * cx,PromiseObject * promise)148 bool isDefaultInstanceWhenPromiseStateIsSane(JSContext* cx, 149 PromiseObject* promise) { 150 return isDefaultInstance(cx, promise, Reinitialize::Disallowed); 151 } 152 153 // Purge the cache and all info associated with it. purge()154 void purge() { 155 if (state_ == State::Initialized) { 156 reset(); 157 } 158 } 159 }; 160 161 } // namespace js 162 163 #endif // vm_PromiseLookup_h 164