summaryrefslogtreecommitdiffstats
path: root/js/src/jsfriendapi.h
diff options
context:
space:
mode:
Diffstat (limited to 'js/src/jsfriendapi.h')
-rw-r--r--js/src/jsfriendapi.h3067
1 files changed, 3067 insertions, 0 deletions
diff --git a/js/src/jsfriendapi.h b/js/src/jsfriendapi.h
new file mode 100644
index 000000000..b1c7cb0dc
--- /dev/null
+++ b/js/src/jsfriendapi.h
@@ -0,0 +1,3067 @@
+/* -*- 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/Maybe.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"
+#include "js/Utility.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(JSContext* cx, 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(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_ZONE_GC,
+ 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_COMPACT_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_RESET_REASON,
+ JS_TELEMETRY_GC_INCREMENTAL_DISABLED,
+ JS_TELEMETRY_GC_NON_INCREMENTAL,
+ JS_TELEMETRY_GC_NON_INCREMENTAL_REASON,
+ 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_GC_NURSERY_BYTES,
+ JS_TELEMETRY_GC_PRETENURE_COUNT,
+ JS_TELEMETRY_DEPRECATED_LANGUAGE_EXTENSIONS_IN_CONTENT,
+ JS_TELEMETRY_DEPRECATED_LANGUAGE_EXTENSIONS_IN_ADDONS,
+ JS_TELEMETRY_ADDON_EXCEPTIONS,
+ JS_TELEMETRY_AOT_USAGE,
+ JS_TELEMETRY_END
+};
+
+typedef void
+(*JSAccumulateTelemetryDataCallback)(int id, uint32_t sample, const char* key);
+
+extern JS_FRIEND_API(void)
+JS_SetAccumulateTelemetryCallback(JSContext* cx, JSAccumulateTelemetryDataCallback callback);
+
+extern JS_FRIEND_API(bool)
+JS_GetIsSecureContext(JSCompartment* compartment);
+
+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, ESClass* cls);
+
+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. Note that there are overloads that do not require the FILE*
+ * parameter, which will default to stderr.
+ */
+
+extern JS_FRIEND_API(void)
+DumpString(JSString* str, FILE* fp);
+
+extern JS_FRIEND_API(void)
+DumpAtom(JSAtom* atom, FILE* fp);
+
+extern JS_FRIEND_API(void)
+DumpObject(JSObject* obj, FILE* fp);
+
+extern JS_FRIEND_API(void)
+DumpChars(const char16_t* s, size_t n, FILE* fp);
+
+extern JS_FRIEND_API(void)
+DumpValue(const JS::Value& val, FILE* fp);
+
+extern JS_FRIEND_API(void)
+DumpId(jsid id, FILE* fp);
+
+extern JS_FRIEND_API(void)
+DumpInterpreterFrame(JSContext* cx, FILE* fp, InterpreterFrame* start = nullptr);
+
+extern JS_FRIEND_API(bool)
+DumpPC(JSContext* cx, FILE* fp);
+
+extern JS_FRIEND_API(bool)
+DumpScript(JSContext* cx, JSScript* scriptArg, FILE* fp);
+
+// Versions for use directly in a debugger (default parameters are not handled
+// well in gdb; built-in handles like stderr are not handled well in lldb.)
+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, FILE* fp);
+
+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);
+
+/**
+ * Set all of the uninitialized lexicals on an object to undefined. Return
+ * true if any lexicals were initialized and false otherwise.
+ * */
+extern JS_FRIEND_API(bool)
+ForceLexicalInitialization(JSContext *cx, HandleObject obj);
+
+} // 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<JS::PropertyDescriptor> 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 {
+
+extern JS_FRIEND_DATA(const js::ClassOps) ProxyClassOps;
+extern JS_FRIEND_DATA(const js::ClassExtension) ProxyClassExtension;
+extern JS_FRIEND_DATA(const js::ObjectOps) ProxyObjectOps;
+
+/*
+ * 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(objectMoved) \
+ { \
+ js::proxy_WeakmapKeyDelegate, \
+ objectMoved \
+ }
+
+#define PROXY_CLASS_WITH_EXT(name, flags, extPtr) \
+ { \
+ name, \
+ js::Class::NON_NATIVE | \
+ JSCLASS_IS_PROXY | \
+ JSCLASS_DELAY_METADATA_BUILDER | \
+ flags, \
+ &js::ProxyClassOps, \
+ JS_NULL_CLASS_SPEC, \
+ extPtr, \
+ &js::ProxyObjectOps \
+ }
+
+#define PROXY_CLASS_DEF(name, flags) \
+ PROXY_CLASS_WITH_EXT(name, flags, &js::ProxyClassExtension)
+
+/*
+ * 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<JS::PropertyDescriptor> 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<JS::PropertyDescriptor> 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 |cx| use |hook| to retrieve lazily-retrieved source code. See the
+ * comments for SourceHook. The context takes ownership of the hook, and
+ * will delete it when the context itself is deleted, or when a new hook is
+ * set.
+ */
+extern JS_FRIEND_API(void)
+SetSourceHook(JSContext* cx, mozilla::UniquePtr<SourceHook> hook);
+
+/** Remove |cx|'s source hook, and return it. The caller now owns the hook. */
+extern JS_FRIEND_API(mozilla::UniquePtr<SourceHook>)
+ForgetSourceHook(JSContext* cx);
+
+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(JSContext* cx, 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
+{
+ JSContext* context;
+
+ explicit WeakMapTracer(JSContext* cx) : context(cx) {}
+
+ // 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(JSContext* cx);
+
+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);
+
+/**
+ * Invoke cellCallback on every gray JSObject in the given zone.
+ */
+extern JS_FRIEND_API(void)
+IterateGrayObjects(JS::Zone* zone, GCThingCallback cellCallback, void* data);
+
+/**
+ * Invoke cellCallback on every gray JSObject in the given zone while cycle
+ * collection is in progress.
+ */
+extern JS_FRIEND_API(void)
+IterateGrayObjectsUnderCC(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 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
+InheritanceProtoKeyForStandardClass(JSProtoKey key)
+{
+ // [Object] has nothing to inherit from.
+ if (key == JSProto_Object)
+ return JSProto_Null;
+
+ // If we're ClassSpec defined return the proto key from that
+ if (ProtoKeyToClass(key)->specDefined())
+ return ProtoKeyToClass(key)->specInheritanceProtoKey();
+
+ // 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);
+
+extern JS_FRIEND_API(JSObject*)
+GetStaticPrototype(JSObject* obj);
+
+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);
+}
+
+template<typename CharType>
+MOZ_ALWAYS_INLINE void
+CopyLinearStringChars(CharType* dest, JSLinearString* s, size_t len, size_t start = 0);
+
+MOZ_ALWAYS_INLINE void
+CopyLinearStringChars(char16_t* dest, JSLinearString* s, size_t len, size_t start = 0)
+{
+ MOZ_ASSERT(start + len <= GetLinearStringLength(s));
+ JS::AutoCheckCannotGC nogc;
+ if (LinearStringHasLatin1Chars(s)) {
+ const JS::Latin1Char* src = GetLatin1LinearStringChars(nogc, s);
+ for (size_t i = 0; i < len; i++)
+ dest[i] = src[start + i];
+ } else {
+ const char16_t* src = GetTwoByteLinearStringChars(nogc, s);
+ mozilla::PodCopy(dest, src + start, len);
+ }
+}
+
+MOZ_ALWAYS_INLINE void
+CopyLinearStringChars(char* dest, JSLinearString* s, size_t len, size_t start = 0)
+{
+ MOZ_ASSERT(start + len <= GetLinearStringLength(s));
+ JS::AutoCheckCannotGC nogc;
+ if (LinearStringHasLatin1Chars(s)) {
+ const JS::Latin1Char* src = GetLatin1LinearStringChars(nogc, s);
+ for (size_t i = 0; i < len; i++)
+ dest[i] = char(src[start + i]);
+ } else {
+ const char16_t* src = GetTwoByteLinearStringChars(nogc, s);
+ for (size_t i = 0; i < len; i++)
+ dest[i] = char(src[start + i]);
+ }
+}
+
+template<typename CharType>
+inline bool
+CopyStringChars(JSContext* cx, CharType* dest, JSString* s, size_t len, size_t start = 0)
+{
+ JSLinearString* linear = StringToLinearString(cx, s);
+ if (!linear)
+ return false;
+
+ CopyLinearStringChars(dest, linear, len, start);
+ 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(JSContext* cx, PreserveWrapperCallback callback);
+
+JS_FRIEND_API(bool)
+IsObjectInContextCompartment(JSObject* obj, const JSContext* cx);
+
+/*
+ * 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)
+{
+ uintptr_t limit = ContextFriendFields::get(cx)->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);
+
+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(JSContext* cx, 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(JSContext* cx, const DOMCallbacks* callbacks);
+
+extern JS_FRIEND_API(const DOMCallbacks*)
+GetDOMCallbacks(JSContext* cx);
+
+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(JSContext* cx, 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 OwnerUnlinked()
+ {
+ ++generation;
+ }
+
+ 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 JS_FRIEND_API(AutoStableStringChars)
+{
+ /*
+ * When copying string char, use this many bytes of inline storage. This is
+ * chosen to allow the inline string types to be copied without allocating.
+ * This is asserted in AutoStableStringChars::allocOwnChars.
+ */
+ static const size_t InlineCapacity = 24;
+
+ /* Ensure the string is kept alive while we're using its chars. */
+ JS::RootedString s_;
+ union {
+ const char16_t* twoByteChars_;
+ const JS::Latin1Char* latin1Chars_;
+ };
+ mozilla::Maybe<Vector<uint8_t, InlineCapacity>> ownChars_;
+ enum State { Uninitialized, Latin1, TwoByte };
+ State state_;
+
+ public:
+ explicit AutoStableStringChars(JSContext* cx)
+ : s_(cx), state_(Uninitialized)
+ {}
+
+ MOZ_MUST_USE
+ bool init(JSContext* cx, JSString* s);
+
+ /* Like init(), but Latin1 chars are inflated to TwoByte. */
+ MOZ_MUST_USE
+ 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 (!ownChars_.isSome() || !ownChars_->extractRawBuffer())
+ return false;
+ state_ = Uninitialized;
+ ownChars_.reset();
+ return true;
+ }
+
+ private:
+ AutoStableStringChars(const AutoStableStringChars& other) = delete;
+ void operator=(const AutoStableStringChars& other) = delete;
+
+ bool baseIsInline(JS::Handle<JSLinearString*> linearString);
+ template <typename T> T* allocOwnChars(JSContext* cx, size_t count);
+ bool copyLatin1Chars(JSContext* cx, JS::Handle<JSLinearString*> linearString);
+ bool copyTwoByteChars(JSContext* cx, JS::Handle<JSLinearString*> linearString);
+ bool copyAndInflateLatin1Chars(JSContext*, JS::Handle<JSLinearString*> linearString);
+};
+
+struct MOZ_STACK_CLASS JS_FRIEND_API(ErrorReport)
+{
+ explicit ErrorReport(JSContext* cx);
+ ~ErrorReport();
+
+ enum SniffingBehavior {
+ WithSideEffects,
+ NoSideEffects
+ };
+
+ /**
+ * Generate a JSErrorReport from the provided thrown value.
+ *
+ * If the value is a (possibly wrapped) Error object, the JSErrorReport will
+ * be exactly initialized from the Error object's information, without
+ * observable side effects. (The Error object's JSErrorReport is reused, if
+ * it has one.)
+ *
+ * Otherwise various attempts are made to derive JSErrorReport information
+ * from |exn| and from the current execution state. This process is
+ * *definitely* inconsistent with any standard, and particulars of the
+ * behavior implemented here generally shouldn't be relied upon.
+ *
+ * If the value of |sniffingBehavior| is |WithSideEffects|, some of these
+ * attempts *may* invoke user-configurable behavior when |exn| is an object:
+ * converting |exn| to a string, detecting and getting properties on |exn|,
+ * accessing |exn|'s prototype chain, and others are possible. Users *must*
+ * tolerate |ErrorReport::init| potentially having arbitrary effects. Any
+ * exceptions thrown by these operations will be caught and silently
+ * ignored, and "default" values will be substituted into the JSErrorReport.
+ *
+ * But if the value of |sniffingBehavior| is |NoSideEffects|, these attempts
+ * *will not* invoke any observable side effects. The JSErrorReport will
+ * simply contain fewer, less precise details.
+ *
+ * Unlike some functions involved in error handling, this function adheres
+ * to the usual JSAPI return value error behavior.
+ */
+ bool init(JSContext* cx, JS::HandleValue exn,
+ SniffingBehavior sniffingBehavior);
+
+ JSErrorReport* report()
+ {
+ return reportp;
+ }
+
+ const JS::ConstUTF8CharsZ toStringResult()
+ {
+ return toStringResult_;
+ }
+
+ 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 populateUncaughtExceptionReportUTF8(JSContext* cx, ...);
+ bool populateUncaughtExceptionReportUTF8VA(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;
+
+ // Or we may need to synthesize a JSErrorReport one of our own.
+ JSErrorReport ownedReport;
+
+ // 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 for our filename.
+ JSAutoByteString filename;
+
+ // We may have a result of error.toString().
+ // FIXME: We should not call error.toString(), since it could have side
+ // effect (see bug 633623).
+ JS::ConstUTF8CharsZ toStringResult_;
+ JSAutoByteString toStringResultBytesStorage;
+};
+
+/* 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,
+
+ /**
+ * Types that don't have their own TypedArray equivalent, for now.
+ */
+ MaxTypedArrayViewType,
+
+ Int64,
+ Float32x4,
+ Int8x16,
+ Int16x8,
+ 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 Int64:
+ case Float64:
+ return 8;
+ case Int8x16:
+ case Int16x8:
+ 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 Int64:
+ case Int8x16:
+ case Int16x8:
+ 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 Int64:
+ case Float32:
+ case Float64:
+ return false;
+ case Int8x16:
+ case Int16x8:
+ case Int32x4:
+ case Float32x4:
+ return true;
+ case MaxTypedArrayViewType:
+ break;
+ }
+ MOZ_CRASH("invalid scalar type");
+}
+
+static inline size_t
+scalarByteSize(Type atype) {
+ switch (atype) {
+ case Int8x16:
+ return 1;
+ case Int16x8:
+ return 2;
+ case Int32x4:
+ case Float32x4:
+ return 4;
+ case Int8:
+ case Uint8:
+ case Uint8Clamped:
+ case Int16:
+ case Uint16:
+ case Int32:
+ case Uint32:
+ case Int64:
+ 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. This
+ * may only be called if
+ * JS::CompartmentCreationOptionsRef(cx).getSharedMemoryAndAtomicsEnabled() is
+ * true.
+ */
+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 detached 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.
+ * This may return a detached 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);
+
+/**
+ * Detach an ArrayBuffer, causing all associated views to no longer refer to
+ * the ArrayBuffer's original attached memory.
+ *
+ * The |changeData| argument is obsolete and ignored.
+ */
+extern JS_FRIEND_API(bool)
+JS_DetachArrayBuffer(JSContext* cx, JS::HandleObject obj);
+
+/**
+ * Check whether the obj is a detached ArrayBufferObject. Note that this may
+ * return false if a security wrapper is encountered that denies the
+ * unwrapping.
+ */
+extern JS_FRIEND_API(bool)
+JS_IsDetachedArrayBufferObject(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;
+ };
+
+ union {
+ uint16_t depth;
+
+ // Additional opcode for some InlinableNative functions.
+ uint16_t nativeOp;
+ };
+
+ // 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(JSContext* cx, ScriptEnvironmentPreparer* preparer);
+
+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(JSContext* cx, 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;
+ }
+ }
+};
+
+// Abstract base class for objects that build allocation metadata for JavaScript
+// values.
+struct AllocationMetadataBuilder {
+ AllocationMetadataBuilder() { }
+
+ // Return a metadata object for the newly constructed object |obj|, or
+ // nullptr if there's no metadata to attach.
+ //
+ // Implementations should treat all errors as fatal; there is no way to
+ // report errors from this callback. In particular, the caller provides an
+ // oomUnsafe for overriding implementations to use.
+ virtual JSObject* build(JSContext* cx, JS::HandleObject obj,
+ AutoEnterOOMUnsafeRegion& oomUnsafe) const
+ {
+ return nullptr;
+ }
+};
+
+/**
+ * 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)
+SetAllocationMetadataBuilder(JSContext* cx, const AllocationMetadataBuilder *callback);
+
+/** Get the metadata associated with an object. */
+JS_FRIEND_API(JSObject*)
+GetAllocationMetadata(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<JS::PropertyDescriptor> ownDesc,
+ JS::ObjectOpResult& result);
+
+JS_FRIEND_API(void)
+ReportASCIIErrorWithId(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 environment 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*)
+GetNearestEnclosingWithEnvironmentObjectForFunction(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 environment 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(JSContext* cx, 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 */
+
+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 JS_FRIEND_DATA(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) {}
+
+ JS_FRIEND_API(void) start(GCHeapProfiler* aGCHeapProfiler);
+ JS_FRIEND_API(void) stop();
+
+ GCHeapProfiler* getGCHeapProfiler() const {
+ return mGCHeapProfiler;
+ }
+
+ static MOZ_ALWAYS_INLINE bool enabled() {
+ return sActiveProfilerCount > 0;
+ }
+
+ static JS_FRIEND_API(MemProfiler*) GetMemProfiler(JSContext* context);
+
+ 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 */