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