/* -*- 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/Casting.h" #include "mozilla/MemoryReporting.h" #include "mozilla/TypedEnum.h" #include "jsbytecode.h" #include "jspubtd.h" #include "js/CallArgs.h" #include "js/CallNonGenericMethod.h" #include "js/Class.h" /* * This macro checks if the stack pointer has exceeded a given limit. If * |tolerance| is non-zero, it returns true only if the stack pointer has * exceeded the limit by more than |tolerance| bytes. */ #if JS_STACK_GROWTH_DIRECTION > 0 # define JS_CHECK_STACK_SIZE_WITH_TOLERANCE(limit, sp, tolerance) \ ((uintptr_t)(sp) < (limit)+(tolerance)) #else # define JS_CHECK_STACK_SIZE_WITH_TOLERANCE(limit, sp, tolerance) \ ((uintptr_t)(sp) > (limit)-(tolerance)) #endif #define JS_CHECK_STACK_SIZE(limit, lval) JS_CHECK_STACK_SIZE_WITH_TOLERANCE(limit, lval, 0) class JSAtom; struct JSErrorFormatString; class JSLinearString; struct JSJitInfo; class JSErrorReport; namespace JS { template class Heap; } /* namespace JS */ namespace js { class JS_FRIEND_API(BaseProxyHandler); } /* namespace js */ extern JS_FRIEND_API(void) JS_SetGrayGCRootsTracer(JSRuntime *rt, JSTraceDataOp traceOp, void *data); extern JS_FRIEND_API(JSString *) JS_GetAnonymousString(JSRuntime *rt); extern JS_FRIEND_API(void) JS_SetIsWorkerRuntime(JSRuntime *rt); 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, JS::HandleObject parent); 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); /* * 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 the shape and all * shapes it reaches, marking all non-shape children found in the * process. Uses bounded stack space. */ extern JS_FRIEND_API(void) JS_TraceShapeCycleCollectorChildren(JSTracer *trc, void *shape); enum { JS_TELEMETRY_GC_REASON, JS_TELEMETRY_GC_IS_COMPARTMENTAL, JS_TELEMETRY_GC_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_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 }; typedef void (* JSAccumulateTelemetryDataCallback)(int id, uint32_t sample); 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); /* Safe to call with input obj == nullptr. Returns non-nullptr iff obj != nullptr. */ extern JS_FRIEND_API(JSObject *) JS_ObjectToInnerObject(JSContext *cx, JS::HandleObject obj); /* Requires obj != nullptr. */ extern JS_FRIEND_API(JSObject *) JS_ObjectToOuterObject(JSContext *cx, JS::HandleObject obj); extern JS_FRIEND_API(JSObject *) JS_CloneObject(JSContext *cx, JS::HandleObject obj, JS::HandleObject proto, JS::HandleObject parent); extern JS_FRIEND_API(JSString *) JS_BasicObjectToString(JSContext *cx, JS::HandleObject obj); extern JS_FRIEND_API(bool) js_GetterOnlyPropertyStub(JSContext *cx, JS::HandleObject obj, JS::HandleId id, bool strict, JS::MutableHandleValue vp); JS_FRIEND_API(void) js_ReportOverRecursed(JSContext *maybecx); JS_FRIEND_API(bool) js_ObjectClassIs(JSContext *cx, JS::HandleObject obj, js::ESClassValue classValue); JS_FRIEND_API(const char *) js_ObjectClassName(JSContext *cx, JS::HandleObject obj); namespace js { JS_FRIEND_API(bool) AddRawValueRoot(JSContext *cx, JS::Value *vp, const char *name); JS_FRIEND_API(void) RemoveRawValueRoot(JSContext *cx, JS::Value *vp); } /* namespace js */ #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) js_DumpString(JSString *str); extern JS_FRIEND_API(void) js_DumpAtom(JSAtom *atom); extern JS_FRIEND_API(void) js_DumpObject(JSObject *obj); extern JS_FRIEND_API(void) js_DumpChars(const jschar *s, size_t n); #endif /* * 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|. */ extern JS_FRIEND_API(bool) JS_CopyPropertyFrom(JSContext *cx, JS::HandleId id, JS::HandleObject target, JS::HandleObject obj); extern JS_FRIEND_API(bool) JS_WrapPropertyDescriptor(JSContext *cx, JS::MutableHandle desc); extern JS_FRIEND_API(bool) JS_WrapAutoIdVector(JSContext *cx, JS::AutoIdVector &props); extern JS_FRIEND_API(bool) JS_EnumerateState(JSContext *cx, JS::HandleObject obj, JSIterateOp enum_op, JS::MutableHandleValue statep, JS::MutableHandleId idp); struct JSFunctionSpecWithHelp { const char *name; JSNative call; uint16_t nargs; uint16_t flags; 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, 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 potention JSClass extensions. */ #define PROXY_MAKE_EXT(outerObject, innerObject, iteratorObject, \ isWrappedNative) \ { \ outerObject, \ innerObject, \ iteratorObject, \ isWrappedNative, \ js::proxy_WeakmapKeyDelegate \ } #define PROXY_CLASS_WITH_EXT(name, extraSlots, flags, callOp, constructOp, ext) \ { \ name, \ js::Class::NON_NATIVE | \ JSCLASS_IS_PROXY | \ JSCLASS_IMPLEMENTS_BARRIERS | \ JSCLASS_HAS_RESERVED_SLOTS(js::PROXY_MINIMUM_SLOTS + (extraSlots)) | \ flags, \ JS_PropertyStub, /* addProperty */ \ JS_DeletePropertyStub, /* delProperty */ \ JS_PropertyStub, /* getProperty */ \ JS_StrictPropertyStub, /* setProperty */ \ JS_EnumerateStub, \ JS_ResolveStub, \ js::proxy_Convert, \ js::proxy_Finalize, /* finalize */ \ callOp, /* call */ \ js::proxy_HasInstance, /* hasInstance */ \ constructOp, /* construct */ \ js::proxy_Trace, /* trace */ \ JS_NULL_CLASS_SPEC, \ ext, \ { \ js::proxy_LookupGeneric, \ js::proxy_LookupProperty, \ js::proxy_LookupElement, \ js::proxy_DefineGeneric, \ js::proxy_DefineProperty, \ js::proxy_DefineElement, \ js::proxy_GetGeneric, \ js::proxy_GetProperty, \ js::proxy_GetElement, \ js::proxy_SetGeneric, \ js::proxy_SetProperty, \ js::proxy_SetElement, \ js::proxy_GetGenericAttributes, \ js::proxy_SetGenericAttributes, \ js::proxy_DeleteProperty, \ js::proxy_DeleteElement, \ js::proxy_Watch, js::proxy_Unwatch, \ js::proxy_Slice, \ nullptr, /* enumerate */ \ nullptr, /* thisObject */ \ } \ } #define PROXY_CLASS_DEF(name, extraSlots, flags, callOp, constructOp) \ PROXY_CLASS_WITH_EXT(name, extraSlots, flags, callOp, constructOp, \ PROXY_MAKE_EXT( \ nullptr, /* outerObject */ \ nullptr, /* innerObject */ \ nullptr, /* iteratorObject */ \ false /* isWrappedNative */ \ )) /* * Proxy stubs, similar to JS_*Stub, for embedder proxy class definitions. * * NB: Should not be called directly. */ extern JS_FRIEND_API(bool) proxy_LookupGeneric(JSContext *cx, JS::HandleObject obj, JS::HandleId id, JS::MutableHandleObject objp, JS::MutableHandle propp); extern JS_FRIEND_API(bool) proxy_LookupProperty(JSContext *cx, JS::HandleObject obj, JS::Handle name, JS::MutableHandleObject objp, JS::MutableHandle propp); extern JS_FRIEND_API(bool) proxy_LookupElement(JSContext *cx, JS::HandleObject obj, uint32_t index, JS::MutableHandleObject objp, JS::MutableHandle propp); extern JS_FRIEND_API(bool) proxy_DefineGeneric(JSContext *cx, JS::HandleObject obj, JS::HandleId id, JS::HandleValue value, JSPropertyOp getter, JSStrictPropertyOp setter, unsigned attrs); extern JS_FRIEND_API(bool) proxy_DefineProperty(JSContext *cx, JS::HandleObject obj, JS::Handle name, JS::HandleValue value, JSPropertyOp getter, JSStrictPropertyOp setter, unsigned attrs); extern JS_FRIEND_API(bool) proxy_DefineElement(JSContext *cx, JS::HandleObject obj, uint32_t index, JS::HandleValue value, JSPropertyOp getter, JSStrictPropertyOp setter, unsigned attrs); extern JS_FRIEND_API(bool) proxy_GetGeneric(JSContext *cx, JS::HandleObject obj, JS::HandleObject receiver, JS::HandleId id, JS::MutableHandleValue vp); extern JS_FRIEND_API(bool) proxy_GetProperty(JSContext *cx, JS::HandleObject obj, JS::HandleObject receiver, JS::Handle name, JS::MutableHandleValue vp); extern JS_FRIEND_API(bool) proxy_GetElement(JSContext *cx, JS::HandleObject obj, JS::HandleObject receiver, uint32_t index, JS::MutableHandleValue vp); extern JS_FRIEND_API(bool) proxy_SetGeneric(JSContext *cx, JS::HandleObject obj, JS::HandleId id, JS::MutableHandleValue bp, bool strict); extern JS_FRIEND_API(bool) proxy_SetProperty(JSContext *cx, JS::HandleObject obj, JS::Handle name, JS::MutableHandleValue bp, bool strict); extern JS_FRIEND_API(bool) proxy_SetElement(JSContext *cx, JS::HandleObject obj, uint32_t index, JS::MutableHandleValue vp, bool strict); extern JS_FRIEND_API(bool) proxy_GetGenericAttributes(JSContext *cx, JS::HandleObject obj, JS::HandleId id, unsigned *attrsp); extern JS_FRIEND_API(bool) proxy_SetGenericAttributes(JSContext *cx, JS::HandleObject obj, JS::HandleId id, unsigned *attrsp); extern JS_FRIEND_API(bool) proxy_DeleteProperty(JSContext *cx, JS::HandleObject obj, JS::Handle name, bool *succeeded); extern JS_FRIEND_API(bool) proxy_DeleteElement(JSContext *cx, JS::HandleObject obj, uint32_t index, bool *succeeded); 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(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(JSContext *cx, JS::HandleObject 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_Slice(JSContext *cx, JS::HandleObject proxy, uint32_t begin, uint32_t end, JS::HandleObject result); /* * 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, jschar **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, SourceHook *hook); /* Remove |rt|'s source hook, and return it. The caller now owns the hook. */ extern JS_FRIEND_API(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) DumpHeapComplete(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); /* * Check whether it is OK to assign an undeclared variable with the name * |propname| at the current location in script. It is not an error if there is * no current script location, or if that location is not an assignment to an * undeclared variable. Reports an error if one needs to be reported (and, * particularly, always reports when it returns false). */ extern JS_FRIEND_API(bool) ReportIfUndeclaredVarAssignment(JSContext *cx, JS::HandleString propname); /* * Returns whether we're in a non-strict property set (in that we're in a * non-strict script and the bytecode we're on is a property set). The return * value does NOT indicate any sort of exception was thrown: it's just a * boolean. */ extern JS_FRIEND_API(bool) IsInNonStrictPropertySet(JSContext *cx); struct WeakMapTracer; /* * 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. */ typedef void (* WeakMapTraceCallback)(WeakMapTracer *trc, JSObject *m, void *k, JSGCTraceKind kkind, void *v, JSGCTraceKind vkind); struct WeakMapTracer { JSRuntime *runtime; WeakMapTraceCallback callback; WeakMapTracer(JSRuntime *rt, WeakMapTraceCallback cb) : runtime(rt), callback(cb) {} }; 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, void *gcthing); extern JS_FRIEND_API(void) VisitGrayWrapperTargets(JS::Zone *zone, GCThingCallback callback, void *closure); extern JS_FRIEND_API(JSObject *) GetWeakmapKeyDelegate(JSObject *key); JS_FRIEND_API(JSGCTraceKind) 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 TypeObject { const Class *clasp; JSObject *proto; }; struct BaseShape { const js::Class *clasp_; JSObject *parent; JSObject *_1; JSCompartment *compartment; }; class Shape { public: shadow::BaseShape *base; jsid _1; uint32_t slotInfo; static const uint32_t FIXED_SLOTS_SHIFT = 27; }; struct Object { shadow::Shape *shape; shadow::TypeObject *type; JS::Value *slots; JS::Value *_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]; } // Reserved slots with index < MAX_FIXED_SLOTS are guaranteed to // be fixed slots. static const uint32_t MAX_FIXED_SLOTS = 16; }; struct Function { Object base; uint16_t nargs; uint16_t flags; /* Used only for natives */ JSNative native; const JSJitInfo *jitinfo; void *_1; }; struct Atom { static const size_t LENGTH_SHIFT = 4; size_t lengthAndFlags; const jschar *chars; }; } /* 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(JSObject *obj) { return reinterpret_cast(obj)->type->clasp; } inline const JSClass * GetObjectJSClass(JSObject *obj) { return js::Jsvalify(GetObjectClass(obj)); } inline bool IsInnerObject(JSObject *obj) { return !!GetObjectClass(obj)->ext.outerObject; } inline bool IsOuterObject(JSObject *obj) { return !!GetObjectClass(obj)->ext.innerObject; } JS_FRIEND_API(bool) IsFunctionObject(JSObject *obj); JS_FRIEND_API(bool) IsScopeObject(JSObject *obj); JS_FRIEND_API(bool) IsCallObject(JSObject *obj); inline JSObject * GetObjectParent(JSObject *obj) { JS_ASSERT(!IsScopeObject(obj)); return reinterpret_cast(obj)->shape->base->parent; } static MOZ_ALWAYS_INLINE JSCompartment * GetObjectCompartment(JSObject *obj) { return reinterpret_cast(obj)->shape->base->compartment; } JS_FRIEND_API(JSObject *) GetObjectParentMaybeScope(JSObject *obj); JS_FRIEND_API(JSObject *) GetGlobalForObjectCrossCompartment(JSObject *obj); // Sidestep the activeContext checking implicitly performed in // JS_SetPendingException. JS_FRIEND_API(void) SetPendingExceptionCrossContext(JSContext *cx, JS::HandleValue v); 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 // For legacy consumers only. This whole concept is going away soon. JS_FRIEND_API(JSObject *) DefaultObjectForContextOrNull(JSContext *cx); JS_FRIEND_API(void) SetDefaultObjectForContext(JSContext *cx, JSObject *obj); 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(JSScript *) 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, JSObject *parent, const char *name); JS_FRIEND_API(JSFunction *) NewFunctionByIdWithReserved(JSContext *cx, JSNative native, unsigned nargs, unsigned flags, JSObject *parent, jsid id); JS_FRIEND_API(JSObject *) InitClassWithReserved(JSContext *cx, JSObject *obj, JSObject *parent_proto, const JSClass *clasp, JSNative constructor, unsigned nargs, const JSPropertySpec *ps, const JSFunctionSpec *fs, const JSPropertySpec *static_ps, const JSFunctionSpec *static_fs); 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) 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) { const shadow::Object *nobj = reinterpret_cast(obj); void **addr = reinterpret_cast(&nobj->fixedSlots()[nobj->numFixedSlots()]); return *addr; } /* * Get a slot that is both reserved for object's clasp *and* is fixed (fits * within the maximum capacity for the object's fixed slots). */ inline const JS::Value & GetReservedSlot(JSObject *obj, size_t slot) { JS_ASSERT(slot < JSCLASS_RESERVED_SLOTS(GetObjectClass(obj))); return reinterpret_cast(obj)->slotRef(slot); } JS_FRIEND_API(void) SetReservedSlotWithBarrier(JSObject *obj, size_t slot, const JS::Value &value); inline void SetReservedSlot(JSObject *obj, size_t slot, const JS::Value &value) { JS_ASSERT(slot < JSCLASS_RESERVED_SLOTS(GetObjectClass(obj))); shadow::Object *sobj = reinterpret_cast(obj); if (sobj->slotRef(slot).isMarkable() #ifdef JSGC_GENERATIONAL || value.isMarkable() #endif ) { SetReservedSlotWithBarrier(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) { JS_ASSERT(slot < GetObjectSlotSpan(obj)); return reinterpret_cast(obj)->slotRef(slot); } inline const jschar * GetAtomChars(JSAtom *atom) { return reinterpret_cast(atom)->chars; } inline size_t GetAtomLength(JSAtom *atom) { using shadow::Atom; return reinterpret_cast(atom)->lengthAndFlags >> Atom::LENGTH_SHIFT; } inline JSLinearString * AtomToLinearString(JSAtom *atom) { return reinterpret_cast(atom); } JS_FRIEND_API(bool) GetPropertyNames(JSContext *cx, JSObject *obj, unsigned flags, JS::AutoIdVector *props); JS_FRIEND_API(bool) AppendUnique(JSContext *cx, JS::AutoIdVector &base, JS::AutoIdVector &others); JS_FRIEND_API(bool) GetGeneric(JSContext *cx, JSObject *obj, JSObject *receiver, jsid id, JS::Value *vp); 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. */ #define JSITER_ENUMERATE 0x1 /* for-in compatible hidden default iterator */ #define JSITER_FOREACH 0x2 /* return [key, value] pair rather than key */ #define JSITER_KEYVALUE 0x4 /* 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 */ JS_FRIEND_API(bool) RunningWithTrustedPrincipals(JSContext *cx); inline uintptr_t GetNativeStackLimit(JSContext *cx) { StackKind kind = RunningWithTrustedPrincipals(cx) ? StackForTrustedScript : StackForUntrustedScript; PerThreadDataFriendFields *mainThread = PerThreadDataFriendFields::getMainThread(GetRuntime(cx)); return mainThread->nativeStackLimit[kind]; } /* * 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. */ #define JS_CHECK_RECURSION(cx, onerror) \ JS_BEGIN_MACRO \ int stackDummy_; \ if (!JS_CHECK_STACK_SIZE(js::GetNativeStackLimit(cx), &stackDummy_)) { \ js_ReportOverRecursed(cx); \ onerror; \ } \ JS_END_MACRO #define JS_CHECK_RECURSION_DONT_REPORT(cx, onerror) \ JS_BEGIN_MACRO \ int stackDummy_; \ if (!JS_CHECK_STACK_SIZE(js::GetNativeStackLimit(cx), &stackDummy_)) { \ onerror; \ } \ JS_END_MACRO #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_CHROME_RECURSION(cx, onerror) \ JS_BEGIN_MACRO \ int stackDummy_; \ if (!JS_CHECK_STACK_SIZE_WITH_TOLERANCE(js::GetNativeStackLimit(cx), \ &stackDummy_, \ 1024 * sizeof(size_t))) \ { \ js_ReportOverRecursed(cx); \ onerror; \ } \ JS_END_MACRO 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); #ifdef JS_THREADSAFE JS_FRIEND_API(bool) ContextHasOutstandingRequests(const JSContext *cx); #endif 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); extern JS_FRIEND_API(const JSStructuredCloneCallbacks *) GetContextStructuredCloneCallbacks(JSContext *cx); extern JS_FRIEND_API(bool) IsContextRunningJS(JSContext *cx); typedef bool (* DOMInstanceClassMatchesProto)(JSObject *protoObject, uint32_t protoID, uint32_t depth); struct JSDOMCallbacks { DOMInstanceClassMatchesProto 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(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(const jschar*) GetErrorTypeName(JSRuntime* rt, int16_t exnType); #ifdef JS_DEBUG extern JS_FRIEND_API(unsigned) GetEnterCompartmentDepth(JSContext* cx); #endif /* 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 { return true; } }; struct ContentCompartmentsOnly : public CompartmentFilter { virtual bool match(JSCompartment *c) const { return !IsSystemCompartment(c); } }; struct ChromeCompartmentsOnly : public CompartmentFilter { virtual bool match(JSCompartment *c) const { return IsSystemCompartment(c); } }; struct SingleCompartment : public CompartmentFilter { JSCompartment *ours; SingleCompartment(JSCompartment *c) : ours(c) {} virtual bool match(JSCompartment *c) const { return c == ours; } }; struct CompartmentsWithPrincipals : public CompartmentFilter { JSPrincipals *principals; CompartmentsWithPrincipals(JSPrincipals *p) : principals(p) {} virtual bool match(JSCompartment *c) const { 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 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 uint32 value. If that value changes then the IC for getting a property will * be invalidated. */ 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 expando; uint32_t generation; }; typedef enum DOMProxyShadowsResult { ShadowCheckFailed, Shadows, DoesntShadow, DoesntShadowUnique } 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(); } /* namespace js */ /* Implemented in jsdate.cpp. */ /* * Detect whether the internal date value is NaN. (Because failure is * out-of-band for js_DateGet*) */ extern JS_FRIEND_API(bool) js_DateIsValid(JSObject* obj); extern JS_FRIEND_API(double) js_DateGetMsecSinceEpoch(JSObject *obj); /* 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, number, count, exception, format) \ name = number, #include "js.msg" #undef MSG_DEF JSErr_Limit } JSErrNum; extern JS_FRIEND_API(const JSErrorFormatString *) js_GetErrorMessage(void *userRef, const char *locale, const unsigned errorNumber); namespace js { // 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); } /* namespace js */ /* Implemented in jsclone.cpp. */ extern JS_FRIEND_API(uint64_t) js_GetSCOffset(JSStructuredCloneWriter* writer); /* Typed Array functions, implemented in jstypedarray.cpp */ namespace js { namespace ArrayBufferView { enum ViewType { TYPE_INT8 = 0, TYPE_UINT8, TYPE_INT16, TYPE_UINT16, TYPE_INT32, TYPE_UINT32, TYPE_FLOAT32, TYPE_FLOAT64, /* * Special type that is a uint8_t, but assignments are clamped to [0, 256). * Treat the raw data type as a uint8_t. */ TYPE_UINT8_CLAMPED, /* * Type returned for a DataView. Note that there is no single element type * in this case. */ TYPE_DATAVIEW, TYPE_MAX }; } /* namespace ArrayBufferView */ } /* namespace js */ typedef js::ArrayBufferView::ViewType JSArrayBufferViewType; /* * 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 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 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); /* * 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); 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 = 4; } // namespace detail /* * Test for specific typed array types (ArrayBufferView subtypes) and return * the unwrapped object if so, else nullptr. Never throws. */ #define JS_DEFINE_DATA_AND_LENGTH_ACCESSOR(Type, type) \ inline void \ Get ## Type ## ArrayLengthAndData(JSObject *obj, uint32_t *length, type **data) \ { \ JS_ASSERT(GetObjectClass(obj) == detail::Type ## ArrayClassPtr); \ const JS::Value &slot = GetReservedSlot(obj, detail::TypedArrayLengthSlot); \ *length = mozilla::SafeCast(slot.toInt32()); \ *data = static_cast(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, 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. extern JS_FRIEND_API(void) GetArrayBufferLengthAndData(JSObject *obj, uint32_t *length, uint8_t **data); } // namespace js /* * 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, int8_t **data); extern JS_FRIEND_API(JSObject *) JS_GetObjectAsUint8Array(JSObject *obj, uint32_t *length, uint8_t **data); extern JS_FRIEND_API(JSObject *) JS_GetObjectAsUint8ClampedArray(JSObject *obj, uint32_t *length, uint8_t **data); extern JS_FRIEND_API(JSObject *) JS_GetObjectAsInt16Array(JSObject *obj, uint32_t *length, int16_t **data); extern JS_FRIEND_API(JSObject *) JS_GetObjectAsUint16Array(JSObject *obj, uint32_t *length, uint16_t **data); extern JS_FRIEND_API(JSObject *) JS_GetObjectAsInt32Array(JSObject *obj, uint32_t *length, int32_t **data); extern JS_FRIEND_API(JSObject *) JS_GetObjectAsUint32Array(JSObject *obj, uint32_t *length, uint32_t **data); extern JS_FRIEND_API(JSObject *) JS_GetObjectAsFloat32Array(JSObject *obj, uint32_t *length, float **data); extern JS_FRIEND_API(JSObject *) JS_GetObjectAsFloat64Array(JSObject *obj, uint32_t *length, double **data); extern JS_FRIEND_API(JSObject *) JS_GetObjectAsArrayBufferView(JSObject *obj, uint32_t *length, uint8_t **data); 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 TYPE_DATAVIEW 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(JSArrayBufferViewType) JS_GetArrayBufferViewType(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); /* * 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); /* * 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. */ extern JS_FRIEND_API(uint8_t *) JS_GetArrayBufferData(JSObject *obj); extern JS_FRIEND_API(int8_t *) JS_GetInt8ArrayData(JSObject *obj); extern JS_FRIEND_API(uint8_t *) JS_GetUint8ArrayData(JSObject *obj); extern JS_FRIEND_API(uint8_t *) JS_GetUint8ClampedArrayData(JSObject *obj); extern JS_FRIEND_API(int16_t *) JS_GetInt16ArrayData(JSObject *obj); extern JS_FRIEND_API(uint16_t *) JS_GetUint16ArrayData(JSObject *obj); extern JS_FRIEND_API(int32_t *) JS_GetInt32ArrayData(JSObject *obj); extern JS_FRIEND_API(uint32_t *) JS_GetUint32ArrayData(JSObject *obj); extern JS_FRIEND_API(float *) JS_GetFloat32ArrayData(JSObject *obj); extern JS_FRIEND_API(double *) JS_GetFloat64ArrayData(JSObject *obj); /* * Stable versions of the above functions where the buffer remains valid as long * as the object is live. */ extern JS_FRIEND_API(uint8_t *) JS_GetStableArrayBufferData(JSContext *cx, JS::HandleObject obj); /* * 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); /* * Return the ArrayBuffer 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, JSObject *obj); 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 obj supports JS_GetDataView* APIs. */ JS_FRIEND_API(bool) JS_IsDataViewObject(JSObject *obj); /* * 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); 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 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 { private: typedef JS::detail::CallArgsBase 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(); } // Add get() as needed }; struct JSJitMethodCallArgsTraits { static const size_t offsetOfArgv = offsetof(JSJitMethodCallArgs, argv_); static const size_t offsetOfArgc = offsetof(JSJitMethodCallArgs, argc_); }; /* * 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. */ 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); struct JSJitInfo { enum OpType { Getter, Setter, Method, ParallelNative, StaticMethod, // 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."); enum AliasSet { // 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. // 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 hasParallelNative() const { return type() == ParallelNative; } 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; /* An alternative native that's safe to call in parallel mode. */ JSParallelNative parallelNative; /* A DOM static method, used for Promise wrappers */ JSNative staticMethod; }; uint16_t protoID; 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 // 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 uint32_t isInfallible : 1; /* Is op fallible? False in setters. */ uint32_t isMovable : 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). */ // XXXbz should we have a JSValueType for the type of the member? uint32_t isInSlot : 1; /* True if this is a getter that can get a member from a slot of the "this" object directly. */ uint32_t isTypedMethod : 1; /* True if this is an instance of JSTypedMethodJitInfo. */ uint32_t slotIndex : 12; /* If isInSlot is true, the index of the slot to get the value from. Otherwise 0. */ }; 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 { namespace detail { /* NEVER DEFINED, DON'T USE. For use by JS_CAST_PARALLEL_NATIVE_TO only. */ inline int CheckIsParallelNative(JSParallelNative parallelNative); } // namespace detail } // namespace JS #define JS_CAST_PARALLEL_NATIVE_TO(v, To) \ (static_cast(sizeof(JS::detail::CheckIsParallelNative(v))), \ reinterpret_cast(v)) /* * You may ask yourself: why do we define a wrapper around a wrapper here? * The answer is that some compilers don't understand initializing a union * as we do below with a construct like: * * reinterpret_cast(JSParallelNativeThreadSafeWrapper) * * (We need the reinterpret_cast because we must initialize the union with * a datum of the type of the union's first member.) * * Presumably this has something to do with template instantiation. * Initializing with a normal function pointer seems to work fine. Hence * the ugliness that you see before you. */ #define JS_JITINFO_NATIVE_PARALLEL(infoName, parallelOp) \ const JSJitInfo infoName = \ {{JS_CAST_PARALLEL_NATIVE_TO(parallelOp, JSJitGetterOp)},0,0,JSJitInfo::ParallelNative,JSJitInfo::AliasEverything,JSVAL_TYPE_MISSING,false,false,false,false,0} #define JS_JITINFO_NATIVE_PARALLEL_THREADSAFE(infoName, wrapperName, serialOp) \ bool wrapperName##_ParallelNativeThreadSafeWrapper(js::ForkJoinContext *cx, unsigned argc, \ JS::Value *vp) \ { \ return JSParallelNativeThreadSafeWrapper(cx, argc, vp); \ } \ JS_JITINFO_NATIVE_PARALLEL(infoName, wrapperName##_ParallelNativeThreadSafeWrapper) static MOZ_ALWAYS_INLINE const JSJitInfo * FUNCTION_VALUE_TO_JITINFO(const JS::Value& v) { JS_ASSERT(js::GetObjectClass(&v.toObject()) == js::FunctionClassPtr); return reinterpret_cast(&v.toObject())->jitinfo; } /* Statically asserted in jsfun.h. */ static const unsigned JS_FUNCTION_INTERPRETED_BIT = 0x1; static MOZ_ALWAYS_INLINE void SET_JITINFO(JSFunction * func, const JSJitInfo *info) { js::shadow::Function *fun = reinterpret_cast(func); JS_ASSERT(!(fun->flags & JS_FUNCTION_INTERPRETED_BIT)); 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); } } /* * 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) { JS_ASSERT(((size_t)atom & 0x7) == 0); jsid id = JSID_FROM_BITS((size_t)atom); JS_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 (MOZ_LIKELY(JSID_IS_INT(id))) return JS::Int32Value(JSID_TO_INT(id)); if (MOZ_LIKELY(JSID_IS_OBJECT(id))) return JS::ObjectValue(*JSID_TO_OBJECT(id)); JS_ASSERT(JSID_IS_VOID(id)); return JS::UndefinedValue(); } extern JS_FRIEND_API(bool) IsTypedArrayThisCheck(JS::IsAcceptableThis test); /* * If the embedder has registered a default JSContext callback, returns the * result of the callback. Otherwise, asserts that |rt| has exactly one * JSContext associated with it, and returns that context. */ extern JS_FRIEND_API(JSContext *) DefaultJSContext(JSRuntime *rt); typedef JSContext* (* DefaultJSContextCallback)(JSRuntime *rt); JS_FRIEND_API(void) SetDefaultJSContextCallback(JSRuntime *rt, DefaultJSContextCallback cb); /* * 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 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 bool (* ObjectMetadataCallback)(JSContext *cx, JSObject **pmetadata); /* * 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. Objects with different metadata have different shape hierarchies, * so for efficiency, objects should generally try to share metadata objects. */ JS_FRIEND_API(void) SetObjectMetadataCallback(JSContext *cx, ObjectMetadataCallback callback); /* Manipulate the metadata associated with an object. */ JS_FRIEND_API(bool) SetObjectMetadata(JSContext *cx, JS::HandleObject obj, JS::HandleObject metadata); JS_FRIEND_API(JSObject *) GetObjectMetadata(JSObject *obj); JS_FRIEND_API(void) UnsafeDefineElement(JSContext *cx, JS::HandleObject obj, uint32_t index, JS::HandleValue value); JS_FRIEND_API(bool) SliceSlowly(JSContext* cx, JS::HandleObject obj, JS::HandleObject receiver, uint32_t begin, uint32_t end, JS::HandleObject result); /* ES5 8.12.8. */ extern JS_FRIEND_API(bool) DefaultValue(JSContext *cx, JS::HandleObject obj, JSType hint, JS::MutableHandleValue vp); /* * Helper function. To approximate a call to the [[DefineOwnProperty]] internal * method described in ES5, first call this, then call JS_DefinePropertyById. * * JS_DefinePropertyById by itself does not enforce the invariants on * non-configurable properties when obj->isNative(). This function performs the * relevant checks (specified in ES5 8.12.9 [[DefineOwnProperty]] steps 1-11), * but only if obj is native. * * The reason for the messiness here is that ES5 uses [[DefineOwnProperty]] as * a sort of extension point, but there is no hook in js::Class, * js::ProxyHandler, or the JSAPI with precisely the right semantics for it. */ extern JS_FRIEND_API(bool) CheckDefineProperty(JSContext *cx, JS::HandleObject obj, JS::HandleId id, JS::HandleValue value, JSPropertyOp getter, JSStrictPropertyOp setter, unsigned attrs); /* * 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()/getPropertyDescriptor() calls. * The caller must supply those results as the 'desc' and 'descIsOwn' * parameters. * * Implemented in jsproxy.cpp. */ JS_FRIEND_API(bool) SetPropertyIgnoringNamedGetter(JSContext *cx, BaseProxyHandler *handler, JS::HandleObject proxy, JS::HandleObject receiver, JS::HandleId id, JS::MutableHandle desc, bool descIsOwn, bool strict, JS::MutableHandleValue vp); } /* namespace js */ extern JS_FRIEND_API(bool) js_DefineOwnProperty(JSContext *cx, JSObject *objArg, jsid idArg, JS::Handle descriptor, bool *bp); extern JS_FRIEND_API(bool) js_ReportIsNotFunction(JSContext *cx, JS::HandleValue v); #ifdef JSGC_GENERATIONAL 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); #else inline void JS_StoreObjectPostBarrierCallback(JSContext* cx, void (*callback)(JSTracer *trc, JSObject *key, void *data), JSObject *key, void *data) {} inline void JS_StoreStringPostBarrierCallback(JSContext* cx, void (*callback)(JSTracer *trc, JSString *key, void *data), JSString *key, void *data) {} #endif /* JSGC_GENERATIONAL */ #endif /* jsfriendapi_h */