| /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- |
| * vim: set ts=8 sts=4 et sw=4 tw=99: |
| * 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 |
| * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
| |
| #ifndef jsfriendapi_h |
| #define jsfriendapi_h |
| |
| #include "mozilla/Atomics.h" |
| #include "mozilla/Casting.h" |
| #include "mozilla/MemoryReporting.h" |
| #include "mozilla/UniquePtr.h" |
| |
| #include "jsapi.h" // For JSAutoByteString. See bug 1033916. |
| #include "jsbytecode.h" |
| #include "jspubtd.h" |
| |
| #include "js/CallArgs.h" |
| #include "js/CallNonGenericMethod.h" |
| #include "js/Class.h" |
| |
| #if JS_STACK_GROWTH_DIRECTION > 0 |
| # define JS_CHECK_STACK_SIZE(limit, sp) (MOZ_LIKELY((uintptr_t)(sp) < (limit))) |
| #else |
| # define JS_CHECK_STACK_SIZE(limit, sp) (MOZ_LIKELY((uintptr_t)(sp) > (limit))) |
| #endif |
| |
| class JSAtom; |
| struct JSErrorFormatString; |
| class JSLinearString; |
| struct JSJitInfo; |
| class JSErrorReport; |
| |
| namespace JS { |
| template <class T> |
| class Heap; |
| } /* namespace JS */ |
| |
| namespace js { |
| class JS_FRIEND_API(BaseProxyHandler); |
| class InterpreterFrame; |
| } /* namespace js */ |
| |
| extern JS_FRIEND_API(void) |
| JS_SetGrayGCRootsTracer(JSRuntime* rt, JSTraceDataOp traceOp, void* data); |
| |
| extern JS_FRIEND_API(JSObject*) |
| JS_FindCompilationScope(JSContext* cx, JS::HandleObject obj); |
| |
| extern JS_FRIEND_API(JSFunction*) |
| JS_GetObjectFunction(JSObject* obj); |
| |
| extern JS_FRIEND_API(bool) |
| JS_SplicePrototype(JSContext* cx, JS::HandleObject obj, JS::HandleObject proto); |
| |
| extern JS_FRIEND_API(JSObject*) |
| JS_NewObjectWithUniqueType(JSContext* cx, const JSClass* clasp, JS::HandleObject proto); |
| |
| /** |
| * Allocate an object in exactly the same way as JS_NewObjectWithGivenProto, but |
| * without invoking the metadata callback on it. This allows creation of |
| * internal bookkeeping objects that are guaranteed to not have metadata |
| * attached to them. |
| */ |
| extern JS_FRIEND_API(JSObject*) |
| JS_NewObjectWithoutMetadata(JSContext* cx, const JSClass* clasp, JS::Handle<JSObject*> proto); |
| |
| extern JS_FRIEND_API(uint32_t) |
| JS_ObjectCountDynamicSlots(JS::HandleObject obj); |
| |
| extern JS_FRIEND_API(size_t) |
| JS_SetProtoCalled(JSContext* cx); |
| |
| extern JS_FRIEND_API(bool) |
| JS_ImmutablePrototypesEnabled(); |
| |
| extern JS_FRIEND_API(size_t) |
| JS_GetCustomIteratorCount(JSContext* cx); |
| |
| extern JS_FRIEND_API(bool) |
| JS_NondeterministicGetWeakMapKeys(JSContext* cx, JS::HandleObject obj, JS::MutableHandleObject ret); |
| |
| extern JS_FRIEND_API(bool) |
| JS_NondeterministicGetWeakSetKeys(JSContext* cx, JS::HandleObject obj, JS::MutableHandleObject ret); |
| |
| // Raw JSScript* because this needs to be callable from a signal handler. |
| extern JS_FRIEND_API(unsigned) |
| JS_PCToLineNumber(JSScript* script, jsbytecode* pc, unsigned* columnp = nullptr); |
| |
| /** |
| * Determine whether the given object is backed by a DeadObjectProxy. |
| * |
| * Such objects hold no other objects (they have no outgoing reference edges) |
| * and will throw if you touch them (e.g. by reading/writing a property). |
| */ |
| extern JS_FRIEND_API(bool) |
| JS_IsDeadWrapper(JSObject* obj); |
| |
| /* |
| * Used by the cycle collector to trace through a shape or object group and |
| * all cycle-participating data it reaches, using bounded stack space. |
| */ |
| extern JS_FRIEND_API(void) |
| JS_TraceShapeCycleCollectorChildren(JS::CallbackTracer* trc, JS::GCCellPtr shape); |
| extern JS_FRIEND_API(void) |
| JS_TraceObjectGroupCycleCollectorChildren(JS::CallbackTracer* trc, JS::GCCellPtr group); |
| |
| enum { |
| JS_TELEMETRY_GC_REASON, |
| JS_TELEMETRY_GC_IS_COMPARTMENTAL, |
| JS_TELEMETRY_GC_MS, |
| JS_TELEMETRY_GC_BUDGET_MS, |
| JS_TELEMETRY_GC_ANIMATION_MS, |
| JS_TELEMETRY_GC_MAX_PAUSE_MS, |
| JS_TELEMETRY_GC_MARK_MS, |
| JS_TELEMETRY_GC_SWEEP_MS, |
| JS_TELEMETRY_GC_MARK_ROOTS_MS, |
| JS_TELEMETRY_GC_MARK_GRAY_MS, |
| JS_TELEMETRY_GC_SLICE_MS, |
| JS_TELEMETRY_GC_SLOW_PHASE, |
| JS_TELEMETRY_GC_MMU_50, |
| JS_TELEMETRY_GC_RESET, |
| JS_TELEMETRY_GC_INCREMENTAL_DISABLED, |
| JS_TELEMETRY_GC_NON_INCREMENTAL, |
| JS_TELEMETRY_GC_SCC_SWEEP_TOTAL_MS, |
| JS_TELEMETRY_GC_SCC_SWEEP_MAX_PAUSE_MS, |
| JS_TELEMETRY_GC_MINOR_REASON, |
| JS_TELEMETRY_GC_MINOR_REASON_LONG, |
| JS_TELEMETRY_GC_MINOR_US, |
| JS_TELEMETRY_DEPRECATED_LANGUAGE_EXTENSIONS_IN_CONTENT, |
| JS_TELEMETRY_DEPRECATED_LANGUAGE_EXTENSIONS_IN_ADDONS, |
| JS_TELEMETRY_ADDON_EXCEPTIONS |
| }; |
| |
| typedef void |
| (*JSAccumulateTelemetryDataCallback)(int id, uint32_t sample, const char* key); |
| |
| extern JS_FRIEND_API(void) |
| JS_SetAccumulateTelemetryCallback(JSRuntime* rt, JSAccumulateTelemetryDataCallback callback); |
| |
| extern JS_FRIEND_API(JSPrincipals*) |
| JS_GetCompartmentPrincipals(JSCompartment* compartment); |
| |
| extern JS_FRIEND_API(void) |
| JS_SetCompartmentPrincipals(JSCompartment* compartment, JSPrincipals* principals); |
| |
| extern JS_FRIEND_API(JSPrincipals*) |
| JS_GetScriptPrincipals(JSScript* script); |
| |
| extern JS_FRIEND_API(bool) |
| JS_ScriptHasMutedErrors(JSScript* script); |
| |
| extern JS_FRIEND_API(JSObject*) |
| JS_CloneObject(JSContext* cx, JS::HandleObject obj, JS::HandleObject proto); |
| |
| /** |
| * Copy the own properties of src to dst in a fast way. src and dst must both |
| * be native and must be in the compartment of cx. They must have the same |
| * class, the same parent, and the same prototype. Class reserved slots will |
| * NOT be copied. |
| * |
| * dst must not have any properties on it before this function is called. |
| * |
| * src must have been allocated via JS_NewObjectWithoutMetadata so that we can |
| * be sure it has no metadata that needs copying to dst. This also means that |
| * dst needs to have the compartment global as its parent. This function will |
| * preserve the existing metadata on dst, if any. |
| */ |
| extern JS_FRIEND_API(bool) |
| JS_InitializePropertiesFromCompatibleNativeObject(JSContext* cx, |
| JS::HandleObject dst, |
| JS::HandleObject src); |
| |
| extern JS_FRIEND_API(JSString*) |
| JS_BasicObjectToString(JSContext* cx, JS::HandleObject obj); |
| |
| namespace js { |
| |
| JS_FRIEND_API(bool) |
| GetBuiltinClass(JSContext* cx, JS::HandleObject obj, ESClassValue* classValue); |
| |
| JS_FRIEND_API(const char*) |
| ObjectClassName(JSContext* cx, JS::HandleObject obj); |
| |
| JS_FRIEND_API(void) |
| ReportOverRecursed(JSContext* maybecx); |
| |
| JS_FRIEND_API(bool) |
| AddRawValueRoot(JSContext* cx, JS::Value* vp, const char* name); |
| |
| JS_FRIEND_API(void) |
| RemoveRawValueRoot(JSContext* cx, JS::Value* vp); |
| |
| JS_FRIEND_API(JSAtom*) |
| GetPropertyNameFromPC(JSScript* script, jsbytecode* pc); |
| |
| #ifdef JS_DEBUG |
| |
| /* |
| * Routines to print out values during debugging. These are FRIEND_API to help |
| * the debugger find them and to support temporarily hacking js::Dump* calls |
| * into other code. |
| */ |
| |
| extern JS_FRIEND_API(void) |
| DumpString(JSString* str); |
| |
| extern JS_FRIEND_API(void) |
| DumpAtom(JSAtom* atom); |
| |
| extern JS_FRIEND_API(void) |
| DumpObject(JSObject* obj); |
| |
| extern JS_FRIEND_API(void) |
| DumpChars(const char16_t* s, size_t n); |
| |
| extern JS_FRIEND_API(void) |
| DumpValue(const JS::Value& val); |
| |
| extern JS_FRIEND_API(void) |
| DumpId(jsid id); |
| |
| extern JS_FRIEND_API(void) |
| DumpInterpreterFrame(JSContext* cx, InterpreterFrame* start = nullptr); |
| |
| extern JS_FRIEND_API(bool) |
| DumpPC(JSContext* cx); |
| |
| extern JS_FRIEND_API(bool) |
| DumpScript(JSContext* cx, JSScript* scriptArg); |
| |
| #endif |
| |
| extern JS_FRIEND_API(void) |
| DumpBacktrace(JSContext* cx); |
| |
| } // namespace js |
| |
| namespace JS { |
| |
| /** Exposed for DumpJSStack */ |
| extern JS_FRIEND_API(char*) |
| FormatStackDump(JSContext* cx, char* buf, bool showArgs, bool showLocals, bool showThisProps); |
| |
| } // namespace JS |
| |
| /** |
| * Copies all own properties from |obj| to |target|. |obj| must be a "native" |
| * object (that is to say, normal-ish - not an Array or a Proxy). |
| * |
| * This function immediately enters a compartment, and does not impose any |
| * restrictions on the compartment of |cx|. |
| */ |
| extern JS_FRIEND_API(bool) |
| JS_CopyPropertiesFrom(JSContext* cx, JS::HandleObject target, JS::HandleObject obj); |
| |
| /* |
| * Single-property version of the above. This function asserts that an |own| |
| * property of the given name exists on |obj|. |
| * |
| * On entry, |cx| must be same-compartment with |obj|. |
| * |
| * The copyBehavior argument controls what happens with |
| * non-configurable properties. |
| */ |
| typedef enum { |
| MakeNonConfigurableIntoConfigurable, |
| CopyNonConfigurableAsIs |
| } PropertyCopyBehavior; |
| |
| extern JS_FRIEND_API(bool) |
| JS_CopyPropertyFrom(JSContext* cx, JS::HandleId id, JS::HandleObject target, |
| JS::HandleObject obj, |
| PropertyCopyBehavior copyBehavior = CopyNonConfigurableAsIs); |
| |
| extern JS_FRIEND_API(bool) |
| JS_WrapPropertyDescriptor(JSContext* cx, JS::MutableHandle<JSPropertyDescriptor> desc); |
| |
| struct JSFunctionSpecWithHelp { |
| const char* name; |
| JSNative call; |
| uint16_t nargs; |
| uint16_t flags; |
| const JSJitInfo* jitInfo; |
| const char* usage; |
| const char* help; |
| }; |
| |
| #define JS_FN_HELP(name,call,nargs,flags,usage,help) \ |
| {name, call, nargs, (flags) | JSPROP_ENUMERATE | JSFUN_STUB_GSOPS, nullptr, usage, help} |
| #define JS_INLINABLE_FN_HELP(name,call,nargs,flags,native,usage,help) \ |
| {name, call, nargs, (flags) | JSPROP_ENUMERATE | JSFUN_STUB_GSOPS, &js::jit::JitInfo_##native,\ |
| usage, help} |
| #define JS_FS_HELP_END \ |
| {nullptr, nullptr, 0, 0, nullptr, nullptr} |
| |
| extern JS_FRIEND_API(bool) |
| JS_DefineFunctionsWithHelp(JSContext* cx, JS::HandleObject obj, const JSFunctionSpecWithHelp* fs); |
| |
| namespace js { |
| |
| /* |
| * Helper Macros for creating JSClasses that function as proxies. |
| * |
| * NB: The macro invocation must be surrounded by braces, so as to |
| * allow for potential JSClass extensions. |
| */ |
| #define PROXY_MAKE_EXT(isWrappedNative, objectMoved) \ |
| { \ |
| isWrappedNative, \ |
| js::proxy_WeakmapKeyDelegate, \ |
| objectMoved \ |
| } |
| |
| #define PROXY_CLASS_WITH_EXT(name, flags, ext) \ |
| { \ |
| name, \ |
| js::Class::NON_NATIVE | \ |
| JSCLASS_IS_PROXY | \ |
| JSCLASS_DELAY_METADATA_CALLBACK | \ |
| flags, \ |
| nullptr, /* addProperty */ \ |
| nullptr, /* delProperty */ \ |
| nullptr, /* getProperty */ \ |
| nullptr, /* setProperty */ \ |
| nullptr, /* enumerate */ \ |
| nullptr, /* resolve */ \ |
| nullptr, /* mayResolve */ \ |
| js::proxy_Finalize, /* finalize */ \ |
| nullptr, /* call */ \ |
| js::proxy_HasInstance, /* hasInstance */ \ |
| nullptr, /* construct */ \ |
| js::proxy_Trace, /* trace */ \ |
| JS_NULL_CLASS_SPEC, \ |
| ext, \ |
| { \ |
| js::proxy_LookupProperty, \ |
| js::proxy_DefineProperty, \ |
| js::proxy_HasProperty, \ |
| js::proxy_GetProperty, \ |
| js::proxy_SetProperty, \ |
| js::proxy_GetOwnPropertyDescriptor, \ |
| js::proxy_DeleteProperty, \ |
| js::proxy_Watch, js::proxy_Unwatch, \ |
| js::proxy_GetElements, \ |
| nullptr, /* enumerate */ \ |
| js::proxy_FunToString, \ |
| } \ |
| } |
| |
| #define PROXY_CLASS_DEF(name, flags) \ |
| PROXY_CLASS_WITH_EXT(name, flags, \ |
| PROXY_MAKE_EXT( \ |
| false, /* isWrappedNative */ \ |
| js::proxy_ObjectMoved \ |
| )) |
| |
| /* |
| * Proxy stubs, similar to JS_*Stub, for embedder proxy class definitions. |
| * |
| * NB: Should not be called directly. |
| */ |
| |
| extern JS_FRIEND_API(bool) |
| proxy_LookupProperty(JSContext* cx, JS::HandleObject obj, JS::HandleId id, JS::MutableHandleObject objp, |
| JS::MutableHandle<Shape*> propp); |
| extern JS_FRIEND_API(bool) |
| proxy_DefineProperty(JSContext* cx, JS::HandleObject obj, JS::HandleId id, |
| JS::Handle<JSPropertyDescriptor> desc, |
| JS::ObjectOpResult& result); |
| extern JS_FRIEND_API(bool) |
| proxy_HasProperty(JSContext* cx, JS::HandleObject obj, JS::HandleId id, bool* foundp); |
| extern JS_FRIEND_API(bool) |
| proxy_GetProperty(JSContext* cx, JS::HandleObject obj, JS::HandleValue receiver, JS::HandleId id, |
| JS::MutableHandleValue vp); |
| extern JS_FRIEND_API(bool) |
| proxy_SetProperty(JSContext* cx, JS::HandleObject obj, JS::HandleId id, JS::HandleValue bp, |
| JS::HandleValue receiver, JS::ObjectOpResult& result); |
| extern JS_FRIEND_API(bool) |
| proxy_GetOwnPropertyDescriptor(JSContext* cx, JS::HandleObject obj, JS::HandleId id, |
| JS::MutableHandle<JSPropertyDescriptor> desc); |
| extern JS_FRIEND_API(bool) |
| proxy_DeleteProperty(JSContext* cx, JS::HandleObject obj, JS::HandleId id, |
| JS::ObjectOpResult& result); |
| |
| extern JS_FRIEND_API(void) |
| proxy_Trace(JSTracer* trc, JSObject* obj); |
| extern JS_FRIEND_API(JSObject*) |
| proxy_WeakmapKeyDelegate(JSObject* obj); |
| extern JS_FRIEND_API(bool) |
| proxy_Convert(JSContext* cx, JS::HandleObject proxy, JSType hint, JS::MutableHandleValue vp); |
| extern JS_FRIEND_API(void) |
| proxy_Finalize(FreeOp* fop, JSObject* obj); |
| extern JS_FRIEND_API(void) |
| proxy_ObjectMoved(JSObject* obj, const JSObject* old); |
| extern JS_FRIEND_API(bool) |
| proxy_HasInstance(JSContext* cx, JS::HandleObject proxy, JS::MutableHandleValue v, bool* bp); |
| extern JS_FRIEND_API(bool) |
| proxy_Call(JSContext* cx, unsigned argc, JS::Value* vp); |
| extern JS_FRIEND_API(bool) |
| proxy_Construct(JSContext* cx, unsigned argc, JS::Value* vp); |
| extern JS_FRIEND_API(JSObject*) |
| proxy_innerObject(JSObject* obj); |
| extern JS_FRIEND_API(bool) |
| proxy_Watch(JSContext* cx, JS::HandleObject obj, JS::HandleId id, JS::HandleObject callable); |
| extern JS_FRIEND_API(bool) |
| proxy_Unwatch(JSContext* cx, JS::HandleObject obj, JS::HandleId id); |
| extern JS_FRIEND_API(bool) |
| proxy_GetElements(JSContext* cx, JS::HandleObject proxy, uint32_t begin, uint32_t end, |
| ElementAdder* adder); |
| extern JS_FRIEND_API(JSString*) |
| proxy_FunToString(JSContext* cx, JS::HandleObject proxy, unsigned indent); |
| |
| /** |
| * A class of objects that return source code on demand. |
| * |
| * When code is compiled with setSourceIsLazy(true), SpiderMonkey doesn't |
| * retain the source code (and doesn't do lazy bytecode generation). If we ever |
| * need the source code, say, in response to a call to Function.prototype. |
| * toSource or Debugger.Source.prototype.text, then we call the 'load' member |
| * function of the instance of this class that has hopefully been registered |
| * with the runtime, passing the code's URL, and hope that it will be able to |
| * find the source. |
| */ |
| class SourceHook { |
| public: |
| virtual ~SourceHook() { } |
| |
| /** |
| * Set |*src| and |*length| to refer to the source code for |filename|. |
| * On success, the caller owns the buffer to which |*src| points, and |
| * should use JS_free to free it. |
| */ |
| virtual bool load(JSContext* cx, const char* filename, char16_t** src, size_t* length) = 0; |
| }; |
| |
| /** |
| * Have |rt| use |hook| to retrieve lazily-retrieved source code. See the |
| * comments for SourceHook. The runtime takes ownership of the hook, and |
| * will delete it when the runtime itself is deleted, or when a new hook is |
| * set. |
| */ |
| extern JS_FRIEND_API(void) |
| SetSourceHook(JSRuntime* rt, mozilla::UniquePtr<SourceHook> hook); |
| |
| /** Remove |rt|'s source hook, and return it. The caller now owns the hook. */ |
| extern JS_FRIEND_API(mozilla::UniquePtr<SourceHook>) |
| ForgetSourceHook(JSRuntime* rt); |
| |
| extern JS_FRIEND_API(JS::Zone*) |
| GetCompartmentZone(JSCompartment* comp); |
| |
| typedef bool |
| (* PreserveWrapperCallback)(JSContext* cx, JSObject* obj); |
| |
| typedef enum { |
| CollectNurseryBeforeDump, |
| IgnoreNurseryObjects |
| } DumpHeapNurseryBehaviour; |
| |
| /** |
| * Dump the complete object graph of heap-allocated things. |
| * fp is the file for the dump output. |
| */ |
| extern JS_FRIEND_API(void) |
| DumpHeap(JSRuntime* rt, FILE* fp, DumpHeapNurseryBehaviour nurseryBehaviour); |
| |
| #ifdef JS_OLD_GETTER_SETTER_METHODS |
| JS_FRIEND_API(bool) obj_defineGetter(JSContext* cx, unsigned argc, JS::Value* vp); |
| JS_FRIEND_API(bool) obj_defineSetter(JSContext* cx, unsigned argc, JS::Value* vp); |
| #endif |
| |
| extern JS_FRIEND_API(bool) |
| IsSystemCompartment(JSCompartment* comp); |
| |
| extern JS_FRIEND_API(bool) |
| IsSystemZone(JS::Zone* zone); |
| |
| extern JS_FRIEND_API(bool) |
| IsAtomsCompartment(JSCompartment* comp); |
| |
| extern JS_FRIEND_API(bool) |
| IsAtomsZone(JS::Zone* zone); |
| |
| struct WeakMapTracer |
| { |
| JSRuntime* runtime; |
| |
| explicit WeakMapTracer(JSRuntime* rt) : runtime(rt) {} |
| |
| // Weak map tracer callback, called once for every binding of every |
| // weak map that was live at the time of the last garbage collection. |
| // |
| // m will be nullptr if the weak map is not contained in a JS Object. |
| // |
| // The callback should not GC (and will assert in a debug build if it does so.) |
| virtual void trace(JSObject* m, JS::GCCellPtr key, JS::GCCellPtr value) = 0; |
| }; |
| |
| extern JS_FRIEND_API(void) |
| TraceWeakMaps(WeakMapTracer* trc); |
| |
| extern JS_FRIEND_API(bool) |
| AreGCGrayBitsValid(JSRuntime* rt); |
| |
| extern JS_FRIEND_API(bool) |
| ZoneGlobalsAreAllGray(JS::Zone* zone); |
| |
| typedef void |
| (*GCThingCallback)(void* closure, JS::GCCellPtr thing); |
| |
| extern JS_FRIEND_API(void) |
| VisitGrayWrapperTargets(JS::Zone* zone, GCThingCallback callback, void* closure); |
| |
| extern JS_FRIEND_API(JSObject*) |
| GetWeakmapKeyDelegate(JSObject* key); |
| |
| JS_FRIEND_API(JS::TraceKind) |
| GCThingTraceKind(void* thing); |
| |
| /** |
| * Invoke cellCallback on every gray JS_OBJECT in the given zone. |
| */ |
| extern JS_FRIEND_API(void) |
| IterateGrayObjects(JS::Zone* zone, GCThingCallback cellCallback, void* data); |
| |
| #ifdef JS_HAS_CTYPES |
| extern JS_FRIEND_API(size_t) |
| SizeOfDataIfCDataObject(mozilla::MallocSizeOf mallocSizeOf, JSObject* obj); |
| #endif |
| |
| extern JS_FRIEND_API(JSCompartment*) |
| GetAnyCompartmentInZone(JS::Zone* zone); |
| |
| /* |
| * Shadow declarations of JS internal structures, for access by inline access |
| * functions below. Do not use these structures in any other way. When adding |
| * new fields for access by inline methods, make sure to add static asserts to |
| * the original header file to ensure that offsets are consistent. |
| */ |
| namespace shadow { |
| |
| struct ObjectGroup { |
| const Class* clasp; |
| JSObject* proto; |
| JSCompartment* compartment; |
| }; |
| |
| struct BaseShape { |
| const js::Class* clasp_; |
| JSObject* parent; |
| }; |
| |
| class Shape { |
| public: |
| shadow::BaseShape* base; |
| jsid _1; |
| uint32_t slotInfo; |
| |
| static const uint32_t FIXED_SLOTS_SHIFT = 27; |
| }; |
| |
| /** |
| * This layout is shared by all native objects. For non-native objects, the |
| * group may always be accessed safely, and other members may be as well, |
| * depending on the object's specific layout. |
| */ |
| struct Object { |
| shadow::ObjectGroup* group; |
| shadow::Shape* shape; |
| JS::Value* slots; |
| void* _1; |
| |
| size_t numFixedSlots() const { return shape->slotInfo >> Shape::FIXED_SLOTS_SHIFT; } |
| JS::Value* fixedSlots() const { |
| return (JS::Value*)(uintptr_t(this) + sizeof(shadow::Object)); |
| } |
| |
| JS::Value& slotRef(size_t slot) const { |
| size_t nfixed = numFixedSlots(); |
| if (slot < nfixed) |
| return fixedSlots()[slot]; |
| return slots[slot - nfixed]; |
| } |
| }; |
| |
| struct Function { |
| Object base; |
| uint16_t nargs; |
| uint16_t flags; |
| /* Used only for natives */ |
| JSNative native; |
| const JSJitInfo* jitinfo; |
| void* _1; |
| }; |
| |
| struct String |
| { |
| static const uint32_t INLINE_CHARS_BIT = JS_BIT(2); |
| static const uint32_t LATIN1_CHARS_BIT = JS_BIT(6); |
| static const uint32_t ROPE_FLAGS = 0; |
| static const uint32_t TYPE_FLAGS_MASK = JS_BIT(6) - 1; |
| uint32_t flags; |
| uint32_t length; |
| union { |
| const JS::Latin1Char* nonInlineCharsLatin1; |
| const char16_t* nonInlineCharsTwoByte; |
| JS::Latin1Char inlineStorageLatin1[1]; |
| char16_t inlineStorageTwoByte[1]; |
| }; |
| }; |
| |
| } /* namespace shadow */ |
| |
| // This is equal to |&JSObject::class_|. Use it in places where you don't want |
| // to #include jsobj.h. |
| extern JS_FRIEND_DATA(const js::Class* const) ObjectClassPtr; |
| |
| inline const js::Class* |
| GetObjectClass(const JSObject* obj) |
| { |
| return reinterpret_cast<const shadow::Object*>(obj)->group->clasp; |
| } |
| |
| inline const JSClass* |
| GetObjectJSClass(JSObject* obj) |
| { |
| return js::Jsvalify(GetObjectClass(obj)); |
| } |
| |
| JS_FRIEND_API(const Class*) |
| ProtoKeyToClass(JSProtoKey key); |
| |
| // Returns true if the standard class identified by |key| inherits from |
| // another standard class (in addition to Object) along its proto chain. |
| // |
| // In practice, this only returns true for Error subtypes. |
| inline bool |
| StandardClassIsDependent(JSProtoKey key) |
| { |
| const Class* clasp = ProtoKeyToClass(key); |
| return clasp && clasp->spec.defined() && clasp->spec.dependent(); |
| } |
| |
| // Returns the key for the class inherited by a given standard class (that |
| // is to say, the prototype of this standard class's prototype). |
| // |
| // You must be sure that this corresponds to a standard class with a cached |
| // JSProtoKey before calling this function. In general |key| will match the |
| // cached proto key, except in cases where multiple JSProtoKeys share a |
| // JSClass. |
| inline JSProtoKey |
| ParentKeyForStandardClass(JSProtoKey key) |
| { |
| // [Object] has nothing to inherit from. |
| if (key == JSProto_Object) |
| return JSProto_Null; |
| |
| // If we're dependent, return the key of the class we depend on. |
| if (StandardClassIsDependent(key)) |
| return ProtoKeyToClass(key)->spec.parentKey(); |
| |
| // Otherwise, we inherit [Object]. |
| return JSProto_Object; |
| } |
| |
| JS_FRIEND_API(bool) |
| IsFunctionObject(JSObject* obj); |
| |
| static MOZ_ALWAYS_INLINE JSCompartment* |
| GetObjectCompartment(JSObject* obj) |
| { |
| return reinterpret_cast<shadow::Object*>(obj)->group->compartment; |
| } |
| |
| JS_FRIEND_API(JSObject*) |
| GetGlobalForObjectCrossCompartment(JSObject* obj); |
| |
| JS_FRIEND_API(JSObject*) |
| GetPrototypeNoProxy(JSObject* obj); |
| |
| JS_FRIEND_API(void) |
| AssertSameCompartment(JSContext* cx, JSObject* obj); |
| |
| #ifdef JS_DEBUG |
| JS_FRIEND_API(void) |
| AssertSameCompartment(JSObject* objA, JSObject* objB); |
| #else |
| inline void AssertSameCompartment(JSObject* objA, JSObject* objB) {} |
| #endif |
| |
| JS_FRIEND_API(void) |
| NotifyAnimationActivity(JSObject* obj); |
| |
| /** |
| * Return the outermost enclosing function (script) of the scripted caller. |
| * This function returns nullptr in several cases: |
| * - no script is running on the context |
| * - the caller is in global or eval code |
| * In particular, this function will "stop" its outermost search at eval() and |
| * thus it will really return the outermost enclosing function *since the |
| * innermost eval*. |
| */ |
| JS_FRIEND_API(JSFunction*) |
| GetOutermostEnclosingFunctionOfScriptedCaller(JSContext* cx); |
| |
| JS_FRIEND_API(JSFunction*) |
| DefineFunctionWithReserved(JSContext* cx, JSObject* obj, const char* name, JSNative call, |
| unsigned nargs, unsigned attrs); |
| |
| JS_FRIEND_API(JSFunction*) |
| NewFunctionWithReserved(JSContext* cx, JSNative call, unsigned nargs, unsigned flags, |
| const char* name); |
| |
| JS_FRIEND_API(JSFunction*) |
| NewFunctionByIdWithReserved(JSContext* cx, JSNative native, unsigned nargs, unsigned flags, |
| jsid id); |
| |
| JS_FRIEND_API(const JS::Value&) |
| GetFunctionNativeReserved(JSObject* fun, size_t which); |
| |
| JS_FRIEND_API(void) |
| SetFunctionNativeReserved(JSObject* fun, size_t which, const JS::Value& val); |
| |
| JS_FRIEND_API(bool) |
| FunctionHasNativeReserved(JSObject* fun); |
| |
| JS_FRIEND_API(bool) |
| GetObjectProto(JSContext* cx, JS::HandleObject obj, JS::MutableHandleObject proto); |
| |
| JS_FRIEND_API(bool) |
| GetOriginalEval(JSContext* cx, JS::HandleObject scope, |
| JS::MutableHandleObject eval); |
| |
| inline void* |
| GetObjectPrivate(JSObject* obj) |
| { |
| MOZ_ASSERT(GetObjectClass(obj)->flags & JSCLASS_HAS_PRIVATE); |
| const shadow::Object* nobj = reinterpret_cast<const shadow::Object*>(obj); |
| void** addr = reinterpret_cast<void**>(&nobj->fixedSlots()[nobj->numFixedSlots()]); |
| return *addr; |
| } |
| |
| inline const JS::Value& |
| GetReservedSlot(JSObject* obj, size_t slot) |
| { |
| MOZ_ASSERT(slot < JSCLASS_RESERVED_SLOTS(GetObjectClass(obj))); |
| return reinterpret_cast<const shadow::Object*>(obj)->slotRef(slot); |
| } |
| |
| JS_FRIEND_API(void) |
| SetReservedOrProxyPrivateSlotWithBarrier(JSObject* obj, size_t slot, const JS::Value& value); |
| |
| inline void |
| SetReservedSlot(JSObject* obj, size_t slot, const JS::Value& value) |
| { |
| MOZ_ASSERT(slot < JSCLASS_RESERVED_SLOTS(GetObjectClass(obj))); |
| shadow::Object* sobj = reinterpret_cast<shadow::Object*>(obj); |
| if (sobj->slotRef(slot).isMarkable() || value.isMarkable()) |
| SetReservedOrProxyPrivateSlotWithBarrier(obj, slot, value); |
| else |
| sobj->slotRef(slot) = value; |
| } |
| |
| JS_FRIEND_API(uint32_t) |
| GetObjectSlotSpan(JSObject* obj); |
| |
| inline const JS::Value& |
| GetObjectSlot(JSObject* obj, size_t slot) |
| { |
| MOZ_ASSERT(slot < GetObjectSlotSpan(obj)); |
| return reinterpret_cast<const shadow::Object*>(obj)->slotRef(slot); |
| } |
| |
| MOZ_ALWAYS_INLINE size_t |
| GetAtomLength(JSAtom* atom) |
| { |
| return reinterpret_cast<shadow::String*>(atom)->length; |
| } |
| |
| static const uint32_t MaxStringLength = (1 << 28) - 1; |
| |
| MOZ_ALWAYS_INLINE size_t |
| GetStringLength(JSString* s) |
| { |
| return reinterpret_cast<shadow::String*>(s)->length; |
| } |
| |
| MOZ_ALWAYS_INLINE size_t |
| GetFlatStringLength(JSFlatString* s) |
| { |
| return reinterpret_cast<shadow::String*>(s)->length; |
| } |
| |
| MOZ_ALWAYS_INLINE size_t |
| GetLinearStringLength(JSLinearString* s) |
| { |
| return reinterpret_cast<shadow::String*>(s)->length; |
| } |
| |
| MOZ_ALWAYS_INLINE bool |
| LinearStringHasLatin1Chars(JSLinearString* s) |
| { |
| return reinterpret_cast<shadow::String*>(s)->flags & shadow::String::LATIN1_CHARS_BIT; |
| } |
| |
| MOZ_ALWAYS_INLINE bool |
| AtomHasLatin1Chars(JSAtom* atom) |
| { |
| return reinterpret_cast<shadow::String*>(atom)->flags & shadow::String::LATIN1_CHARS_BIT; |
| } |
| |
| MOZ_ALWAYS_INLINE bool |
| StringHasLatin1Chars(JSString* s) |
| { |
| return reinterpret_cast<shadow::String*>(s)->flags & shadow::String::LATIN1_CHARS_BIT; |
| } |
| |
| MOZ_ALWAYS_INLINE const JS::Latin1Char* |
| GetLatin1LinearStringChars(const JS::AutoCheckCannotGC& nogc, JSLinearString* linear) |
| { |
| MOZ_ASSERT(LinearStringHasLatin1Chars(linear)); |
| |
| using shadow::String; |
| String* s = reinterpret_cast<String*>(linear); |
| if (s->flags & String::INLINE_CHARS_BIT) |
| return s->inlineStorageLatin1; |
| return s->nonInlineCharsLatin1; |
| } |
| |
| MOZ_ALWAYS_INLINE const char16_t* |
| GetTwoByteLinearStringChars(const JS::AutoCheckCannotGC& nogc, JSLinearString* linear) |
| { |
| MOZ_ASSERT(!LinearStringHasLatin1Chars(linear)); |
| |
| using shadow::String; |
| String* s = reinterpret_cast<String*>(linear); |
| if (s->flags & String::INLINE_CHARS_BIT) |
| return s->inlineStorageTwoByte; |
| return s->nonInlineCharsTwoByte; |
| } |
| |
| MOZ_ALWAYS_INLINE JSLinearString* |
| AtomToLinearString(JSAtom* atom) |
| { |
| return reinterpret_cast<JSLinearString*>(atom); |
| } |
| |
| MOZ_ALWAYS_INLINE JSFlatString* |
| AtomToFlatString(JSAtom* atom) |
| { |
| return reinterpret_cast<JSFlatString*>(atom); |
| } |
| |
| MOZ_ALWAYS_INLINE JSLinearString* |
| FlatStringToLinearString(JSFlatString* s) |
| { |
| return reinterpret_cast<JSLinearString*>(s); |
| } |
| |
| MOZ_ALWAYS_INLINE const JS::Latin1Char* |
| GetLatin1AtomChars(const JS::AutoCheckCannotGC& nogc, JSAtom* atom) |
| { |
| return GetLatin1LinearStringChars(nogc, AtomToLinearString(atom)); |
| } |
| |
| MOZ_ALWAYS_INLINE const char16_t* |
| GetTwoByteAtomChars(const JS::AutoCheckCannotGC& nogc, JSAtom* atom) |
| { |
| return GetTwoByteLinearStringChars(nogc, AtomToLinearString(atom)); |
| } |
| |
| JS_FRIEND_API(JSLinearString*) |
| StringToLinearStringSlow(JSContext* cx, JSString* str); |
| |
| MOZ_ALWAYS_INLINE JSLinearString* |
| StringToLinearString(JSContext* cx, JSString* str) |
| { |
| using shadow::String; |
| String* s = reinterpret_cast<String*>(str); |
| if (MOZ_UNLIKELY((s->flags & String::TYPE_FLAGS_MASK) == String::ROPE_FLAGS)) |
| return StringToLinearStringSlow(cx, str); |
| return reinterpret_cast<JSLinearString*>(str); |
| } |
| |
| MOZ_ALWAYS_INLINE void |
| CopyLinearStringChars(char16_t* dest, JSLinearString* s, size_t len) |
| { |
| JS::AutoCheckCannotGC nogc; |
| if (LinearStringHasLatin1Chars(s)) { |
| const JS::Latin1Char* src = GetLatin1LinearStringChars(nogc, s); |
| for (size_t i = 0; i < len; i++) |
| dest[i] = src[i]; |
| } else { |
| const char16_t* src = GetTwoByteLinearStringChars(nogc, s); |
| mozilla::PodCopy(dest, src, len); |
| } |
| } |
| |
| inline bool |
| CopyStringChars(JSContext* cx, char16_t* dest, JSString* s, size_t len) |
| { |
| JSLinearString* linear = StringToLinearString(cx, s); |
| if (!linear) |
| return false; |
| |
| CopyLinearStringChars(dest, linear, len); |
| return true; |
| } |
| |
| inline void |
| CopyFlatStringChars(char16_t* dest, JSFlatString* s, size_t len) |
| { |
| CopyLinearStringChars(dest, FlatStringToLinearString(s), len); |
| } |
| |
| /** |
| * Add some or all property keys of obj to the id vector *props. |
| * |
| * The flags parameter controls which property keys are added. Pass a |
| * combination of the following bits: |
| * |
| * JSITER_OWNONLY - Don't also search the prototype chain; only consider |
| * obj's own properties. |
| * |
| * JSITER_HIDDEN - Include nonenumerable properties. |
| * |
| * JSITER_SYMBOLS - Include property keys that are symbols. The default |
| * behavior is to filter out symbols. |
| * |
| * JSITER_SYMBOLSONLY - Exclude non-symbol property keys. |
| * |
| * This is the closest C++ API we have to `Reflect.ownKeys(obj)`, or |
| * equivalently, the ES6 [[OwnPropertyKeys]] internal method. Pass |
| * `JSITER_OWNONLY | JSITER_HIDDEN | JSITER_SYMBOLS` as flags to get |
| * results that match the output of Reflect.ownKeys. |
| */ |
| JS_FRIEND_API(bool) |
| GetPropertyKeys(JSContext* cx, JS::HandleObject obj, unsigned flags, JS::AutoIdVector* props); |
| |
| JS_FRIEND_API(bool) |
| AppendUnique(JSContext* cx, JS::AutoIdVector& base, JS::AutoIdVector& others); |
| |
| JS_FRIEND_API(bool) |
| StringIsArrayIndex(JSLinearString* str, uint32_t* indexp); |
| |
| JS_FRIEND_API(void) |
| SetPreserveWrapperCallback(JSRuntime* rt, PreserveWrapperCallback callback); |
| |
| JS_FRIEND_API(bool) |
| IsObjectInContextCompartment(JSObject* obj, const JSContext* cx); |
| |
| /* |
| * NB: these flag bits are encoded into the bytecode stream in the immediate |
| * operand of JSOP_ITER, so don't change them without advancing vm/Xdr.h's |
| * XDR_BYTECODE_VERSION. |
| * NB: keep these in sync with the copy in builtin/SelfHostingDefines.h. |
| * The first three are omitted because they shouldn't be used in new code. |
| */ |
| #define JSITER_ENUMERATE 0x1 /* for-in compatible hidden default iterator */ |
| #define JSITER_FOREACH 0x2 /* get obj[key] for each property */ |
| #define JSITER_KEYVALUE 0x4 /* obsolete destructuring for-in wants [key, value] */ |
| #define JSITER_OWNONLY 0x8 /* iterate over obj's own properties only */ |
| #define JSITER_HIDDEN 0x10 /* also enumerate non-enumerable properties */ |
| #define JSITER_SYMBOLS 0x20 /* also include symbol property keys */ |
| #define JSITER_SYMBOLSONLY 0x40 /* exclude string property keys */ |
| |
| JS_FRIEND_API(bool) |
| RunningWithTrustedPrincipals(JSContext* cx); |
| |
| inline uintptr_t |
| GetNativeStackLimit(JSContext* cx, StackKind kind, int extraAllowance = 0) |
| { |
| PerThreadDataFriendFields* mainThread = |
| PerThreadDataFriendFields::getMainThread(GetRuntime(cx)); |
| uintptr_t limit = mainThread->nativeStackLimit[kind]; |
| #if JS_STACK_GROWTH_DIRECTION > 0 |
| limit += extraAllowance; |
| #else |
| limit -= extraAllowance; |
| #endif |
| return limit; |
| } |
| |
| inline uintptr_t |
| GetNativeStackLimit(JSContext* cx, int extraAllowance = 0) |
| { |
| StackKind kind = RunningWithTrustedPrincipals(cx) ? StackForTrustedScript |
| : StackForUntrustedScript; |
| return GetNativeStackLimit(cx, kind, extraAllowance); |
| } |
| |
| /* |
| * These macros report a stack overflow and run |onerror| if we are close to |
| * using up the C stack. The JS_CHECK_CHROME_RECURSION variant gives us a |
| * little extra space so that we can ensure that crucial code is able to run. |
| * JS_CHECK_RECURSION_CONSERVATIVE allows less space than any other check, |
| * including a safety buffer (as in, it uses the untrusted limit and subtracts |
| * a little more from it). |
| */ |
| |
| #define JS_CHECK_RECURSION_LIMIT(cx, limit, onerror) \ |
| JS_BEGIN_MACRO \ |
| int stackDummy_; \ |
| if (!JS_CHECK_STACK_SIZE(limit, &stackDummy_)) { \ |
| js::ReportOverRecursed(cx); \ |
| onerror; \ |
| } \ |
| JS_END_MACRO |
| |
| #define JS_CHECK_RECURSION(cx, onerror) \ |
| JS_CHECK_RECURSION_LIMIT(cx, js::GetNativeStackLimit(cx), onerror) |
| |
| #define JS_CHECK_RECURSION_LIMIT_DONT_REPORT(cx, limit, onerror) \ |
| JS_BEGIN_MACRO \ |
| int stackDummy_; \ |
| if (!JS_CHECK_STACK_SIZE(limit, &stackDummy_)) { \ |
| onerror; \ |
| } \ |
| JS_END_MACRO |
| |
| #define JS_CHECK_RECURSION_DONT_REPORT(cx, onerror) \ |
| JS_CHECK_RECURSION_LIMIT_DONT_REPORT(cx, js::GetNativeStackLimit(cx), onerror) |
| |
| #define JS_CHECK_RECURSION_WITH_SP_DONT_REPORT(cx, sp, onerror) \ |
| JS_BEGIN_MACRO \ |
| if (!JS_CHECK_STACK_SIZE(js::GetNativeStackLimit(cx), sp)) { \ |
| onerror; \ |
| } \ |
| JS_END_MACRO |
| |
| #define JS_CHECK_RECURSION_WITH_SP(cx, sp, onerror) \ |
| JS_BEGIN_MACRO \ |
| if (!JS_CHECK_STACK_SIZE(js::GetNativeStackLimit(cx), sp)) { \ |
| js::ReportOverRecursed(cx); \ |
| onerror; \ |
| } \ |
| JS_END_MACRO |
| |
| #define JS_CHECK_SYSTEM_RECURSION(cx, onerror) \ |
| JS_CHECK_RECURSION_LIMIT(cx, js::GetNativeStackLimit(cx, js::StackForSystemCode), onerror) |
| |
| #define JS_CHECK_RECURSION_CONSERVATIVE(cx, onerror) \ |
| JS_CHECK_RECURSION_LIMIT(cx, \ |
| js::GetNativeStackLimit(cx, js::StackForUntrustedScript, -1024 * int(sizeof(size_t))), \ |
| onerror) |
| |
| #define JS_CHECK_RECURSION_CONSERVATIVE_DONT_REPORT(cx, onerror) \ |
| JS_CHECK_RECURSION_LIMIT_DONT_REPORT(cx, \ |
| js::GetNativeStackLimit(cx, js::StackForUntrustedScript, -1024 * int(sizeof(size_t))), \ |
| onerror) |
| |
| JS_FRIEND_API(void) |
| StartPCCountProfiling(JSContext* cx); |
| |
| JS_FRIEND_API(void) |
| StopPCCountProfiling(JSContext* cx); |
| |
| JS_FRIEND_API(void) |
| PurgePCCounts(JSContext* cx); |
| |
| JS_FRIEND_API(size_t) |
| GetPCCountScriptCount(JSContext* cx); |
| |
| JS_FRIEND_API(JSString*) |
| GetPCCountScriptSummary(JSContext* cx, size_t script); |
| |
| JS_FRIEND_API(JSString*) |
| GetPCCountScriptContents(JSContext* cx, size_t script); |
| |
| /** |
| * Generate lcov trace file content for the current compartment, and allocate a |
| * new buffer and return the content in it, the size of the newly allocated |
| * content within the buffer would be set to the length out-param. |
| * |
| * In case of out-of-memory, this function returns nullptr and does not set any |
| * value to the length out-param. |
| */ |
| JS_FRIEND_API(char*) |
| GetCodeCoverageSummary(JSContext* cx, size_t* length); |
| |
| JS_FRIEND_API(bool) |
| ContextHasOutstandingRequests(const JSContext* cx); |
| |
| typedef void |
| (* ActivityCallback)(void* arg, bool active); |
| |
| /** |
| * Sets a callback that is run whenever the runtime goes idle - the |
| * last active request ceases - and begins activity - when it was |
| * idle and a request begins. |
| */ |
| JS_FRIEND_API(void) |
| SetActivityCallback(JSRuntime* rt, ActivityCallback cb, void* arg); |
| |
| typedef bool |
| (* DOMInstanceClassHasProtoAtDepth)(const Class* instanceClass, |
| uint32_t protoID, uint32_t depth); |
| struct JSDOMCallbacks { |
| DOMInstanceClassHasProtoAtDepth instanceClassMatchesProto; |
| }; |
| typedef struct JSDOMCallbacks DOMCallbacks; |
| |
| extern JS_FRIEND_API(void) |
| SetDOMCallbacks(JSRuntime* rt, const DOMCallbacks* callbacks); |
| |
| extern JS_FRIEND_API(const DOMCallbacks*) |
| GetDOMCallbacks(JSRuntime* rt); |
| |
| extern JS_FRIEND_API(JSObject*) |
| GetTestingFunctions(JSContext* cx); |
| |
| /** |
| * Helper to convert FreeOp to JSFreeOp when the definition of FreeOp is not |
| * available and the compiler does not know that FreeOp inherits from |
| * JSFreeOp. |
| */ |
| inline JSFreeOp* |
| CastToJSFreeOp(FreeOp* fop) |
| { |
| return reinterpret_cast<JSFreeOp*>(fop); |
| } |
| |
| /* Implemented in jsexn.cpp. */ |
| |
| /** |
| * Get an error type name from a JSExnType constant. |
| * Returns nullptr for invalid arguments and JSEXN_INTERNALERR |
| */ |
| extern JS_FRIEND_API(JSFlatString*) |
| GetErrorTypeName(JSRuntime* rt, int16_t exnType); |
| |
| #ifdef JS_DEBUG |
| extern JS_FRIEND_API(unsigned) |
| GetEnterCompartmentDepth(JSContext* cx); |
| #endif |
| |
| class RegExpGuard; |
| extern JS_FRIEND_API(bool) |
| RegExpToSharedNonInline(JSContext* cx, JS::HandleObject regexp, RegExpGuard* shared); |
| |
| /* Implemented in jswrapper.cpp. */ |
| typedef enum NukeReferencesToWindow { |
| NukeWindowReferences, |
| DontNukeWindowReferences |
| } NukeReferencesToWindow; |
| |
| /* |
| * These filters are designed to be ephemeral stack classes, and thus don't |
| * do any rooting or holding of their members. |
| */ |
| struct CompartmentFilter { |
| virtual bool match(JSCompartment* c) const = 0; |
| }; |
| |
| struct AllCompartments : public CompartmentFilter { |
| virtual bool match(JSCompartment* c) const override { return true; } |
| }; |
| |
| struct ContentCompartmentsOnly : public CompartmentFilter { |
| virtual bool match(JSCompartment* c) const override { |
| return !IsSystemCompartment(c); |
| } |
| }; |
| |
| struct ChromeCompartmentsOnly : public CompartmentFilter { |
| virtual bool match(JSCompartment* c) const override { |
| return IsSystemCompartment(c); |
| } |
| }; |
| |
| struct SingleCompartment : public CompartmentFilter { |
| JSCompartment* ours; |
| explicit SingleCompartment(JSCompartment* c) : ours(c) {} |
| virtual bool match(JSCompartment* c) const override { return c == ours; } |
| }; |
| |
| struct CompartmentsWithPrincipals : public CompartmentFilter { |
| JSPrincipals* principals; |
| explicit CompartmentsWithPrincipals(JSPrincipals* p) : principals(p) {} |
| virtual bool match(JSCompartment* c) const override { |
| return JS_GetCompartmentPrincipals(c) == principals; |
| } |
| }; |
| |
| extern JS_FRIEND_API(bool) |
| NukeCrossCompartmentWrappers(JSContext* cx, |
| const CompartmentFilter& sourceFilter, |
| const CompartmentFilter& targetFilter, |
| NukeReferencesToWindow nukeReferencesToWindow); |
| |
| /* Specify information about DOMProxy proxies in the DOM, for use by ICs. */ |
| |
| /* |
| * The DOMProxyShadowsCheck function will be called to check if the property for |
| * id should be gotten from the prototype, or if there is an own property that |
| * shadows it. |
| * * If ShadowsViaDirectExpando is returned, then the slot at |
| * listBaseExpandoSlot contains an expando object which has the property in |
| * question. |
| * * If ShadowsViaIndirectExpando is returned, then the slot at |
| * listBaseExpandoSlot contains a private pointer to an ExpandoAndGeneration |
| * and the expando object in the ExpandoAndGeneration has the property in |
| * question. |
| * * If DoesntShadow is returned then the slot at listBaseExpandoSlot should |
| * either be undefined or point to an expando object that would contain the |
| * own property. |
| * * If DoesntShadowUnique is returned then the slot at listBaseExpandoSlot |
| * should contain a private pointer to a ExpandoAndGeneration, which contains |
| * a JS::Value that should either be undefined or point to an expando object, |
| * and a uint64 value. If that value changes then the IC for getting a |
| * property will be invalidated. |
| * * If Shadows is returned, that means the property is an own property of the |
| * proxy but doesn't live on the expando object. |
| */ |
| |
| struct ExpandoAndGeneration { |
| ExpandoAndGeneration() |
| : expando(JS::UndefinedValue()), |
| generation(0) |
| {} |
| |
| void Unlink() |
| { |
| ++generation; |
| expando.setUndefined(); |
| } |
| |
| static size_t offsetOfExpando() |
| { |
| return offsetof(ExpandoAndGeneration, expando); |
| } |
| |
| static size_t offsetOfGeneration() |
| { |
| return offsetof(ExpandoAndGeneration, generation); |
| } |
| |
| JS::Heap<JS::Value> expando; |
| uint64_t generation; |
| }; |
| |
| typedef enum DOMProxyShadowsResult { |
| ShadowCheckFailed, |
| Shadows, |
| DoesntShadow, |
| DoesntShadowUnique, |
| ShadowsViaDirectExpando, |
| ShadowsViaIndirectExpando |
| } DOMProxyShadowsResult; |
| typedef DOMProxyShadowsResult |
| (* DOMProxyShadowsCheck)(JSContext* cx, JS::HandleObject object, JS::HandleId id); |
| JS_FRIEND_API(void) |
| SetDOMProxyInformation(const void* domProxyHandlerFamily, uint32_t domProxyExpandoSlot, |
| DOMProxyShadowsCheck domProxyShadowsCheck); |
| |
| const void* GetDOMProxyHandlerFamily(); |
| uint32_t GetDOMProxyExpandoSlot(); |
| DOMProxyShadowsCheck GetDOMProxyShadowsCheck(); |
| inline bool DOMProxyIsShadowing(DOMProxyShadowsResult result) { |
| return result == Shadows || |
| result == ShadowsViaDirectExpando || |
| result == ShadowsViaIndirectExpando; |
| } |
| |
| /* Implemented in jsdate.cpp. */ |
| |
| /** Detect whether the internal date value is NaN. */ |
| extern JS_FRIEND_API(bool) |
| DateIsValid(JSContext* cx, JS::HandleObject obj, bool* isValid); |
| |
| extern JS_FRIEND_API(bool) |
| DateGetMsecSinceEpoch(JSContext* cx, JS::HandleObject obj, double* msecSinceEpoch); |
| |
| } /* namespace js */ |
| |
| /* Implemented in jscntxt.cpp. */ |
| |
| /** |
| * Report an exception, which is currently realized as a printf-style format |
| * string and its arguments. |
| */ |
| typedef enum JSErrNum { |
| #define MSG_DEF(name, count, exception, format) \ |
| name, |
| #include "js.msg" |
| #undef MSG_DEF |
| JSErr_Limit |
| } JSErrNum; |
| |
| namespace js { |
| |
| extern JS_FRIEND_API(const JSErrorFormatString*) |
| GetErrorMessage(void* userRef, const unsigned errorNumber); |
| |
| // AutoStableStringChars is here so we can use it in ErrorReport. It |
| // should get moved out of here if we can manage it. See bug 1040316. |
| |
| /** |
| * This class provides safe access to a string's chars across a GC. Once |
| * we allocate strings and chars in the nursery (bug 903519), this class |
| * will have to make a copy of the string's chars if they are allocated |
| * in the nursery, so it's best to avoid using this class unless you really |
| * need it. It's usually more efficient to use the latin1Chars/twoByteChars |
| * JSString methods and often the code can be rewritten so that only indexes |
| * instead of char pointers are used in parts of the code that can GC. |
| */ |
| class MOZ_STACK_CLASS AutoStableStringChars |
| { |
| /* Ensure the string is kept alive while we're using its chars. */ |
| JS::RootedString s_; |
| union { |
| const char16_t* twoByteChars_; |
| const JS::Latin1Char* latin1Chars_; |
| }; |
| enum State { Uninitialized, Latin1, TwoByte }; |
| State state_; |
| bool ownsChars_; |
| |
| public: |
| explicit AutoStableStringChars(JSContext* cx) |
| : s_(cx), state_(Uninitialized), ownsChars_(false) |
| {} |
| ~AutoStableStringChars(); |
| |
| MOZ_WARN_UNUSED_RESULT |
| bool init(JSContext* cx, JSString* s); |
| |
| /* Like init(), but Latin1 chars are inflated to TwoByte. */ |
| MOZ_WARN_UNUSED_RESULT |
| bool initTwoByte(JSContext* cx, JSString* s); |
| |
| bool isLatin1() const { return state_ == Latin1; } |
| bool isTwoByte() const { return state_ == TwoByte; } |
| |
| const char16_t* twoByteChars() const { |
| MOZ_ASSERT(state_ == TwoByte); |
| return twoByteChars_; |
| } |
| |
| mozilla::Range<const JS::Latin1Char> latin1Range() const { |
| MOZ_ASSERT(state_ == Latin1); |
| return mozilla::Range<const JS::Latin1Char>(latin1Chars_, |
| GetStringLength(s_)); |
| } |
| |
| mozilla::Range<const char16_t> twoByteRange() const { |
| MOZ_ASSERT(state_ == TwoByte); |
| return mozilla::Range<const char16_t>(twoByteChars_, |
| GetStringLength(s_)); |
| } |
| |
| /* If we own the chars, transfer ownership to the caller. */ |
| bool maybeGiveOwnershipToCaller() { |
| MOZ_ASSERT(state_ != Uninitialized); |
| if (!ownsChars_) |
| return false; |
| state_ = Uninitialized; |
| ownsChars_ = false; |
| return true; |
| } |
| |
| private: |
| AutoStableStringChars(const AutoStableStringChars& other) = delete; |
| void operator=(const AutoStableStringChars& other) = delete; |
| }; |
| |
| /** |
| * Creates a string of the form |ErrorType: ErrorMessage| for a JSErrorReport, |
| * which generally matches the toString() behavior of an ErrorObject. |
| */ |
| extern JS_FRIEND_API(JSString*) |
| ErrorReportToString(JSContext* cx, JSErrorReport* reportp); |
| |
| struct MOZ_STACK_CLASS JS_FRIEND_API(ErrorReport) |
| { |
| explicit ErrorReport(JSContext* cx); |
| ~ErrorReport(); |
| |
| bool init(JSContext* cx, JS::HandleValue exn); |
| |
| JSErrorReport* report() |
| { |
| return reportp; |
| } |
| |
| const char* message() |
| { |
| return message_; |
| } |
| |
| private: |
| // More or less an equivalent of JS_ReportErrorNumber/js::ReportErrorNumberVA |
| // but fills in an ErrorReport instead of reporting it. Uses varargs to |
| // make it simpler to call js::ExpandErrorArgumentsVA. |
| // |
| // Returns false if we fail to actually populate the ErrorReport |
| // for some reason (probably out of memory). |
| bool populateUncaughtExceptionReport(JSContext* cx, ...); |
| bool populateUncaughtExceptionReportVA(JSContext* cx, va_list ap); |
| |
| // Reports exceptions from add-on scopes to telementry. |
| void ReportAddonExceptionToTelementry(JSContext* cx); |
| |
| // We may have a provided JSErrorReport, so need a way to represent that. |
| JSErrorReport* reportp; |
| |
| // And we may have a message. |
| const char* message_; |
| |
| // Or we may need to synthesize a JSErrorReport one of our own. |
| JSErrorReport ownedReport; |
| |
| // Or a message of our own. If this is non-null, we need to clean up both |
| // it and ownedReport. |
| char* ownedMessage; |
| |
| // And we have a string to maybe keep alive that has pointers into |
| // it from ownedReport. |
| JS::RootedString str; |
| |
| // And keep its chars alive too. |
| AutoStableStringChars strChars; |
| |
| // And we need to root our exception value. |
| JS::RootedObject exnObject; |
| |
| // And possibly some byte storage for our message_. |
| JSAutoByteString bytesStorage; |
| |
| // And for our filename. |
| JSAutoByteString filename; |
| |
| // True if we need to free message_ and the stuff in ownedReport |
| bool ownsMessageAndReport; |
| }; |
| |
| /* Implemented in vm/StructuredClone.cpp. */ |
| extern JS_FRIEND_API(uint64_t) |
| GetSCOffset(JSStructuredCloneWriter* writer); |
| |
| namespace Scalar { |
| |
| /** |
| * Scalar types that can appear in typed arrays and typed objects. The enum |
| * values must to be kept in sync with the JS_SCALARTYPEREPR_ constants, as |
| * well as the TypedArrayObject::classes and TypedArrayObject::protoClasses |
| * definitions. |
| */ |
| enum Type { |
| Int8 = 0, |
| Uint8, |
| Int16, |
| Uint16, |
| Int32, |
| Uint32, |
| Float32, |
| Float64, |
| |
| /** |
| * Special type that is a uint8_t, but assignments are clamped to [0, 256). |
| * Treat the raw data type as a uint8_t. |
| */ |
| Uint8Clamped, |
| |
| /** |
| * SIMD types don't have their own TypedArray equivalent, for now. |
| */ |
| MaxTypedArrayViewType, |
| |
| Float32x4, |
| Int32x4 |
| }; |
| |
| static inline size_t |
| byteSize(Type atype) |
| { |
| switch (atype) { |
| case Int8: |
| case Uint8: |
| case Uint8Clamped: |
| return 1; |
| case Int16: |
| case Uint16: |
| return 2; |
| case Int32: |
| case Uint32: |
| case Float32: |
| return 4; |
| case Float64: |
| return 8; |
| case Int32x4: |
| case Float32x4: |
| return 16; |
| default: |
| MOZ_CRASH("invalid scalar type"); |
| } |
| } |
| |
| static inline bool |
| isSignedIntType(Type atype) { |
| switch (atype) { |
| case Int8: |
| case Int16: |
| case Int32: |
| case Int32x4: |
| return true; |
| case Uint8: |
| case Uint8Clamped: |
| case Uint16: |
| case Uint32: |
| case Float32: |
| case Float64: |
| case Float32x4: |
| return false; |
| default: |
| MOZ_CRASH("invalid scalar type"); |
| } |
| } |
| |
| static inline bool |
| isSimdType(Type atype) { |
| switch (atype) { |
| case Int8: |
| case Uint8: |
| case Uint8Clamped: |
| case Int16: |
| case Uint16: |
| case Int32: |
| case Uint32: |
| case Float32: |
| case Float64: |
| return false; |
| case Int32x4: |
| case Float32x4: |
| return true; |
| case MaxTypedArrayViewType: |
| break; |
| } |
| MOZ_CRASH("invalid scalar type"); |
| } |
| |
| static inline size_t |
| scalarByteSize(Type atype) { |
| switch (atype) { |
| case Int32x4: |
| case Float32x4: |
| return 4; |
| case Int8: |
| case Uint8: |
| case Uint8Clamped: |
| case Int16: |
| case Uint16: |
| case Int32: |
| case Uint32: |
| case Float32: |
| case Float64: |
| case MaxTypedArrayViewType: |
| break; |
| } |
| MOZ_CRASH("invalid simd type"); |
| } |
| |
| } /* namespace Scalar */ |
| } /* namespace js */ |
| |
| /* |
| * Create a new typed array with nelements elements. |
| * |
| * These functions (except the WithBuffer variants) fill in the array with zeros. |
| */ |
| |
| extern JS_FRIEND_API(JSObject*) |
| JS_NewInt8Array(JSContext* cx, uint32_t nelements); |
| extern JS_FRIEND_API(JSObject*) |
| JS_NewUint8Array(JSContext* cx, uint32_t nelements); |
| extern JS_FRIEND_API(JSObject*) |
| JS_NewUint8ClampedArray(JSContext* cx, uint32_t nelements); |
| extern JS_FRIEND_API(JSObject*) |
| JS_NewInt16Array(JSContext* cx, uint32_t nelements); |
| extern JS_FRIEND_API(JSObject*) |
| JS_NewUint16Array(JSContext* cx, uint32_t nelements); |
| extern JS_FRIEND_API(JSObject*) |
| JS_NewInt32Array(JSContext* cx, uint32_t nelements); |
| extern JS_FRIEND_API(JSObject*) |
| JS_NewUint32Array(JSContext* cx, uint32_t nelements); |
| extern JS_FRIEND_API(JSObject*) |
| JS_NewFloat32Array(JSContext* cx, uint32_t nelements); |
| extern JS_FRIEND_API(JSObject*) |
| JS_NewFloat64Array(JSContext* cx, uint32_t nelements); |
| |
| /* |
| * Create a new typed array and copy in values from the given object. The |
| * object is used as if it were an array; that is, the new array (if |
| * successfully created) will have length given by array.length, and its |
| * elements will be those specified by array[0], array[1], and so on, after |
| * conversion to the typed array element type. |
| */ |
| |
| extern JS_FRIEND_API(JSObject*) |
| JS_NewInt8ArrayFromArray(JSContext* cx, JS::HandleObject array); |
| extern JS_FRIEND_API(JSObject*) |
| JS_NewUint8ArrayFromArray(JSContext* cx, JS::HandleObject array); |
| extern JS_FRIEND_API(JSObject*) |
| JS_NewUint8ClampedArrayFromArray(JSContext* cx, JS::HandleObject array); |
| extern JS_FRIEND_API(JSObject*) |
| JS_NewInt16ArrayFromArray(JSContext* cx, JS::HandleObject array); |
| extern JS_FRIEND_API(JSObject*) |
| JS_NewUint16ArrayFromArray(JSContext* cx, JS::HandleObject array); |
| extern JS_FRIEND_API(JSObject*) |
| JS_NewInt32ArrayFromArray(JSContext* cx, JS::HandleObject array); |
| extern JS_FRIEND_API(JSObject*) |
| JS_NewUint32ArrayFromArray(JSContext* cx, JS::HandleObject array); |
| extern JS_FRIEND_API(JSObject*) |
| JS_NewFloat32ArrayFromArray(JSContext* cx, JS::HandleObject array); |
| extern JS_FRIEND_API(JSObject*) |
| JS_NewFloat64ArrayFromArray(JSContext* cx, JS::HandleObject array); |
| |
| /* |
| * Create a new typed array using the given ArrayBuffer or |
| * SharedArrayBuffer for storage. The length value is optional; if -1 |
| * is passed, enough elements to use up the remainder of the byte |
| * array is used as the default value. |
| */ |
| |
| extern JS_FRIEND_API(JSObject*) |
| JS_NewInt8ArrayWithBuffer(JSContext* cx, JS::HandleObject arrayBuffer, |
| uint32_t byteOffset, int32_t length); |
| extern JS_FRIEND_API(JSObject*) |
| JS_NewUint8ArrayWithBuffer(JSContext* cx, JS::HandleObject arrayBuffer, |
| uint32_t byteOffset, int32_t length); |
| extern JS_FRIEND_API(JSObject*) |
| JS_NewUint8ClampedArrayWithBuffer(JSContext* cx, JS::HandleObject arrayBuffer, |
| uint32_t byteOffset, int32_t length); |
| extern JS_FRIEND_API(JSObject*) |
| JS_NewInt16ArrayWithBuffer(JSContext* cx, JS::HandleObject arrayBuffer, |
| uint32_t byteOffset, int32_t length); |
| extern JS_FRIEND_API(JSObject*) |
| JS_NewUint16ArrayWithBuffer(JSContext* cx, JS::HandleObject arrayBuffer, |
| uint32_t byteOffset, int32_t length); |
| extern JS_FRIEND_API(JSObject*) |
| JS_NewInt32ArrayWithBuffer(JSContext* cx, JS::HandleObject arrayBuffer, |
| uint32_t byteOffset, int32_t length); |
| extern JS_FRIEND_API(JSObject*) |
| JS_NewUint32ArrayWithBuffer(JSContext* cx, JS::HandleObject arrayBuffer, |
| uint32_t byteOffset, int32_t length); |
| extern JS_FRIEND_API(JSObject*) |
| JS_NewFloat32ArrayWithBuffer(JSContext* cx, JS::HandleObject arrayBuffer, |
| uint32_t byteOffset, int32_t length); |
| extern JS_FRIEND_API(JSObject*) |
| JS_NewFloat64ArrayWithBuffer(JSContext* cx, JS::HandleObject arrayBuffer, |
| uint32_t byteOffset, int32_t length); |
| |
| /** |
| * Create a new SharedArrayBuffer with the given byte length. |
| */ |
| extern JS_FRIEND_API(JSObject*) |
| JS_NewSharedArrayBuffer(JSContext* cx, uint32_t nbytes); |
| |
| /** |
| * Create a new ArrayBuffer with the given byte length. |
| */ |
| extern JS_FRIEND_API(JSObject*) |
| JS_NewArrayBuffer(JSContext* cx, uint32_t nbytes); |
| |
| /** |
| * Check whether obj supports JS_GetTypedArray* APIs. Note that this may return |
| * false if a security wrapper is encountered that denies the unwrapping. If |
| * this test or one of the JS_Is*Array tests succeeds, then it is safe to call |
| * the various accessor JSAPI calls defined below. |
| */ |
| extern JS_FRIEND_API(bool) |
| JS_IsTypedArrayObject(JSObject* obj); |
| |
| /** |
| * Check whether obj supports JS_GetArrayBufferView* APIs. Note that this may |
| * return false if a security wrapper is encountered that denies the |
| * unwrapping. If this test or one of the more specific tests succeeds, then it |
| * is safe to call the various ArrayBufferView accessor JSAPI calls defined |
| * below. |
| */ |
| extern JS_FRIEND_API(bool) |
| JS_IsArrayBufferViewObject(JSObject* obj); |
| |
| /* |
| * Test for specific typed array types (ArrayBufferView subtypes) |
| */ |
| |
| extern JS_FRIEND_API(bool) |
| JS_IsInt8Array(JSObject* obj); |
| extern JS_FRIEND_API(bool) |
| JS_IsUint8Array(JSObject* obj); |
| extern JS_FRIEND_API(bool) |
| JS_IsUint8ClampedArray(JSObject* obj); |
| extern JS_FRIEND_API(bool) |
| JS_IsInt16Array(JSObject* obj); |
| extern JS_FRIEND_API(bool) |
| JS_IsUint16Array(JSObject* obj); |
| extern JS_FRIEND_API(bool) |
| JS_IsInt32Array(JSObject* obj); |
| extern JS_FRIEND_API(bool) |
| JS_IsUint32Array(JSObject* obj); |
| extern JS_FRIEND_API(bool) |
| JS_IsFloat32Array(JSObject* obj); |
| extern JS_FRIEND_API(bool) |
| JS_IsFloat64Array(JSObject* obj); |
| |
| /** |
| * Return the isShared flag of a typed array, which denotes whether |
| * the underlying buffer is a SharedArrayBuffer. |
| * |
| * |obj| must have passed a JS_IsTypedArrayObject/JS_Is*Array test, or somehow |
| * be known that it would pass such a test: it is a typed array or a wrapper of |
| * a typed array, and the unwrapping will succeed. |
| */ |
| extern JS_FRIEND_API(bool) |
| JS_GetTypedArraySharedness(JSObject* obj); |
| |
| /* |
| * Test for specific typed array types (ArrayBufferView subtypes) and return |
| * the unwrapped object if so, else nullptr. Never throws. |
| */ |
| |
| namespace js { |
| |
| extern JS_FRIEND_API(JSObject*) |
| UnwrapInt8Array(JSObject* obj); |
| extern JS_FRIEND_API(JSObject*) |
| UnwrapUint8Array(JSObject* obj); |
| extern JS_FRIEND_API(JSObject*) |
| UnwrapUint8ClampedArray(JSObject* obj); |
| extern JS_FRIEND_API(JSObject*) |
| UnwrapInt16Array(JSObject* obj); |
| extern JS_FRIEND_API(JSObject*) |
| UnwrapUint16Array(JSObject* obj); |
| extern JS_FRIEND_API(JSObject*) |
| UnwrapInt32Array(JSObject* obj); |
| extern JS_FRIEND_API(JSObject*) |
| UnwrapUint32Array(JSObject* obj); |
| extern JS_FRIEND_API(JSObject*) |
| UnwrapFloat32Array(JSObject* obj); |
| extern JS_FRIEND_API(JSObject*) |
| UnwrapFloat64Array(JSObject* obj); |
| |
| extern JS_FRIEND_API(JSObject*) |
| UnwrapArrayBuffer(JSObject* obj); |
| |
| extern JS_FRIEND_API(JSObject*) |
| UnwrapArrayBufferView(JSObject* obj); |
| |
| extern JS_FRIEND_API(JSObject*) |
| UnwrapSharedArrayBuffer(JSObject* obj); |
| |
| |
| namespace detail { |
| |
| extern JS_FRIEND_DATA(const Class* const) Int8ArrayClassPtr; |
| extern JS_FRIEND_DATA(const Class* const) Uint8ArrayClassPtr; |
| extern JS_FRIEND_DATA(const Class* const) Uint8ClampedArrayClassPtr; |
| extern JS_FRIEND_DATA(const Class* const) Int16ArrayClassPtr; |
| extern JS_FRIEND_DATA(const Class* const) Uint16ArrayClassPtr; |
| extern JS_FRIEND_DATA(const Class* const) Int32ArrayClassPtr; |
| extern JS_FRIEND_DATA(const Class* const) Uint32ArrayClassPtr; |
| extern JS_FRIEND_DATA(const Class* const) Float32ArrayClassPtr; |
| extern JS_FRIEND_DATA(const Class* const) Float64ArrayClassPtr; |
| |
| const size_t TypedArrayLengthSlot = 1; |
| |
| } // namespace detail |
| |
| #define JS_DEFINE_DATA_AND_LENGTH_ACCESSOR(Type, type) \ |
| inline void \ |
| Get ## Type ## ArrayLengthAndData(JSObject* obj, uint32_t* length, bool* isSharedMemory, type** data) \ |
| { \ |
| MOZ_ASSERT(GetObjectClass(obj) == detail::Type ## ArrayClassPtr); \ |
| const JS::Value& lenSlot = GetReservedSlot(obj, detail::TypedArrayLengthSlot); \ |
| *length = mozilla::AssertedCast<uint32_t>(lenSlot.toInt32()); \ |
| *isSharedMemory = JS_GetTypedArraySharedness(obj); \ |
| *data = static_cast<type*>(GetObjectPrivate(obj)); \ |
| } |
| |
| JS_DEFINE_DATA_AND_LENGTH_ACCESSOR(Int8, int8_t) |
| JS_DEFINE_DATA_AND_LENGTH_ACCESSOR(Uint8, uint8_t) |
| JS_DEFINE_DATA_AND_LENGTH_ACCESSOR(Uint8Clamped, uint8_t) |
| JS_DEFINE_DATA_AND_LENGTH_ACCESSOR(Int16, int16_t) |
| JS_DEFINE_DATA_AND_LENGTH_ACCESSOR(Uint16, uint16_t) |
| JS_DEFINE_DATA_AND_LENGTH_ACCESSOR(Int32, int32_t) |
| JS_DEFINE_DATA_AND_LENGTH_ACCESSOR(Uint32, uint32_t) |
| JS_DEFINE_DATA_AND_LENGTH_ACCESSOR(Float32, float) |
| JS_DEFINE_DATA_AND_LENGTH_ACCESSOR(Float64, double) |
| |
| #undef JS_DEFINE_DATA_AND_LENGTH_ACCESSOR |
| |
| // This one isn't inlined because it's rather tricky (by dint of having to deal |
| // with a dozen-plus classes and varying slot layouts. |
| extern JS_FRIEND_API(void) |
| GetArrayBufferViewLengthAndData(JSObject* obj, uint32_t* length, bool* isSharedMemory, uint8_t** data); |
| |
| // This one isn't inlined because there are a bunch of different ArrayBuffer |
| // classes that would have to be individually handled here. |
| // |
| // There is an isShared out argument for API consistency (eases use from DOM). |
| // It will always be set to false. |
| extern JS_FRIEND_API(void) |
| GetArrayBufferLengthAndData(JSObject* obj, uint32_t* length, bool* isSharedMemory, uint8_t** data); |
| |
| // Ditto for SharedArrayBuffer. |
| // |
| // There is an isShared out argument for API consistency (eases use from DOM). |
| // It will always be set to true. |
| extern JS_FRIEND_API(void) |
| GetSharedArrayBufferLengthAndData(JSObject* obj, uint32_t* length, bool* isSharedMemory, uint8_t** data); |
| |
| } // namespace js |
| |
| JS_FRIEND_API(uint8_t*) |
| JS_GetSharedArrayBufferData(JSObject* obj, bool* isSharedMemory, const JS::AutoCheckCannotGC&); |
| |
| /* |
| * Unwrap Typed arrays all at once. Return nullptr without throwing if the |
| * object cannot be viewed as the correct typed array, or the typed array |
| * object on success, filling both outparameters. |
| */ |
| extern JS_FRIEND_API(JSObject*) |
| JS_GetObjectAsInt8Array(JSObject* obj, uint32_t* length, bool* isSharedMemory, int8_t** data); |
| extern JS_FRIEND_API(JSObject*) |
| JS_GetObjectAsUint8Array(JSObject* obj, uint32_t* length, bool* isSharedMemory, uint8_t** data); |
| extern JS_FRIEND_API(JSObject*) |
| JS_GetObjectAsUint8ClampedArray(JSObject* obj, uint32_t* length, bool* isSharedMemory, uint8_t** data); |
| extern JS_FRIEND_API(JSObject*) |
| JS_GetObjectAsInt16Array(JSObject* obj, uint32_t* length, bool* isSharedMemory, int16_t** data); |
| extern JS_FRIEND_API(JSObject*) |
| JS_GetObjectAsUint16Array(JSObject* obj, uint32_t* length, bool* isSharedMemory, uint16_t** data); |
| extern JS_FRIEND_API(JSObject*) |
| JS_GetObjectAsInt32Array(JSObject* obj, uint32_t* length, bool* isSharedMemory, int32_t** data); |
| extern JS_FRIEND_API(JSObject*) |
| JS_GetObjectAsUint32Array(JSObject* obj, uint32_t* length, bool* isSharedMemory, uint32_t** data); |
| extern JS_FRIEND_API(JSObject*) |
| JS_GetObjectAsFloat32Array(JSObject* obj, uint32_t* length, bool* isSharedMemory, float** data); |
| extern JS_FRIEND_API(JSObject*) |
| JS_GetObjectAsFloat64Array(JSObject* obj, uint32_t* length, bool* isSharedMemory, double** data); |
| extern JS_FRIEND_API(JSObject*) |
| JS_GetObjectAsArrayBufferView(JSObject* obj, uint32_t* length, bool* isSharedMemory, uint8_t** data); |
| |
| /* |
| * Unwrap an ArrayBuffer, return nullptr if it's a different type. |
| */ |
| extern JS_FRIEND_API(JSObject*) |
| JS_GetObjectAsArrayBuffer(JSObject* obj, uint32_t* length, uint8_t** data); |
| |
| /* |
| * Get the type of elements in a typed array, or MaxTypedArrayViewType if a DataView. |
| * |
| * |obj| must have passed a JS_IsArrayBufferView/JS_Is*Array test, or somehow |
| * be known that it would pass such a test: it is an ArrayBufferView or a |
| * wrapper of an ArrayBufferView, and the unwrapping will succeed. |
| */ |
| extern JS_FRIEND_API(js::Scalar::Type) |
| JS_GetArrayBufferViewType(JSObject* obj); |
| |
| extern JS_FRIEND_API(js::Scalar::Type) |
| JS_GetSharedArrayBufferViewType(JSObject* obj); |
| |
| /* |
| * Check whether obj supports the JS_GetArrayBuffer* APIs. Note that this may |
| * return false if a security wrapper is encountered that denies the |
| * unwrapping. If this test succeeds, then it is safe to call the various |
| * accessor JSAPI calls defined below. |
| */ |
| extern JS_FRIEND_API(bool) |
| JS_IsArrayBufferObject(JSObject* obj); |
| |
| extern JS_FRIEND_API(bool) |
| JS_IsSharedArrayBufferObject(JSObject* obj); |
| |
| /** |
| * Return the available byte length of an array buffer. |
| * |
| * |obj| must have passed a JS_IsArrayBufferObject test, or somehow be known |
| * that it would pass such a test: it is an ArrayBuffer or a wrapper of an |
| * ArrayBuffer, and the unwrapping will succeed. |
| */ |
| extern JS_FRIEND_API(uint32_t) |
| JS_GetArrayBufferByteLength(JSObject* obj); |
| |
| extern JS_FRIEND_API(uint32_t) |
| JS_GetSharedArrayBufferByteLength(JSObject* obj); |
| |
| /** |
| * Return true if the arrayBuffer contains any data. This will return false for |
| * ArrayBuffer.prototype and neutered ArrayBuffers. |
| * |
| * |obj| must have passed a JS_IsArrayBufferObject test, or somehow be known |
| * that it would pass such a test: it is an ArrayBuffer or a wrapper of an |
| * ArrayBuffer, and the unwrapping will succeed. |
| */ |
| extern JS_FRIEND_API(bool) |
| JS_ArrayBufferHasData(JSObject* obj); |
| |
| /** |
| * Return a pointer to the start of the data referenced by a typed array. The |
| * data is still owned by the typed array, and should not be modified on |
| * another thread. Furthermore, the pointer can become invalid on GC (if the |
| * data is small and fits inside the array's GC header), so callers must take |
| * care not to hold on across anything that could GC. |
| * |
| * |obj| must have passed a JS_IsArrayBufferObject test, or somehow be known |
| * that it would pass such a test: it is an ArrayBuffer or a wrapper of an |
| * ArrayBuffer, and the unwrapping will succeed. |
| * |
| * *isSharedMemory will be set to false, the argument is present to simplify |
| * its use from code that also interacts with SharedArrayBuffer. |
| */ |
| extern JS_FRIEND_API(uint8_t*) |
| JS_GetArrayBufferData(JSObject* obj, bool* isSharedMemory, const JS::AutoCheckCannotGC&); |
| |
| /** |
| * Check whether the obj is ArrayBufferObject and memory mapped. Note that this |
| * may return false if a security wrapper is encountered that denies the |
| * unwrapping. |
| */ |
| extern JS_FRIEND_API(bool) |
| JS_IsMappedArrayBufferObject(JSObject* obj); |
| |
| /** |
| * Return the number of elements in a typed array. |
| * |
| * |obj| must have passed a JS_IsTypedArrayObject/JS_Is*Array test, or somehow |
| * be known that it would pass such a test: it is a typed array or a wrapper of |
| * a typed array, and the unwrapping will succeed. |
| */ |
| extern JS_FRIEND_API(uint32_t) |
| JS_GetTypedArrayLength(JSObject* obj); |
| |
| /** |
| * Return the byte offset from the start of an array buffer to the start of a |
| * typed array view. |
| * |
| * |obj| must have passed a JS_IsTypedArrayObject/JS_Is*Array test, or somehow |
| * be known that it would pass such a test: it is a typed array or a wrapper of |
| * a typed array, and the unwrapping will succeed. |
| */ |
| extern JS_FRIEND_API(uint32_t) |
| JS_GetTypedArrayByteOffset(JSObject* obj); |
| |
| /** |
| * Return the byte length of a typed array. |
| * |
| * |obj| must have passed a JS_IsTypedArrayObject/JS_Is*Array test, or somehow |
| * be known that it would pass such a test: it is a typed array or a wrapper of |
| * a typed array, and the unwrapping will succeed. |
| */ |
| extern JS_FRIEND_API(uint32_t) |
| JS_GetTypedArrayByteLength(JSObject* obj); |
| |
| /** |
| * Check whether obj supports JS_ArrayBufferView* APIs. Note that this may |
| * return false if a security wrapper is encountered that denies the |
| * unwrapping. |
| */ |
| extern JS_FRIEND_API(bool) |
| JS_IsArrayBufferViewObject(JSObject* obj); |
| |
| /** |
| * More generic name for JS_GetTypedArrayByteLength to cover DataViews as well |
| */ |
| extern JS_FRIEND_API(uint32_t) |
| JS_GetArrayBufferViewByteLength(JSObject* obj); |
| |
| /* |
| * Return a pointer to the start of the data referenced by a typed array. The |
| * data is still owned by the typed array, and should not be modified on |
| * another thread. Furthermore, the pointer can become invalid on GC (if the |
| * data is small and fits inside the array's GC header), so callers must take |
| * care not to hold on across anything that could GC. |
| * |
| * |obj| must have passed a JS_Is*Array test, or somehow be known that it would |
| * pass such a test: it is a typed array or a wrapper of a typed array, and the |
| * unwrapping will succeed. |
| * |
| * *isSharedMemory will be set to true if the typed array maps a |
| * SharedArrayBuffer, otherwise to false. |
| */ |
| |
| extern JS_FRIEND_API(int8_t*) |
| JS_GetInt8ArrayData(JSObject* obj, bool* isSharedMemory, const JS::AutoCheckCannotGC&); |
| extern JS_FRIEND_API(uint8_t*) |
| JS_GetUint8ArrayData(JSObject* obj, bool* isSharedMemory, const JS::AutoCheckCannotGC&); |
| extern JS_FRIEND_API(uint8_t*) |
| JS_GetUint8ClampedArrayData(JSObject* obj, bool* isSharedMemory, const JS::AutoCheckCannotGC&); |
| extern JS_FRIEND_API(int16_t*) |
| JS_GetInt16ArrayData(JSObject* obj, bool* isSharedMemory, const JS::AutoCheckCannotGC&); |
| extern JS_FRIEND_API(uint16_t*) |
| JS_GetUint16ArrayData(JSObject* obj, bool* isSharedMemory, const JS::AutoCheckCannotGC&); |
| extern JS_FRIEND_API(int32_t*) |
| JS_GetInt32ArrayData(JSObject* obj, bool* isSharedMemory, const JS::AutoCheckCannotGC&); |
| extern JS_FRIEND_API(uint32_t*) |
| JS_GetUint32ArrayData(JSObject* obj, bool* isSharedMemory, const JS::AutoCheckCannotGC&); |
| extern JS_FRIEND_API(float*) |
| JS_GetFloat32ArrayData(JSObject* obj, bool* isSharedMemory, const JS::AutoCheckCannotGC&); |
| extern JS_FRIEND_API(double*) |
| JS_GetFloat64ArrayData(JSObject* obj, bool* isSharedMemory, const JS::AutoCheckCannotGC&); |
| |
| /** |
| * Same as above, but for any kind of ArrayBufferView. Prefer the type-specific |
| * versions when possible. |
| */ |
| extern JS_FRIEND_API(void*) |
| JS_GetArrayBufferViewData(JSObject* obj, bool* isSharedMemory, const JS::AutoCheckCannotGC&); |
| |
| /** |
| * Return the ArrayBuffer or SharedArrayBuffer underlying an |
| * ArrayBufferView. If the buffer has been neutered, this will still |
| * return the neutered buffer. |obj| must be an object that would |
| * return true for JS_IsArrayBufferViewObject(). |
| */ |
| extern JS_FRIEND_API(JSObject*) |
| JS_GetArrayBufferViewBuffer(JSContext* cx, JS::HandleObject obj, bool* isSharedMemory); |
| |
| typedef enum { |
| ChangeData, |
| KeepData |
| } NeuterDataDisposition; |
| |
| /** |
| * Set an ArrayBuffer's length to 0 and neuter all of its views. |
| * |
| * The |changeData| argument is a hint to inform internal behavior with respect |
| * to the internal pointer to the ArrayBuffer's data after being neutered. |
| * There is no guarantee it will be respected. But if it is respected, the |
| * ArrayBuffer's internal data pointer will, or will not, have changed |
| * accordingly. |
| */ |
| extern JS_FRIEND_API(bool) |
| JS_NeuterArrayBuffer(JSContext* cx, JS::HandleObject obj, |
| NeuterDataDisposition changeData); |
| |
| /** |
| * Check whether the obj is ArrayBufferObject and neutered. Note that this |
| * may return false if a security wrapper is encountered that denies the |
| * unwrapping. |
| */ |
| extern JS_FRIEND_API(bool) |
| JS_IsNeuteredArrayBufferObject(JSObject* obj); |
| |
| /** |
| * Check whether obj supports JS_GetDataView* APIs. |
| */ |
| JS_FRIEND_API(bool) |
| JS_IsDataViewObject(JSObject* obj); |
| |
| /** |
| * Create a new DataView using the given ArrayBuffer for storage. The given |
| * buffer must be an ArrayBuffer (or a cross-compartment wrapper of an |
| * ArrayBuffer), and the offset and length must fit within the bounds of the |
| * arrayBuffer. Currently, nullptr will be returned and an exception will be |
| * thrown if these conditions do not hold, but do not depend on that behavior. |
| */ |
| JS_FRIEND_API(JSObject*) |
| JS_NewDataView(JSContext* cx, JS::HandleObject arrayBuffer, uint32_t byteOffset, int32_t byteLength); |
| |
| /** |
| * Return the byte offset of a data view into its array buffer. |obj| must be a |
| * DataView. |
| * |
| * |obj| must have passed a JS_IsDataViewObject test, or somehow be known that |
| * it would pass such a test: it is a data view or a wrapper of a data view, |
| * and the unwrapping will succeed. |
| */ |
| JS_FRIEND_API(uint32_t) |
| JS_GetDataViewByteOffset(JSObject* obj); |
| |
| /** |
| * Return the byte length of a data view. |
| * |
| * |obj| must have passed a JS_IsDataViewObject test, or somehow be known that |
| * it would pass such a test: it is a data view or a wrapper of a data view, |
| * and the unwrapping will succeed. If cx is nullptr, then DEBUG builds may be |
| * unable to assert when unwrapping should be disallowed. |
| */ |
| JS_FRIEND_API(uint32_t) |
| JS_GetDataViewByteLength(JSObject* obj); |
| |
| /** |
| * Return a pointer to the beginning of the data referenced by a DataView. |
| * |
| * |obj| must have passed a JS_IsDataViewObject test, or somehow be known that |
| * it would pass such a test: it is a data view or a wrapper of a data view, |
| * and the unwrapping will succeed. If cx is nullptr, then DEBUG builds may be |
| * unable to assert when unwrapping should be disallowed. |
| */ |
| JS_FRIEND_API(void*) |
| JS_GetDataViewData(JSObject* obj, const JS::AutoCheckCannotGC&); |
| |
| namespace js { |
| |
| /** |
| * Add a watchpoint -- in the Object.prototype.watch sense -- to |obj| for the |
| * property |id|, using the callable object |callable| as the function to be |
| * called for notifications. |
| * |
| * This is an internal function exposed -- temporarily -- only so that DOM |
| * proxies can be watchable. Don't use it! We'll soon kill off the |
| * Object.prototype.{,un}watch functions, at which point this will go too. |
| */ |
| extern JS_FRIEND_API(bool) |
| WatchGuts(JSContext* cx, JS::HandleObject obj, JS::HandleId id, JS::HandleObject callable); |
| |
| /** |
| * Remove a watchpoint -- in the Object.prototype.watch sense -- from |obj| for |
| * the property |id|. |
| * |
| * This is an internal function exposed -- temporarily -- only so that DOM |
| * proxies can be watchable. Don't use it! We'll soon kill off the |
| * Object.prototype.{,un}watch functions, at which point this will go too. |
| */ |
| extern JS_FRIEND_API(bool) |
| UnwatchGuts(JSContext* cx, JS::HandleObject obj, JS::HandleId id); |
| |
| namespace jit { |
| |
| enum class InlinableNative : uint16_t; |
| |
| } // namespace jit |
| |
| } // namespace js |
| |
| /** |
| * A class, expected to be passed by value, which represents the CallArgs for a |
| * JSJitGetterOp. |
| */ |
| class JSJitGetterCallArgs : protected JS::MutableHandleValue |
| { |
| public: |
| explicit JSJitGetterCallArgs(const JS::CallArgs& args) |
| : JS::MutableHandleValue(args.rval()) |
| {} |
| |
| explicit JSJitGetterCallArgs(JS::RootedValue* rooted) |
| : JS::MutableHandleValue(rooted) |
| {} |
| |
| JS::MutableHandleValue rval() { |
| return *this; |
| } |
| }; |
| |
| /** |
| * A class, expected to be passed by value, which represents the CallArgs for a |
| * JSJitSetterOp. |
| */ |
| class JSJitSetterCallArgs : protected JS::MutableHandleValue |
| { |
| public: |
| explicit JSJitSetterCallArgs(const JS::CallArgs& args) |
| : JS::MutableHandleValue(args[0]) |
| {} |
| |
| JS::MutableHandleValue operator[](unsigned i) { |
| MOZ_ASSERT(i == 0); |
| return *this; |
| } |
| |
| unsigned length() const { return 1; } |
| |
| // Add get() or maybe hasDefined() as needed |
| }; |
| |
| struct JSJitMethodCallArgsTraits; |
| |
| /** |
| * A class, expected to be passed by reference, which represents the CallArgs |
| * for a JSJitMethodOp. |
| */ |
| class JSJitMethodCallArgs : protected JS::detail::CallArgsBase<JS::detail::NoUsedRval> |
| { |
| private: |
| typedef JS::detail::CallArgsBase<JS::detail::NoUsedRval> Base; |
| friend struct JSJitMethodCallArgsTraits; |
| |
| public: |
| explicit JSJitMethodCallArgs(const JS::CallArgs& args) { |
| argv_ = args.array(); |
| argc_ = args.length(); |
| } |
| |
| JS::MutableHandleValue rval() const { |
| return Base::rval(); |
| } |
| |
| unsigned length() const { return Base::length(); } |
| |
| JS::MutableHandleValue operator[](unsigned i) const { |
| return Base::operator[](i); |
| } |
| |
| bool hasDefined(unsigned i) const { |
| return Base::hasDefined(i); |
| } |
| |
| JSObject& callee() const { |
| // We can't use Base::callee() because that will try to poke at |
| // this->usedRval_, which we don't have. |
| return argv_[-2].toObject(); |
| } |
| |
| JS::HandleValue get(unsigned i) const { |
| return Base::get(i); |
| } |
| }; |
| |
| struct JSJitMethodCallArgsTraits |
| { |
| static const size_t offsetOfArgv = offsetof(JSJitMethodCallArgs, argv_); |
| static const size_t offsetOfArgc = offsetof(JSJitMethodCallArgs, argc_); |
| }; |
| |
| typedef bool |
| (* JSJitGetterOp)(JSContext* cx, JS::HandleObject thisObj, |
| void* specializedThis, JSJitGetterCallArgs args); |
| typedef bool |
| (* JSJitSetterOp)(JSContext* cx, JS::HandleObject thisObj, |
| void* specializedThis, JSJitSetterCallArgs args); |
| typedef bool |
| (* JSJitMethodOp)(JSContext* cx, JS::HandleObject thisObj, |
| void* specializedThis, const JSJitMethodCallArgs& args); |
| |
| /** |
| * This struct contains metadata passed from the DOM to the JS Engine for JIT |
| * optimizations on DOM property accessors. Eventually, this should be made |
| * available to general JSAPI users, but we are not currently ready to do so. |
| */ |
| struct JSJitInfo { |
| enum OpType { |
| Getter, |
| Setter, |
| Method, |
| StaticMethod, |
| InlinableNative, |
| // Must be last |
| OpTypeCount |
| }; |
| |
| enum ArgType { |
| // Basic types |
| String = (1 << 0), |
| Integer = (1 << 1), // Only 32-bit or less |
| Double = (1 << 2), // Maybe we want to add Float sometime too |
| Boolean = (1 << 3), |
| Object = (1 << 4), |
| Null = (1 << 5), |
| |
| // And derived types |
| Numeric = Integer | Double, |
| // Should "Primitive" use the WebIDL definition, which |
| // excludes string and null, or the typical JS one that includes them? |
| Primitive = Numeric | Boolean | Null | String, |
| ObjectOrNull = Object | Null, |
| Any = ObjectOrNull | Primitive, |
| |
| // Our sentinel value. |
| ArgTypeListEnd = (1 << 31) |
| }; |
| |
| static_assert(Any & String, "Any must include String."); |
| static_assert(Any & Integer, "Any must include Integer."); |
| static_assert(Any & Double, "Any must include Double."); |
| static_assert(Any & Boolean, "Any must include Boolean."); |
| static_assert(Any & Object, "Any must include Object."); |
| static_assert(Any & Null, "Any must include Null."); |
| |
| /** |
| * An enum that describes what this getter/setter/method aliases. This |
| * determines what things can be hoisted past this call, and if this |
| * call is movable what it can be hoisted past. |
| */ |
| enum AliasSet { |
| /** |
| * Alias nothing: a constant value, getting it can't affect any other |
| * values, nothing can affect it. |
| */ |
| AliasNone, |
| |
| /** |
| * Alias things that can modify the DOM but nothing else. Doing the |
| * call can't affect the behavior of any other function. |
| */ |
| AliasDOMSets, |
| |
| /** |
| * Alias the world. Calling this can change arbitrary values anywhere |
| * in the system. Most things fall in this bucket. |
| */ |
| AliasEverything, |
| |
| /** Must be last. */ |
| AliasSetCount |
| }; |
| |
| bool needsOuterizedThisObject() const |
| { |
| return type() != Getter && type() != Setter; |
| } |
| |
| bool isTypedMethodJitInfo() const |
| { |
| return isTypedMethod; |
| } |
| |
| OpType type() const |
| { |
| return OpType(type_); |
| } |
| |
| AliasSet aliasSet() const |
| { |
| return AliasSet(aliasSet_); |
| } |
| |
| JSValueType returnType() const |
| { |
| return JSValueType(returnType_); |
| } |
| |
| union { |
| JSJitGetterOp getter; |
| JSJitSetterOp setter; |
| JSJitMethodOp method; |
| /** A DOM static method, used for Promise wrappers */ |
| JSNative staticMethod; |
| }; |
| |
| union { |
| uint16_t protoID; |
| js::jit::InlinableNative inlinableNative; |
| }; |
| |
| uint16_t depth; |
| |
| // These fields are carefully packed to take up 4 bytes. If you need more |
| // bits for whatever reason, please see if you can steal bits from existing |
| // fields before adding more members to this structure. |
| |
| #define JITINFO_OP_TYPE_BITS 4 |
| #define JITINFO_ALIAS_SET_BITS 4 |
| #define JITINFO_RETURN_TYPE_BITS 8 |
| #define JITINFO_SLOT_INDEX_BITS 10 |
| |
| /** The OpType that says what sort of function we are. */ |
| uint32_t type_ : JITINFO_OP_TYPE_BITS; |
| |
| /** |
| * The alias set for this op. This is a _minimal_ alias set; in |
| * particular for a method it does not include whatever argument |
| * conversions might do. That's covered by argTypes and runtime |
| * analysis of the actual argument types being passed in. |
| */ |
| uint32_t aliasSet_ : JITINFO_ALIAS_SET_BITS; |
| |
| /** The return type tag. Might be JSVAL_TYPE_UNKNOWN. */ |
| uint32_t returnType_ : JITINFO_RETURN_TYPE_BITS; |
| |
| static_assert(OpTypeCount <= (1 << JITINFO_OP_TYPE_BITS), |
| "Not enough space for OpType"); |
| static_assert(AliasSetCount <= (1 << JITINFO_ALIAS_SET_BITS), |
| "Not enough space for AliasSet"); |
| static_assert((sizeof(JSValueType) * 8) <= JITINFO_RETURN_TYPE_BITS, |
| "Not enough space for JSValueType"); |
| |
| #undef JITINFO_RETURN_TYPE_BITS |
| #undef JITINFO_ALIAS_SET_BITS |
| #undef JITINFO_OP_TYPE_BITS |
| |
| /** Is op fallible? False in setters. */ |
| uint32_t isInfallible : 1; |
| |
| /** |
| * Is op movable? To be movable the op must |
| * not AliasEverything, but even that might |
| * not be enough (e.g. in cases when it can |
| * throw or is explicitly not movable). |
| */ |
| uint32_t isMovable : 1; |
| |
| /** |
| * Can op be dead-code eliminated? Again, this |
| * depends on whether the op can throw, in |
| * addition to the alias set. |
| */ |
| uint32_t isEliminatable : 1; |
| |
| // XXXbz should we have a JSValueType for the type of the member? |
| /** |
| * True if this is a getter that can always |
| * get the value from a slot of the "this" object. |
| */ |
| uint32_t isAlwaysInSlot : 1; |
| |
| /** |
| * True if this is a getter that can sometimes (if the slot doesn't contain |
| * UndefinedValue()) get the value from a slot of the "this" object. |
| */ |
| uint32_t isLazilyCachedInSlot : 1; |
| |
| /** True if this is an instance of JSTypedMethodJitInfo. */ |
| uint32_t isTypedMethod : 1; |
| |
| /** |
| * If isAlwaysInSlot or isSometimesInSlot is true, |
| * the index of the slot to get the value from. |
| * Otherwise 0. |
| */ |
| uint32_t slotIndex : JITINFO_SLOT_INDEX_BITS; |
| |
| static const size_t maxSlotIndex = (1 << JITINFO_SLOT_INDEX_BITS) - 1; |
| |
| #undef JITINFO_SLOT_INDEX_BITS |
| }; |
| |
| static_assert(sizeof(JSJitInfo) == (sizeof(void*) + 2 * sizeof(uint32_t)), |
| "There are several thousand instances of JSJitInfo stored in " |
| "a binary. Please don't increase its space requirements without " |
| "verifying that there is no other way forward (better packing, " |
| "smaller datatypes for fields, subclassing, etc.)."); |
| |
| struct JSTypedMethodJitInfo |
| { |
| // We use C-style inheritance here, rather than C++ style inheritance |
| // because not all compilers support brace-initialization for non-aggregate |
| // classes. Using C++ style inheritance and constructors instead of |
| // brace-initialization would also force the creation of static |
| // constructors (on some compilers) when JSJitInfo and JSTypedMethodJitInfo |
| // structures are declared. Since there can be several thousand of these |
| // structures present and we want to have roughly equivalent performance |
| // across a range of compilers, we do things manually. |
| JSJitInfo base; |
| |
| const JSJitInfo::ArgType* const argTypes; /* For a method, a list of sets of |
| types that the function |
| expects. This can be used, |
| for example, to figure out |
| when argument coercions can |
| have side-effects. */ |
| }; |
| |
| namespace js { |
| |
| static MOZ_ALWAYS_INLINE shadow::Function* |
| FunctionObjectToShadowFunction(JSObject* fun) |
| { |
| MOZ_ASSERT(GetObjectClass(fun) == FunctionClassPtr); |
| return reinterpret_cast<shadow::Function*>(fun); |
| } |
| |
| /* Statically asserted in jsfun.h. */ |
| static const unsigned JS_FUNCTION_INTERPRETED_BITS = 0x0201; |
| |
| // Return whether the given function object is native. |
| static MOZ_ALWAYS_INLINE bool |
| FunctionObjectIsNative(JSObject* fun) |
| { |
| return !(FunctionObjectToShadowFunction(fun)->flags & JS_FUNCTION_INTERPRETED_BITS); |
| } |
| |
| static MOZ_ALWAYS_INLINE JSNative |
| GetFunctionObjectNative(JSObject* fun) |
| { |
| MOZ_ASSERT(FunctionObjectIsNative(fun)); |
| return FunctionObjectToShadowFunction(fun)->native; |
| } |
| |
| } // namespace js |
| |
| static MOZ_ALWAYS_INLINE const JSJitInfo* |
| FUNCTION_VALUE_TO_JITINFO(const JS::Value& v) |
| { |
| MOZ_ASSERT(js::FunctionObjectIsNative(&v.toObject())); |
| return js::FunctionObjectToShadowFunction(&v.toObject())->jitinfo; |
| } |
| |
| static MOZ_ALWAYS_INLINE void |
| SET_JITINFO(JSFunction * func, const JSJitInfo* info) |
| { |
| js::shadow::Function* fun = reinterpret_cast<js::shadow::Function*>(func); |
| MOZ_ASSERT(!(fun->flags & js::JS_FUNCTION_INTERPRETED_BITS)); |
| fun->jitinfo = info; |
| } |
| |
| /* |
| * Engine-internal extensions of jsid. This code is here only until we |
| * eliminate Gecko's dependencies on it! |
| */ |
| |
| static MOZ_ALWAYS_INLINE jsid |
| JSID_FROM_BITS(size_t bits) |
| { |
| jsid id; |
| JSID_BITS(id) = bits; |
| return id; |
| } |
| |
| namespace js { |
| namespace detail { |
| bool IdMatchesAtom(jsid id, JSAtom* atom); |
| } // namespace detail |
| } // namespace js |
| |
| /** |
| * Must not be used on atoms that are representable as integer jsids. |
| * Prefer NameToId or AtomToId over this function: |
| * |
| * A PropertyName is an atom that does not contain an integer in the range |
| * [0, UINT32_MAX]. However, jsid can only hold an integer in the range |
| * [0, JSID_INT_MAX] (where JSID_INT_MAX == 2^31-1). Thus, for the range of |
| * integers (JSID_INT_MAX, UINT32_MAX], to represent as a jsid 'id', it must be |
| * the case JSID_IS_ATOM(id) and !JSID_TO_ATOM(id)->isPropertyName(). In most |
| * cases when creating a jsid, code does not have to care about this corner |
| * case because: |
| * |
| * - When given an arbitrary JSAtom*, AtomToId must be used, which checks for |
| * integer atoms representable as integer jsids, and does this conversion. |
| * |
| * - When given a PropertyName*, NameToId can be used which which does not need |
| * to do any dynamic checks. |
| * |
| * Thus, it is only the rare third case which needs this function, which |
| * handles any JSAtom* that is known not to be representable with an int jsid. |
| */ |
| static MOZ_ALWAYS_INLINE jsid |
| NON_INTEGER_ATOM_TO_JSID(JSAtom* atom) |
| { |
| MOZ_ASSERT(((size_t)atom & 0x7) == 0); |
| jsid id = JSID_FROM_BITS((size_t)atom); |
| MOZ_ASSERT(js::detail::IdMatchesAtom(id, atom)); |
| return id; |
| } |
| |
| /* All strings stored in jsids are atomized, but are not necessarily property names. */ |
| static MOZ_ALWAYS_INLINE bool |
| JSID_IS_ATOM(jsid id) |
| { |
| return JSID_IS_STRING(id); |
| } |
| |
| static MOZ_ALWAYS_INLINE bool |
| JSID_IS_ATOM(jsid id, JSAtom* atom) |
| { |
| return id == JSID_FROM_BITS((size_t)atom); |
| } |
| |
| static MOZ_ALWAYS_INLINE JSAtom* |
| JSID_TO_ATOM(jsid id) |
| { |
| return (JSAtom*)JSID_TO_STRING(id); |
| } |
| |
| JS_STATIC_ASSERT(sizeof(jsid) == sizeof(void*)); |
| |
| namespace js { |
| |
| static MOZ_ALWAYS_INLINE JS::Value |
| IdToValue(jsid id) |
| { |
| if (JSID_IS_STRING(id)) |
| return JS::StringValue(JSID_TO_STRING(id)); |
| if (JSID_IS_INT(id)) |
| return JS::Int32Value(JSID_TO_INT(id)); |
| if (JSID_IS_SYMBOL(id)) |
| return JS::SymbolValue(JSID_TO_SYMBOL(id)); |
| MOZ_ASSERT(JSID_IS_VOID(id)); |
| return JS::UndefinedValue(); |
| } |
| |
| /** |
| * If the embedder has registered a ScriptEnvironmentPreparer, |
| * PrepareScriptEnvironmentAndInvoke will call the preparer's 'invoke' method |
| * with the given |closure|, with the assumption that the preparer will set up |
| * any state necessary to run script in |scope|, invoke |closure| with a valid |
| * JSContext*, report any exceptions thrown from the closure, and return. |
| * |
| * If no preparer is registered, PrepareScriptEnvironmentAndInvoke will assert |
| * that |rt| has exactly one JSContext associated with it, enter the compartment |
| * of |scope| on that context, and invoke |closure|. |
| * |
| * In both cases, PrepareScriptEnvironmentAndInvoke will report any exceptions |
| * that are thrown by the closure. Consumers who want to propagate back |
| * whether the closure succeeded should do so via members of the closure |
| * itself. |
| */ |
| |
| struct ScriptEnvironmentPreparer { |
| struct Closure { |
| virtual bool operator()(JSContext* cx) = 0; |
| }; |
| |
| virtual void invoke(JS::HandleObject scope, Closure& closure) = 0; |
| }; |
| |
| extern JS_FRIEND_API(void) |
| PrepareScriptEnvironmentAndInvoke(JSContext* cx, JS::HandleObject scope, |
| ScriptEnvironmentPreparer::Closure& closure); |
| |
| JS_FRIEND_API(void) |
| SetScriptEnvironmentPreparer(JSRuntime* rt, ScriptEnvironmentPreparer* |
| preparer); |
| |
| /** |
| * To help embedders enforce their invariants, we allow them to specify in |
| * advance which JSContext should be passed to JSAPI calls. If this is set |
| * to a non-null value, the assertSameCompartment machinery does double- |
| * duty (in debug builds) to verify that it matches the cx being used. |
| */ |
| #ifdef DEBUG |
| JS_FRIEND_API(void) |
| Debug_SetActiveJSContext(JSRuntime* rt, JSContext* cx); |
| #else |
| inline void |
| Debug_SetActiveJSContext(JSRuntime* rt, JSContext* cx) {} |
| #endif |
| |
| enum CTypesActivityType { |
| CTYPES_CALL_BEGIN, |
| CTYPES_CALL_END, |
| CTYPES_CALLBACK_BEGIN, |
| CTYPES_CALLBACK_END |
| }; |
| |
| typedef void |
| (* CTypesActivityCallback)(JSContext* cx, CTypesActivityType type); |
| |
| /** |
| * Sets a callback that is run whenever js-ctypes is about to be used when |
| * calling into C. |
| */ |
| JS_FRIEND_API(void) |
| SetCTypesActivityCallback(JSRuntime* rt, CTypesActivityCallback cb); |
| |
| class MOZ_RAII JS_FRIEND_API(AutoCTypesActivityCallback) { |
| private: |
| JSContext* cx; |
| CTypesActivityCallback callback; |
| CTypesActivityType endType; |
| MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER |
| |
| public: |
| AutoCTypesActivityCallback(JSContext* cx, CTypesActivityType beginType, |
| CTypesActivityType endType |
| MOZ_GUARD_OBJECT_NOTIFIER_PARAM); |
| ~AutoCTypesActivityCallback() { |
| DoEndCallback(); |
| } |
| void DoEndCallback() { |
| if (callback) { |
| callback(cx, endType); |
| callback = nullptr; |
| } |
| } |
| }; |
| |
| typedef JSObject* |
| (* ObjectMetadataCallback)(JSContext* cx, JSObject* obj); |
| |
| /** |
| * Specify a callback to invoke when creating each JS object in the current |
| * compartment, which may return a metadata object to associate with the |
| * object. |
| */ |
| JS_FRIEND_API(void) |
| SetObjectMetadataCallback(JSContext* cx, ObjectMetadataCallback callback); |
| |
| /** Get the metadata associated with an object. */ |
| JS_FRIEND_API(JSObject*) |
| GetObjectMetadata(JSObject* obj); |
| |
| JS_FRIEND_API(bool) |
| GetElementsWithAdder(JSContext* cx, JS::HandleObject obj, JS::HandleObject receiver, |
| uint32_t begin, uint32_t end, js::ElementAdder* adder); |
| |
| JS_FRIEND_API(bool) |
| ForwardToNative(JSContext* cx, JSNative native, const JS::CallArgs& args); |
| |
| /** |
| * Helper function for HTMLDocument and HTMLFormElement. |
| * |
| * These are the only two interfaces that have [OverrideBuiltins], a named |
| * getter, and no named setter. They're implemented as proxies with a custom |
| * getOwnPropertyDescriptor() method. Unfortunately, overriding |
| * getOwnPropertyDescriptor() automatically affects the behavior of set(), |
| * which normally is just common sense but is *not* desired for these two |
| * interfaces. |
| * |
| * The fix is for these two interfaces to override set() to ignore the |
| * getOwnPropertyDescriptor() override. |
| * |
| * SetPropertyIgnoringNamedGetter is exposed to make it easier to override |
| * set() in this way. It carries out all the steps of BaseProxyHandler::set() |
| * except the initial getOwnPropertyDescriptor() call. The caller must supply |
| * that descriptor as the 'ownDesc' parameter. |
| * |
| * Implemented in proxy/BaseProxyHandler.cpp. |
| */ |
| JS_FRIEND_API(bool) |
| SetPropertyIgnoringNamedGetter(JSContext* cx, JS::HandleObject obj, JS::HandleId id, |
| JS::HandleValue v, JS::HandleValue receiver, |
| JS::Handle<JSPropertyDescriptor> ownDesc, |
| JS::ObjectOpResult& result); |
| |
| JS_FRIEND_API(void) |
| ReportErrorWithId(JSContext* cx, const char* msg, JS::HandleId id); |
| |
| // This function is for one specific use case, please don't use this for anything else! |
| extern JS_FRIEND_API(bool) |
| ExecuteInGlobalAndReturnScope(JSContext* cx, JS::HandleObject obj, JS::HandleScript script, |
| JS::MutableHandleObject scope); |
| |
| #if defined(XP_WIN) && defined(_WIN64) |
| // Parameters use void* types to avoid #including windows.h. The return value of |
| // this function is returned from the exception handler. |
| typedef long |
| (*JitExceptionHandler)(void* exceptionRecord, // PEXECTION_RECORD |
| void* context); // PCONTEXT |
| |
| /** |
| * Windows uses "structured exception handling" to handle faults. When a fault |
| * occurs, the stack is searched for a handler (similar to C++ exception |
| * handling). If the search does not find a handler, the "unhandled exception |
| * filter" is called. Breakpad uses the unhandled exception filter to do crash |
| * reporting. Unfortunately, on Win64, JIT code on the stack completely throws |
| * off this unwinding process and prevents the unhandled exception filter from |
| * being called. The reason is that Win64 requires unwind information be |
| * registered for all code regions and JIT code has none. While it is possible |
| * to register full unwind information for JIT code, this is a lot of work (one |
| * has to be able to recover the frame pointer at any PC) so instead we register |
| * a handler for all JIT code that simply calls breakpad's unhandled exception |
| * filter (which will perform crash reporting and then terminate the process). |
| * This would be wrong if there was an outer __try block that expected to handle |
| * the fault, but this is not generally allowed. |
| * |
| * Gecko must call SetJitExceptionFilter before any JIT code is compiled and |
| * only once per process. |
| */ |
| extern JS_FRIEND_API(void) |
| SetJitExceptionHandler(JitExceptionHandler handler); |
| #endif |
| |
| /** |
| * Get the nearest enclosing with scope object for a given function. If the |
| * function is not scripted or is not enclosed by a with scope, returns the |
| * global. |
| */ |
| extern JS_FRIEND_API(JSObject*) |
| GetNearestEnclosingWithScopeObjectForFunction(JSFunction* fun); |
| |
| /** |
| * Get the first SavedFrame object in this SavedFrame stack whose principals are |
| * subsumed by the cx's principals. If there is no such frame, return nullptr. |
| * |
| * Do NOT pass a non-SavedFrame object here. |
| * |
| * The savedFrame and cx do not need to be in the same compartment. |
| */ |
| extern JS_FRIEND_API(JSObject*) |
| GetFirstSubsumedSavedFrame(JSContext* cx, JS::HandleObject savedFrame, JS::SavedFrameSelfHosted selfHosted); |
| |
| extern JS_FRIEND_API(bool) |
| ReportIsNotFunction(JSContext* cx, JS::HandleValue v); |
| |
| extern JS_FRIEND_API(JSObject*) |
| ConvertArgsToArray(JSContext* cx, const JS::CallArgs& args); |
| |
| /** |
| * Window and WindowProxy |
| * |
| * The functions below have to do with Windows and WindowProxies. There's an |
| * invariant that actual Window objects (the global objects of web pages) are |
| * never directly exposed to script. Instead we often substitute a WindowProxy. |
| * |
| * The scope chain, on the other hand, contains the Window and never its |
| * WindowProxy. |
| * |
| * As a result, we have calls to these "substitute-this-object-for-that-object" |
| * functions sprinkled at apparently arbitrary (but actually *very* carefully |
| * and nervously selected) places throughout the engine and indeed the |
| * universe. |
| */ |
| |
| /** |
| * Tell the JS engine which Class is used for WindowProxy objects. Used by the |
| * functions below. |
| */ |
| extern JS_FRIEND_API(void) |
| SetWindowProxyClass(JSRuntime* rt, const Class* clasp); |
| |
| /** |
| * Associates a WindowProxy with a Window (global object). `windowProxy` must |
| * have the Class set by SetWindowProxyClass. |
| */ |
| extern JS_FRIEND_API(void) |
| SetWindowProxy(JSContext* cx, JS::HandleObject global, JS::HandleObject windowProxy); |
| |
| namespace detail { |
| |
| JS_FRIEND_API(bool) |
| IsWindowSlow(JSObject* obj); |
| |
| } // namespace detail |
| |
| /** |
| * Returns true iff `obj` is a global object with an associated WindowProxy, |
| * see SetWindowProxy. |
| */ |
| inline bool |
| IsWindow(JSObject* obj) |
| { |
| if (GetObjectClass(obj)->flags & JSCLASS_IS_GLOBAL) |
| return detail::IsWindowSlow(obj); |
| return false; |
| } |
| |
| /** |
| * Returns true iff `obj` has the WindowProxy Class (see SetWindowProxyClass). |
| */ |
| JS_FRIEND_API(bool) |
| IsWindowProxy(JSObject* obj); |
| |
| /** |
| * If `obj` is a Window, get its associated WindowProxy (or a CCW or dead |
| * wrapper if the page was navigated away from), else return `obj`. This |
| * function is infallible and never returns nullptr. |
| */ |
| extern JS_FRIEND_API(JSObject*) |
| ToWindowProxyIfWindow(JSObject* obj); |
| |
| /** |
| * If `obj` is a WindowProxy, get its associated Window (the compartment's |
| * global), else return `obj`. This function is infallible and never returns |
| * nullptr. |
| */ |
| extern JS_FRIEND_API(JSObject*) |
| ToWindowIfWindowProxy(JSObject* obj); |
| |
| } /* namespace js */ |
| |
| extern JS_FRIEND_API(void) |
| JS_StoreObjectPostBarrierCallback(JSContext* cx, |
| void (*callback)(JSTracer* trc, JSObject* key, void* data), |
| JSObject* key, void* data); |
| |
| extern JS_FRIEND_API(void) |
| JS_StoreStringPostBarrierCallback(JSContext* cx, |
| void (*callback)(JSTracer* trc, JSString* key, void* data), |
| JSString* key, void* data); |
| |
| /** |
| * Forcibly clear postbarrier callbacks queued by the previous two methods. |
| * This should be used when the object owning the postbarriered pointers is |
| * being destroyed outside of a garbage collection. |
| * |
| * This currently works by performing a minor GC. |
| */ |
| extern JS_FRIEND_API(void) |
| JS_ClearAllPostBarrierCallbacks(JSRuntime *rt); |
| |
| class NativeProfiler |
| { |
| public: |
| virtual ~NativeProfiler() {}; |
| virtual void sampleNative(void* addr, uint32_t size) = 0; |
| virtual void removeNative(void* addr) = 0; |
| virtual void reset() = 0; |
| }; |
| |
| class GCHeapProfiler |
| { |
| public: |
| virtual ~GCHeapProfiler() {}; |
| virtual void sampleTenured(void* addr, uint32_t size) = 0; |
| virtual void sampleNursery(void* addr, uint32_t size) = 0; |
| virtual void markTenuredStart() = 0; |
| virtual void markTenured(void* addr) = 0; |
| virtual void sweepTenured() = 0; |
| virtual void sweepNursery() = 0; |
| virtual void moveNurseryToTenured(void* addrOld, void* addrNew) = 0; |
| virtual void reset() = 0; |
| }; |
| |
| class MemProfiler |
| { |
| static mozilla::Atomic<uint32_t, mozilla::Relaxed> sActiveProfilerCount; |
| static NativeProfiler* sNativeProfiler; |
| |
| static GCHeapProfiler* GetGCHeapProfiler(void* addr); |
| static GCHeapProfiler* GetGCHeapProfiler(JSRuntime* runtime); |
| |
| static NativeProfiler* GetNativeProfiler() { |
| return sNativeProfiler; |
| } |
| |
| GCHeapProfiler* mGCHeapProfiler; |
| JSRuntime* mRuntime; |
| |
| public: |
| explicit MemProfiler(JSRuntime* aRuntime) : mGCHeapProfiler(nullptr), mRuntime(aRuntime) {} |
| |
| void start(GCHeapProfiler* aGCHeapProfiler); |
| void stop(); |
| |
| GCHeapProfiler* getGCHeapProfiler() const { |
| return mGCHeapProfiler; |
| } |
| |
| static MOZ_ALWAYS_INLINE bool enabled() { |
| return sActiveProfilerCount > 0; |
| } |
| |
| static MemProfiler* GetMemProfiler(JSRuntime* runtime); |
| |
| static void SetNativeProfiler(NativeProfiler* aProfiler) { |
| sNativeProfiler = aProfiler; |
| } |
| |
| static MOZ_ALWAYS_INLINE void SampleNative(void* addr, uint32_t size) { |
| JS::AutoSuppressGCAnalysis nogc; |
| |
| if (MOZ_LIKELY(!enabled())) |
| return; |
| |
| NativeProfiler* profiler = GetNativeProfiler(); |
| if (profiler) |
| profiler->sampleNative(addr, size); |
| } |
| |
| static MOZ_ALWAYS_INLINE void SampleTenured(void* addr, uint32_t size) { |
| JS::AutoSuppressGCAnalysis nogc; |
| |
| if (MOZ_LIKELY(!enabled())) |
| return; |
| |
| GCHeapProfiler* profiler = GetGCHeapProfiler(addr); |
| if (profiler) |
| profiler->sampleTenured(addr, size); |
| } |
| |
| static MOZ_ALWAYS_INLINE void SampleNursery(void* addr, uint32_t size) { |
| JS::AutoSuppressGCAnalysis nogc; |
| |
| if (MOZ_LIKELY(!enabled())) |
| return; |
| |
| GCHeapProfiler* profiler = GetGCHeapProfiler(addr); |
| if (profiler) |
| profiler->sampleNursery(addr, size); |
| } |
| |
| static MOZ_ALWAYS_INLINE void RemoveNative(void* addr) { |
| JS::AutoSuppressGCAnalysis nogc; |
| |
| if (MOZ_LIKELY(!enabled())) |
| return; |
| |
| NativeProfiler* profiler = GetNativeProfiler(); |
| if (profiler) |
| profiler->removeNative(addr); |
| } |
| |
| static MOZ_ALWAYS_INLINE void MarkTenuredStart(JSRuntime* runtime) { |
| JS::AutoSuppressGCAnalysis nogc; |
| |
| if (MOZ_LIKELY(!enabled())) |
| return; |
| |
| GCHeapProfiler* profiler = GetGCHeapProfiler(runtime); |
| if (profiler) |
| profiler->markTenuredStart(); |
| } |
| |
| static MOZ_ALWAYS_INLINE void MarkTenured(void* addr) { |
| JS::AutoSuppressGCAnalysis nogc; |
| |
| if (MOZ_LIKELY(!enabled())) |
| return; |
| |
| GCHeapProfiler* profiler = GetGCHeapProfiler(addr); |
| if (profiler) |
| profiler->markTenured(addr); |
| } |
| |
| static MOZ_ALWAYS_INLINE void SweepTenured(JSRuntime* runtime) { |
| JS::AutoSuppressGCAnalysis nogc; |
| |
| if (MOZ_LIKELY(!enabled())) |
| return; |
| |
| GCHeapProfiler* profiler = GetGCHeapProfiler(runtime); |
| if (profiler) |
| profiler->sweepTenured(); |
| } |
| |
| static MOZ_ALWAYS_INLINE void SweepNursery(JSRuntime* runtime) { |
| JS::AutoSuppressGCAnalysis nogc; |
| |
| if (MOZ_LIKELY(!enabled())) |
| return; |
| |
| GCHeapProfiler* profiler = GetGCHeapProfiler(runtime); |
| if (profiler) |
| profiler->sweepNursery(); |
| } |
| |
| static MOZ_ALWAYS_INLINE void MoveNurseryToTenured(void* addrOld, void* addrNew) { |
| JS::AutoSuppressGCAnalysis nogc; |
| |
| if (MOZ_LIKELY(!enabled())) |
| return; |
| |
| GCHeapProfiler* profiler = GetGCHeapProfiler(addrOld); |
| if (profiler) |
| profiler->moveNurseryToTenured(addrOld, addrNew); |
| } |
| }; |
| |
| #endif /* jsfriendapi_h */ |