/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- * * 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 "jsclass.h" #include "jspubtd.h" #include "jsprvtd.h" #include "mozilla/GuardObjects.h" JS_BEGIN_EXTERN_C 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(JSObject *) JS_FindCompilationScope(JSContext *cx, JSRawObject obj); extern JS_FRIEND_API(JSFunction *) JS_GetObjectFunction(JSRawObject obj); extern JS_FRIEND_API(JSObject *) JS_GetGlobalForFrame(JSStackFrame *fp); extern JS_FRIEND_API(JSBool) JS_SplicePrototype(JSContext *cx, JSObject *obj, JSObject *proto); extern JS_FRIEND_API(JSObject *) JS_NewObjectWithUniqueType(JSContext *cx, JSClass *clasp, JSObject *proto, JSObject *parent); extern JS_FRIEND_API(uint32_t) JS_ObjectCountDynamicSlots(JSHandleObject obj); extern JS_FRIEND_API(void) JS_ShrinkGCBuffers(JSRuntime *rt); extern JS_FRIEND_API(size_t) JS_GetE4XObjectsCreated(JSContext *cx); extern JS_FRIEND_API(size_t) JS_SetProtoCalled(JSContext *cx); extern JS_FRIEND_API(size_t) JS_GetCustomIteratorCount(JSContext *cx); extern JS_FRIEND_API(JSBool) JS_NondeterministicGetWeakMapKeys(JSContext *cx, JSObject *obj, JSObject **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(JSBool) 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 == NULL. Returns non-NULL iff obj != NULL. */ extern JS_FRIEND_API(JSObject *) JS_ObjectToInnerObject(JSContext *cx, JSObject *obj); /* Requires obj != NULL. */ extern JS_FRIEND_API(JSObject *) JS_ObjectToOuterObject(JSContext *cx, JSObject *obj); extern JS_FRIEND_API(JSObject *) JS_CloneObject(JSContext *cx, JSObject *obj, JSObject *proto, JSObject *parent); extern JS_FRIEND_API(JSBool) js_GetterOnlyPropertyStub(JSContext *cx, JSHandleObject obj, JSHandleId id, JSBool strict, JSMutableHandleValue vp); JS_FRIEND_API(void) js_ReportOverRecursed(JSContext *maybecx); #ifdef 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 #ifdef __cplusplus extern JS_FRIEND_API(bool) JS_CopyPropertiesFrom(JSContext *cx, JSObject *target, JSObject *obj); extern JS_FRIEND_API(JSBool) JS_WrapPropertyDescriptor(JSContext *cx, js::PropertyDescriptor *desc); extern JS_FRIEND_API(JSBool) JS_WrapAutoIdVector(JSContext *cx, JS::AutoIdVector &props); extern JS_FRIEND_API(JSBool) JS_EnumerateState(JSContext *cx, JSHandleObject 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 \ {NULL, NULL, 0, 0, NULL, NULL} extern JS_FRIEND_API(bool) JS_DefineFunctionsWithHelp(JSContext *cx, JSObject *obj, const JSFunctionSpecWithHelp *fs); #endif JS_END_EXTERN_C #ifdef __cplusplus typedef bool (* JS_SourceHook)(JSContext *cx, JSScript *script, jschar **src, uint32_t *length); extern JS_FRIEND_API(void) JS_SetSourceHook(JSRuntime *rt, JS_SourceHook hook); namespace js { inline JSRuntime * GetRuntime(const JSContext *cx) { return ContextFriendFields::get(cx)->runtime; } typedef bool (* PreserveWrapperCallback)(JSContext *cx, JSObject *obj); /* * 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); class JS_FRIEND_API(AutoSwitchCompartment) { private: JSContext *cx; JSCompartment *oldCompartment; public: AutoSwitchCompartment(JSContext *cx, JSCompartment *newCompartment JS_GUARD_OBJECT_NOTIFIER_PARAM); AutoSwitchCompartment(JSContext *cx, JSHandleObject target JS_GUARD_OBJECT_NOTIFIER_PARAM); ~AutoSwitchCompartment(); JS_DECL_USE_GUARD_OBJECT_NOTIFIER }; #ifdef OLD_GETTER_SETTER_METHODS JS_FRIEND_API(JSBool) obj_defineGetter(JSContext *cx, unsigned argc, js::Value *vp); JS_FRIEND_API(JSBool) obj_defineSetter(JSContext *cx, unsigned argc, js::Value *vp); #endif extern JS_FRIEND_API(bool) IsSystemCompartment(const JSCompartment *compartment); extern JS_FRIEND_API(bool) IsAtomsCompartment(const JSCompartment *c); /* * Check whether it is OK to assign an undeclared property with name * propname of the global object in the current script on cx. Reports * an error if one needs to be reported (in particular in all cases * when it returns false). */ extern JS_FRIEND_API(bool) CheckUndeclaredVarAssignment(JSContext *cx, JSString *propname); 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 NULL 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) GCThingIsMarkedGray(void *thing); typedef void (GCThingCallback)(void *closure, void *gcthing); extern JS_FRIEND_API(void) VisitGrayWrapperTargets(JSCompartment *comp, GCThingCallback *callback, void *closure); extern JS_FRIEND_API(JSObject *) GetWeakmapKeyDelegate(JSObject *key); /* * 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 { JSObject *proto; }; struct BaseShape { js::Class *clasp; JSObject *parent; }; struct Shape { BaseShape *base; jsid _1; uint32_t slotInfo; static const uint32_t FIXED_SLOTS_SHIFT = 27; }; struct Object { Shape *shape; TypeObject *type; js::Value *slots; js::Value *_1; size_t numFixedSlots() const { return shape->slotInfo >> Shape::FIXED_SLOTS_SHIFT; } Value *fixedSlots() const { return (Value *)(uintptr_t(this) + sizeof(shadow::Object)); } js::Value &slotRef(size_t slot) const { size_t nfixed = numFixedSlots(); if (slot < nfixed) return fixedSlots()[slot]; return slots[slot - nfixed]; } }; struct Function { Object base; uint16_t nargs; uint16_t flags; /* Used only for natives */ Native native; const JSJitInfo *jitinfo; void *_1; }; struct Atom { size_t _; const jschar *chars; }; } /* namespace shadow */ extern JS_FRIEND_DATA(js::Class) AnyNameClass; extern JS_FRIEND_DATA(js::Class) AttributeNameClass; extern JS_FRIEND_DATA(js::Class) CallClass; extern JS_FRIEND_DATA(js::Class) DeclEnvClass; extern JS_FRIEND_DATA(js::Class) FunctionClass; extern JS_FRIEND_DATA(js::Class) FunctionProxyClass; extern JS_FRIEND_DATA(js::Class) NamespaceClass; extern JS_FRIEND_DATA(js::Class) OuterWindowProxyClass; extern JS_FRIEND_DATA(js::Class) ObjectProxyClass; extern JS_FRIEND_DATA(js::Class) QNameClass; extern JS_FRIEND_DATA(js::Class) XMLClass; extern JS_FRIEND_DATA(js::Class) ObjectClass; inline js::Class * GetObjectClass(RawObject obj) { return reinterpret_cast(obj)->shape->base->clasp; } inline JSClass * GetObjectJSClass(RawObject obj) { return js::Jsvalify(GetObjectClass(obj)); } JS_FRIEND_API(bool) IsScopeObject(RawObject obj); inline JSObject * GetObjectParent(RawObject obj) { JS_ASSERT(!IsScopeObject(obj)); return reinterpret_cast(obj)->shape->base->parent; } JS_FRIEND_API(JSObject *) GetObjectParentMaybeScope(RawObject obj); JS_FRIEND_API(JSObject *) GetGlobalForObjectCrossCompartment(RawObject obj); JS_FRIEND_API(void) NotifyAnimationActivity(RawObject obj); JS_FRIEND_API(bool) IsOriginalScriptFunction(JSFunction *fun); /* * Return the outermost enclosing function (script) of the scripted caller. * This function returns NULL 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, JSClass *clasp, JSNative constructor, unsigned nargs, JSPropertySpec *ps, JSFunctionSpec *fs, JSPropertySpec *static_ps, JSFunctionSpec *static_fs); JS_FRIEND_API(const Value &) GetFunctionNativeReserved(RawObject fun, size_t which); JS_FRIEND_API(void) SetFunctionNativeReserved(RawObject fun, size_t which, const Value &val); inline bool GetObjectProto(JSContext *cx, JSObject *obj, JSObject **proto) { js::Class *clasp = GetObjectClass(obj); if (clasp == &js::ObjectProxyClass || clasp == &js::OuterWindowProxyClass || clasp == &js::FunctionProxyClass) { return JS_GetPrototype(cx, obj, proto); } *proto = reinterpret_cast(obj)->type->proto; return true; } inline void * GetObjectPrivate(RawObject 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 Value & GetReservedSlot(RawObject obj, size_t slot) { JS_ASSERT(slot < JSCLASS_RESERVED_SLOTS(GetObjectClass(obj))); return reinterpret_cast(obj)->slotRef(slot); } JS_FRIEND_API(void) SetReservedSlotWithBarrier(RawObject obj, size_t slot, const Value &value); inline void SetReservedSlot(RawObject obj, size_t slot, const Value &value) { JS_ASSERT(slot < JSCLASS_RESERVED_SLOTS(GetObjectClass(obj))); shadow::Object *sobj = reinterpret_cast(obj); if (sobj->slotRef(slot).isMarkable()) SetReservedSlotWithBarrier(obj, slot, value); else sobj->slotRef(slot) = value; } JS_FRIEND_API(uint32_t) GetObjectSlotSpan(RawObject obj); inline const Value & GetObjectSlot(RawObject 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 JSLinearString * AtomToLinearString(JSAtom *atom) { return reinterpret_cast(atom); } static inline js::PropertyOp CastAsJSPropertyOp(RawObject object) { return JS_DATA_TO_FUNC_PTR(js::PropertyOp, object); } static inline js::StrictPropertyOp CastAsJSStrictPropertyOp(RawObject object) { return JS_DATA_TO_FUNC_PTR(js::StrictPropertyOp, object); } JS_FRIEND_API(bool) GetPropertyNames(JSContext *cx, RawObject obj, unsigned flags, js::AutoIdVector *props); JS_FRIEND_API(bool) GetGeneric(JSContext *cx, JSObject *obj, JSObject *receiver, jsid id, 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(RawObject 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 */ #define JSITER_FOR_OF 0x20 /* harmony for-of loop */ inline uintptr_t GetNativeStackLimit(const JSRuntime *rt) { return RuntimeFriendFields::get(rt)->nativeStackLimit; } #define JS_CHECK_RECURSION(cx, onerror) \ JS_BEGIN_MACRO \ int stackDummy_; \ if (!JS_CHECK_STACK_SIZE(js::GetNativeStackLimit(js::GetRuntime(cx)), &stackDummy_)) { \ 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); /* * A call stack can be specified to the JS engine such that all JS entry/exits * to functions push/pop an entry to/from the specified stack. * * For more detailed information, see vm/SPSProfiler.h */ class ProfileEntry { /* * All fields are marked volatile to prevent the compiler from re-ordering * instructions. Namely this sequence: * * entry[size] = ...; * size++; * * If the size modification were somehow reordered before the stores, then * if a sample were taken it would be examining bogus information. * * A ProfileEntry represents both a C++ profile entry and a JS one. Both use * the string as a description, but JS uses the sp as NULL to indicate that * it is a JS entry. The script_ is then only ever examined for a JS entry, * and the idx is used by both, but with different meanings. */ const char * volatile string; // Descriptive string of this entry void * volatile sp; // Relevant stack pointer for the entry JSScript * volatile script_; // if js(), non-null script which is running int32_t volatile idx; // if js(), idx of pc, otherwise line number public: /* * All of these methods are marked with the 'volatile' keyword because SPS's * representation of the stack is stored such that all ProfileEntry * instances are volatile. These methods would not be available unless they * were marked as volatile as well */ bool js() volatile { JS_ASSERT_IF(sp == NULL, script_ != NULL); return sp == NULL; } uint32_t line() volatile { JS_ASSERT(!js()); return idx; } JSScript *script() volatile { JS_ASSERT(js()); return script_; } void *stackAddress() volatile { return sp; } const char *label() volatile { return string; } void setLine(uint32_t line) volatile { JS_ASSERT(!js()); idx = line; } void setLabel(const char *string) volatile { this->string = string; } void setStackAddress(void *sp) volatile { this->sp = sp; } void setScript(JSScript *script) volatile { script_ = script; } /* we can't know the layout of JSScript, so look in vm/SPSProfiler.cpp */ JS_FRIEND_API(jsbytecode *) pc() volatile; JS_FRIEND_API(void) setPC(jsbytecode *pc) volatile; static size_t offsetOfString() { return offsetof(ProfileEntry, string); } static size_t offsetOfStackAddress() { return offsetof(ProfileEntry, sp); } static size_t offsetOfPCIdx() { return offsetof(ProfileEntry, idx); } static size_t offsetOfScript() { return offsetof(ProfileEntry, script_); } /* * The index used in the entry can either be a line number or the offset of * a pc into a script's code. To signify a NULL pc, use a -1 index. This is * checked against in pc() and setPC() to set/get the right pc. */ static const int32_t NullPCIndex = -1; }; JS_FRIEND_API(void) SetRuntimeProfilingStack(JSRuntime *rt, ProfileEntry *stack, uint32_t *size, uint32_t max); JS_FRIEND_API(void) EnableRuntimeProfilingStack(JSRuntime *rt, bool enabled); JS_FRIEND_API(jsbytecode*) ProfilingGetPC(JSRuntime *rt, JSScript *script, void *ip); #ifdef JS_THREADSAFE JS_FRIEND_API(void *) GetOwnerThread(const JSContext *cx); JS_FRIEND_API(bool) ContextHasOutstandingRequests(const JSContext *cx); #endif JS_FRIEND_API(JSCompartment *) GetContextCompartment(const JSContext *cx); JS_FRIEND_API(bool) HasUnrootedGlobal(const JSContext *cx); typedef void (* ActivityCallback)(void *arg, JSBool 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(JSVersion) VersionSetMoarXML(JSVersion version, bool enable); extern JS_FRIEND_API(bool) CanCallContextDebugHandler(JSContext *cx); extern JS_FRIEND_API(JSTrapStatus) CallContextDebugHandler(JSContext *cx, JSScript *script, jsbytecode *bc, Value *rval); extern JS_FRIEND_API(bool) IsContextRunningJS(JSContext *cx); class SystemAllocPolicy; typedef Vector CompartmentVector; extern JS_FRIEND_API(const CompartmentVector&) GetRuntimeCompartments(JSRuntime *rt); #define GCREASONS(D) \ /* Reasons internal to the JS engine */ \ D(API) \ D(MAYBEGC) \ D(LAST_CONTEXT) \ D(DESTROY_CONTEXT) \ D(LAST_DITCH) \ D(TOO_MUCH_MALLOC) \ D(ALLOC_TRIGGER) \ D(DEBUG_GC) \ D(DEBUG_MODE_GC) \ D(TRANSPLANT) \ D(RESET) \ \ /* Reasons from Firefox */ \ D(DOM_WINDOW_UTILS) \ D(COMPONENT_UTILS) \ D(MEM_PRESSURE) \ D(CC_WAITING) \ D(CC_FORCED) \ D(LOAD_END) \ D(POST_COMPARTMENT) \ D(PAGE_HIDE) \ D(NSJSCONTEXT_DESTROY) \ D(SET_NEW_DOCUMENT) \ D(SET_DOC_SHELL) \ D(DOM_UTILS) \ D(DOM_IPC) \ D(DOM_WORKER) \ D(INTER_SLICE_GC) \ D(REFRESH_FRAME) \ D(FULL_GC_TIMER) \ D(SHUTDOWN_CC) namespace gcreason { /* GCReasons will end up looking like JSGC_MAYBEGC */ enum Reason { #define MAKE_REASON(name) name, GCREASONS(MAKE_REASON) #undef MAKE_REASON NO_REASON, NUM_REASONS, /* * For telemetry, we want to keep a fixed max bucket size over time so we * don't have to switch histograms. 100 is conservative; as of this writing * there are 26. But the cost of extra buckets seems to be low while the * cost of switching histograms is high. */ NUM_TELEMETRY_REASONS = 100 }; } /* namespace gcreason */ extern JS_FRIEND_API(void) PrepareCompartmentForGC(JSCompartment *comp); extern JS_FRIEND_API(void) PrepareForFullGC(JSRuntime *rt); extern JS_FRIEND_API(void) PrepareForIncrementalGC(JSRuntime *rt); extern JS_FRIEND_API(bool) IsGCScheduled(JSRuntime *rt); extern JS_FRIEND_API(void) SkipCompartmentForGC(JSCompartment *comp); /* * When triggering a GC using one of the functions below, it is first necessary * to select the compartments to be collected. To do this, you can call * PrepareCompartmentForGC on each compartment, or you can call PrepareForFullGC * to select all compartments. Failing to select any compartment is an error. */ extern JS_FRIEND_API(void) GCForReason(JSRuntime *rt, gcreason::Reason reason); extern JS_FRIEND_API(void) ShrinkingGC(JSRuntime *rt, gcreason::Reason reason); extern JS_FRIEND_API(void) IncrementalGC(JSRuntime *rt, gcreason::Reason reason, int64_t millis = 0); extern JS_FRIEND_API(void) FinishIncrementalGC(JSRuntime *rt, gcreason::Reason reason); enum GCProgress { /* * During non-incremental GC, the GC is bracketed by JSGC_CYCLE_BEGIN/END * callbacks. During an incremental GC, the sequence of callbacks is as * follows: * JSGC_CYCLE_BEGIN, JSGC_SLICE_END (first slice) * JSGC_SLICE_BEGIN, JSGC_SLICE_END (second slice) * ... * JSGC_SLICE_BEGIN, JSGC_CYCLE_END (last slice) */ GC_CYCLE_BEGIN, GC_SLICE_BEGIN, GC_SLICE_END, GC_CYCLE_END }; struct JS_FRIEND_API(GCDescription) { bool isCompartment; GCDescription(bool isCompartment) : isCompartment(isCompartment) {} jschar *formatMessage(JSRuntime *rt) const; jschar *formatJSON(JSRuntime *rt, uint64_t timestamp) const; }; typedef void (* GCSliceCallback)(JSRuntime *rt, GCProgress progress, const GCDescription &desc); extern JS_FRIEND_API(GCSliceCallback) SetGCSliceCallback(JSRuntime *rt, GCSliceCallback callback); typedef void (* AnalysisPurgeCallback)(JSRuntime *rt, JSFlatString *desc); extern JS_FRIEND_API(AnalysisPurgeCallback) SetAnalysisPurgeCallback(JSRuntime *rt, AnalysisPurgeCallback callback); /* Was the most recent GC run incrementally? */ extern JS_FRIEND_API(bool) WasIncrementalGC(JSRuntime *rt); typedef JSBool (* DOMInstanceClassMatchesProto)(JSHandleObject 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); /* * Signals a good place to do an incremental slice, because the browser is * drawing a frame. */ extern JS_FRIEND_API(void) NotifyDidPaint(JSRuntime *rt); extern JS_FRIEND_API(bool) IsIncrementalGCEnabled(JSRuntime *rt); JS_FRIEND_API(bool) IsIncrementalGCInProgress(JSRuntime *rt); extern JS_FRIEND_API(void) DisableIncrementalGC(JSRuntime *rt); extern JS_FRIEND_API(bool) IsIncrementalBarrierNeeded(JSRuntime *rt); extern JS_FRIEND_API(bool) IsIncrementalBarrierNeeded(JSContext *cx); extern JS_FRIEND_API(bool) IsIncrementalBarrierNeededOnObject(RawObject obj); extern JS_FRIEND_API(bool) IsIncrementalBarrierNeededOnScript(JSScript *obj); extern JS_FRIEND_API(void) IncrementalReferenceBarrier(void *ptr); extern JS_FRIEND_API(void) IncrementalValueBarrier(const Value &v); extern JS_FRIEND_API(void) PokeGC(JSRuntime *rt); class ObjectPtr { JSObject *value; public: ObjectPtr() : value(NULL) {} ObjectPtr(JSObject *obj) : value(obj) {} /* Always call finalize before the destructor. */ ~ObjectPtr() { JS_ASSERT(!value); } void finalize(JSRuntime *rt) { if (IsIncrementalBarrierNeeded(rt)) IncrementalReferenceBarrier(value); value = NULL; } void init(JSObject *obj) { value = obj; } JSObject *get() const { return value; } void writeBarrierPre(JSRuntime *rt) { IncrementalReferenceBarrier(value); } ObjectPtr &operator=(JSObject *obj) { IncrementalReferenceBarrier(value); value = obj; return *this; } JSObject &operator*() const { return *value; } JSObject *operator->() const { return value; } operator JSObject *() const { return value; } }; 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 NULL for invalid arguments and JSEXN_INTERNALERR */ extern JS_FRIEND_API(const jschar*) GetErrorTypeName(JSContext* cx, int16_t exnType); /* 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(JSBool) NukeCrossCompartmentWrappers(JSContext* cx, const CompartmentFilter& sourceFilter, const CompartmentFilter& targetFilter, NukeReferencesToWindow nukeReferencesToWindow); /* Specify information about ListBase proxies in the DOM, for use by ICs. */ JS_FRIEND_API(void) SetListBaseInformation(void *listBaseHandlerFamily, uint32_t listBaseExpandoSlot); void *GetListBaseHandlerFamily(); uint32_t GetListBaseExpandoSlot(); } /* namespace js */ #endif /* 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(JSBool) js_DateIsValid(JSObject* obj); extern JS_FRIEND_API(double) js_DateGetMsecSinceEpoch(JSRawObject 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); /* Implemented in jsclone.cpp. */ extern JS_FRIEND_API(uint64_t) js_GetSCOffset(JSStructuredCloneWriter* writer); /* Typed Array functions, implemented in jstypedarray.cpp */ #ifdef __cplusplus 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_MAX }; } /* namespace ArrayBufferView */ } /* namespace js */ typedef js::ArrayBufferView::ViewType JSArrayBufferViewType; #else typedef uint32_t JSArrayBufferViewType; #endif /* __cplusplus */ /* * 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, JSObject *array); extern JS_FRIEND_API(JSObject *) JS_NewUint8ArrayFromArray(JSContext *cx, JSObject *array); extern JS_FRIEND_API(JSObject *) JS_NewUint8ClampedArrayFromArray(JSContext *cx, JSObject *array); extern JS_FRIEND_API(JSObject *) JS_NewInt16ArrayFromArray(JSContext *cx, JSObject *array); extern JS_FRIEND_API(JSObject *) JS_NewUint16ArrayFromArray(JSContext *cx, JSObject *array); extern JS_FRIEND_API(JSObject *) JS_NewInt32ArrayFromArray(JSContext *cx, JSObject *array); extern JS_FRIEND_API(JSObject *) JS_NewUint32ArrayFromArray(JSContext *cx, JSObject *array); extern JS_FRIEND_API(JSObject *) JS_NewFloat32ArrayFromArray(JSContext *cx, JSObject *array); extern JS_FRIEND_API(JSObject *) JS_NewFloat64ArrayFromArray(JSContext *cx, JSObject *array); /* * Create a new typed array using the given ArrayBuffer for storage. byteOffset * must not exceed (signed) INT32_MAX. 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, JSObject *arrayBuffer, uint32_t byteOffset, int32_t length); extern JS_FRIEND_API(JSObject *) JS_NewUint8ArrayWithBuffer(JSContext *cx, JSObject *arrayBuffer, uint32_t byteOffset, int32_t length); extern JS_FRIEND_API(JSObject *) JS_NewUint8ClampedArrayWithBuffer(JSContext *cx, JSObject *arrayBuffer, uint32_t byteOffset, int32_t length); extern JS_FRIEND_API(JSObject *) JS_NewInt16ArrayWithBuffer(JSContext *cx, JSObject *arrayBuffer, uint32_t byteOffset, int32_t length); extern JS_FRIEND_API(JSObject *) JS_NewUint16ArrayWithBuffer(JSContext *cx, JSObject *arrayBuffer, uint32_t byteOffset, int32_t length); extern JS_FRIEND_API(JSObject *) JS_NewInt32ArrayWithBuffer(JSContext *cx, JSObject *arrayBuffer, uint32_t byteOffset, int32_t length); extern JS_FRIEND_API(JSObject *) JS_NewUint32ArrayWithBuffer(JSContext *cx, JSObject *arrayBuffer, uint32_t byteOffset, int32_t length); extern JS_FRIEND_API(JSObject *) JS_NewFloat32ArrayWithBuffer(JSContext *cx, JSObject *arrayBuffer, uint32_t byteOffset, int32_t length); extern JS_FRIEND_API(JSObject *) JS_NewFloat64ArrayWithBuffer(JSContext *cx, JSObject *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(JSBool) JS_IsTypedArrayObject(JSObject *obj, JSContext *cx); /* * 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. cx MUST be non-NULL and valid. */ extern JS_FRIEND_API(JSBool) JS_IsArrayBufferViewObject(JSObject *obj, JSContext *cx); /* * Test for specific typed array types (ArrayBufferView subtypes) */ extern JS_FRIEND_API(JSBool) JS_IsInt8Array(JSObject *obj, JSContext *cx); extern JS_FRIEND_API(JSBool) JS_IsUint8Array(JSObject *obj, JSContext *cx); extern JS_FRIEND_API(JSBool) JS_IsUint8ClampedArray(JSObject *obj, JSContext *cx); extern JS_FRIEND_API(JSBool) JS_IsInt16Array(JSObject *obj, JSContext *cx); extern JS_FRIEND_API(JSBool) JS_IsUint16Array(JSObject *obj, JSContext *cx); extern JS_FRIEND_API(JSBool) JS_IsInt32Array(JSObject *obj, JSContext *cx); extern JS_FRIEND_API(JSBool) JS_IsUint32Array(JSObject *obj, JSContext *cx); extern JS_FRIEND_API(JSBool) JS_IsFloat32Array(JSObject *obj, JSContext *cx); extern JS_FRIEND_API(JSBool) JS_IsFloat64Array(JSObject *obj, JSContext *cx); /* * Unwrap Typed arrays all at once. Return NULL 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(JSContext *cx, JSObject *obj, uint32_t *length, int8_t **data); extern JS_FRIEND_API(JSObject *) JS_GetObjectAsUint8Array(JSContext *cx, JSObject *obj, uint32_t *length, uint8_t **data); extern JS_FRIEND_API(JSObject *) JS_GetObjectAsUint8ClampedArray(JSContext *cx, JSObject *obj, uint32_t *length, uint8_t **data); extern JS_FRIEND_API(JSObject *) JS_GetObjectAsInt16Array(JSContext *cx, JSObject *obj, uint32_t *length, int16_t **data); extern JS_FRIEND_API(JSObject *) JS_GetObjectAsUint16Array(JSContext *cx, JSObject *obj, uint32_t *length, uint16_t **data); extern JS_FRIEND_API(JSObject *) JS_GetObjectAsInt32Array(JSContext *cx, JSObject *obj, uint32_t *length, int32_t **data); extern JS_FRIEND_API(JSObject *) JS_GetObjectAsUint32Array(JSContext *cx, JSObject *obj, uint32_t *length, uint32_t **data); extern JS_FRIEND_API(JSObject *) JS_GetObjectAsFloat32Array(JSContext *cx, JSObject *obj, uint32_t *length, float **data); extern JS_FRIEND_API(JSObject *) JS_GetObjectAsFloat64Array(JSContext *cx, JSObject *obj, uint32_t *length, double **data); extern JS_FRIEND_API(JSObject *) JS_GetObjectAsArrayBufferView(JSContext *cx, JSObject *obj, uint32_t *length, uint8_t **data); extern JS_FRIEND_API(JSObject *) JS_GetObjectAsArrayBuffer(JSContext *cx, JSObject *obj, uint32_t *length, uint8_t **data); /* * Get the type 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. If cx is NULL, then DEBUG * builds may be unable to assert when unwrapping should be disallowed. */ extern JS_FRIEND_API(JSArrayBufferViewType) JS_GetTypedArrayType(JSObject *obj, JSContext *maybecx); /* * 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(JSBool) JS_IsArrayBufferObject(JSObject *obj, JSContext *maybecx); /* * 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. If cx is NULL, then DEBUG * builds may be unable to assert when unwrapping should be disallowed. */ extern JS_FRIEND_API(uint32_t) JS_GetArrayBufferByteLength(JSObject *obj, JSContext *maybecx); /* * Return a pointer to an array buffer's data. The buffer is still owned by the * array buffer object, and should not be modified on another thread. The * returned pointer is stable across GCs. * * |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. If cx is NULL, then DEBUG * builds may be unable to assert when unwrapping should be disallowed. */ extern JS_FRIEND_API(uint8_t *) JS_GetArrayBufferData(JSObject *obj, JSContext *maybecx); /* * 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. If cx is NULL, then DEBUG * builds may be unable to assert when unwrapping should be disallowed. */ extern JS_FRIEND_API(uint32_t) JS_GetTypedArrayLength(JSObject *obj, JSContext *cx); /* * 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. If cx is NULL, then DEBUG * builds may be unable to assert when unwrapping should be disallowed. */ extern JS_FRIEND_API(uint32_t) JS_GetTypedArrayByteOffset(JSObject *obj, JSContext *cx); /* * 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. If cx is NULL, then DEBUG * builds may be unable to assert when unwrapping should be disallowed. */ extern JS_FRIEND_API(uint32_t) JS_GetTypedArrayByteLength(JSObject *obj, JSContext *cx); /* * 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(JSBool) JS_IsArrayBufferViewObject(JSObject *obj, JSContext *cx); /* * More generic name for JS_GetTypedArrayByteLength to cover DataViews as well */ extern JS_FRIEND_API(uint32_t) JS_GetArrayBufferViewByteLength(JSObject *obj, JSContext *cx); /* * 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. * * |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. If cx is NULL, then DEBUG builds may be unable to * assert when unwrapping should be disallowed. */ extern JS_FRIEND_API(int8_t *) JS_GetInt8ArrayData(JSObject *obj, JSContext *maybecx); extern JS_FRIEND_API(uint8_t *) JS_GetUint8ArrayData(JSObject *obj, JSContext *maybecx); extern JS_FRIEND_API(uint8_t *) JS_GetUint8ClampedArrayData(JSObject *obj, JSContext *maybecx); extern JS_FRIEND_API(int16_t *) JS_GetInt16ArrayData(JSObject *obj, JSContext *maybecx); extern JS_FRIEND_API(uint16_t *) JS_GetUint16ArrayData(JSObject *obj, JSContext *maybecx); extern JS_FRIEND_API(int32_t *) JS_GetInt32ArrayData(JSObject *obj, JSContext *maybecx); extern JS_FRIEND_API(uint32_t *) JS_GetUint32ArrayData(JSObject *obj, JSContext *maybecx); extern JS_FRIEND_API(float *) JS_GetFloat32ArrayData(JSObject *obj, JSContext *maybecx); extern JS_FRIEND_API(double *) JS_GetFloat64ArrayData(JSObject *obj, JSContext *maybecx); /* * 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, JSContext *maybecx); /* * Check whether obj supports JS_GetDataView* APIs. Note that this may fail and * throw an exception if a security wrapper is encountered that denies the * operation. */ JS_FRIEND_API(JSBool) JS_IsDataViewObject(JSContext *cx, JSObject *obj, JSBool *isDataView); /* * 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. If cx is NULL, then DEBUG builds may be * unable to assert when unwrapping should be disallowed. */ JS_FRIEND_API(uint32_t) JS_GetDataViewByteOffset(JSObject *obj, JSContext *maybecx); /* * 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 NULL, then DEBUG builds may be * unable to assert when unwrapping should be disallowed. */ JS_FRIEND_API(uint32_t) JS_GetDataViewByteLength(JSObject *obj, JSContext *maybecx); /* * 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 NULL, then DEBUG builds may be * unable to assert when unwrapping should be disallowed. */ JS_FRIEND_API(void *) JS_GetDataViewData(JSObject *obj, JSContext *maybecx); #ifdef __cplusplus /* * 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 (* JSJitPropertyOp)(JSContext *cx, JSHandleObject thisObj, void *specializedThis, JS::Value *vp); typedef bool (* JSJitMethodOp)(JSContext *cx, JSHandleObject thisObj, void *specializedThis, unsigned argc, JS::Value *vp); struct JSJitInfo { enum OpType { Getter, Setter, Method }; JSJitPropertyOp op; uint32_t protoID; uint32_t depth; OpType type; bool isInfallible; /* Is op fallible? False in setters. */ bool isConstant; /* Getting a construction-time constant? */ }; static JS_ALWAYS_INLINE const JSJitInfo * FUNCTION_VALUE_TO_JITINFO(const JS::Value& v) { JS_ASSERT(js::GetObjectClass(&v.toObject()) == &js::FunctionClass); return reinterpret_cast(&v.toObject())->jitinfo; } static JS_ALWAYS_INLINE void SET_JITINFO(JSFunction * func, const JSJitInfo *info) { js::shadow::Function *fun = reinterpret_cast(func); /* JS_ASSERT(func->isNative()). 0x4000 is JSFUN_INTERPRETED */ JS_ASSERT(!(fun->flags & 0x4000)); fun->jitinfo = info; } #endif /* __cplusplus */ /* * Engine-internal extensions of jsid. This code is here only until we * eliminate Gecko's dependencies on it! */ static JS_ALWAYS_INLINE jsid JSID_FROM_BITS(size_t bits) { jsid id; JSID_BITS(id) = bits; return id; } /* * 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 JS_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(id == INTERNED_STRING_TO_JSID(NULL, (JSString*)atom)); return id; } /* All strings stored in jsids are atomized, but are not necessarily property names. */ static JS_ALWAYS_INLINE JSBool JSID_IS_ATOM(jsid id) { return JSID_IS_STRING(id); } static JS_ALWAYS_INLINE JSBool JSID_IS_ATOM(jsid id, JSAtom *atom) { return id == JSID_FROM_BITS((size_t)atom); } static JS_ALWAYS_INLINE JSAtom * JSID_TO_ATOM(jsid id) { return (JSAtom *)JSID_TO_STRING(id); } JS_STATIC_ASSERT(sizeof(jsid) == JS_BYTES_PER_WORD); #ifdef __cplusplus namespace js { static JS_ALWAYS_INLINE Value IdToValue(jsid id) { if (JSID_IS_STRING(id)) return StringValue(JSID_TO_STRING(id)); if (JS_LIKELY(JSID_IS_INT(id))) return Int32Value(JSID_TO_INT(id)); if (JS_LIKELY(JSID_IS_OBJECT(id))) return ObjectValue(*JSID_TO_OBJECT(id)); JS_ASSERT(JSID_IS_DEFAULT_XML_NAMESPACE(id) || JSID_IS_VOID(id)); return UndefinedValue(); } static JS_ALWAYS_INLINE jsval IdToJsval(jsid id) { return IdToValue(id); } } /* namespace js */ #endif /* __cplusplus */ #endif /* jsfriendapi_h___ */