michael@0: /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- michael@0: * vim: set ts=8 sts=4 et sw=4 tw=99: michael@0: * This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: #ifndef jsfriendapi_h michael@0: #define jsfriendapi_h michael@0: michael@0: #include "mozilla/Casting.h" michael@0: #include "mozilla/MemoryReporting.h" michael@0: #include "mozilla/TypedEnum.h" michael@0: michael@0: #include "jsbytecode.h" michael@0: #include "jspubtd.h" michael@0: michael@0: #include "js/CallArgs.h" michael@0: #include "js/CallNonGenericMethod.h" michael@0: #include "js/Class.h" michael@0: michael@0: /* michael@0: * This macro checks if the stack pointer has exceeded a given limit. If michael@0: * |tolerance| is non-zero, it returns true only if the stack pointer has michael@0: * exceeded the limit by more than |tolerance| bytes. michael@0: */ michael@0: #if JS_STACK_GROWTH_DIRECTION > 0 michael@0: # define JS_CHECK_STACK_SIZE_WITH_TOLERANCE(limit, sp, tolerance) \ michael@0: ((uintptr_t)(sp) < (limit)+(tolerance)) michael@0: #else michael@0: # define JS_CHECK_STACK_SIZE_WITH_TOLERANCE(limit, sp, tolerance) \ michael@0: ((uintptr_t)(sp) > (limit)-(tolerance)) michael@0: #endif michael@0: michael@0: #define JS_CHECK_STACK_SIZE(limit, lval) JS_CHECK_STACK_SIZE_WITH_TOLERANCE(limit, lval, 0) michael@0: michael@0: class JSAtom; michael@0: struct JSErrorFormatString; michael@0: class JSLinearString; michael@0: struct JSJitInfo; michael@0: class JSErrorReport; michael@0: michael@0: namespace JS { michael@0: template michael@0: class Heap; michael@0: } /* namespace JS */ michael@0: michael@0: namespace js { michael@0: class JS_FRIEND_API(BaseProxyHandler); michael@0: } /* namespace js */ michael@0: michael@0: extern JS_FRIEND_API(void) michael@0: JS_SetGrayGCRootsTracer(JSRuntime *rt, JSTraceDataOp traceOp, void *data); michael@0: michael@0: extern JS_FRIEND_API(JSString *) michael@0: JS_GetAnonymousString(JSRuntime *rt); michael@0: michael@0: extern JS_FRIEND_API(void) michael@0: JS_SetIsWorkerRuntime(JSRuntime *rt); michael@0: michael@0: extern JS_FRIEND_API(JSObject *) michael@0: JS_FindCompilationScope(JSContext *cx, JS::HandleObject obj); michael@0: michael@0: extern JS_FRIEND_API(JSFunction *) michael@0: JS_GetObjectFunction(JSObject *obj); michael@0: michael@0: extern JS_FRIEND_API(bool) michael@0: JS_SplicePrototype(JSContext *cx, JS::HandleObject obj, JS::HandleObject proto); michael@0: michael@0: extern JS_FRIEND_API(JSObject *) michael@0: JS_NewObjectWithUniqueType(JSContext *cx, const JSClass *clasp, JS::HandleObject proto, michael@0: JS::HandleObject parent); michael@0: michael@0: extern JS_FRIEND_API(uint32_t) michael@0: JS_ObjectCountDynamicSlots(JS::HandleObject obj); michael@0: michael@0: extern JS_FRIEND_API(size_t) michael@0: JS_SetProtoCalled(JSContext *cx); michael@0: michael@0: extern JS_FRIEND_API(size_t) michael@0: JS_GetCustomIteratorCount(JSContext *cx); michael@0: michael@0: extern JS_FRIEND_API(bool) michael@0: JS_NondeterministicGetWeakMapKeys(JSContext *cx, JS::HandleObject obj, JS::MutableHandleObject ret); michael@0: michael@0: /* michael@0: * Determine whether the given object is backed by a DeadObjectProxy. michael@0: * michael@0: * Such objects hold no other objects (they have no outgoing reference edges) michael@0: * and will throw if you touch them (e.g. by reading/writing a property). michael@0: */ michael@0: extern JS_FRIEND_API(bool) michael@0: JS_IsDeadWrapper(JSObject *obj); michael@0: michael@0: /* michael@0: * Used by the cycle collector to trace through the shape and all michael@0: * shapes it reaches, marking all non-shape children found in the michael@0: * process. Uses bounded stack space. michael@0: */ michael@0: extern JS_FRIEND_API(void) michael@0: JS_TraceShapeCycleCollectorChildren(JSTracer *trc, void *shape); michael@0: michael@0: enum { michael@0: JS_TELEMETRY_GC_REASON, michael@0: JS_TELEMETRY_GC_IS_COMPARTMENTAL, michael@0: JS_TELEMETRY_GC_MS, michael@0: JS_TELEMETRY_GC_MAX_PAUSE_MS, michael@0: JS_TELEMETRY_GC_MARK_MS, michael@0: JS_TELEMETRY_GC_SWEEP_MS, michael@0: JS_TELEMETRY_GC_MARK_ROOTS_MS, michael@0: JS_TELEMETRY_GC_MARK_GRAY_MS, michael@0: JS_TELEMETRY_GC_SLICE_MS, michael@0: JS_TELEMETRY_GC_MMU_50, michael@0: JS_TELEMETRY_GC_RESET, michael@0: JS_TELEMETRY_GC_INCREMENTAL_DISABLED, michael@0: JS_TELEMETRY_GC_NON_INCREMENTAL, michael@0: JS_TELEMETRY_GC_SCC_SWEEP_TOTAL_MS, michael@0: JS_TELEMETRY_GC_SCC_SWEEP_MAX_PAUSE_MS michael@0: }; michael@0: michael@0: typedef void michael@0: (* JSAccumulateTelemetryDataCallback)(int id, uint32_t sample); michael@0: michael@0: extern JS_FRIEND_API(void) michael@0: JS_SetAccumulateTelemetryCallback(JSRuntime *rt, JSAccumulateTelemetryDataCallback callback); michael@0: michael@0: extern JS_FRIEND_API(JSPrincipals *) michael@0: JS_GetCompartmentPrincipals(JSCompartment *compartment); michael@0: michael@0: extern JS_FRIEND_API(void) michael@0: JS_SetCompartmentPrincipals(JSCompartment *compartment, JSPrincipals *principals); michael@0: michael@0: /* Safe to call with input obj == nullptr. Returns non-nullptr iff obj != nullptr. */ michael@0: extern JS_FRIEND_API(JSObject *) michael@0: JS_ObjectToInnerObject(JSContext *cx, JS::HandleObject obj); michael@0: michael@0: /* Requires obj != nullptr. */ michael@0: extern JS_FRIEND_API(JSObject *) michael@0: JS_ObjectToOuterObject(JSContext *cx, JS::HandleObject obj); michael@0: michael@0: extern JS_FRIEND_API(JSObject *) michael@0: JS_CloneObject(JSContext *cx, JS::HandleObject obj, JS::HandleObject proto, michael@0: JS::HandleObject parent); michael@0: michael@0: extern JS_FRIEND_API(JSString *) michael@0: JS_BasicObjectToString(JSContext *cx, JS::HandleObject obj); michael@0: michael@0: extern JS_FRIEND_API(bool) michael@0: js_GetterOnlyPropertyStub(JSContext *cx, JS::HandleObject obj, JS::HandleId id, bool strict, michael@0: JS::MutableHandleValue vp); michael@0: michael@0: JS_FRIEND_API(void) michael@0: js_ReportOverRecursed(JSContext *maybecx); michael@0: michael@0: JS_FRIEND_API(bool) michael@0: js_ObjectClassIs(JSContext *cx, JS::HandleObject obj, js::ESClassValue classValue); michael@0: michael@0: JS_FRIEND_API(const char *) michael@0: js_ObjectClassName(JSContext *cx, JS::HandleObject obj); michael@0: michael@0: namespace js { michael@0: michael@0: JS_FRIEND_API(bool) michael@0: AddRawValueRoot(JSContext *cx, JS::Value *vp, const char *name); michael@0: michael@0: JS_FRIEND_API(void) michael@0: RemoveRawValueRoot(JSContext *cx, JS::Value *vp); michael@0: michael@0: } /* namespace js */ michael@0: michael@0: #ifdef JS_DEBUG michael@0: michael@0: /* michael@0: * Routines to print out values during debugging. These are FRIEND_API to help michael@0: * the debugger find them and to support temporarily hacking js_Dump* calls michael@0: * into other code. michael@0: */ michael@0: michael@0: extern JS_FRIEND_API(void) michael@0: js_DumpString(JSString *str); michael@0: michael@0: extern JS_FRIEND_API(void) michael@0: js_DumpAtom(JSAtom *atom); michael@0: michael@0: extern JS_FRIEND_API(void) michael@0: js_DumpObject(JSObject *obj); michael@0: michael@0: extern JS_FRIEND_API(void) michael@0: js_DumpChars(const jschar *s, size_t n); michael@0: #endif michael@0: michael@0: /* michael@0: * Copies all own properties from |obj| to |target|. |obj| must be a "native" michael@0: * object (that is to say, normal-ish - not an Array or a Proxy). michael@0: * michael@0: * This function immediately enters a compartment, and does not impose any michael@0: * restrictions on the compartment of |cx|. michael@0: */ michael@0: extern JS_FRIEND_API(bool) michael@0: JS_CopyPropertiesFrom(JSContext *cx, JS::HandleObject target, JS::HandleObject obj); michael@0: michael@0: /* michael@0: * Single-property version of the above. This function asserts that an |own| michael@0: * property of the given name exists on |obj|. michael@0: * michael@0: * On entry, |cx| must be same-compartment with |obj|. michael@0: */ michael@0: extern JS_FRIEND_API(bool) michael@0: JS_CopyPropertyFrom(JSContext *cx, JS::HandleId id, JS::HandleObject target, michael@0: JS::HandleObject obj); michael@0: michael@0: extern JS_FRIEND_API(bool) michael@0: JS_WrapPropertyDescriptor(JSContext *cx, JS::MutableHandle desc); michael@0: michael@0: extern JS_FRIEND_API(bool) michael@0: JS_WrapAutoIdVector(JSContext *cx, JS::AutoIdVector &props); michael@0: michael@0: extern JS_FRIEND_API(bool) michael@0: JS_EnumerateState(JSContext *cx, JS::HandleObject obj, JSIterateOp enum_op, michael@0: JS::MutableHandleValue statep, JS::MutableHandleId idp); michael@0: michael@0: struct JSFunctionSpecWithHelp { michael@0: const char *name; michael@0: JSNative call; michael@0: uint16_t nargs; michael@0: uint16_t flags; michael@0: const char *usage; michael@0: const char *help; michael@0: }; michael@0: michael@0: #define JS_FN_HELP(name,call,nargs,flags,usage,help) \ michael@0: {name, call, nargs, (flags) | JSPROP_ENUMERATE | JSFUN_STUB_GSOPS, usage, help} michael@0: #define JS_FS_HELP_END \ michael@0: {nullptr, nullptr, 0, 0, nullptr, nullptr} michael@0: michael@0: extern JS_FRIEND_API(bool) michael@0: JS_DefineFunctionsWithHelp(JSContext *cx, JS::HandleObject obj, const JSFunctionSpecWithHelp *fs); michael@0: michael@0: namespace js { michael@0: michael@0: /* michael@0: * Helper Macros for creating JSClasses that function as proxies. michael@0: * michael@0: * NB: The macro invocation must be surrounded by braces, so as to michael@0: * allow for potention JSClass extensions. michael@0: */ michael@0: #define PROXY_MAKE_EXT(outerObject, innerObject, iteratorObject, \ michael@0: isWrappedNative) \ michael@0: { \ michael@0: outerObject, \ michael@0: innerObject, \ michael@0: iteratorObject, \ michael@0: isWrappedNative, \ michael@0: js::proxy_WeakmapKeyDelegate \ michael@0: } michael@0: michael@0: #define PROXY_CLASS_WITH_EXT(name, extraSlots, flags, callOp, constructOp, ext) \ michael@0: { \ michael@0: name, \ michael@0: js::Class::NON_NATIVE | \ michael@0: JSCLASS_IS_PROXY | \ michael@0: JSCLASS_IMPLEMENTS_BARRIERS | \ michael@0: JSCLASS_HAS_RESERVED_SLOTS(js::PROXY_MINIMUM_SLOTS + (extraSlots)) | \ michael@0: flags, \ michael@0: JS_PropertyStub, /* addProperty */ \ michael@0: JS_DeletePropertyStub, /* delProperty */ \ michael@0: JS_PropertyStub, /* getProperty */ \ michael@0: JS_StrictPropertyStub, /* setProperty */ \ michael@0: JS_EnumerateStub, \ michael@0: JS_ResolveStub, \ michael@0: js::proxy_Convert, \ michael@0: js::proxy_Finalize, /* finalize */ \ michael@0: callOp, /* call */ \ michael@0: js::proxy_HasInstance, /* hasInstance */ \ michael@0: constructOp, /* construct */ \ michael@0: js::proxy_Trace, /* trace */ \ michael@0: JS_NULL_CLASS_SPEC, \ michael@0: ext, \ michael@0: { \ michael@0: js::proxy_LookupGeneric, \ michael@0: js::proxy_LookupProperty, \ michael@0: js::proxy_LookupElement, \ michael@0: js::proxy_DefineGeneric, \ michael@0: js::proxy_DefineProperty, \ michael@0: js::proxy_DefineElement, \ michael@0: js::proxy_GetGeneric, \ michael@0: js::proxy_GetProperty, \ michael@0: js::proxy_GetElement, \ michael@0: js::proxy_SetGeneric, \ michael@0: js::proxy_SetProperty, \ michael@0: js::proxy_SetElement, \ michael@0: js::proxy_GetGenericAttributes, \ michael@0: js::proxy_SetGenericAttributes, \ michael@0: js::proxy_DeleteProperty, \ michael@0: js::proxy_DeleteElement, \ michael@0: js::proxy_Watch, js::proxy_Unwatch, \ michael@0: js::proxy_Slice, \ michael@0: nullptr, /* enumerate */ \ michael@0: nullptr, /* thisObject */ \ michael@0: } \ michael@0: } michael@0: michael@0: #define PROXY_CLASS_DEF(name, extraSlots, flags, callOp, constructOp) \ michael@0: PROXY_CLASS_WITH_EXT(name, extraSlots, flags, callOp, constructOp, \ michael@0: PROXY_MAKE_EXT( \ michael@0: nullptr, /* outerObject */ \ michael@0: nullptr, /* innerObject */ \ michael@0: nullptr, /* iteratorObject */ \ michael@0: false /* isWrappedNative */ \ michael@0: )) michael@0: michael@0: /* michael@0: * Proxy stubs, similar to JS_*Stub, for embedder proxy class definitions. michael@0: * michael@0: * NB: Should not be called directly. michael@0: */ michael@0: michael@0: extern JS_FRIEND_API(bool) michael@0: proxy_LookupGeneric(JSContext *cx, JS::HandleObject obj, JS::HandleId id, JS::MutableHandleObject objp, michael@0: JS::MutableHandle propp); michael@0: extern JS_FRIEND_API(bool) michael@0: proxy_LookupProperty(JSContext *cx, JS::HandleObject obj, JS::Handle name, michael@0: JS::MutableHandleObject objp, JS::MutableHandle propp); michael@0: extern JS_FRIEND_API(bool) michael@0: proxy_LookupElement(JSContext *cx, JS::HandleObject obj, uint32_t index, JS::MutableHandleObject objp, michael@0: JS::MutableHandle propp); michael@0: extern JS_FRIEND_API(bool) michael@0: proxy_DefineGeneric(JSContext *cx, JS::HandleObject obj, JS::HandleId id, JS::HandleValue value, michael@0: JSPropertyOp getter, JSStrictPropertyOp setter, unsigned attrs); michael@0: extern JS_FRIEND_API(bool) michael@0: proxy_DefineProperty(JSContext *cx, JS::HandleObject obj, JS::Handle name, michael@0: JS::HandleValue value, JSPropertyOp getter, JSStrictPropertyOp setter, michael@0: unsigned attrs); michael@0: extern JS_FRIEND_API(bool) michael@0: proxy_DefineElement(JSContext *cx, JS::HandleObject obj, uint32_t index, JS::HandleValue value, michael@0: JSPropertyOp getter, JSStrictPropertyOp setter, unsigned attrs); michael@0: extern JS_FRIEND_API(bool) michael@0: proxy_GetGeneric(JSContext *cx, JS::HandleObject obj, JS::HandleObject receiver, JS::HandleId id, michael@0: JS::MutableHandleValue vp); michael@0: extern JS_FRIEND_API(bool) michael@0: proxy_GetProperty(JSContext *cx, JS::HandleObject obj, JS::HandleObject receiver, michael@0: JS::Handle name, JS::MutableHandleValue vp); michael@0: extern JS_FRIEND_API(bool) michael@0: proxy_GetElement(JSContext *cx, JS::HandleObject obj, JS::HandleObject receiver, uint32_t index, michael@0: JS::MutableHandleValue vp); michael@0: extern JS_FRIEND_API(bool) michael@0: proxy_SetGeneric(JSContext *cx, JS::HandleObject obj, JS::HandleId id, michael@0: JS::MutableHandleValue bp, bool strict); michael@0: extern JS_FRIEND_API(bool) michael@0: proxy_SetProperty(JSContext *cx, JS::HandleObject obj, JS::Handle name, michael@0: JS::MutableHandleValue bp, bool strict); michael@0: extern JS_FRIEND_API(bool) michael@0: proxy_SetElement(JSContext *cx, JS::HandleObject obj, uint32_t index, JS::MutableHandleValue vp, michael@0: bool strict); michael@0: extern JS_FRIEND_API(bool) michael@0: proxy_GetGenericAttributes(JSContext *cx, JS::HandleObject obj, JS::HandleId id, unsigned *attrsp); michael@0: extern JS_FRIEND_API(bool) michael@0: proxy_SetGenericAttributes(JSContext *cx, JS::HandleObject obj, JS::HandleId id, unsigned *attrsp); michael@0: extern JS_FRIEND_API(bool) michael@0: proxy_DeleteProperty(JSContext *cx, JS::HandleObject obj, JS::Handle name, michael@0: bool *succeeded); michael@0: extern JS_FRIEND_API(bool) michael@0: proxy_DeleteElement(JSContext *cx, JS::HandleObject obj, uint32_t index, bool *succeeded); michael@0: michael@0: extern JS_FRIEND_API(void) michael@0: proxy_Trace(JSTracer *trc, JSObject *obj); michael@0: extern JS_FRIEND_API(JSObject *) michael@0: proxy_WeakmapKeyDelegate(JSObject *obj); michael@0: extern JS_FRIEND_API(bool) michael@0: proxy_Convert(JSContext *cx, JS::HandleObject proxy, JSType hint, JS::MutableHandleValue vp); michael@0: extern JS_FRIEND_API(void) michael@0: proxy_Finalize(FreeOp *fop, JSObject *obj); michael@0: extern JS_FRIEND_API(bool) michael@0: proxy_HasInstance(JSContext *cx, JS::HandleObject proxy, JS::MutableHandleValue v, bool *bp); michael@0: extern JS_FRIEND_API(bool) michael@0: proxy_Call(JSContext *cx, unsigned argc, JS::Value *vp); michael@0: extern JS_FRIEND_API(bool) michael@0: proxy_Construct(JSContext *cx, unsigned argc, JS::Value *vp); michael@0: extern JS_FRIEND_API(JSObject *) michael@0: proxy_innerObject(JSContext *cx, JS::HandleObject obj); michael@0: extern JS_FRIEND_API(bool) michael@0: proxy_Watch(JSContext *cx, JS::HandleObject obj, JS::HandleId id, JS::HandleObject callable); michael@0: extern JS_FRIEND_API(bool) michael@0: proxy_Unwatch(JSContext *cx, JS::HandleObject obj, JS::HandleId id); michael@0: extern JS_FRIEND_API(bool) michael@0: proxy_Slice(JSContext *cx, JS::HandleObject proxy, uint32_t begin, uint32_t end, michael@0: JS::HandleObject result); michael@0: michael@0: /* michael@0: * A class of objects that return source code on demand. michael@0: * michael@0: * When code is compiled with setSourceIsLazy(true), SpiderMonkey doesn't michael@0: * retain the source code (and doesn't do lazy bytecode generation). If we ever michael@0: * need the source code, say, in response to a call to Function.prototype. michael@0: * toSource or Debugger.Source.prototype.text, then we call the 'load' member michael@0: * function of the instance of this class that has hopefully been registered michael@0: * with the runtime, passing the code's URL, and hope that it will be able to michael@0: * find the source. michael@0: */ michael@0: class SourceHook { michael@0: public: michael@0: virtual ~SourceHook() { } michael@0: michael@0: /* michael@0: * Set |*src| and |*length| to refer to the source code for |filename|. michael@0: * On success, the caller owns the buffer to which |*src| points, and michael@0: * should use JS_free to free it. michael@0: */ michael@0: virtual bool load(JSContext *cx, const char *filename, jschar **src, size_t *length) = 0; michael@0: }; michael@0: michael@0: /* michael@0: * Have |rt| use |hook| to retrieve lazily-retrieved source code. See the michael@0: * comments for SourceHook. The runtime takes ownership of the hook, and michael@0: * will delete it when the runtime itself is deleted, or when a new hook is michael@0: * set. michael@0: */ michael@0: extern JS_FRIEND_API(void) michael@0: SetSourceHook(JSRuntime *rt, SourceHook *hook); michael@0: michael@0: /* Remove |rt|'s source hook, and return it. The caller now owns the hook. */ michael@0: extern JS_FRIEND_API(SourceHook *) michael@0: ForgetSourceHook(JSRuntime *rt); michael@0: michael@0: extern JS_FRIEND_API(JS::Zone *) michael@0: GetCompartmentZone(JSCompartment *comp); michael@0: michael@0: typedef bool michael@0: (* PreserveWrapperCallback)(JSContext *cx, JSObject *obj); michael@0: michael@0: typedef enum { michael@0: CollectNurseryBeforeDump, michael@0: IgnoreNurseryObjects michael@0: } DumpHeapNurseryBehaviour; michael@0: michael@0: /* michael@0: * Dump the complete object graph of heap-allocated things. michael@0: * fp is the file for the dump output. michael@0: */ michael@0: extern JS_FRIEND_API(void) michael@0: DumpHeapComplete(JSRuntime *rt, FILE *fp, DumpHeapNurseryBehaviour nurseryBehaviour); michael@0: michael@0: #ifdef JS_OLD_GETTER_SETTER_METHODS michael@0: JS_FRIEND_API(bool) obj_defineGetter(JSContext *cx, unsigned argc, JS::Value *vp); michael@0: JS_FRIEND_API(bool) obj_defineSetter(JSContext *cx, unsigned argc, JS::Value *vp); michael@0: #endif michael@0: michael@0: extern JS_FRIEND_API(bool) michael@0: IsSystemCompartment(JSCompartment *comp); michael@0: michael@0: extern JS_FRIEND_API(bool) michael@0: IsSystemZone(JS::Zone *zone); michael@0: michael@0: extern JS_FRIEND_API(bool) michael@0: IsAtomsCompartment(JSCompartment *comp); michael@0: michael@0: /* michael@0: * Check whether it is OK to assign an undeclared variable with the name michael@0: * |propname| at the current location in script. It is not an error if there is michael@0: * no current script location, or if that location is not an assignment to an michael@0: * undeclared variable. Reports an error if one needs to be reported (and, michael@0: * particularly, always reports when it returns false). michael@0: */ michael@0: extern JS_FRIEND_API(bool) michael@0: ReportIfUndeclaredVarAssignment(JSContext *cx, JS::HandleString propname); michael@0: michael@0: /* michael@0: * Returns whether we're in a non-strict property set (in that we're in a michael@0: * non-strict script and the bytecode we're on is a property set). The return michael@0: * value does NOT indicate any sort of exception was thrown: it's just a michael@0: * boolean. michael@0: */ michael@0: extern JS_FRIEND_API(bool) michael@0: IsInNonStrictPropertySet(JSContext *cx); michael@0: michael@0: struct WeakMapTracer; michael@0: michael@0: /* michael@0: * Weak map tracer callback, called once for every binding of every michael@0: * weak map that was live at the time of the last garbage collection. michael@0: * michael@0: * m will be nullptr if the weak map is not contained in a JS Object. michael@0: */ michael@0: typedef void michael@0: (* WeakMapTraceCallback)(WeakMapTracer *trc, JSObject *m, michael@0: void *k, JSGCTraceKind kkind, michael@0: void *v, JSGCTraceKind vkind); michael@0: michael@0: struct WeakMapTracer { michael@0: JSRuntime *runtime; michael@0: WeakMapTraceCallback callback; michael@0: michael@0: WeakMapTracer(JSRuntime *rt, WeakMapTraceCallback cb) michael@0: : runtime(rt), callback(cb) {} michael@0: }; michael@0: michael@0: extern JS_FRIEND_API(void) michael@0: TraceWeakMaps(WeakMapTracer *trc); michael@0: michael@0: extern JS_FRIEND_API(bool) michael@0: AreGCGrayBitsValid(JSRuntime *rt); michael@0: michael@0: extern JS_FRIEND_API(bool) michael@0: ZoneGlobalsAreAllGray(JS::Zone *zone); michael@0: michael@0: typedef void michael@0: (*GCThingCallback)(void *closure, void *gcthing); michael@0: michael@0: extern JS_FRIEND_API(void) michael@0: VisitGrayWrapperTargets(JS::Zone *zone, GCThingCallback callback, void *closure); michael@0: michael@0: extern JS_FRIEND_API(JSObject *) michael@0: GetWeakmapKeyDelegate(JSObject *key); michael@0: michael@0: JS_FRIEND_API(JSGCTraceKind) michael@0: GCThingTraceKind(void *thing); michael@0: michael@0: /* michael@0: * Invoke cellCallback on every gray JS_OBJECT in the given zone. michael@0: */ michael@0: extern JS_FRIEND_API(void) michael@0: IterateGrayObjects(JS::Zone *zone, GCThingCallback cellCallback, void *data); michael@0: michael@0: #ifdef JS_HAS_CTYPES michael@0: extern JS_FRIEND_API(size_t) michael@0: SizeOfDataIfCDataObject(mozilla::MallocSizeOf mallocSizeOf, JSObject *obj); michael@0: #endif michael@0: michael@0: extern JS_FRIEND_API(JSCompartment *) michael@0: GetAnyCompartmentInZone(JS::Zone *zone); michael@0: michael@0: /* michael@0: * Shadow declarations of JS internal structures, for access by inline access michael@0: * functions below. Do not use these structures in any other way. When adding michael@0: * new fields for access by inline methods, make sure to add static asserts to michael@0: * the original header file to ensure that offsets are consistent. michael@0: */ michael@0: namespace shadow { michael@0: michael@0: struct TypeObject { michael@0: const Class *clasp; michael@0: JSObject *proto; michael@0: }; michael@0: michael@0: struct BaseShape { michael@0: const js::Class *clasp_; michael@0: JSObject *parent; michael@0: JSObject *_1; michael@0: JSCompartment *compartment; michael@0: }; michael@0: michael@0: class Shape { michael@0: public: michael@0: shadow::BaseShape *base; michael@0: jsid _1; michael@0: uint32_t slotInfo; michael@0: michael@0: static const uint32_t FIXED_SLOTS_SHIFT = 27; michael@0: }; michael@0: michael@0: struct Object { michael@0: shadow::Shape *shape; michael@0: shadow::TypeObject *type; michael@0: JS::Value *slots; michael@0: JS::Value *_1; michael@0: michael@0: size_t numFixedSlots() const { return shape->slotInfo >> Shape::FIXED_SLOTS_SHIFT; } michael@0: JS::Value *fixedSlots() const { michael@0: return (JS::Value *)(uintptr_t(this) + sizeof(shadow::Object)); michael@0: } michael@0: michael@0: JS::Value &slotRef(size_t slot) const { michael@0: size_t nfixed = numFixedSlots(); michael@0: if (slot < nfixed) michael@0: return fixedSlots()[slot]; michael@0: return slots[slot - nfixed]; michael@0: } michael@0: michael@0: // Reserved slots with index < MAX_FIXED_SLOTS are guaranteed to michael@0: // be fixed slots. michael@0: static const uint32_t MAX_FIXED_SLOTS = 16; michael@0: }; michael@0: michael@0: struct Function { michael@0: Object base; michael@0: uint16_t nargs; michael@0: uint16_t flags; michael@0: /* Used only for natives */ michael@0: JSNative native; michael@0: const JSJitInfo *jitinfo; michael@0: void *_1; michael@0: }; michael@0: michael@0: struct Atom { michael@0: static const size_t LENGTH_SHIFT = 4; michael@0: size_t lengthAndFlags; michael@0: const jschar *chars; michael@0: }; michael@0: michael@0: } /* namespace shadow */ michael@0: michael@0: // This is equal to |&JSObject::class_|. Use it in places where you don't want michael@0: // to #include jsobj.h. michael@0: extern JS_FRIEND_DATA(const js::Class* const) ObjectClassPtr; michael@0: michael@0: inline const js::Class * michael@0: GetObjectClass(JSObject *obj) michael@0: { michael@0: return reinterpret_cast(obj)->type->clasp; michael@0: } michael@0: michael@0: inline const JSClass * michael@0: GetObjectJSClass(JSObject *obj) michael@0: { michael@0: return js::Jsvalify(GetObjectClass(obj)); michael@0: } michael@0: michael@0: inline bool michael@0: IsInnerObject(JSObject *obj) { michael@0: return !!GetObjectClass(obj)->ext.outerObject; michael@0: } michael@0: michael@0: inline bool michael@0: IsOuterObject(JSObject *obj) { michael@0: return !!GetObjectClass(obj)->ext.innerObject; michael@0: } michael@0: michael@0: JS_FRIEND_API(bool) michael@0: IsFunctionObject(JSObject *obj); michael@0: michael@0: JS_FRIEND_API(bool) michael@0: IsScopeObject(JSObject *obj); michael@0: michael@0: JS_FRIEND_API(bool) michael@0: IsCallObject(JSObject *obj); michael@0: michael@0: inline JSObject * michael@0: GetObjectParent(JSObject *obj) michael@0: { michael@0: JS_ASSERT(!IsScopeObject(obj)); michael@0: return reinterpret_cast(obj)->shape->base->parent; michael@0: } michael@0: michael@0: static MOZ_ALWAYS_INLINE JSCompartment * michael@0: GetObjectCompartment(JSObject *obj) michael@0: { michael@0: return reinterpret_cast(obj)->shape->base->compartment; michael@0: } michael@0: michael@0: JS_FRIEND_API(JSObject *) michael@0: GetObjectParentMaybeScope(JSObject *obj); michael@0: michael@0: JS_FRIEND_API(JSObject *) michael@0: GetGlobalForObjectCrossCompartment(JSObject *obj); michael@0: michael@0: // Sidestep the activeContext checking implicitly performed in michael@0: // JS_SetPendingException. michael@0: JS_FRIEND_API(void) michael@0: SetPendingExceptionCrossContext(JSContext *cx, JS::HandleValue v); michael@0: michael@0: JS_FRIEND_API(void) michael@0: AssertSameCompartment(JSContext *cx, JSObject *obj); michael@0: michael@0: #ifdef JS_DEBUG michael@0: JS_FRIEND_API(void) michael@0: AssertSameCompartment(JSObject *objA, JSObject *objB); michael@0: #else michael@0: inline void AssertSameCompartment(JSObject *objA, JSObject *objB) {} michael@0: #endif michael@0: michael@0: // For legacy consumers only. This whole concept is going away soon. michael@0: JS_FRIEND_API(JSObject *) michael@0: DefaultObjectForContextOrNull(JSContext *cx); michael@0: michael@0: JS_FRIEND_API(void) michael@0: SetDefaultObjectForContext(JSContext *cx, JSObject *obj); michael@0: michael@0: JS_FRIEND_API(void) michael@0: NotifyAnimationActivity(JSObject *obj); michael@0: michael@0: /* michael@0: * Return the outermost enclosing function (script) of the scripted caller. michael@0: * This function returns nullptr in several cases: michael@0: * - no script is running on the context michael@0: * - the caller is in global or eval code michael@0: * In particular, this function will "stop" its outermost search at eval() and michael@0: * thus it will really return the outermost enclosing function *since the michael@0: * innermost eval*. michael@0: */ michael@0: JS_FRIEND_API(JSScript *) michael@0: GetOutermostEnclosingFunctionOfScriptedCaller(JSContext *cx); michael@0: michael@0: JS_FRIEND_API(JSFunction *) michael@0: DefineFunctionWithReserved(JSContext *cx, JSObject *obj, const char *name, JSNative call, michael@0: unsigned nargs, unsigned attrs); michael@0: michael@0: JS_FRIEND_API(JSFunction *) michael@0: NewFunctionWithReserved(JSContext *cx, JSNative call, unsigned nargs, unsigned flags, michael@0: JSObject *parent, const char *name); michael@0: michael@0: JS_FRIEND_API(JSFunction *) michael@0: NewFunctionByIdWithReserved(JSContext *cx, JSNative native, unsigned nargs, unsigned flags, michael@0: JSObject *parent, jsid id); michael@0: michael@0: JS_FRIEND_API(JSObject *) michael@0: InitClassWithReserved(JSContext *cx, JSObject *obj, JSObject *parent_proto, michael@0: const JSClass *clasp, JSNative constructor, unsigned nargs, michael@0: const JSPropertySpec *ps, const JSFunctionSpec *fs, michael@0: const JSPropertySpec *static_ps, const JSFunctionSpec *static_fs); michael@0: michael@0: JS_FRIEND_API(const JS::Value &) michael@0: GetFunctionNativeReserved(JSObject *fun, size_t which); michael@0: michael@0: JS_FRIEND_API(void) michael@0: SetFunctionNativeReserved(JSObject *fun, size_t which, const JS::Value &val); michael@0: michael@0: JS_FRIEND_API(bool) michael@0: GetObjectProto(JSContext *cx, JS::HandleObject obj, JS::MutableHandleObject proto); michael@0: michael@0: JS_FRIEND_API(bool) michael@0: GetOriginalEval(JSContext *cx, JS::HandleObject scope, michael@0: JS::MutableHandleObject eval); michael@0: michael@0: inline void * michael@0: GetObjectPrivate(JSObject *obj) michael@0: { michael@0: const shadow::Object *nobj = reinterpret_cast(obj); michael@0: void **addr = reinterpret_cast(&nobj->fixedSlots()[nobj->numFixedSlots()]); michael@0: return *addr; michael@0: } michael@0: michael@0: /* michael@0: * Get a slot that is both reserved for object's clasp *and* is fixed (fits michael@0: * within the maximum capacity for the object's fixed slots). michael@0: */ michael@0: inline const JS::Value & michael@0: GetReservedSlot(JSObject *obj, size_t slot) michael@0: { michael@0: JS_ASSERT(slot < JSCLASS_RESERVED_SLOTS(GetObjectClass(obj))); michael@0: return reinterpret_cast(obj)->slotRef(slot); michael@0: } michael@0: michael@0: JS_FRIEND_API(void) michael@0: SetReservedSlotWithBarrier(JSObject *obj, size_t slot, const JS::Value &value); michael@0: michael@0: inline void michael@0: SetReservedSlot(JSObject *obj, size_t slot, const JS::Value &value) michael@0: { michael@0: JS_ASSERT(slot < JSCLASS_RESERVED_SLOTS(GetObjectClass(obj))); michael@0: shadow::Object *sobj = reinterpret_cast(obj); michael@0: if (sobj->slotRef(slot).isMarkable() michael@0: #ifdef JSGC_GENERATIONAL michael@0: || value.isMarkable() michael@0: #endif michael@0: ) michael@0: { michael@0: SetReservedSlotWithBarrier(obj, slot, value); michael@0: } else { michael@0: sobj->slotRef(slot) = value; michael@0: } michael@0: } michael@0: michael@0: JS_FRIEND_API(uint32_t) michael@0: GetObjectSlotSpan(JSObject *obj); michael@0: michael@0: inline const JS::Value & michael@0: GetObjectSlot(JSObject *obj, size_t slot) michael@0: { michael@0: JS_ASSERT(slot < GetObjectSlotSpan(obj)); michael@0: return reinterpret_cast(obj)->slotRef(slot); michael@0: } michael@0: michael@0: inline const jschar * michael@0: GetAtomChars(JSAtom *atom) michael@0: { michael@0: return reinterpret_cast(atom)->chars; michael@0: } michael@0: michael@0: inline size_t michael@0: GetAtomLength(JSAtom *atom) michael@0: { michael@0: using shadow::Atom; michael@0: return reinterpret_cast(atom)->lengthAndFlags >> Atom::LENGTH_SHIFT; michael@0: } michael@0: michael@0: inline JSLinearString * michael@0: AtomToLinearString(JSAtom *atom) michael@0: { michael@0: return reinterpret_cast(atom); michael@0: } michael@0: michael@0: JS_FRIEND_API(bool) michael@0: GetPropertyNames(JSContext *cx, JSObject *obj, unsigned flags, JS::AutoIdVector *props); michael@0: michael@0: JS_FRIEND_API(bool) michael@0: AppendUnique(JSContext *cx, JS::AutoIdVector &base, JS::AutoIdVector &others); michael@0: michael@0: JS_FRIEND_API(bool) michael@0: GetGeneric(JSContext *cx, JSObject *obj, JSObject *receiver, jsid id, JS::Value *vp); michael@0: michael@0: JS_FRIEND_API(bool) michael@0: StringIsArrayIndex(JSLinearString *str, uint32_t *indexp); michael@0: michael@0: JS_FRIEND_API(void) michael@0: SetPreserveWrapperCallback(JSRuntime *rt, PreserveWrapperCallback callback); michael@0: michael@0: JS_FRIEND_API(bool) michael@0: IsObjectInContextCompartment(JSObject *obj, const JSContext *cx); michael@0: michael@0: /* michael@0: * NB: these flag bits are encoded into the bytecode stream in the immediate michael@0: * operand of JSOP_ITER, so don't change them without advancing vm/Xdr.h's michael@0: * XDR_BYTECODE_VERSION. michael@0: */ michael@0: #define JSITER_ENUMERATE 0x1 /* for-in compatible hidden default iterator */ michael@0: #define JSITER_FOREACH 0x2 /* return [key, value] pair rather than key */ michael@0: #define JSITER_KEYVALUE 0x4 /* destructuring for-in wants [key, value] */ michael@0: #define JSITER_OWNONLY 0x8 /* iterate over obj's own properties only */ michael@0: #define JSITER_HIDDEN 0x10 /* also enumerate non-enumerable properties */ michael@0: michael@0: JS_FRIEND_API(bool) michael@0: RunningWithTrustedPrincipals(JSContext *cx); michael@0: michael@0: inline uintptr_t michael@0: GetNativeStackLimit(JSContext *cx) michael@0: { michael@0: StackKind kind = RunningWithTrustedPrincipals(cx) ? StackForTrustedScript michael@0: : StackForUntrustedScript; michael@0: PerThreadDataFriendFields *mainThread = michael@0: PerThreadDataFriendFields::getMainThread(GetRuntime(cx)); michael@0: return mainThread->nativeStackLimit[kind]; michael@0: } michael@0: michael@0: /* michael@0: * These macros report a stack overflow and run |onerror| if we are close to michael@0: * using up the C stack. The JS_CHECK_CHROME_RECURSION variant gives us a little michael@0: * extra space so that we can ensure that crucial code is able to run. michael@0: */ michael@0: michael@0: #define JS_CHECK_RECURSION(cx, onerror) \ michael@0: JS_BEGIN_MACRO \ michael@0: int stackDummy_; \ michael@0: if (!JS_CHECK_STACK_SIZE(js::GetNativeStackLimit(cx), &stackDummy_)) { \ michael@0: js_ReportOverRecursed(cx); \ michael@0: onerror; \ michael@0: } \ michael@0: JS_END_MACRO michael@0: michael@0: #define JS_CHECK_RECURSION_DONT_REPORT(cx, onerror) \ michael@0: JS_BEGIN_MACRO \ michael@0: int stackDummy_; \ michael@0: if (!JS_CHECK_STACK_SIZE(js::GetNativeStackLimit(cx), &stackDummy_)) { \ michael@0: onerror; \ michael@0: } \ michael@0: JS_END_MACRO michael@0: michael@0: #define JS_CHECK_RECURSION_WITH_SP_DONT_REPORT(cx, sp, onerror) \ michael@0: JS_BEGIN_MACRO \ michael@0: if (!JS_CHECK_STACK_SIZE(js::GetNativeStackLimit(cx), sp)) { \ michael@0: onerror; \ michael@0: } \ michael@0: JS_END_MACRO michael@0: michael@0: #define JS_CHECK_RECURSION_WITH_SP(cx, sp, onerror) \ michael@0: JS_BEGIN_MACRO \ michael@0: if (!JS_CHECK_STACK_SIZE(js::GetNativeStackLimit(cx), sp)) { \ michael@0: js_ReportOverRecursed(cx); \ michael@0: onerror; \ michael@0: } \ michael@0: JS_END_MACRO michael@0: michael@0: #define JS_CHECK_CHROME_RECURSION(cx, onerror) \ michael@0: JS_BEGIN_MACRO \ michael@0: int stackDummy_; \ michael@0: if (!JS_CHECK_STACK_SIZE_WITH_TOLERANCE(js::GetNativeStackLimit(cx), \ michael@0: &stackDummy_, \ michael@0: 1024 * sizeof(size_t))) \ michael@0: { \ michael@0: js_ReportOverRecursed(cx); \ michael@0: onerror; \ michael@0: } \ michael@0: JS_END_MACRO michael@0: michael@0: JS_FRIEND_API(void) michael@0: StartPCCountProfiling(JSContext *cx); michael@0: michael@0: JS_FRIEND_API(void) michael@0: StopPCCountProfiling(JSContext *cx); michael@0: michael@0: JS_FRIEND_API(void) michael@0: PurgePCCounts(JSContext *cx); michael@0: michael@0: JS_FRIEND_API(size_t) michael@0: GetPCCountScriptCount(JSContext *cx); michael@0: michael@0: JS_FRIEND_API(JSString *) michael@0: GetPCCountScriptSummary(JSContext *cx, size_t script); michael@0: michael@0: JS_FRIEND_API(JSString *) michael@0: GetPCCountScriptContents(JSContext *cx, size_t script); michael@0: michael@0: #ifdef JS_THREADSAFE michael@0: JS_FRIEND_API(bool) michael@0: ContextHasOutstandingRequests(const JSContext *cx); michael@0: #endif michael@0: michael@0: typedef void michael@0: (* ActivityCallback)(void *arg, bool active); michael@0: michael@0: /* michael@0: * Sets a callback that is run whenever the runtime goes idle - the michael@0: * last active request ceases - and begins activity - when it was michael@0: * idle and a request begins. michael@0: */ michael@0: JS_FRIEND_API(void) michael@0: SetActivityCallback(JSRuntime *rt, ActivityCallback cb, void *arg); michael@0: michael@0: extern JS_FRIEND_API(const JSStructuredCloneCallbacks *) michael@0: GetContextStructuredCloneCallbacks(JSContext *cx); michael@0: michael@0: extern JS_FRIEND_API(bool) michael@0: IsContextRunningJS(JSContext *cx); michael@0: michael@0: typedef bool michael@0: (* DOMInstanceClassMatchesProto)(JSObject *protoObject, uint32_t protoID, uint32_t depth); michael@0: struct JSDOMCallbacks { michael@0: DOMInstanceClassMatchesProto instanceClassMatchesProto; michael@0: }; michael@0: typedef struct JSDOMCallbacks DOMCallbacks; michael@0: michael@0: extern JS_FRIEND_API(void) michael@0: SetDOMCallbacks(JSRuntime *rt, const DOMCallbacks *callbacks); michael@0: michael@0: extern JS_FRIEND_API(const DOMCallbacks *) michael@0: GetDOMCallbacks(JSRuntime *rt); michael@0: michael@0: extern JS_FRIEND_API(JSObject *) michael@0: GetTestingFunctions(JSContext *cx); michael@0: michael@0: /* michael@0: * Helper to convert FreeOp to JSFreeOp when the definition of FreeOp is not michael@0: * available and the compiler does not know that FreeOp inherits from michael@0: * JSFreeOp. michael@0: */ michael@0: inline JSFreeOp * michael@0: CastToJSFreeOp(FreeOp *fop) michael@0: { michael@0: return reinterpret_cast(fop); michael@0: } michael@0: michael@0: /* Implemented in jsexn.cpp. */ michael@0: michael@0: /* michael@0: * Get an error type name from a JSExnType constant. michael@0: * Returns nullptr for invalid arguments and JSEXN_INTERNALERR michael@0: */ michael@0: extern JS_FRIEND_API(const jschar*) michael@0: GetErrorTypeName(JSRuntime* rt, int16_t exnType); michael@0: michael@0: #ifdef JS_DEBUG michael@0: extern JS_FRIEND_API(unsigned) michael@0: GetEnterCompartmentDepth(JSContext* cx); michael@0: #endif michael@0: michael@0: /* Implemented in jswrapper.cpp. */ michael@0: typedef enum NukeReferencesToWindow { michael@0: NukeWindowReferences, michael@0: DontNukeWindowReferences michael@0: } NukeReferencesToWindow; michael@0: michael@0: /* michael@0: * These filters are designed to be ephemeral stack classes, and thus don't michael@0: * do any rooting or holding of their members. michael@0: */ michael@0: struct CompartmentFilter { michael@0: virtual bool match(JSCompartment *c) const = 0; michael@0: }; michael@0: michael@0: struct AllCompartments : public CompartmentFilter { michael@0: virtual bool match(JSCompartment *c) const { return true; } michael@0: }; michael@0: michael@0: struct ContentCompartmentsOnly : public CompartmentFilter { michael@0: virtual bool match(JSCompartment *c) const { michael@0: return !IsSystemCompartment(c); michael@0: } michael@0: }; michael@0: michael@0: struct ChromeCompartmentsOnly : public CompartmentFilter { michael@0: virtual bool match(JSCompartment *c) const { michael@0: return IsSystemCompartment(c); michael@0: } michael@0: }; michael@0: michael@0: struct SingleCompartment : public CompartmentFilter { michael@0: JSCompartment *ours; michael@0: SingleCompartment(JSCompartment *c) : ours(c) {} michael@0: virtual bool match(JSCompartment *c) const { return c == ours; } michael@0: }; michael@0: michael@0: struct CompartmentsWithPrincipals : public CompartmentFilter { michael@0: JSPrincipals *principals; michael@0: CompartmentsWithPrincipals(JSPrincipals *p) : principals(p) {} michael@0: virtual bool match(JSCompartment *c) const { michael@0: return JS_GetCompartmentPrincipals(c) == principals; michael@0: } michael@0: }; michael@0: michael@0: extern JS_FRIEND_API(bool) michael@0: NukeCrossCompartmentWrappers(JSContext* cx, michael@0: const CompartmentFilter& sourceFilter, michael@0: const CompartmentFilter& targetFilter, michael@0: NukeReferencesToWindow nukeReferencesToWindow); michael@0: michael@0: /* Specify information about DOMProxy proxies in the DOM, for use by ICs. */ michael@0: michael@0: /* michael@0: * The DOMProxyShadowsCheck function will be called to check if the property for michael@0: * id should be gotten from the prototype, or if there is an own property that michael@0: * shadows it. michael@0: * If DoesntShadow is returned then the slot at listBaseExpandoSlot should michael@0: * either be undefined or point to an expando object that would contain the own michael@0: * property. michael@0: * If DoesntShadowUnique is returned then the slot at listBaseExpandoSlot should michael@0: * contain a private pointer to a ExpandoAndGeneration, which contains a michael@0: * JS::Value that should either be undefined or point to an expando object, and michael@0: * a uint32 value. If that value changes then the IC for getting a property will michael@0: * be invalidated. michael@0: */ michael@0: michael@0: struct ExpandoAndGeneration { michael@0: ExpandoAndGeneration() michael@0: : expando(JS::UndefinedValue()), michael@0: generation(0) michael@0: {} michael@0: michael@0: void Unlink() michael@0: { michael@0: ++generation; michael@0: expando.setUndefined(); michael@0: } michael@0: michael@0: static size_t offsetOfExpando() michael@0: { michael@0: return offsetof(ExpandoAndGeneration, expando); michael@0: } michael@0: michael@0: static size_t offsetOfGeneration() michael@0: { michael@0: return offsetof(ExpandoAndGeneration, generation); michael@0: } michael@0: michael@0: JS::Heap expando; michael@0: uint32_t generation; michael@0: }; michael@0: michael@0: typedef enum DOMProxyShadowsResult { michael@0: ShadowCheckFailed, michael@0: Shadows, michael@0: DoesntShadow, michael@0: DoesntShadowUnique michael@0: } DOMProxyShadowsResult; michael@0: typedef DOMProxyShadowsResult michael@0: (* DOMProxyShadowsCheck)(JSContext* cx, JS::HandleObject object, JS::HandleId id); michael@0: JS_FRIEND_API(void) michael@0: SetDOMProxyInformation(const void *domProxyHandlerFamily, uint32_t domProxyExpandoSlot, michael@0: DOMProxyShadowsCheck domProxyShadowsCheck); michael@0: michael@0: const void *GetDOMProxyHandlerFamily(); michael@0: uint32_t GetDOMProxyExpandoSlot(); michael@0: DOMProxyShadowsCheck GetDOMProxyShadowsCheck(); michael@0: michael@0: } /* namespace js */ michael@0: michael@0: /* Implemented in jsdate.cpp. */ michael@0: michael@0: /* michael@0: * Detect whether the internal date value is NaN. (Because failure is michael@0: * out-of-band for js_DateGet*) michael@0: */ michael@0: extern JS_FRIEND_API(bool) michael@0: js_DateIsValid(JSObject* obj); michael@0: michael@0: extern JS_FRIEND_API(double) michael@0: js_DateGetMsecSinceEpoch(JSObject *obj); michael@0: michael@0: /* Implemented in jscntxt.cpp. */ michael@0: michael@0: /* michael@0: * Report an exception, which is currently realized as a printf-style format michael@0: * string and its arguments. michael@0: */ michael@0: typedef enum JSErrNum { michael@0: #define MSG_DEF(name, number, count, exception, format) \ michael@0: name = number, michael@0: #include "js.msg" michael@0: #undef MSG_DEF michael@0: JSErr_Limit michael@0: } JSErrNum; michael@0: michael@0: extern JS_FRIEND_API(const JSErrorFormatString *) michael@0: js_GetErrorMessage(void *userRef, const char *locale, const unsigned errorNumber); michael@0: michael@0: namespace js { michael@0: michael@0: // Creates a string of the form |ErrorType: ErrorMessage| for a JSErrorReport, michael@0: // which generally matches the toString() behavior of an ErrorObject. michael@0: extern JS_FRIEND_API(JSString *) michael@0: ErrorReportToString(JSContext *cx, JSErrorReport *reportp); michael@0: michael@0: } /* namespace js */ michael@0: michael@0: michael@0: /* Implemented in jsclone.cpp. */ michael@0: michael@0: extern JS_FRIEND_API(uint64_t) michael@0: js_GetSCOffset(JSStructuredCloneWriter* writer); michael@0: michael@0: /* Typed Array functions, implemented in jstypedarray.cpp */ michael@0: michael@0: namespace js { michael@0: namespace ArrayBufferView { michael@0: michael@0: enum ViewType { michael@0: TYPE_INT8 = 0, michael@0: TYPE_UINT8, michael@0: TYPE_INT16, michael@0: TYPE_UINT16, michael@0: TYPE_INT32, michael@0: TYPE_UINT32, michael@0: TYPE_FLOAT32, michael@0: TYPE_FLOAT64, michael@0: michael@0: /* michael@0: * Special type that is a uint8_t, but assignments are clamped to [0, 256). michael@0: * Treat the raw data type as a uint8_t. michael@0: */ michael@0: TYPE_UINT8_CLAMPED, michael@0: michael@0: /* michael@0: * Type returned for a DataView. Note that there is no single element type michael@0: * in this case. michael@0: */ michael@0: TYPE_DATAVIEW, michael@0: michael@0: TYPE_MAX michael@0: }; michael@0: michael@0: } /* namespace ArrayBufferView */ michael@0: michael@0: } /* namespace js */ michael@0: michael@0: typedef js::ArrayBufferView::ViewType JSArrayBufferViewType; michael@0: michael@0: /* michael@0: * Create a new typed array with nelements elements. michael@0: * michael@0: * These functions (except the WithBuffer variants) fill in the array with zeros. michael@0: */ michael@0: michael@0: extern JS_FRIEND_API(JSObject *) michael@0: JS_NewInt8Array(JSContext *cx, uint32_t nelements); michael@0: extern JS_FRIEND_API(JSObject *) michael@0: JS_NewUint8Array(JSContext *cx, uint32_t nelements); michael@0: extern JS_FRIEND_API(JSObject *) michael@0: JS_NewUint8ClampedArray(JSContext *cx, uint32_t nelements); michael@0: michael@0: extern JS_FRIEND_API(JSObject *) michael@0: JS_NewInt16Array(JSContext *cx, uint32_t nelements); michael@0: extern JS_FRIEND_API(JSObject *) michael@0: JS_NewUint16Array(JSContext *cx, uint32_t nelements); michael@0: extern JS_FRIEND_API(JSObject *) michael@0: JS_NewInt32Array(JSContext *cx, uint32_t nelements); michael@0: extern JS_FRIEND_API(JSObject *) michael@0: JS_NewUint32Array(JSContext *cx, uint32_t nelements); michael@0: extern JS_FRIEND_API(JSObject *) michael@0: JS_NewFloat32Array(JSContext *cx, uint32_t nelements); michael@0: extern JS_FRIEND_API(JSObject *) michael@0: JS_NewFloat64Array(JSContext *cx, uint32_t nelements); michael@0: michael@0: /* michael@0: * Create a new typed array and copy in values from the given object. The michael@0: * object is used as if it were an array; that is, the new array (if michael@0: * successfully created) will have length given by array.length, and its michael@0: * elements will be those specified by array[0], array[1], and so on, after michael@0: * conversion to the typed array element type. michael@0: */ michael@0: michael@0: extern JS_FRIEND_API(JSObject *) michael@0: JS_NewInt8ArrayFromArray(JSContext *cx, JS::HandleObject array); michael@0: extern JS_FRIEND_API(JSObject *) michael@0: JS_NewUint8ArrayFromArray(JSContext *cx, JS::HandleObject array); michael@0: extern JS_FRIEND_API(JSObject *) michael@0: JS_NewUint8ClampedArrayFromArray(JSContext *cx, JS::HandleObject array); michael@0: extern JS_FRIEND_API(JSObject *) michael@0: JS_NewInt16ArrayFromArray(JSContext *cx, JS::HandleObject array); michael@0: extern JS_FRIEND_API(JSObject *) michael@0: JS_NewUint16ArrayFromArray(JSContext *cx, JS::HandleObject array); michael@0: extern JS_FRIEND_API(JSObject *) michael@0: JS_NewInt32ArrayFromArray(JSContext *cx, JS::HandleObject array); michael@0: extern JS_FRIEND_API(JSObject *) michael@0: JS_NewUint32ArrayFromArray(JSContext *cx, JS::HandleObject array); michael@0: extern JS_FRIEND_API(JSObject *) michael@0: JS_NewFloat32ArrayFromArray(JSContext *cx, JS::HandleObject array); michael@0: extern JS_FRIEND_API(JSObject *) michael@0: JS_NewFloat64ArrayFromArray(JSContext *cx, JS::HandleObject array); michael@0: michael@0: /* michael@0: * Create a new typed array using the given ArrayBuffer for storage. The michael@0: * length value is optional; if -1 is passed, enough elements to use up the michael@0: * remainder of the byte array is used as the default value. michael@0: */ michael@0: michael@0: extern JS_FRIEND_API(JSObject *) michael@0: JS_NewInt8ArrayWithBuffer(JSContext *cx, JS::HandleObject arrayBuffer, michael@0: uint32_t byteOffset, int32_t length); michael@0: extern JS_FRIEND_API(JSObject *) michael@0: JS_NewUint8ArrayWithBuffer(JSContext *cx, JS::HandleObject arrayBuffer, michael@0: uint32_t byteOffset, int32_t length); michael@0: extern JS_FRIEND_API(JSObject *) michael@0: JS_NewUint8ClampedArrayWithBuffer(JSContext *cx, JS::HandleObject arrayBuffer, michael@0: uint32_t byteOffset, int32_t length); michael@0: extern JS_FRIEND_API(JSObject *) michael@0: JS_NewInt16ArrayWithBuffer(JSContext *cx, JS::HandleObject arrayBuffer, michael@0: uint32_t byteOffset, int32_t length); michael@0: extern JS_FRIEND_API(JSObject *) michael@0: JS_NewUint16ArrayWithBuffer(JSContext *cx, JS::HandleObject arrayBuffer, michael@0: uint32_t byteOffset, int32_t length); michael@0: extern JS_FRIEND_API(JSObject *) michael@0: JS_NewInt32ArrayWithBuffer(JSContext *cx, JS::HandleObject arrayBuffer, michael@0: uint32_t byteOffset, int32_t length); michael@0: extern JS_FRIEND_API(JSObject *) michael@0: JS_NewUint32ArrayWithBuffer(JSContext *cx, JS::HandleObject arrayBuffer, michael@0: uint32_t byteOffset, int32_t length); michael@0: extern JS_FRIEND_API(JSObject *) michael@0: JS_NewFloat32ArrayWithBuffer(JSContext *cx, JS::HandleObject arrayBuffer, michael@0: uint32_t byteOffset, int32_t length); michael@0: extern JS_FRIEND_API(JSObject *) michael@0: JS_NewFloat64ArrayWithBuffer(JSContext *cx, JS::HandleObject arrayBuffer, michael@0: uint32_t byteOffset, int32_t length); michael@0: michael@0: /* michael@0: * Create a new ArrayBuffer with the given byte length. michael@0: */ michael@0: extern JS_FRIEND_API(JSObject *) michael@0: JS_NewArrayBuffer(JSContext *cx, uint32_t nbytes); michael@0: michael@0: /* michael@0: * Check whether obj supports JS_GetTypedArray* APIs. Note that this may return michael@0: * false if a security wrapper is encountered that denies the unwrapping. If michael@0: * this test or one of the JS_Is*Array tests succeeds, then it is safe to call michael@0: * the various accessor JSAPI calls defined below. michael@0: */ michael@0: extern JS_FRIEND_API(bool) michael@0: JS_IsTypedArrayObject(JSObject *obj); michael@0: michael@0: /* michael@0: * Check whether obj supports JS_GetArrayBufferView* APIs. Note that this may michael@0: * return false if a security wrapper is encountered that denies the michael@0: * unwrapping. If this test or one of the more specific tests succeeds, then it michael@0: * is safe to call the various ArrayBufferView accessor JSAPI calls defined michael@0: * below. michael@0: */ michael@0: extern JS_FRIEND_API(bool) michael@0: JS_IsArrayBufferViewObject(JSObject *obj); michael@0: michael@0: /* michael@0: * Test for specific typed array types (ArrayBufferView subtypes) michael@0: */ michael@0: michael@0: extern JS_FRIEND_API(bool) michael@0: JS_IsInt8Array(JSObject *obj); michael@0: extern JS_FRIEND_API(bool) michael@0: JS_IsUint8Array(JSObject *obj); michael@0: extern JS_FRIEND_API(bool) michael@0: JS_IsUint8ClampedArray(JSObject *obj); michael@0: extern JS_FRIEND_API(bool) michael@0: JS_IsInt16Array(JSObject *obj); michael@0: extern JS_FRIEND_API(bool) michael@0: JS_IsUint16Array(JSObject *obj); michael@0: extern JS_FRIEND_API(bool) michael@0: JS_IsInt32Array(JSObject *obj); michael@0: extern JS_FRIEND_API(bool) michael@0: JS_IsUint32Array(JSObject *obj); michael@0: extern JS_FRIEND_API(bool) michael@0: JS_IsFloat32Array(JSObject *obj); michael@0: extern JS_FRIEND_API(bool) michael@0: JS_IsFloat64Array(JSObject *obj); michael@0: michael@0: /* michael@0: * Test for specific typed array types (ArrayBufferView subtypes) and return michael@0: * the unwrapped object if so, else nullptr. Never throws. michael@0: */ michael@0: michael@0: namespace js { michael@0: michael@0: extern JS_FRIEND_API(JSObject *) michael@0: UnwrapInt8Array(JSObject *obj); michael@0: extern JS_FRIEND_API(JSObject *) michael@0: UnwrapUint8Array(JSObject *obj); michael@0: extern JS_FRIEND_API(JSObject *) michael@0: UnwrapUint8ClampedArray(JSObject *obj); michael@0: extern JS_FRIEND_API(JSObject *) michael@0: UnwrapInt16Array(JSObject *obj); michael@0: extern JS_FRIEND_API(JSObject *) michael@0: UnwrapUint16Array(JSObject *obj); michael@0: extern JS_FRIEND_API(JSObject *) michael@0: UnwrapInt32Array(JSObject *obj); michael@0: extern JS_FRIEND_API(JSObject *) michael@0: UnwrapUint32Array(JSObject *obj); michael@0: extern JS_FRIEND_API(JSObject *) michael@0: UnwrapFloat32Array(JSObject *obj); michael@0: extern JS_FRIEND_API(JSObject *) michael@0: UnwrapFloat64Array(JSObject *obj); michael@0: michael@0: extern JS_FRIEND_API(JSObject *) michael@0: UnwrapArrayBuffer(JSObject *obj); michael@0: michael@0: extern JS_FRIEND_API(JSObject *) michael@0: UnwrapArrayBufferView(JSObject *obj); michael@0: michael@0: namespace detail { michael@0: michael@0: extern JS_FRIEND_DATA(const Class* const) Int8ArrayClassPtr; michael@0: extern JS_FRIEND_DATA(const Class* const) Uint8ArrayClassPtr; michael@0: extern JS_FRIEND_DATA(const Class* const) Uint8ClampedArrayClassPtr; michael@0: extern JS_FRIEND_DATA(const Class* const) Int16ArrayClassPtr; michael@0: extern JS_FRIEND_DATA(const Class* const) Uint16ArrayClassPtr; michael@0: extern JS_FRIEND_DATA(const Class* const) Int32ArrayClassPtr; michael@0: extern JS_FRIEND_DATA(const Class* const) Uint32ArrayClassPtr; michael@0: extern JS_FRIEND_DATA(const Class* const) Float32ArrayClassPtr; michael@0: extern JS_FRIEND_DATA(const Class* const) Float64ArrayClassPtr; michael@0: michael@0: const size_t TypedArrayLengthSlot = 4; michael@0: michael@0: } // namespace detail michael@0: michael@0: /* michael@0: * Test for specific typed array types (ArrayBufferView subtypes) and return michael@0: * the unwrapped object if so, else nullptr. Never throws. michael@0: */ michael@0: michael@0: #define JS_DEFINE_DATA_AND_LENGTH_ACCESSOR(Type, type) \ michael@0: inline void \ michael@0: Get ## Type ## ArrayLengthAndData(JSObject *obj, uint32_t *length, type **data) \ michael@0: { \ michael@0: JS_ASSERT(GetObjectClass(obj) == detail::Type ## ArrayClassPtr); \ michael@0: const JS::Value &slot = GetReservedSlot(obj, detail::TypedArrayLengthSlot); \ michael@0: *length = mozilla::SafeCast(slot.toInt32()); \ michael@0: *data = static_cast(GetObjectPrivate(obj)); \ michael@0: } michael@0: michael@0: JS_DEFINE_DATA_AND_LENGTH_ACCESSOR(Int8, int8_t) michael@0: JS_DEFINE_DATA_AND_LENGTH_ACCESSOR(Uint8, uint8_t) michael@0: JS_DEFINE_DATA_AND_LENGTH_ACCESSOR(Uint8Clamped, uint8_t) michael@0: JS_DEFINE_DATA_AND_LENGTH_ACCESSOR(Int16, int16_t) michael@0: JS_DEFINE_DATA_AND_LENGTH_ACCESSOR(Uint16, uint16_t) michael@0: JS_DEFINE_DATA_AND_LENGTH_ACCESSOR(Int32, int32_t) michael@0: JS_DEFINE_DATA_AND_LENGTH_ACCESSOR(Uint32, uint32_t) michael@0: JS_DEFINE_DATA_AND_LENGTH_ACCESSOR(Float32, float) michael@0: JS_DEFINE_DATA_AND_LENGTH_ACCESSOR(Float64, double) michael@0: michael@0: #undef JS_DEFINE_DATA_AND_LENGTH_ACCESSOR michael@0: michael@0: // This one isn't inlined because it's rather tricky (by dint of having to deal michael@0: // with a dozen-plus classes and varying slot layouts. michael@0: extern JS_FRIEND_API(void) michael@0: GetArrayBufferViewLengthAndData(JSObject *obj, uint32_t *length, uint8_t **data); michael@0: michael@0: // This one isn't inlined because there are a bunch of different ArrayBuffer michael@0: // classes that would have to be individually handled here. michael@0: extern JS_FRIEND_API(void) michael@0: GetArrayBufferLengthAndData(JSObject *obj, uint32_t *length, uint8_t **data); michael@0: michael@0: } // namespace js michael@0: michael@0: /* michael@0: * Unwrap Typed arrays all at once. Return nullptr without throwing if the michael@0: * object cannot be viewed as the correct typed array, or the typed array michael@0: * object on success, filling both outparameters. michael@0: */ michael@0: extern JS_FRIEND_API(JSObject *) michael@0: JS_GetObjectAsInt8Array(JSObject *obj, uint32_t *length, int8_t **data); michael@0: extern JS_FRIEND_API(JSObject *) michael@0: JS_GetObjectAsUint8Array(JSObject *obj, uint32_t *length, uint8_t **data); michael@0: extern JS_FRIEND_API(JSObject *) michael@0: JS_GetObjectAsUint8ClampedArray(JSObject *obj, uint32_t *length, uint8_t **data); michael@0: extern JS_FRIEND_API(JSObject *) michael@0: JS_GetObjectAsInt16Array(JSObject *obj, uint32_t *length, int16_t **data); michael@0: extern JS_FRIEND_API(JSObject *) michael@0: JS_GetObjectAsUint16Array(JSObject *obj, uint32_t *length, uint16_t **data); michael@0: extern JS_FRIEND_API(JSObject *) michael@0: JS_GetObjectAsInt32Array(JSObject *obj, uint32_t *length, int32_t **data); michael@0: extern JS_FRIEND_API(JSObject *) michael@0: JS_GetObjectAsUint32Array(JSObject *obj, uint32_t *length, uint32_t **data); michael@0: extern JS_FRIEND_API(JSObject *) michael@0: JS_GetObjectAsFloat32Array(JSObject *obj, uint32_t *length, float **data); michael@0: extern JS_FRIEND_API(JSObject *) michael@0: JS_GetObjectAsFloat64Array(JSObject *obj, uint32_t *length, double **data); michael@0: extern JS_FRIEND_API(JSObject *) michael@0: JS_GetObjectAsArrayBufferView(JSObject *obj, uint32_t *length, uint8_t **data); michael@0: extern JS_FRIEND_API(JSObject *) michael@0: JS_GetObjectAsArrayBuffer(JSObject *obj, uint32_t *length, uint8_t **data); michael@0: michael@0: /* michael@0: * Get the type of elements in a typed array, or TYPE_DATAVIEW if a DataView. michael@0: * michael@0: * |obj| must have passed a JS_IsArrayBufferView/JS_Is*Array test, or somehow michael@0: * be known that it would pass such a test: it is an ArrayBufferView or a michael@0: * wrapper of an ArrayBufferView, and the unwrapping will succeed. michael@0: */ michael@0: extern JS_FRIEND_API(JSArrayBufferViewType) michael@0: JS_GetArrayBufferViewType(JSObject *obj); michael@0: michael@0: /* michael@0: * Check whether obj supports the JS_GetArrayBuffer* APIs. Note that this may michael@0: * return false if a security wrapper is encountered that denies the michael@0: * unwrapping. If this test succeeds, then it is safe to call the various michael@0: * accessor JSAPI calls defined below. michael@0: */ michael@0: extern JS_FRIEND_API(bool) michael@0: JS_IsArrayBufferObject(JSObject *obj); michael@0: michael@0: /* michael@0: * Return the available byte length of an array buffer. michael@0: * michael@0: * |obj| must have passed a JS_IsArrayBufferObject test, or somehow be known michael@0: * that it would pass such a test: it is an ArrayBuffer or a wrapper of an michael@0: * ArrayBuffer, and the unwrapping will succeed. michael@0: */ michael@0: extern JS_FRIEND_API(uint32_t) michael@0: JS_GetArrayBufferByteLength(JSObject *obj); michael@0: michael@0: /* michael@0: * Check whether the obj is ArrayBufferObject and memory mapped. Note that this michael@0: * may return false if a security wrapper is encountered that denies the michael@0: * unwrapping. michael@0: */ michael@0: extern JS_FRIEND_API(bool) michael@0: JS_IsMappedArrayBufferObject(JSObject *obj); michael@0: michael@0: /* michael@0: * Return the number of elements in a typed array. michael@0: * michael@0: * |obj| must have passed a JS_IsTypedArrayObject/JS_Is*Array test, or somehow michael@0: * be known that it would pass such a test: it is a typed array or a wrapper of michael@0: * a typed array, and the unwrapping will succeed. michael@0: */ michael@0: extern JS_FRIEND_API(uint32_t) michael@0: JS_GetTypedArrayLength(JSObject *obj); michael@0: michael@0: /* michael@0: * Return the byte offset from the start of an array buffer to the start of a michael@0: * typed array view. michael@0: * michael@0: * |obj| must have passed a JS_IsTypedArrayObject/JS_Is*Array test, or somehow michael@0: * be known that it would pass such a test: it is a typed array or a wrapper of michael@0: * a typed array, and the unwrapping will succeed. michael@0: */ michael@0: extern JS_FRIEND_API(uint32_t) michael@0: JS_GetTypedArrayByteOffset(JSObject *obj); michael@0: michael@0: /* michael@0: * Return the byte length of a typed array. michael@0: * michael@0: * |obj| must have passed a JS_IsTypedArrayObject/JS_Is*Array test, or somehow michael@0: * be known that it would pass such a test: it is a typed array or a wrapper of michael@0: * a typed array, and the unwrapping will succeed. michael@0: */ michael@0: extern JS_FRIEND_API(uint32_t) michael@0: JS_GetTypedArrayByteLength(JSObject *obj); michael@0: michael@0: /* michael@0: * Check whether obj supports JS_ArrayBufferView* APIs. Note that this may michael@0: * return false if a security wrapper is encountered that denies the michael@0: * unwrapping. michael@0: */ michael@0: extern JS_FRIEND_API(bool) michael@0: JS_IsArrayBufferViewObject(JSObject *obj); michael@0: michael@0: /* michael@0: * More generic name for JS_GetTypedArrayByteLength to cover DataViews as well michael@0: */ michael@0: extern JS_FRIEND_API(uint32_t) michael@0: JS_GetArrayBufferViewByteLength(JSObject *obj); michael@0: michael@0: /* michael@0: * Return a pointer to the start of the data referenced by a typed array. The michael@0: * data is still owned by the typed array, and should not be modified on michael@0: * another thread. Furthermore, the pointer can become invalid on GC (if the michael@0: * data is small and fits inside the array's GC header), so callers must take michael@0: * care not to hold on across anything that could GC. michael@0: * michael@0: * |obj| must have passed a JS_Is*Array test, or somehow be known that it would michael@0: * pass such a test: it is a typed array or a wrapper of a typed array, and the michael@0: * unwrapping will succeed. michael@0: */ michael@0: michael@0: extern JS_FRIEND_API(uint8_t *) michael@0: JS_GetArrayBufferData(JSObject *obj); michael@0: extern JS_FRIEND_API(int8_t *) michael@0: JS_GetInt8ArrayData(JSObject *obj); michael@0: extern JS_FRIEND_API(uint8_t *) michael@0: JS_GetUint8ArrayData(JSObject *obj); michael@0: extern JS_FRIEND_API(uint8_t *) michael@0: JS_GetUint8ClampedArrayData(JSObject *obj); michael@0: extern JS_FRIEND_API(int16_t *) michael@0: JS_GetInt16ArrayData(JSObject *obj); michael@0: extern JS_FRIEND_API(uint16_t *) michael@0: JS_GetUint16ArrayData(JSObject *obj); michael@0: extern JS_FRIEND_API(int32_t *) michael@0: JS_GetInt32ArrayData(JSObject *obj); michael@0: extern JS_FRIEND_API(uint32_t *) michael@0: JS_GetUint32ArrayData(JSObject *obj); michael@0: extern JS_FRIEND_API(float *) michael@0: JS_GetFloat32ArrayData(JSObject *obj); michael@0: extern JS_FRIEND_API(double *) michael@0: JS_GetFloat64ArrayData(JSObject *obj); michael@0: michael@0: /* michael@0: * Stable versions of the above functions where the buffer remains valid as long michael@0: * as the object is live. michael@0: */ michael@0: extern JS_FRIEND_API(uint8_t *) michael@0: JS_GetStableArrayBufferData(JSContext *cx, JS::HandleObject obj); michael@0: michael@0: /* michael@0: * Same as above, but for any kind of ArrayBufferView. Prefer the type-specific michael@0: * versions when possible. michael@0: */ michael@0: extern JS_FRIEND_API(void *) michael@0: JS_GetArrayBufferViewData(JSObject *obj); michael@0: michael@0: /* michael@0: * Return the ArrayBuffer underlying an ArrayBufferView. If the buffer has been michael@0: * neutered, this will still return the neutered buffer. |obj| must be an michael@0: * object that would return true for JS_IsArrayBufferViewObject(). michael@0: */ michael@0: extern JS_FRIEND_API(JSObject *) michael@0: JS_GetArrayBufferViewBuffer(JSContext *cx, JSObject *obj); michael@0: michael@0: typedef enum { michael@0: ChangeData, michael@0: KeepData michael@0: } NeuterDataDisposition; michael@0: michael@0: /* michael@0: * Set an ArrayBuffer's length to 0 and neuter all of its views. michael@0: * michael@0: * The |changeData| argument is a hint to inform internal behavior with respect michael@0: * to the internal pointer to the ArrayBuffer's data after being neutered. michael@0: * There is no guarantee it will be respected. But if it is respected, the michael@0: * ArrayBuffer's internal data pointer will, or will not, have changed michael@0: * accordingly. michael@0: */ michael@0: extern JS_FRIEND_API(bool) michael@0: JS_NeuterArrayBuffer(JSContext *cx, JS::HandleObject obj, michael@0: NeuterDataDisposition changeData); michael@0: michael@0: /* michael@0: * Check whether obj supports JS_GetDataView* APIs. michael@0: */ michael@0: JS_FRIEND_API(bool) michael@0: JS_IsDataViewObject(JSObject *obj); michael@0: michael@0: /* michael@0: * Return the byte offset of a data view into its array buffer. |obj| must be a michael@0: * DataView. michael@0: * michael@0: * |obj| must have passed a JS_IsDataViewObject test, or somehow be known that michael@0: * it would pass such a test: it is a data view or a wrapper of a data view, michael@0: * and the unwrapping will succeed. michael@0: */ michael@0: JS_FRIEND_API(uint32_t) michael@0: JS_GetDataViewByteOffset(JSObject *obj); michael@0: michael@0: /* michael@0: * Return the byte length of a data view. michael@0: * michael@0: * |obj| must have passed a JS_IsDataViewObject test, or somehow be known that michael@0: * it would pass such a test: it is a data view or a wrapper of a data view, michael@0: * and the unwrapping will succeed. If cx is nullptr, then DEBUG builds may be michael@0: * unable to assert when unwrapping should be disallowed. michael@0: */ michael@0: JS_FRIEND_API(uint32_t) michael@0: JS_GetDataViewByteLength(JSObject *obj); michael@0: michael@0: /* michael@0: * Return a pointer to the beginning of the data referenced by a DataView. michael@0: * michael@0: * |obj| must have passed a JS_IsDataViewObject test, or somehow be known that michael@0: * it would pass such a test: it is a data view or a wrapper of a data view, michael@0: * and the unwrapping will succeed. If cx is nullptr, then DEBUG builds may be michael@0: * unable to assert when unwrapping should be disallowed. michael@0: */ michael@0: JS_FRIEND_API(void *) michael@0: JS_GetDataViewData(JSObject *obj); michael@0: michael@0: namespace js { michael@0: michael@0: /* michael@0: * Add a watchpoint -- in the Object.prototype.watch sense -- to |obj| for the michael@0: * property |id|, using the callable object |callable| as the function to be michael@0: * called for notifications. michael@0: * michael@0: * This is an internal function exposed -- temporarily -- only so that DOM michael@0: * proxies can be watchable. Don't use it! We'll soon kill off the michael@0: * Object.prototype.{,un}watch functions, at which point this will go too. michael@0: */ michael@0: extern JS_FRIEND_API(bool) michael@0: WatchGuts(JSContext *cx, JS::HandleObject obj, JS::HandleId id, JS::HandleObject callable); michael@0: michael@0: /* michael@0: * Remove a watchpoint -- in the Object.prototype.watch sense -- from |obj| for michael@0: * the property |id|. michael@0: * michael@0: * This is an internal function exposed -- temporarily -- only so that DOM michael@0: * proxies can be watchable. Don't use it! We'll soon kill off the michael@0: * Object.prototype.{,un}watch functions, at which point this will go too. michael@0: */ michael@0: extern JS_FRIEND_API(bool) michael@0: UnwatchGuts(JSContext *cx, JS::HandleObject obj, JS::HandleId id); michael@0: michael@0: } // namespace js michael@0: michael@0: /* michael@0: * A class, expected to be passed by value, which represents the CallArgs for a michael@0: * JSJitGetterOp. michael@0: */ michael@0: class JSJitGetterCallArgs : protected JS::MutableHandleValue michael@0: { michael@0: public: michael@0: explicit JSJitGetterCallArgs(const JS::CallArgs& args) michael@0: : JS::MutableHandleValue(args.rval()) michael@0: {} michael@0: michael@0: explicit JSJitGetterCallArgs(JS::RootedValue* rooted) michael@0: : JS::MutableHandleValue(rooted) michael@0: {} michael@0: michael@0: JS::MutableHandleValue rval() { michael@0: return *this; michael@0: } michael@0: }; michael@0: michael@0: /* michael@0: * A class, expected to be passed by value, which represents the CallArgs for a michael@0: * JSJitSetterOp. michael@0: */ michael@0: class JSJitSetterCallArgs : protected JS::MutableHandleValue michael@0: { michael@0: public: michael@0: explicit JSJitSetterCallArgs(const JS::CallArgs& args) michael@0: : JS::MutableHandleValue(args[0]) michael@0: {} michael@0: michael@0: JS::MutableHandleValue operator[](unsigned i) { michael@0: MOZ_ASSERT(i == 0); michael@0: return *this; michael@0: } michael@0: michael@0: unsigned length() const { return 1; } michael@0: michael@0: // Add get() or maybe hasDefined() as needed michael@0: }; michael@0: michael@0: struct JSJitMethodCallArgsTraits; michael@0: michael@0: /* michael@0: * A class, expected to be passed by reference, which represents the CallArgs michael@0: * for a JSJitMethodOp. michael@0: */ michael@0: class JSJitMethodCallArgs : protected JS::detail::CallArgsBase michael@0: { michael@0: private: michael@0: typedef JS::detail::CallArgsBase Base; michael@0: friend struct JSJitMethodCallArgsTraits; michael@0: michael@0: public: michael@0: explicit JSJitMethodCallArgs(const JS::CallArgs& args) { michael@0: argv_ = args.array(); michael@0: argc_ = args.length(); michael@0: } michael@0: michael@0: JS::MutableHandleValue rval() const { michael@0: return Base::rval(); michael@0: } michael@0: michael@0: unsigned length() const { return Base::length(); } michael@0: michael@0: JS::MutableHandleValue operator[](unsigned i) const { michael@0: return Base::operator[](i); michael@0: } michael@0: michael@0: bool hasDefined(unsigned i) const { michael@0: return Base::hasDefined(i); michael@0: } michael@0: michael@0: JSObject &callee() const { michael@0: // We can't use Base::callee() because that will try to poke at michael@0: // this->usedRval_, which we don't have. michael@0: return argv_[-2].toObject(); michael@0: } michael@0: michael@0: // Add get() as needed michael@0: }; michael@0: michael@0: struct JSJitMethodCallArgsTraits michael@0: { michael@0: static const size_t offsetOfArgv = offsetof(JSJitMethodCallArgs, argv_); michael@0: static const size_t offsetOfArgc = offsetof(JSJitMethodCallArgs, argc_); michael@0: }; michael@0: michael@0: /* michael@0: * This struct contains metadata passed from the DOM to the JS Engine for JIT michael@0: * optimizations on DOM property accessors. Eventually, this should be made michael@0: * available to general JSAPI users, but we are not currently ready to do so. michael@0: */ michael@0: typedef bool michael@0: (* JSJitGetterOp)(JSContext *cx, JS::HandleObject thisObj, michael@0: void *specializedThis, JSJitGetterCallArgs args); michael@0: typedef bool michael@0: (* JSJitSetterOp)(JSContext *cx, JS::HandleObject thisObj, michael@0: void *specializedThis, JSJitSetterCallArgs args); michael@0: typedef bool michael@0: (* JSJitMethodOp)(JSContext *cx, JS::HandleObject thisObj, michael@0: void *specializedThis, const JSJitMethodCallArgs& args); michael@0: michael@0: struct JSJitInfo { michael@0: enum OpType { michael@0: Getter, michael@0: Setter, michael@0: Method, michael@0: ParallelNative, michael@0: StaticMethod, michael@0: // Must be last michael@0: OpTypeCount michael@0: }; michael@0: michael@0: enum ArgType { michael@0: // Basic types michael@0: String = (1 << 0), michael@0: Integer = (1 << 1), // Only 32-bit or less michael@0: Double = (1 << 2), // Maybe we want to add Float sometime too michael@0: Boolean = (1 << 3), michael@0: Object = (1 << 4), michael@0: Null = (1 << 5), michael@0: michael@0: // And derived types michael@0: Numeric = Integer | Double, michael@0: // Should "Primitive" use the WebIDL definition, which michael@0: // excludes string and null, or the typical JS one that includes them? michael@0: Primitive = Numeric | Boolean | Null | String, michael@0: ObjectOrNull = Object | Null, michael@0: Any = ObjectOrNull | Primitive, michael@0: michael@0: // Our sentinel value. michael@0: ArgTypeListEnd = (1 << 31) michael@0: }; michael@0: michael@0: static_assert(Any & String, "Any must include String."); michael@0: static_assert(Any & Integer, "Any must include Integer."); michael@0: static_assert(Any & Double, "Any must include Double."); michael@0: static_assert(Any & Boolean, "Any must include Boolean."); michael@0: static_assert(Any & Object, "Any must include Object."); michael@0: static_assert(Any & Null, "Any must include Null."); michael@0: michael@0: enum AliasSet { michael@0: // An enum that describes what this getter/setter/method aliases. This michael@0: // determines what things can be hoisted past this call, and if this michael@0: // call is movable what it can be hoisted past. michael@0: michael@0: // Alias nothing: a constant value, getting it can't affect any other michael@0: // values, nothing can affect it. michael@0: AliasNone, michael@0: michael@0: // Alias things that can modify the DOM but nothing else. Doing the michael@0: // call can't affect the behavior of any other function. michael@0: AliasDOMSets, michael@0: michael@0: // Alias the world. Calling this can change arbitrary values anywhere michael@0: // in the system. Most things fall in this bucket. michael@0: AliasEverything, michael@0: michael@0: // Must be last. michael@0: AliasSetCount michael@0: }; michael@0: michael@0: bool hasParallelNative() const michael@0: { michael@0: return type() == ParallelNative; michael@0: } michael@0: michael@0: bool needsOuterizedThisObject() const michael@0: { michael@0: return type() != Getter && type() != Setter; michael@0: } michael@0: michael@0: bool isTypedMethodJitInfo() const michael@0: { michael@0: return isTypedMethod; michael@0: } michael@0: michael@0: OpType type() const michael@0: { michael@0: return OpType(type_); michael@0: } michael@0: michael@0: AliasSet aliasSet() const michael@0: { michael@0: return AliasSet(aliasSet_); michael@0: } michael@0: michael@0: JSValueType returnType() const michael@0: { michael@0: return JSValueType(returnType_); michael@0: } michael@0: michael@0: union { michael@0: JSJitGetterOp getter; michael@0: JSJitSetterOp setter; michael@0: JSJitMethodOp method; michael@0: /* An alternative native that's safe to call in parallel mode. */ michael@0: JSParallelNative parallelNative; michael@0: /* A DOM static method, used for Promise wrappers */ michael@0: JSNative staticMethod; michael@0: }; michael@0: michael@0: uint16_t protoID; michael@0: uint16_t depth; michael@0: michael@0: // These fields are carefully packed to take up 4 bytes. If you need more michael@0: // bits for whatever reason, please see if you can steal bits from existing michael@0: // fields before adding more members to this structure. michael@0: michael@0: #define JITINFO_OP_TYPE_BITS 4 michael@0: #define JITINFO_ALIAS_SET_BITS 4 michael@0: #define JITINFO_RETURN_TYPE_BITS 8 michael@0: michael@0: // The OpType that says what sort of function we are. michael@0: uint32_t type_ : JITINFO_OP_TYPE_BITS; michael@0: michael@0: // The alias set for this op. This is a _minimal_ alias set; in michael@0: // particular for a method it does not include whatever argument michael@0: // conversions might do. That's covered by argTypes and runtime michael@0: // analysis of the actual argument types being passed in. michael@0: uint32_t aliasSet_ : JITINFO_ALIAS_SET_BITS; michael@0: michael@0: // The return type tag. Might be JSVAL_TYPE_UNKNOWN. michael@0: uint32_t returnType_ : JITINFO_RETURN_TYPE_BITS; michael@0: michael@0: static_assert(OpTypeCount <= (1 << JITINFO_OP_TYPE_BITS), michael@0: "Not enough space for OpType"); michael@0: static_assert(AliasSetCount <= (1 << JITINFO_ALIAS_SET_BITS), michael@0: "Not enough space for AliasSet"); michael@0: static_assert((sizeof(JSValueType) * 8) <= JITINFO_RETURN_TYPE_BITS, michael@0: "Not enough space for JSValueType"); michael@0: michael@0: #undef JITINFO_RETURN_TYPE_BITS michael@0: #undef JITINFO_ALIAS_SET_BITS michael@0: #undef JITINFO_OP_TYPE_BITS michael@0: michael@0: uint32_t isInfallible : 1; /* Is op fallible? False in setters. */ michael@0: uint32_t isMovable : 1; /* Is op movable? To be movable the op must michael@0: not AliasEverything, but even that might michael@0: not be enough (e.g. in cases when it can michael@0: throw). */ michael@0: // XXXbz should we have a JSValueType for the type of the member? michael@0: uint32_t isInSlot : 1; /* True if this is a getter that can get a member michael@0: from a slot of the "this" object directly. */ michael@0: uint32_t isTypedMethod : 1; /* True if this is an instance of michael@0: JSTypedMethodJitInfo. */ michael@0: uint32_t slotIndex : 12; /* If isInSlot is true, the index of the slot to michael@0: get the value from. Otherwise 0. */ michael@0: }; michael@0: michael@0: static_assert(sizeof(JSJitInfo) == (sizeof(void*) + 2 * sizeof(uint32_t)), michael@0: "There are several thousand instances of JSJitInfo stored in " michael@0: "a binary. Please don't increase its space requirements without " michael@0: "verifying that there is no other way forward (better packing, " michael@0: "smaller datatypes for fields, subclassing, etc.)."); michael@0: michael@0: struct JSTypedMethodJitInfo michael@0: { michael@0: // We use C-style inheritance here, rather than C++ style inheritance michael@0: // because not all compilers support brace-initialization for non-aggregate michael@0: // classes. Using C++ style inheritance and constructors instead of michael@0: // brace-initialization would also force the creation of static michael@0: // constructors (on some compilers) when JSJitInfo and JSTypedMethodJitInfo michael@0: // structures are declared. Since there can be several thousand of these michael@0: // structures present and we want to have roughly equivalent performance michael@0: // across a range of compilers, we do things manually. michael@0: JSJitInfo base; michael@0: michael@0: const JSJitInfo::ArgType* const argTypes; /* For a method, a list of sets of michael@0: types that the function michael@0: expects. This can be used, michael@0: for example, to figure out michael@0: when argument coercions can michael@0: have side-effects. */ michael@0: }; michael@0: michael@0: namespace JS { michael@0: namespace detail { michael@0: michael@0: /* NEVER DEFINED, DON'T USE. For use by JS_CAST_PARALLEL_NATIVE_TO only. */ michael@0: inline int CheckIsParallelNative(JSParallelNative parallelNative); michael@0: michael@0: } // namespace detail michael@0: } // namespace JS michael@0: michael@0: #define JS_CAST_PARALLEL_NATIVE_TO(v, To) \ michael@0: (static_cast(sizeof(JS::detail::CheckIsParallelNative(v))), \ michael@0: reinterpret_cast(v)) michael@0: michael@0: /* michael@0: * You may ask yourself: why do we define a wrapper around a wrapper here? michael@0: * The answer is that some compilers don't understand initializing a union michael@0: * as we do below with a construct like: michael@0: * michael@0: * reinterpret_cast(JSParallelNativeThreadSafeWrapper) michael@0: * michael@0: * (We need the reinterpret_cast because we must initialize the union with michael@0: * a datum of the type of the union's first member.) michael@0: * michael@0: * Presumably this has something to do with template instantiation. michael@0: * Initializing with a normal function pointer seems to work fine. Hence michael@0: * the ugliness that you see before you. michael@0: */ michael@0: #define JS_JITINFO_NATIVE_PARALLEL(infoName, parallelOp) \ michael@0: const JSJitInfo infoName = \ michael@0: {{JS_CAST_PARALLEL_NATIVE_TO(parallelOp, JSJitGetterOp)},0,0,JSJitInfo::ParallelNative,JSJitInfo::AliasEverything,JSVAL_TYPE_MISSING,false,false,false,false,0} michael@0: michael@0: #define JS_JITINFO_NATIVE_PARALLEL_THREADSAFE(infoName, wrapperName, serialOp) \ michael@0: bool wrapperName##_ParallelNativeThreadSafeWrapper(js::ForkJoinContext *cx, unsigned argc, \ michael@0: JS::Value *vp) \ michael@0: { \ michael@0: return JSParallelNativeThreadSafeWrapper(cx, argc, vp); \ michael@0: } \ michael@0: JS_JITINFO_NATIVE_PARALLEL(infoName, wrapperName##_ParallelNativeThreadSafeWrapper) michael@0: michael@0: static MOZ_ALWAYS_INLINE const JSJitInfo * michael@0: FUNCTION_VALUE_TO_JITINFO(const JS::Value& v) michael@0: { michael@0: JS_ASSERT(js::GetObjectClass(&v.toObject()) == js::FunctionClassPtr); michael@0: return reinterpret_cast(&v.toObject())->jitinfo; michael@0: } michael@0: michael@0: /* Statically asserted in jsfun.h. */ michael@0: static const unsigned JS_FUNCTION_INTERPRETED_BIT = 0x1; michael@0: michael@0: static MOZ_ALWAYS_INLINE void michael@0: SET_JITINFO(JSFunction * func, const JSJitInfo *info) michael@0: { michael@0: js::shadow::Function *fun = reinterpret_cast(func); michael@0: JS_ASSERT(!(fun->flags & JS_FUNCTION_INTERPRETED_BIT)); michael@0: fun->jitinfo = info; michael@0: } michael@0: michael@0: /* michael@0: * Engine-internal extensions of jsid. This code is here only until we michael@0: * eliminate Gecko's dependencies on it! michael@0: */ michael@0: michael@0: static MOZ_ALWAYS_INLINE jsid michael@0: JSID_FROM_BITS(size_t bits) michael@0: { michael@0: jsid id; michael@0: JSID_BITS(id) = bits; michael@0: return id; michael@0: } michael@0: michael@0: namespace js { michael@0: namespace detail { michael@0: bool IdMatchesAtom(jsid id, JSAtom *atom); michael@0: } michael@0: } michael@0: michael@0: /* michael@0: * Must not be used on atoms that are representable as integer jsids. michael@0: * Prefer NameToId or AtomToId over this function: michael@0: * michael@0: * A PropertyName is an atom that does not contain an integer in the range michael@0: * [0, UINT32_MAX]. However, jsid can only hold an integer in the range michael@0: * [0, JSID_INT_MAX] (where JSID_INT_MAX == 2^31-1). Thus, for the range of michael@0: * integers (JSID_INT_MAX, UINT32_MAX], to represent as a jsid 'id', it must be michael@0: * the case JSID_IS_ATOM(id) and !JSID_TO_ATOM(id)->isPropertyName(). In most michael@0: * cases when creating a jsid, code does not have to care about this corner michael@0: * case because: michael@0: * michael@0: * - When given an arbitrary JSAtom*, AtomToId must be used, which checks for michael@0: * integer atoms representable as integer jsids, and does this conversion. michael@0: * michael@0: * - When given a PropertyName*, NameToId can be used which which does not need michael@0: * to do any dynamic checks. michael@0: * michael@0: * Thus, it is only the rare third case which needs this function, which michael@0: * handles any JSAtom* that is known not to be representable with an int jsid. michael@0: */ michael@0: static MOZ_ALWAYS_INLINE jsid michael@0: NON_INTEGER_ATOM_TO_JSID(JSAtom *atom) michael@0: { michael@0: JS_ASSERT(((size_t)atom & 0x7) == 0); michael@0: jsid id = JSID_FROM_BITS((size_t)atom); michael@0: JS_ASSERT(js::detail::IdMatchesAtom(id, atom)); michael@0: return id; michael@0: } michael@0: michael@0: /* All strings stored in jsids are atomized, but are not necessarily property names. */ michael@0: static MOZ_ALWAYS_INLINE bool michael@0: JSID_IS_ATOM(jsid id) michael@0: { michael@0: return JSID_IS_STRING(id); michael@0: } michael@0: michael@0: static MOZ_ALWAYS_INLINE bool michael@0: JSID_IS_ATOM(jsid id, JSAtom *atom) michael@0: { michael@0: return id == JSID_FROM_BITS((size_t)atom); michael@0: } michael@0: michael@0: static MOZ_ALWAYS_INLINE JSAtom * michael@0: JSID_TO_ATOM(jsid id) michael@0: { michael@0: return (JSAtom *)JSID_TO_STRING(id); michael@0: } michael@0: michael@0: JS_STATIC_ASSERT(sizeof(jsid) == sizeof(void*)); michael@0: michael@0: namespace js { michael@0: michael@0: static MOZ_ALWAYS_INLINE JS::Value michael@0: IdToValue(jsid id) michael@0: { michael@0: if (JSID_IS_STRING(id)) michael@0: return JS::StringValue(JSID_TO_STRING(id)); michael@0: if (MOZ_LIKELY(JSID_IS_INT(id))) michael@0: return JS::Int32Value(JSID_TO_INT(id)); michael@0: if (MOZ_LIKELY(JSID_IS_OBJECT(id))) michael@0: return JS::ObjectValue(*JSID_TO_OBJECT(id)); michael@0: JS_ASSERT(JSID_IS_VOID(id)); michael@0: return JS::UndefinedValue(); michael@0: } michael@0: michael@0: extern JS_FRIEND_API(bool) michael@0: IsTypedArrayThisCheck(JS::IsAcceptableThis test); michael@0: michael@0: /* michael@0: * If the embedder has registered a default JSContext callback, returns the michael@0: * result of the callback. Otherwise, asserts that |rt| has exactly one michael@0: * JSContext associated with it, and returns that context. michael@0: */ michael@0: extern JS_FRIEND_API(JSContext *) michael@0: DefaultJSContext(JSRuntime *rt); michael@0: michael@0: typedef JSContext* michael@0: (* DefaultJSContextCallback)(JSRuntime *rt); michael@0: michael@0: JS_FRIEND_API(void) michael@0: SetDefaultJSContextCallback(JSRuntime *rt, DefaultJSContextCallback cb); michael@0: michael@0: /* michael@0: * To help embedders enforce their invariants, we allow them to specify in michael@0: * advance which JSContext should be passed to JSAPI calls. If this is set michael@0: * to a non-null value, the assertSameCompartment machinery does double- michael@0: * duty (in debug builds) to verify that it matches the cx being used. michael@0: */ michael@0: #ifdef DEBUG michael@0: JS_FRIEND_API(void) michael@0: Debug_SetActiveJSContext(JSRuntime *rt, JSContext *cx); michael@0: #else michael@0: inline void michael@0: Debug_SetActiveJSContext(JSRuntime *rt, JSContext *cx) {}; michael@0: #endif michael@0: michael@0: michael@0: enum CTypesActivityType { michael@0: CTYPES_CALL_BEGIN, michael@0: CTYPES_CALL_END, michael@0: CTYPES_CALLBACK_BEGIN, michael@0: CTYPES_CALLBACK_END michael@0: }; michael@0: michael@0: typedef void michael@0: (* CTypesActivityCallback)(JSContext *cx, CTypesActivityType type); michael@0: michael@0: /* michael@0: * Sets a callback that is run whenever js-ctypes is about to be used when michael@0: * calling into C. michael@0: */ michael@0: JS_FRIEND_API(void) michael@0: SetCTypesActivityCallback(JSRuntime *rt, CTypesActivityCallback cb); michael@0: michael@0: class JS_FRIEND_API(AutoCTypesActivityCallback) { michael@0: private: michael@0: JSContext *cx; michael@0: CTypesActivityCallback callback; michael@0: CTypesActivityType endType; michael@0: MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER michael@0: michael@0: public: michael@0: AutoCTypesActivityCallback(JSContext *cx, CTypesActivityType beginType, michael@0: CTypesActivityType endType michael@0: MOZ_GUARD_OBJECT_NOTIFIER_PARAM); michael@0: ~AutoCTypesActivityCallback() { michael@0: DoEndCallback(); michael@0: } michael@0: void DoEndCallback() { michael@0: if (callback) { michael@0: callback(cx, endType); michael@0: callback = nullptr; michael@0: } michael@0: } michael@0: }; michael@0: michael@0: typedef bool michael@0: (* ObjectMetadataCallback)(JSContext *cx, JSObject **pmetadata); michael@0: michael@0: /* michael@0: * Specify a callback to invoke when creating each JS object in the current michael@0: * compartment, which may return a metadata object to associate with the michael@0: * object. Objects with different metadata have different shape hierarchies, michael@0: * so for efficiency, objects should generally try to share metadata objects. michael@0: */ michael@0: JS_FRIEND_API(void) michael@0: SetObjectMetadataCallback(JSContext *cx, ObjectMetadataCallback callback); michael@0: michael@0: /* Manipulate the metadata associated with an object. */ michael@0: michael@0: JS_FRIEND_API(bool) michael@0: SetObjectMetadata(JSContext *cx, JS::HandleObject obj, JS::HandleObject metadata); michael@0: michael@0: JS_FRIEND_API(JSObject *) michael@0: GetObjectMetadata(JSObject *obj); michael@0: michael@0: JS_FRIEND_API(void) michael@0: UnsafeDefineElement(JSContext *cx, JS::HandleObject obj, uint32_t index, JS::HandleValue value); michael@0: michael@0: JS_FRIEND_API(bool) michael@0: SliceSlowly(JSContext* cx, JS::HandleObject obj, JS::HandleObject receiver, michael@0: uint32_t begin, uint32_t end, JS::HandleObject result); michael@0: michael@0: /* ES5 8.12.8. */ michael@0: extern JS_FRIEND_API(bool) michael@0: DefaultValue(JSContext *cx, JS::HandleObject obj, JSType hint, JS::MutableHandleValue vp); michael@0: michael@0: /* michael@0: * Helper function. To approximate a call to the [[DefineOwnProperty]] internal michael@0: * method described in ES5, first call this, then call JS_DefinePropertyById. michael@0: * michael@0: * JS_DefinePropertyById by itself does not enforce the invariants on michael@0: * non-configurable properties when obj->isNative(). This function performs the michael@0: * relevant checks (specified in ES5 8.12.9 [[DefineOwnProperty]] steps 1-11), michael@0: * but only if obj is native. michael@0: * michael@0: * The reason for the messiness here is that ES5 uses [[DefineOwnProperty]] as michael@0: * a sort of extension point, but there is no hook in js::Class, michael@0: * js::ProxyHandler, or the JSAPI with precisely the right semantics for it. michael@0: */ michael@0: extern JS_FRIEND_API(bool) michael@0: CheckDefineProperty(JSContext *cx, JS::HandleObject obj, JS::HandleId id, JS::HandleValue value, michael@0: JSPropertyOp getter, JSStrictPropertyOp setter, unsigned attrs); michael@0: michael@0: /* michael@0: * Helper function for HTMLDocument and HTMLFormElement. michael@0: * michael@0: * These are the only two interfaces that have [OverrideBuiltins], a named michael@0: * getter, and no named setter. They're implemented as proxies with a custom michael@0: * getOwnPropertyDescriptor() method. Unfortunately, overriding michael@0: * getOwnPropertyDescriptor() automatically affects the behavior of set(), michael@0: * which normally is just common sense but is *not* desired for these two michael@0: * interfaces. michael@0: * michael@0: * The fix is for these two interfaces to override set() to ignore the michael@0: * getOwnPropertyDescriptor() override. michael@0: * michael@0: * SetPropertyIgnoringNamedGetter is exposed to make it easier to override michael@0: * set() in this way. It carries out all the steps of BaseProxyHandler::set() michael@0: * except the initial getOwnPropertyDescriptor()/getPropertyDescriptor() calls. michael@0: * The caller must supply those results as the 'desc' and 'descIsOwn' michael@0: * parameters. michael@0: * michael@0: * Implemented in jsproxy.cpp. michael@0: */ michael@0: JS_FRIEND_API(bool) michael@0: SetPropertyIgnoringNamedGetter(JSContext *cx, BaseProxyHandler *handler, michael@0: JS::HandleObject proxy, JS::HandleObject receiver, michael@0: JS::HandleId id, JS::MutableHandle desc, michael@0: bool descIsOwn, bool strict, JS::MutableHandleValue vp); michael@0: michael@0: } /* namespace js */ michael@0: michael@0: extern JS_FRIEND_API(bool) michael@0: js_DefineOwnProperty(JSContext *cx, JSObject *objArg, jsid idArg, michael@0: JS::Handle descriptor, bool *bp); michael@0: michael@0: extern JS_FRIEND_API(bool) michael@0: js_ReportIsNotFunction(JSContext *cx, JS::HandleValue v); michael@0: michael@0: #ifdef JSGC_GENERATIONAL michael@0: extern JS_FRIEND_API(void) michael@0: JS_StoreObjectPostBarrierCallback(JSContext* cx, michael@0: void (*callback)(JSTracer *trc, JSObject *key, void *data), michael@0: JSObject *key, void *data); michael@0: michael@0: extern JS_FRIEND_API(void) michael@0: JS_StoreStringPostBarrierCallback(JSContext* cx, michael@0: void (*callback)(JSTracer *trc, JSString *key, void *data), michael@0: JSString *key, void *data); michael@0: #else michael@0: inline void michael@0: JS_StoreObjectPostBarrierCallback(JSContext* cx, michael@0: void (*callback)(JSTracer *trc, JSObject *key, void *data), michael@0: JSObject *key, void *data) {} michael@0: michael@0: inline void michael@0: JS_StoreStringPostBarrierCallback(JSContext* cx, michael@0: void (*callback)(JSTracer *trc, JSString *key, void *data), michael@0: JSString *key, void *data) {} michael@0: #endif /* JSGC_GENERATIONAL */ michael@0: michael@0: #endif /* jsfriendapi_h */