1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
2  * vim: set ts=8 sts=4 et sw=4 tw=99:
3  * This Source Code Form is subject to the terms of the Mozilla Public
4  * License, v. 2.0. If a copy of the MPL was not distributed with this
5  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 
7 #ifndef jsfriendapi_h
8 #define jsfriendapi_h
9 
10 #include "mozilla/Atomics.h"
11 #include "mozilla/Casting.h"
12 #include "mozilla/MemoryReporting.h"
13 #include "mozilla/UniquePtr.h"
14 
15 #include "jsapi.h" // For JSAutoByteString.  See bug 1033916.
16 #include "jsbytecode.h"
17 #include "jspubtd.h"
18 
19 #include "js/CallArgs.h"
20 #include "js/CallNonGenericMethod.h"
21 #include "js/Class.h"
22 
23 #if JS_STACK_GROWTH_DIRECTION > 0
24 # define JS_CHECK_STACK_SIZE(limit, sp) (MOZ_LIKELY((uintptr_t)(sp) < (limit)))
25 #else
26 # define JS_CHECK_STACK_SIZE(limit, sp) (MOZ_LIKELY((uintptr_t)(sp) > (limit)))
27 #endif
28 
29 class JSAtom;
30 struct JSErrorFormatString;
31 class JSLinearString;
32 struct JSJitInfo;
33 class JSErrorReport;
34 
35 namespace JS {
36 template <class T>
37 class Heap;
38 } /* namespace JS */
39 
40 namespace js {
41 class JS_FRIEND_API(BaseProxyHandler);
42 class InterpreterFrame;
43 } /* namespace js */
44 
45 extern JS_FRIEND_API(void)
46 JS_SetGrayGCRootsTracer(JSRuntime* rt, JSTraceDataOp traceOp, void* data);
47 
48 extern JS_FRIEND_API(JSObject*)
49 JS_FindCompilationScope(JSContext* cx, JS::HandleObject obj);
50 
51 extern JS_FRIEND_API(JSFunction*)
52 JS_GetObjectFunction(JSObject* obj);
53 
54 extern JS_FRIEND_API(bool)
55 JS_SplicePrototype(JSContext* cx, JS::HandleObject obj, JS::HandleObject proto);
56 
57 extern JS_FRIEND_API(JSObject*)
58 JS_NewObjectWithUniqueType(JSContext* cx, const JSClass* clasp, JS::HandleObject proto);
59 
60 /**
61  * Allocate an object in exactly the same way as JS_NewObjectWithGivenProto, but
62  * without invoking the metadata callback on it.  This allows creation of
63  * internal bookkeeping objects that are guaranteed to not have metadata
64  * attached to them.
65  */
66 extern JS_FRIEND_API(JSObject*)
67 JS_NewObjectWithoutMetadata(JSContext* cx, const JSClass* clasp, JS::Handle<JSObject*> proto);
68 
69 extern JS_FRIEND_API(uint32_t)
70 JS_ObjectCountDynamicSlots(JS::HandleObject obj);
71 
72 extern JS_FRIEND_API(size_t)
73 JS_SetProtoCalled(JSContext* cx);
74 
75 extern JS_FRIEND_API(bool)
76 JS_ImmutablePrototypesEnabled();
77 
78 extern JS_FRIEND_API(size_t)
79 JS_GetCustomIteratorCount(JSContext* cx);
80 
81 extern JS_FRIEND_API(bool)
82 JS_NondeterministicGetWeakMapKeys(JSContext* cx, JS::HandleObject obj, JS::MutableHandleObject ret);
83 
84 extern JS_FRIEND_API(bool)
85 JS_NondeterministicGetWeakSetKeys(JSContext* cx, JS::HandleObject obj, JS::MutableHandleObject ret);
86 
87 // Raw JSScript* because this needs to be callable from a signal handler.
88 extern JS_FRIEND_API(unsigned)
89 JS_PCToLineNumber(JSScript* script, jsbytecode* pc, unsigned* columnp = nullptr);
90 
91 /**
92  * Determine whether the given object is backed by a DeadObjectProxy.
93  *
94  * Such objects hold no other objects (they have no outgoing reference edges)
95  * and will throw if you touch them (e.g. by reading/writing a property).
96  */
97 extern JS_FRIEND_API(bool)
98 JS_IsDeadWrapper(JSObject* obj);
99 
100 /*
101  * Used by the cycle collector to trace through a shape or object group and
102  * all cycle-participating data it reaches, using bounded stack space.
103  */
104 extern JS_FRIEND_API(void)
105 JS_TraceShapeCycleCollectorChildren(JS::CallbackTracer* trc, JS::GCCellPtr shape);
106 extern JS_FRIEND_API(void)
107 JS_TraceObjectGroupCycleCollectorChildren(JS::CallbackTracer* trc, JS::GCCellPtr group);
108 
109 enum {
110     JS_TELEMETRY_GC_REASON,
111     JS_TELEMETRY_GC_IS_COMPARTMENTAL,
112     JS_TELEMETRY_GC_MS,
113     JS_TELEMETRY_GC_BUDGET_MS,
114     JS_TELEMETRY_GC_ANIMATION_MS,
115     JS_TELEMETRY_GC_MAX_PAUSE_MS,
116     JS_TELEMETRY_GC_MARK_MS,
117     JS_TELEMETRY_GC_SWEEP_MS,
118     JS_TELEMETRY_GC_MARK_ROOTS_MS,
119     JS_TELEMETRY_GC_MARK_GRAY_MS,
120     JS_TELEMETRY_GC_SLICE_MS,
121     JS_TELEMETRY_GC_SLOW_PHASE,
122     JS_TELEMETRY_GC_MMU_50,
123     JS_TELEMETRY_GC_RESET,
124     JS_TELEMETRY_GC_INCREMENTAL_DISABLED,
125     JS_TELEMETRY_GC_NON_INCREMENTAL,
126     JS_TELEMETRY_GC_SCC_SWEEP_TOTAL_MS,
127     JS_TELEMETRY_GC_SCC_SWEEP_MAX_PAUSE_MS,
128     JS_TELEMETRY_GC_MINOR_REASON,
129     JS_TELEMETRY_GC_MINOR_REASON_LONG,
130     JS_TELEMETRY_GC_MINOR_US,
131     JS_TELEMETRY_DEPRECATED_LANGUAGE_EXTENSIONS_IN_CONTENT,
132     JS_TELEMETRY_DEPRECATED_LANGUAGE_EXTENSIONS_IN_ADDONS,
133     JS_TELEMETRY_ADDON_EXCEPTIONS
134 };
135 
136 typedef void
137 (*JSAccumulateTelemetryDataCallback)(int id, uint32_t sample, const char* key);
138 
139 extern JS_FRIEND_API(void)
140 JS_SetAccumulateTelemetryCallback(JSRuntime* rt, JSAccumulateTelemetryDataCallback callback);
141 
142 extern JS_FRIEND_API(JSPrincipals*)
143 JS_GetCompartmentPrincipals(JSCompartment* compartment);
144 
145 extern JS_FRIEND_API(void)
146 JS_SetCompartmentPrincipals(JSCompartment* compartment, JSPrincipals* principals);
147 
148 extern JS_FRIEND_API(JSPrincipals*)
149 JS_GetScriptPrincipals(JSScript* script);
150 
151 extern JS_FRIEND_API(bool)
152 JS_ScriptHasMutedErrors(JSScript* script);
153 
154 extern JS_FRIEND_API(JSObject*)
155 JS_CloneObject(JSContext* cx, JS::HandleObject obj, JS::HandleObject proto);
156 
157 /**
158  * Copy the own properties of src to dst in a fast way.  src and dst must both
159  * be native and must be in the compartment of cx.  They must have the same
160  * class, the same parent, and the same prototype.  Class reserved slots will
161  * NOT be copied.
162  *
163  * dst must not have any properties on it before this function is called.
164  *
165  * src must have been allocated via JS_NewObjectWithoutMetadata so that we can
166  * be sure it has no metadata that needs copying to dst.  This also means that
167  * dst needs to have the compartment global as its parent.  This function will
168  * preserve the existing metadata on dst, if any.
169  */
170 extern JS_FRIEND_API(bool)
171 JS_InitializePropertiesFromCompatibleNativeObject(JSContext* cx,
172                                                   JS::HandleObject dst,
173                                                   JS::HandleObject src);
174 
175 extern JS_FRIEND_API(JSString*)
176 JS_BasicObjectToString(JSContext* cx, JS::HandleObject obj);
177 
178 namespace js {
179 
180 JS_FRIEND_API(bool)
181 GetBuiltinClass(JSContext* cx, JS::HandleObject obj, ESClassValue* classValue);
182 
183 JS_FRIEND_API(const char*)
184 ObjectClassName(JSContext* cx, JS::HandleObject obj);
185 
186 JS_FRIEND_API(void)
187 ReportOverRecursed(JSContext* maybecx);
188 
189 JS_FRIEND_API(bool)
190 AddRawValueRoot(JSContext* cx, JS::Value* vp, const char* name);
191 
192 JS_FRIEND_API(void)
193 RemoveRawValueRoot(JSContext* cx, JS::Value* vp);
194 
195 JS_FRIEND_API(JSAtom*)
196 GetPropertyNameFromPC(JSScript* script, jsbytecode* pc);
197 
198 #ifdef JS_DEBUG
199 
200 /*
201  * Routines to print out values during debugging.  These are FRIEND_API to help
202  * the debugger find them and to support temporarily hacking js::Dump* calls
203  * into other code.
204  */
205 
206 extern JS_FRIEND_API(void)
207 DumpString(JSString* str);
208 
209 extern JS_FRIEND_API(void)
210 DumpAtom(JSAtom* atom);
211 
212 extern JS_FRIEND_API(void)
213 DumpObject(JSObject* obj);
214 
215 extern JS_FRIEND_API(void)
216 DumpChars(const char16_t* s, size_t n);
217 
218 extern JS_FRIEND_API(void)
219 DumpValue(const JS::Value& val);
220 
221 extern JS_FRIEND_API(void)
222 DumpId(jsid id);
223 
224 extern JS_FRIEND_API(void)
225 DumpInterpreterFrame(JSContext* cx, InterpreterFrame* start = nullptr);
226 
227 extern JS_FRIEND_API(bool)
228 DumpPC(JSContext* cx);
229 
230 extern JS_FRIEND_API(bool)
231 DumpScript(JSContext* cx, JSScript* scriptArg);
232 
233 #endif
234 
235 extern JS_FRIEND_API(void)
236 DumpBacktrace(JSContext* cx);
237 
238 } // namespace js
239 
240 namespace JS {
241 
242 /** Exposed for DumpJSStack */
243 extern JS_FRIEND_API(char*)
244 FormatStackDump(JSContext* cx, char* buf, bool showArgs, bool showLocals, bool showThisProps);
245 
246 } // namespace JS
247 
248 /**
249  * Copies all own properties from |obj| to |target|. |obj| must be a "native"
250  * object (that is to say, normal-ish - not an Array or a Proxy).
251  *
252  * This function immediately enters a compartment, and does not impose any
253  * restrictions on the compartment of |cx|.
254  */
255 extern JS_FRIEND_API(bool)
256 JS_CopyPropertiesFrom(JSContext* cx, JS::HandleObject target, JS::HandleObject obj);
257 
258 /*
259  * Single-property version of the above. This function asserts that an |own|
260  * property of the given name exists on |obj|.
261  *
262  * On entry, |cx| must be same-compartment with |obj|.
263  *
264  * The copyBehavior argument controls what happens with
265  * non-configurable properties.
266  */
267 typedef enum  {
268     MakeNonConfigurableIntoConfigurable,
269     CopyNonConfigurableAsIs
270 } PropertyCopyBehavior;
271 
272 extern JS_FRIEND_API(bool)
273 JS_CopyPropertyFrom(JSContext* cx, JS::HandleId id, JS::HandleObject target,
274                     JS::HandleObject obj,
275                     PropertyCopyBehavior copyBehavior = CopyNonConfigurableAsIs);
276 
277 extern JS_FRIEND_API(bool)
278 JS_WrapPropertyDescriptor(JSContext* cx, JS::MutableHandle<JSPropertyDescriptor> desc);
279 
280 struct JSFunctionSpecWithHelp {
281     const char*     name;
282     JSNative        call;
283     uint16_t        nargs;
284     uint16_t        flags;
285     const JSJitInfo* jitInfo;
286     const char*     usage;
287     const char*     help;
288 };
289 
290 #define JS_FN_HELP(name,call,nargs,flags,usage,help)                          \
291     {name, call, nargs, (flags) | JSPROP_ENUMERATE | JSFUN_STUB_GSOPS, nullptr, usage, help}
292 #define JS_INLINABLE_FN_HELP(name,call,nargs,flags,native,usage,help)         \
293     {name, call, nargs, (flags) | JSPROP_ENUMERATE | JSFUN_STUB_GSOPS, &js::jit::JitInfo_##native,\
294      usage, help}
295 #define JS_FS_HELP_END                                                        \
296     {nullptr, nullptr, 0, 0, nullptr, nullptr}
297 
298 extern JS_FRIEND_API(bool)
299 JS_DefineFunctionsWithHelp(JSContext* cx, JS::HandleObject obj, const JSFunctionSpecWithHelp* fs);
300 
301 namespace js {
302 
303 /*
304  * Helper Macros for creating JSClasses that function as proxies.
305  *
306  * NB: The macro invocation must be surrounded by braces, so as to
307  *     allow for potential JSClass extensions.
308  */
309 #define PROXY_MAKE_EXT(isWrappedNative, objectMoved)                    \
310     {                                                                   \
311         isWrappedNative,                                                \
312         js::proxy_WeakmapKeyDelegate,                                   \
313         objectMoved                                                     \
314     }
315 
316 #define PROXY_CLASS_WITH_EXT(name, flags, ext)                                          \
317     {                                                                                   \
318         name,                                                                           \
319         js::Class::NON_NATIVE |                                                         \
320             JSCLASS_IS_PROXY |                                                          \
321             JSCLASS_DELAY_METADATA_CALLBACK |                                           \
322             flags,                                                                      \
323         nullptr,                 /* addProperty */                                      \
324         nullptr,                 /* delProperty */                                      \
325         nullptr,                 /* getProperty */                                      \
326         nullptr,                 /* setProperty */                                      \
327         nullptr,                 /* enumerate */                                        \
328         nullptr,                 /* resolve */                                          \
329         nullptr,                 /* mayResolve */                                       \
330         js::proxy_Finalize,      /* finalize    */                                      \
331         nullptr,                 /* call        */                                      \
332         js::proxy_HasInstance,   /* hasInstance */                                      \
333         nullptr,                 /* construct   */                                      \
334         js::proxy_Trace,         /* trace       */                                      \
335         JS_NULL_CLASS_SPEC,                                                             \
336         ext,                                                                            \
337         {                                                                               \
338             js::proxy_LookupProperty,                                                   \
339             js::proxy_DefineProperty,                                                   \
340             js::proxy_HasProperty,                                                      \
341             js::proxy_GetProperty,                                                      \
342             js::proxy_SetProperty,                                                      \
343             js::proxy_GetOwnPropertyDescriptor,                                         \
344             js::proxy_DeleteProperty,                                                   \
345             js::proxy_Watch, js::proxy_Unwatch,                                         \
346             js::proxy_GetElements,                                                      \
347             nullptr,             /* enumerate       */                                  \
348             js::proxy_FunToString,                                                      \
349         }                                                                               \
350     }
351 
352 #define PROXY_CLASS_DEF(name, flags)                                    \
353   PROXY_CLASS_WITH_EXT(name, flags,                                     \
354                        PROXY_MAKE_EXT(                                  \
355                          false,   /* isWrappedNative */                 \
356                          js::proxy_ObjectMoved                          \
357                        ))
358 
359 /*
360  * Proxy stubs, similar to JS_*Stub, for embedder proxy class definitions.
361  *
362  * NB: Should not be called directly.
363  */
364 
365 extern JS_FRIEND_API(bool)
366 proxy_LookupProperty(JSContext* cx, JS::HandleObject obj, JS::HandleId id, JS::MutableHandleObject objp,
367                     JS::MutableHandle<Shape*> propp);
368 extern JS_FRIEND_API(bool)
369 proxy_DefineProperty(JSContext* cx, JS::HandleObject obj, JS::HandleId id,
370                      JS::Handle<JSPropertyDescriptor> desc,
371                      JS::ObjectOpResult& result);
372 extern JS_FRIEND_API(bool)
373 proxy_HasProperty(JSContext* cx, JS::HandleObject obj, JS::HandleId id, bool* foundp);
374 extern JS_FRIEND_API(bool)
375 proxy_GetProperty(JSContext* cx, JS::HandleObject obj, JS::HandleValue receiver, JS::HandleId id,
376                   JS::MutableHandleValue vp);
377 extern JS_FRIEND_API(bool)
378 proxy_SetProperty(JSContext* cx, JS::HandleObject obj, JS::HandleId id, JS::HandleValue bp,
379                   JS::HandleValue receiver, JS::ObjectOpResult& result);
380 extern JS_FRIEND_API(bool)
381 proxy_GetOwnPropertyDescriptor(JSContext* cx, JS::HandleObject obj, JS::HandleId id,
382                                JS::MutableHandle<JSPropertyDescriptor> desc);
383 extern JS_FRIEND_API(bool)
384 proxy_DeleteProperty(JSContext* cx, JS::HandleObject obj, JS::HandleId id,
385                      JS::ObjectOpResult& result);
386 
387 extern JS_FRIEND_API(void)
388 proxy_Trace(JSTracer* trc, JSObject* obj);
389 extern JS_FRIEND_API(JSObject*)
390 proxy_WeakmapKeyDelegate(JSObject* obj);
391 extern JS_FRIEND_API(bool)
392 proxy_Convert(JSContext* cx, JS::HandleObject proxy, JSType hint, JS::MutableHandleValue vp);
393 extern JS_FRIEND_API(void)
394 proxy_Finalize(FreeOp* fop, JSObject* obj);
395 extern JS_FRIEND_API(void)
396 proxy_ObjectMoved(JSObject* obj, const JSObject* old);
397 extern JS_FRIEND_API(bool)
398 proxy_HasInstance(JSContext* cx, JS::HandleObject proxy, JS::MutableHandleValue v, bool* bp);
399 extern JS_FRIEND_API(bool)
400 proxy_Call(JSContext* cx, unsigned argc, JS::Value* vp);
401 extern JS_FRIEND_API(bool)
402 proxy_Construct(JSContext* cx, unsigned argc, JS::Value* vp);
403 extern JS_FRIEND_API(JSObject*)
404 proxy_innerObject(JSObject* obj);
405 extern JS_FRIEND_API(bool)
406 proxy_Watch(JSContext* cx, JS::HandleObject obj, JS::HandleId id, JS::HandleObject callable);
407 extern JS_FRIEND_API(bool)
408 proxy_Unwatch(JSContext* cx, JS::HandleObject obj, JS::HandleId id);
409 extern JS_FRIEND_API(bool)
410 proxy_GetElements(JSContext* cx, JS::HandleObject proxy, uint32_t begin, uint32_t end,
411                   ElementAdder* adder);
412 extern JS_FRIEND_API(JSString*)
413 proxy_FunToString(JSContext* cx, JS::HandleObject proxy, unsigned indent);
414 
415 /**
416  * A class of objects that return source code on demand.
417  *
418  * When code is compiled with setSourceIsLazy(true), SpiderMonkey doesn't
419  * retain the source code (and doesn't do lazy bytecode generation). If we ever
420  * need the source code, say, in response to a call to Function.prototype.
421  * toSource or Debugger.Source.prototype.text, then we call the 'load' member
422  * function of the instance of this class that has hopefully been registered
423  * with the runtime, passing the code's URL, and hope that it will be able to
424  * find the source.
425  */
426 class SourceHook {
427   public:
~SourceHook()428     virtual ~SourceHook() { }
429 
430     /**
431      * Set |*src| and |*length| to refer to the source code for |filename|.
432      * On success, the caller owns the buffer to which |*src| points, and
433      * should use JS_free to free it.
434      */
435     virtual bool load(JSContext* cx, const char* filename, char16_t** src, size_t* length) = 0;
436 };
437 
438 /**
439  * Have |rt| use |hook| to retrieve lazily-retrieved source code. See the
440  * comments for SourceHook. The runtime takes ownership of the hook, and
441  * will delete it when the runtime itself is deleted, or when a new hook is
442  * set.
443  */
444 extern JS_FRIEND_API(void)
445 SetSourceHook(JSRuntime* rt, mozilla::UniquePtr<SourceHook> hook);
446 
447 /** Remove |rt|'s source hook, and return it. The caller now owns the hook. */
448 extern JS_FRIEND_API(mozilla::UniquePtr<SourceHook>)
449 ForgetSourceHook(JSRuntime* rt);
450 
451 extern JS_FRIEND_API(JS::Zone*)
452 GetCompartmentZone(JSCompartment* comp);
453 
454 typedef bool
455 (* PreserveWrapperCallback)(JSContext* cx, JSObject* obj);
456 
457 typedef enum  {
458     CollectNurseryBeforeDump,
459     IgnoreNurseryObjects
460 } DumpHeapNurseryBehaviour;
461 
462  /**
463   * Dump the complete object graph of heap-allocated things.
464   * fp is the file for the dump output.
465   */
466 extern JS_FRIEND_API(void)
467 DumpHeap(JSRuntime* rt, FILE* fp, DumpHeapNurseryBehaviour nurseryBehaviour);
468 
469 #ifdef JS_OLD_GETTER_SETTER_METHODS
470 JS_FRIEND_API(bool) obj_defineGetter(JSContext* cx, unsigned argc, JS::Value* vp);
471 JS_FRIEND_API(bool) obj_defineSetter(JSContext* cx, unsigned argc, JS::Value* vp);
472 #endif
473 
474 extern JS_FRIEND_API(bool)
475 IsSystemCompartment(JSCompartment* comp);
476 
477 extern JS_FRIEND_API(bool)
478 IsSystemZone(JS::Zone* zone);
479 
480 extern JS_FRIEND_API(bool)
481 IsAtomsCompartment(JSCompartment* comp);
482 
483 extern JS_FRIEND_API(bool)
484 IsAtomsZone(JS::Zone* zone);
485 
486 struct WeakMapTracer
487 {
488     JSRuntime* runtime;
489 
WeakMapTracerWeakMapTracer490     explicit WeakMapTracer(JSRuntime* rt) : runtime(rt) {}
491 
492     // Weak map tracer callback, called once for every binding of every
493     // weak map that was live at the time of the last garbage collection.
494     //
495     // m will be nullptr if the weak map is not contained in a JS Object.
496     //
497     // The callback should not GC (and will assert in a debug build if it does so.)
498     virtual void trace(JSObject* m, JS::GCCellPtr key, JS::GCCellPtr value) = 0;
499 };
500 
501 extern JS_FRIEND_API(void)
502 TraceWeakMaps(WeakMapTracer* trc);
503 
504 extern JS_FRIEND_API(bool)
505 AreGCGrayBitsValid(JSRuntime* rt);
506 
507 extern JS_FRIEND_API(bool)
508 ZoneGlobalsAreAllGray(JS::Zone* zone);
509 
510 typedef void
511 (*GCThingCallback)(void* closure, JS::GCCellPtr thing);
512 
513 extern JS_FRIEND_API(void)
514 VisitGrayWrapperTargets(JS::Zone* zone, GCThingCallback callback, void* closure);
515 
516 extern JS_FRIEND_API(JSObject*)
517 GetWeakmapKeyDelegate(JSObject* key);
518 
519 JS_FRIEND_API(JS::TraceKind)
520 GCThingTraceKind(void* thing);
521 
522 /**
523  * Invoke cellCallback on every gray JS_OBJECT in the given zone.
524  */
525 extern JS_FRIEND_API(void)
526 IterateGrayObjects(JS::Zone* zone, GCThingCallback cellCallback, void* data);
527 
528 #ifdef JS_HAS_CTYPES
529 extern JS_FRIEND_API(size_t)
530 SizeOfDataIfCDataObject(mozilla::MallocSizeOf mallocSizeOf, JSObject* obj);
531 #endif
532 
533 extern JS_FRIEND_API(JSCompartment*)
534 GetAnyCompartmentInZone(JS::Zone* zone);
535 
536 /*
537  * Shadow declarations of JS internal structures, for access by inline access
538  * functions below. Do not use these structures in any other way. When adding
539  * new fields for access by inline methods, make sure to add static asserts to
540  * the original header file to ensure that offsets are consistent.
541  */
542 namespace shadow {
543 
544 struct ObjectGroup {
545     const Class* clasp;
546     JSObject*   proto;
547     JSCompartment* compartment;
548 };
549 
550 struct BaseShape {
551     const js::Class* clasp_;
552     JSObject* parent;
553 };
554 
555 class Shape {
556 public:
557     shadow::BaseShape* base;
558     jsid              _1;
559     uint32_t          slotInfo;
560 
561     static const uint32_t FIXED_SLOTS_SHIFT = 27;
562 };
563 
564 /**
565  * This layout is shared by all native objects. For non-native objects, the
566  * group may always be accessed safely, and other members may be as well,
567  * depending on the object's specific layout.
568  */
569 struct Object {
570     shadow::ObjectGroup* group;
571     shadow::Shape*      shape;
572     JS::Value*          slots;
573     void*               _1;
574 
numFixedSlotsObject575     size_t numFixedSlots() const { return shape->slotInfo >> Shape::FIXED_SLOTS_SHIFT; }
fixedSlotsObject576     JS::Value* fixedSlots() const {
577         return (JS::Value*)(uintptr_t(this) + sizeof(shadow::Object));
578     }
579 
slotRefObject580     JS::Value& slotRef(size_t slot) const {
581         size_t nfixed = numFixedSlots();
582         if (slot < nfixed)
583             return fixedSlots()[slot];
584         return slots[slot - nfixed];
585     }
586 };
587 
588 struct Function {
589     Object base;
590     uint16_t nargs;
591     uint16_t flags;
592     /* Used only for natives */
593     JSNative native;
594     const JSJitInfo* jitinfo;
595     void* _1;
596 };
597 
598 struct String
599 {
600     static const uint32_t INLINE_CHARS_BIT = JS_BIT(2);
601     static const uint32_t LATIN1_CHARS_BIT = JS_BIT(6);
602     static const uint32_t ROPE_FLAGS       = 0;
603     static const uint32_t TYPE_FLAGS_MASK  = JS_BIT(6) - 1;
604     uint32_t flags;
605     uint32_t length;
606     union {
607         const JS::Latin1Char* nonInlineCharsLatin1;
608         const char16_t* nonInlineCharsTwoByte;
609         JS::Latin1Char inlineStorageLatin1[1];
610         char16_t inlineStorageTwoByte[1];
611     };
612 };
613 
614 } /* namespace shadow */
615 
616 // This is equal to |&JSObject::class_|.  Use it in places where you don't want
617 // to #include jsobj.h.
618 extern JS_FRIEND_DATA(const js::Class* const) ObjectClassPtr;
619 
620 inline const js::Class*
GetObjectClass(const JSObject * obj)621 GetObjectClass(const JSObject* obj)
622 {
623     return reinterpret_cast<const shadow::Object*>(obj)->group->clasp;
624 }
625 
626 inline const JSClass*
GetObjectJSClass(JSObject * obj)627 GetObjectJSClass(JSObject* obj)
628 {
629     return js::Jsvalify(GetObjectClass(obj));
630 }
631 
632 JS_FRIEND_API(const Class*)
633 ProtoKeyToClass(JSProtoKey key);
634 
635 // Returns true if the standard class identified by |key| inherits from
636 // another standard class (in addition to Object) along its proto chain.
637 //
638 // In practice, this only returns true for Error subtypes.
639 inline bool
StandardClassIsDependent(JSProtoKey key)640 StandardClassIsDependent(JSProtoKey key)
641 {
642     const Class* clasp = ProtoKeyToClass(key);
643     return clasp && clasp->spec.defined() && clasp->spec.dependent();
644 }
645 
646 // Returns the key for the class inherited by a given standard class (that
647 // is to say, the prototype of this standard class's prototype).
648 //
649 // You must be sure that this corresponds to a standard class with a cached
650 // JSProtoKey before calling this function. In general |key| will match the
651 // cached proto key, except in cases where multiple JSProtoKeys share a
652 // JSClass.
653 inline JSProtoKey
ParentKeyForStandardClass(JSProtoKey key)654 ParentKeyForStandardClass(JSProtoKey key)
655 {
656     // [Object] has nothing to inherit from.
657     if (key == JSProto_Object)
658         return JSProto_Null;
659 
660     // If we're dependent, return the key of the class we depend on.
661     if (StandardClassIsDependent(key))
662         return ProtoKeyToClass(key)->spec.parentKey();
663 
664     // Otherwise, we inherit [Object].
665     return JSProto_Object;
666 }
667 
668 JS_FRIEND_API(bool)
669 IsFunctionObject(JSObject* obj);
670 
671 static MOZ_ALWAYS_INLINE JSCompartment*
GetObjectCompartment(JSObject * obj)672 GetObjectCompartment(JSObject* obj)
673 {
674     return reinterpret_cast<shadow::Object*>(obj)->group->compartment;
675 }
676 
677 JS_FRIEND_API(JSObject*)
678 GetGlobalForObjectCrossCompartment(JSObject* obj);
679 
680 JS_FRIEND_API(JSObject*)
681 GetPrototypeNoProxy(JSObject* obj);
682 
683 JS_FRIEND_API(void)
684 AssertSameCompartment(JSContext* cx, JSObject* obj);
685 
686 #ifdef JS_DEBUG
687 JS_FRIEND_API(void)
688 AssertSameCompartment(JSObject* objA, JSObject* objB);
689 #else
AssertSameCompartment(JSObject * objA,JSObject * objB)690 inline void AssertSameCompartment(JSObject* objA, JSObject* objB) {}
691 #endif
692 
693 JS_FRIEND_API(void)
694 NotifyAnimationActivity(JSObject* obj);
695 
696 /**
697  * Return the outermost enclosing function (script) of the scripted caller.
698  * This function returns nullptr in several cases:
699  *  - no script is running on the context
700  *  - the caller is in global or eval code
701  * In particular, this function will "stop" its outermost search at eval() and
702  * thus it will really return the outermost enclosing function *since the
703  * innermost eval*.
704  */
705 JS_FRIEND_API(JSFunction*)
706 GetOutermostEnclosingFunctionOfScriptedCaller(JSContext* cx);
707 
708 JS_FRIEND_API(JSFunction*)
709 DefineFunctionWithReserved(JSContext* cx, JSObject* obj, const char* name, JSNative call,
710                            unsigned nargs, unsigned attrs);
711 
712 JS_FRIEND_API(JSFunction*)
713 NewFunctionWithReserved(JSContext* cx, JSNative call, unsigned nargs, unsigned flags,
714                         const char* name);
715 
716 JS_FRIEND_API(JSFunction*)
717 NewFunctionByIdWithReserved(JSContext* cx, JSNative native, unsigned nargs, unsigned flags,
718                             jsid id);
719 
720 JS_FRIEND_API(const JS::Value&)
721 GetFunctionNativeReserved(JSObject* fun, size_t which);
722 
723 JS_FRIEND_API(void)
724 SetFunctionNativeReserved(JSObject* fun, size_t which, const JS::Value& val);
725 
726 JS_FRIEND_API(bool)
727 FunctionHasNativeReserved(JSObject* fun);
728 
729 JS_FRIEND_API(bool)
730 GetObjectProto(JSContext* cx, JS::HandleObject obj, JS::MutableHandleObject proto);
731 
732 JS_FRIEND_API(bool)
733 GetOriginalEval(JSContext* cx, JS::HandleObject scope,
734                 JS::MutableHandleObject eval);
735 
736 inline void*
GetObjectPrivate(JSObject * obj)737 GetObjectPrivate(JSObject* obj)
738 {
739     MOZ_ASSERT(GetObjectClass(obj)->flags & JSCLASS_HAS_PRIVATE);
740     const shadow::Object* nobj = reinterpret_cast<const shadow::Object*>(obj);
741     void** addr = reinterpret_cast<void**>(&nobj->fixedSlots()[nobj->numFixedSlots()]);
742     return *addr;
743 }
744 
745 inline const JS::Value&
GetReservedSlot(JSObject * obj,size_t slot)746 GetReservedSlot(JSObject* obj, size_t slot)
747 {
748     MOZ_ASSERT(slot < JSCLASS_RESERVED_SLOTS(GetObjectClass(obj)));
749     return reinterpret_cast<const shadow::Object*>(obj)->slotRef(slot);
750 }
751 
752 JS_FRIEND_API(void)
753 SetReservedOrProxyPrivateSlotWithBarrier(JSObject* obj, size_t slot, const JS::Value& value);
754 
755 inline void
SetReservedSlot(JSObject * obj,size_t slot,const JS::Value & value)756 SetReservedSlot(JSObject* obj, size_t slot, const JS::Value& value)
757 {
758     MOZ_ASSERT(slot < JSCLASS_RESERVED_SLOTS(GetObjectClass(obj)));
759     shadow::Object* sobj = reinterpret_cast<shadow::Object*>(obj);
760     if (sobj->slotRef(slot).isMarkable() || value.isMarkable())
761         SetReservedOrProxyPrivateSlotWithBarrier(obj, slot, value);
762     else
763         sobj->slotRef(slot) = value;
764 }
765 
766 JS_FRIEND_API(uint32_t)
767 GetObjectSlotSpan(JSObject* obj);
768 
769 inline const JS::Value&
GetObjectSlot(JSObject * obj,size_t slot)770 GetObjectSlot(JSObject* obj, size_t slot)
771 {
772     MOZ_ASSERT(slot < GetObjectSlotSpan(obj));
773     return reinterpret_cast<const shadow::Object*>(obj)->slotRef(slot);
774 }
775 
776 MOZ_ALWAYS_INLINE size_t
GetAtomLength(JSAtom * atom)777 GetAtomLength(JSAtom* atom)
778 {
779     return reinterpret_cast<shadow::String*>(atom)->length;
780 }
781 
782 static const uint32_t MaxStringLength = (1 << 28) - 1;
783 
784 MOZ_ALWAYS_INLINE size_t
GetStringLength(JSString * s)785 GetStringLength(JSString* s)
786 {
787     return reinterpret_cast<shadow::String*>(s)->length;
788 }
789 
790 MOZ_ALWAYS_INLINE size_t
GetFlatStringLength(JSFlatString * s)791 GetFlatStringLength(JSFlatString* s)
792 {
793     return reinterpret_cast<shadow::String*>(s)->length;
794 }
795 
796 MOZ_ALWAYS_INLINE size_t
GetLinearStringLength(JSLinearString * s)797 GetLinearStringLength(JSLinearString* s)
798 {
799     return reinterpret_cast<shadow::String*>(s)->length;
800 }
801 
802 MOZ_ALWAYS_INLINE bool
LinearStringHasLatin1Chars(JSLinearString * s)803 LinearStringHasLatin1Chars(JSLinearString* s)
804 {
805     return reinterpret_cast<shadow::String*>(s)->flags & shadow::String::LATIN1_CHARS_BIT;
806 }
807 
808 MOZ_ALWAYS_INLINE bool
AtomHasLatin1Chars(JSAtom * atom)809 AtomHasLatin1Chars(JSAtom* atom)
810 {
811     return reinterpret_cast<shadow::String*>(atom)->flags & shadow::String::LATIN1_CHARS_BIT;
812 }
813 
814 MOZ_ALWAYS_INLINE bool
StringHasLatin1Chars(JSString * s)815 StringHasLatin1Chars(JSString* s)
816 {
817     return reinterpret_cast<shadow::String*>(s)->flags & shadow::String::LATIN1_CHARS_BIT;
818 }
819 
820 MOZ_ALWAYS_INLINE const JS::Latin1Char*
GetLatin1LinearStringChars(const JS::AutoCheckCannotGC & nogc,JSLinearString * linear)821 GetLatin1LinearStringChars(const JS::AutoCheckCannotGC& nogc, JSLinearString* linear)
822 {
823     MOZ_ASSERT(LinearStringHasLatin1Chars(linear));
824 
825     using shadow::String;
826     String* s = reinterpret_cast<String*>(linear);
827     if (s->flags & String::INLINE_CHARS_BIT)
828         return s->inlineStorageLatin1;
829     return s->nonInlineCharsLatin1;
830 }
831 
832 MOZ_ALWAYS_INLINE const char16_t*
GetTwoByteLinearStringChars(const JS::AutoCheckCannotGC & nogc,JSLinearString * linear)833 GetTwoByteLinearStringChars(const JS::AutoCheckCannotGC& nogc, JSLinearString* linear)
834 {
835     MOZ_ASSERT(!LinearStringHasLatin1Chars(linear));
836 
837     using shadow::String;
838     String* s = reinterpret_cast<String*>(linear);
839     if (s->flags & String::INLINE_CHARS_BIT)
840         return s->inlineStorageTwoByte;
841     return s->nonInlineCharsTwoByte;
842 }
843 
844 MOZ_ALWAYS_INLINE JSLinearString*
AtomToLinearString(JSAtom * atom)845 AtomToLinearString(JSAtom* atom)
846 {
847     return reinterpret_cast<JSLinearString*>(atom);
848 }
849 
850 MOZ_ALWAYS_INLINE JSFlatString*
AtomToFlatString(JSAtom * atom)851 AtomToFlatString(JSAtom* atom)
852 {
853     return reinterpret_cast<JSFlatString*>(atom);
854 }
855 
856 MOZ_ALWAYS_INLINE JSLinearString*
FlatStringToLinearString(JSFlatString * s)857 FlatStringToLinearString(JSFlatString* s)
858 {
859     return reinterpret_cast<JSLinearString*>(s);
860 }
861 
862 MOZ_ALWAYS_INLINE const JS::Latin1Char*
GetLatin1AtomChars(const JS::AutoCheckCannotGC & nogc,JSAtom * atom)863 GetLatin1AtomChars(const JS::AutoCheckCannotGC& nogc, JSAtom* atom)
864 {
865     return GetLatin1LinearStringChars(nogc, AtomToLinearString(atom));
866 }
867 
868 MOZ_ALWAYS_INLINE const char16_t*
GetTwoByteAtomChars(const JS::AutoCheckCannotGC & nogc,JSAtom * atom)869 GetTwoByteAtomChars(const JS::AutoCheckCannotGC& nogc, JSAtom* atom)
870 {
871     return GetTwoByteLinearStringChars(nogc, AtomToLinearString(atom));
872 }
873 
874 JS_FRIEND_API(JSLinearString*)
875 StringToLinearStringSlow(JSContext* cx, JSString* str);
876 
877 MOZ_ALWAYS_INLINE JSLinearString*
StringToLinearString(JSContext * cx,JSString * str)878 StringToLinearString(JSContext* cx, JSString* str)
879 {
880     using shadow::String;
881     String* s = reinterpret_cast<String*>(str);
882     if (MOZ_UNLIKELY((s->flags & String::TYPE_FLAGS_MASK) == String::ROPE_FLAGS))
883         return StringToLinearStringSlow(cx, str);
884     return reinterpret_cast<JSLinearString*>(str);
885 }
886 
887 MOZ_ALWAYS_INLINE void
CopyLinearStringChars(char16_t * dest,JSLinearString * s,size_t len)888 CopyLinearStringChars(char16_t* dest, JSLinearString* s, size_t len)
889 {
890     JS::AutoCheckCannotGC nogc;
891     if (LinearStringHasLatin1Chars(s)) {
892         const JS::Latin1Char* src = GetLatin1LinearStringChars(nogc, s);
893         for (size_t i = 0; i < len; i++)
894             dest[i] = src[i];
895     } else {
896         const char16_t* src = GetTwoByteLinearStringChars(nogc, s);
897         mozilla::PodCopy(dest, src, len);
898     }
899 }
900 
901 inline bool
CopyStringChars(JSContext * cx,char16_t * dest,JSString * s,size_t len)902 CopyStringChars(JSContext* cx, char16_t* dest, JSString* s, size_t len)
903 {
904     JSLinearString* linear = StringToLinearString(cx, s);
905     if (!linear)
906         return false;
907 
908     CopyLinearStringChars(dest, linear, len);
909     return true;
910 }
911 
912 inline void
CopyFlatStringChars(char16_t * dest,JSFlatString * s,size_t len)913 CopyFlatStringChars(char16_t* dest, JSFlatString* s, size_t len)
914 {
915     CopyLinearStringChars(dest, FlatStringToLinearString(s), len);
916 }
917 
918 /**
919  * Add some or all property keys of obj to the id vector *props.
920  *
921  * The flags parameter controls which property keys are added. Pass a
922  * combination of the following bits:
923  *
924  *     JSITER_OWNONLY - Don't also search the prototype chain; only consider
925  *       obj's own properties.
926  *
927  *     JSITER_HIDDEN - Include nonenumerable properties.
928  *
929  *     JSITER_SYMBOLS - Include property keys that are symbols. The default
930  *       behavior is to filter out symbols.
931  *
932  *     JSITER_SYMBOLSONLY - Exclude non-symbol property keys.
933  *
934  * This is the closest C++ API we have to `Reflect.ownKeys(obj)`, or
935  * equivalently, the ES6 [[OwnPropertyKeys]] internal method. Pass
936  * `JSITER_OWNONLY | JSITER_HIDDEN | JSITER_SYMBOLS` as flags to get
937  * results that match the output of Reflect.ownKeys.
938  */
939 JS_FRIEND_API(bool)
940 GetPropertyKeys(JSContext* cx, JS::HandleObject obj, unsigned flags, JS::AutoIdVector* props);
941 
942 JS_FRIEND_API(bool)
943 AppendUnique(JSContext* cx, JS::AutoIdVector& base, JS::AutoIdVector& others);
944 
945 JS_FRIEND_API(bool)
946 StringIsArrayIndex(JSLinearString* str, uint32_t* indexp);
947 
948 JS_FRIEND_API(void)
949 SetPreserveWrapperCallback(JSRuntime* rt, PreserveWrapperCallback callback);
950 
951 JS_FRIEND_API(bool)
952 IsObjectInContextCompartment(JSObject* obj, const JSContext* cx);
953 
954 /*
955  * NB: these flag bits are encoded into the bytecode stream in the immediate
956  * operand of JSOP_ITER, so don't change them without advancing vm/Xdr.h's
957  * XDR_BYTECODE_VERSION.
958  * NB: keep these in sync with the copy in builtin/SelfHostingDefines.h.
959  * The first three are omitted because they shouldn't be used in new code.
960  */
961 #define JSITER_ENUMERATE  0x1   /* for-in compatible hidden default iterator */
962 #define JSITER_FOREACH    0x2   /* get obj[key] for each property */
963 #define JSITER_KEYVALUE   0x4   /* obsolete destructuring for-in wants [key, value] */
964 #define JSITER_OWNONLY    0x8   /* iterate over obj's own properties only */
965 #define JSITER_HIDDEN     0x10  /* also enumerate non-enumerable properties */
966 #define JSITER_SYMBOLS    0x20  /* also include symbol property keys */
967 #define JSITER_SYMBOLSONLY 0x40 /* exclude string property keys */
968 
969 JS_FRIEND_API(bool)
970 RunningWithTrustedPrincipals(JSContext* cx);
971 
972 inline uintptr_t
973 GetNativeStackLimit(JSContext* cx, StackKind kind, int extraAllowance = 0)
974 {
975     PerThreadDataFriendFields* mainThread =
976       PerThreadDataFriendFields::getMainThread(GetRuntime(cx));
977     uintptr_t limit = mainThread->nativeStackLimit[kind];
978 #if JS_STACK_GROWTH_DIRECTION > 0
979     limit += extraAllowance;
980 #else
981     limit -= extraAllowance;
982 #endif
983     return limit;
984 }
985 
986 inline uintptr_t
987 GetNativeStackLimit(JSContext* cx, int extraAllowance = 0)
988 {
989     StackKind kind = RunningWithTrustedPrincipals(cx) ? StackForTrustedScript
990                                                       : StackForUntrustedScript;
991     return GetNativeStackLimit(cx, kind, extraAllowance);
992 }
993 
994 /*
995  * These macros report a stack overflow and run |onerror| if we are close to
996  * using up the C stack. The JS_CHECK_CHROME_RECURSION variant gives us a
997  * little extra space so that we can ensure that crucial code is able to run.
998  * JS_CHECK_RECURSION_CONSERVATIVE allows less space than any other check,
999  * including a safety buffer (as in, it uses the untrusted limit and subtracts
1000  * a little more from it).
1001  */
1002 
1003 #define JS_CHECK_RECURSION_LIMIT(cx, limit, onerror)                            \
1004     JS_BEGIN_MACRO                                                              \
1005         int stackDummy_;                                                        \
1006         if (!JS_CHECK_STACK_SIZE(limit, &stackDummy_)) {                        \
1007             js::ReportOverRecursed(cx);                                         \
1008             onerror;                                                            \
1009         }                                                                       \
1010     JS_END_MACRO
1011 
1012 #define JS_CHECK_RECURSION(cx, onerror)                                         \
1013     JS_CHECK_RECURSION_LIMIT(cx, js::GetNativeStackLimit(cx), onerror)
1014 
1015 #define JS_CHECK_RECURSION_LIMIT_DONT_REPORT(cx, limit, onerror)                \
1016     JS_BEGIN_MACRO                                                              \
1017         int stackDummy_;                                                        \
1018         if (!JS_CHECK_STACK_SIZE(limit, &stackDummy_)) {                        \
1019             onerror;                                                            \
1020         }                                                                       \
1021     JS_END_MACRO
1022 
1023 #define JS_CHECK_RECURSION_DONT_REPORT(cx, onerror)                             \
1024     JS_CHECK_RECURSION_LIMIT_DONT_REPORT(cx, js::GetNativeStackLimit(cx), onerror)
1025 
1026 #define JS_CHECK_RECURSION_WITH_SP_DONT_REPORT(cx, sp, onerror)                 \
1027     JS_BEGIN_MACRO                                                              \
1028         if (!JS_CHECK_STACK_SIZE(js::GetNativeStackLimit(cx), sp)) {            \
1029             onerror;                                                            \
1030         }                                                                       \
1031     JS_END_MACRO
1032 
1033 #define JS_CHECK_RECURSION_WITH_SP(cx, sp, onerror)                             \
1034     JS_BEGIN_MACRO                                                              \
1035         if (!JS_CHECK_STACK_SIZE(js::GetNativeStackLimit(cx), sp)) {            \
1036             js::ReportOverRecursed(cx);                                         \
1037             onerror;                                                            \
1038         }                                                                       \
1039     JS_END_MACRO
1040 
1041 #define JS_CHECK_SYSTEM_RECURSION(cx, onerror)                                  \
1042     JS_CHECK_RECURSION_LIMIT(cx, js::GetNativeStackLimit(cx, js::StackForSystemCode), onerror)
1043 
1044 #define JS_CHECK_RECURSION_CONSERVATIVE(cx, onerror)                            \
1045     JS_CHECK_RECURSION_LIMIT(cx,                                                \
1046                              js::GetNativeStackLimit(cx, js::StackForUntrustedScript, -1024 * int(sizeof(size_t))), \
1047                              onerror)
1048 
1049 #define JS_CHECK_RECURSION_CONSERVATIVE_DONT_REPORT(cx, onerror)                \
1050     JS_CHECK_RECURSION_LIMIT_DONT_REPORT(cx,                                    \
1051                                          js::GetNativeStackLimit(cx, js::StackForUntrustedScript, -1024 * int(sizeof(size_t))), \
1052                                          onerror)
1053 
1054 JS_FRIEND_API(void)
1055 StartPCCountProfiling(JSContext* cx);
1056 
1057 JS_FRIEND_API(void)
1058 StopPCCountProfiling(JSContext* cx);
1059 
1060 JS_FRIEND_API(void)
1061 PurgePCCounts(JSContext* cx);
1062 
1063 JS_FRIEND_API(size_t)
1064 GetPCCountScriptCount(JSContext* cx);
1065 
1066 JS_FRIEND_API(JSString*)
1067 GetPCCountScriptSummary(JSContext* cx, size_t script);
1068 
1069 JS_FRIEND_API(JSString*)
1070 GetPCCountScriptContents(JSContext* cx, size_t script);
1071 
1072 /**
1073  * Generate lcov trace file content for the current compartment, and allocate a
1074  * new buffer and return the content in it, the size of the newly allocated
1075  * content within the buffer would be set to the length out-param.
1076  *
1077  * In case of out-of-memory, this function returns nullptr and does not set any
1078  * value to the length out-param.
1079  */
1080 JS_FRIEND_API(char*)
1081 GetCodeCoverageSummary(JSContext* cx, size_t* length);
1082 
1083 JS_FRIEND_API(bool)
1084 ContextHasOutstandingRequests(const JSContext* cx);
1085 
1086 typedef void
1087 (* ActivityCallback)(void* arg, bool active);
1088 
1089 /**
1090  * Sets a callback that is run whenever the runtime goes idle - the
1091  * last active request ceases - and begins activity - when it was
1092  * idle and a request begins.
1093  */
1094 JS_FRIEND_API(void)
1095 SetActivityCallback(JSRuntime* rt, ActivityCallback cb, void* arg);
1096 
1097 typedef bool
1098 (* DOMInstanceClassHasProtoAtDepth)(const Class* instanceClass,
1099                                     uint32_t protoID, uint32_t depth);
1100 struct JSDOMCallbacks {
1101     DOMInstanceClassHasProtoAtDepth instanceClassMatchesProto;
1102 };
1103 typedef struct JSDOMCallbacks DOMCallbacks;
1104 
1105 extern JS_FRIEND_API(void)
1106 SetDOMCallbacks(JSRuntime* rt, const DOMCallbacks* callbacks);
1107 
1108 extern JS_FRIEND_API(const DOMCallbacks*)
1109 GetDOMCallbacks(JSRuntime* rt);
1110 
1111 extern JS_FRIEND_API(JSObject*)
1112 GetTestingFunctions(JSContext* cx);
1113 
1114 /**
1115  * Helper to convert FreeOp to JSFreeOp when the definition of FreeOp is not
1116  * available and the compiler does not know that FreeOp inherits from
1117  * JSFreeOp.
1118  */
1119 inline JSFreeOp*
CastToJSFreeOp(FreeOp * fop)1120 CastToJSFreeOp(FreeOp* fop)
1121 {
1122     return reinterpret_cast<JSFreeOp*>(fop);
1123 }
1124 
1125 /* Implemented in jsexn.cpp. */
1126 
1127 /**
1128  * Get an error type name from a JSExnType constant.
1129  * Returns nullptr for invalid arguments and JSEXN_INTERNALERR
1130  */
1131 extern JS_FRIEND_API(JSFlatString*)
1132 GetErrorTypeName(JSRuntime* rt, int16_t exnType);
1133 
1134 #ifdef JS_DEBUG
1135 extern JS_FRIEND_API(unsigned)
1136 GetEnterCompartmentDepth(JSContext* cx);
1137 #endif
1138 
1139 class RegExpGuard;
1140 extern JS_FRIEND_API(bool)
1141 RegExpToSharedNonInline(JSContext* cx, JS::HandleObject regexp, RegExpGuard* shared);
1142 
1143 /* Implemented in jswrapper.cpp. */
1144 typedef enum NukeReferencesToWindow {
1145     NukeWindowReferences,
1146     DontNukeWindowReferences
1147 } NukeReferencesToWindow;
1148 
1149 /*
1150  * These filters are designed to be ephemeral stack classes, and thus don't
1151  * do any rooting or holding of their members.
1152  */
1153 struct CompartmentFilter {
1154     virtual bool match(JSCompartment* c) const = 0;
1155 };
1156 
1157 struct AllCompartments : public CompartmentFilter {
matchAllCompartments1158     virtual bool match(JSCompartment* c) const override { return true; }
1159 };
1160 
1161 struct ContentCompartmentsOnly : public CompartmentFilter {
matchContentCompartmentsOnly1162     virtual bool match(JSCompartment* c) const override {
1163         return !IsSystemCompartment(c);
1164     }
1165 };
1166 
1167 struct ChromeCompartmentsOnly : public CompartmentFilter {
matchChromeCompartmentsOnly1168     virtual bool match(JSCompartment* c) const override {
1169         return IsSystemCompartment(c);
1170     }
1171 };
1172 
1173 struct SingleCompartment : public CompartmentFilter {
1174     JSCompartment* ours;
SingleCompartmentSingleCompartment1175     explicit SingleCompartment(JSCompartment* c) : ours(c) {}
matchSingleCompartment1176     virtual bool match(JSCompartment* c) const override { return c == ours; }
1177 };
1178 
1179 struct CompartmentsWithPrincipals : public CompartmentFilter {
1180     JSPrincipals* principals;
CompartmentsWithPrincipalsCompartmentsWithPrincipals1181     explicit CompartmentsWithPrincipals(JSPrincipals* p) : principals(p) {}
matchCompartmentsWithPrincipals1182     virtual bool match(JSCompartment* c) const override {
1183         return JS_GetCompartmentPrincipals(c) == principals;
1184     }
1185 };
1186 
1187 extern JS_FRIEND_API(bool)
1188 NukeCrossCompartmentWrappers(JSContext* cx,
1189                              const CompartmentFilter& sourceFilter,
1190                              const CompartmentFilter& targetFilter,
1191                              NukeReferencesToWindow nukeReferencesToWindow);
1192 
1193 /* Specify information about DOMProxy proxies in the DOM, for use by ICs. */
1194 
1195 /*
1196  * The DOMProxyShadowsCheck function will be called to check if the property for
1197  * id should be gotten from the prototype, or if there is an own property that
1198  * shadows it.
1199  * * If ShadowsViaDirectExpando is returned, then the slot at
1200  *   listBaseExpandoSlot contains an expando object which has the property in
1201  *   question.
1202  * * If ShadowsViaIndirectExpando is returned, then the slot at
1203  *   listBaseExpandoSlot contains a private pointer to an ExpandoAndGeneration
1204  *   and the expando object in the ExpandoAndGeneration has the property in
1205  *   question.
1206  * * If DoesntShadow is returned then the slot at listBaseExpandoSlot should
1207  *   either be undefined or point to an expando object that would contain the
1208  *   own property.
1209  * * If DoesntShadowUnique is returned then the slot at listBaseExpandoSlot
1210  *   should contain a private pointer to a ExpandoAndGeneration, which contains
1211  *   a JS::Value that should either be undefined or point to an expando object,
1212  *   and a uint64 value. If that value changes then the IC for getting a
1213  *   property will be invalidated.
1214  * * If Shadows is returned, that means the property is an own property of the
1215  *   proxy but doesn't live on the expando object.
1216  */
1217 
1218 struct ExpandoAndGeneration {
ExpandoAndGenerationExpandoAndGeneration1219   ExpandoAndGeneration()
1220     : expando(JS::UndefinedValue()),
1221       generation(0)
1222   {}
1223 
UnlinkExpandoAndGeneration1224   void Unlink()
1225   {
1226       ++generation;
1227       expando.setUndefined();
1228   }
1229 
offsetOfExpandoExpandoAndGeneration1230   static size_t offsetOfExpando()
1231   {
1232       return offsetof(ExpandoAndGeneration, expando);
1233   }
1234 
offsetOfGenerationExpandoAndGeneration1235   static size_t offsetOfGeneration()
1236   {
1237       return offsetof(ExpandoAndGeneration, generation);
1238   }
1239 
1240   JS::Heap<JS::Value> expando;
1241   uint64_t generation;
1242 };
1243 
1244 typedef enum DOMProxyShadowsResult {
1245   ShadowCheckFailed,
1246   Shadows,
1247   DoesntShadow,
1248   DoesntShadowUnique,
1249   ShadowsViaDirectExpando,
1250   ShadowsViaIndirectExpando
1251 } DOMProxyShadowsResult;
1252 typedef DOMProxyShadowsResult
1253 (* DOMProxyShadowsCheck)(JSContext* cx, JS::HandleObject object, JS::HandleId id);
1254 JS_FRIEND_API(void)
1255 SetDOMProxyInformation(const void* domProxyHandlerFamily, uint32_t domProxyExpandoSlot,
1256                        DOMProxyShadowsCheck domProxyShadowsCheck);
1257 
1258 const void* GetDOMProxyHandlerFamily();
1259 uint32_t GetDOMProxyExpandoSlot();
1260 DOMProxyShadowsCheck GetDOMProxyShadowsCheck();
DOMProxyIsShadowing(DOMProxyShadowsResult result)1261 inline bool DOMProxyIsShadowing(DOMProxyShadowsResult result) {
1262     return result == Shadows ||
1263            result == ShadowsViaDirectExpando ||
1264            result == ShadowsViaIndirectExpando;
1265 }
1266 
1267 /* Implemented in jsdate.cpp. */
1268 
1269 /** Detect whether the internal date value is NaN. */
1270 extern JS_FRIEND_API(bool)
1271 DateIsValid(JSContext* cx, JS::HandleObject obj, bool* isValid);
1272 
1273 extern JS_FRIEND_API(bool)
1274 DateGetMsecSinceEpoch(JSContext* cx, JS::HandleObject obj, double* msecSinceEpoch);
1275 
1276 } /* namespace js */
1277 
1278 /* Implemented in jscntxt.cpp. */
1279 
1280 /**
1281  * Report an exception, which is currently realized as a printf-style format
1282  * string and its arguments.
1283  */
1284 typedef enum JSErrNum {
1285 #define MSG_DEF(name, count, exception, format) \
1286     name,
1287 #include "js.msg"
1288 #undef MSG_DEF
1289     JSErr_Limit
1290 } JSErrNum;
1291 
1292 namespace js {
1293 
1294 extern JS_FRIEND_API(const JSErrorFormatString*)
1295 GetErrorMessage(void* userRef, const unsigned errorNumber);
1296 
1297 // AutoStableStringChars is here so we can use it in ErrorReport.  It
1298 // should get moved out of here if we can manage it.  See bug 1040316.
1299 
1300 /**
1301  * This class provides safe access to a string's chars across a GC. Once
1302  * we allocate strings and chars in the nursery (bug 903519), this class
1303  * will have to make a copy of the string's chars if they are allocated
1304  * in the nursery, so it's best to avoid using this class unless you really
1305  * need it. It's usually more efficient to use the latin1Chars/twoByteChars
1306  * JSString methods and often the code can be rewritten so that only indexes
1307  * instead of char pointers are used in parts of the code that can GC.
1308  */
1309 class MOZ_STACK_CLASS AutoStableStringChars
1310 {
1311     /* Ensure the string is kept alive while we're using its chars. */
1312     JS::RootedString s_;
1313     union {
1314         const char16_t* twoByteChars_;
1315         const JS::Latin1Char* latin1Chars_;
1316     };
1317     enum State { Uninitialized, Latin1, TwoByte };
1318     State state_;
1319     bool ownsChars_;
1320 
1321   public:
AutoStableStringChars(JSContext * cx)1322     explicit AutoStableStringChars(JSContext* cx)
1323       : s_(cx), state_(Uninitialized), ownsChars_(false)
1324     {}
1325     ~AutoStableStringChars();
1326 
1327     MOZ_WARN_UNUSED_RESULT
1328     bool init(JSContext* cx, JSString* s);
1329 
1330     /* Like init(), but Latin1 chars are inflated to TwoByte. */
1331     MOZ_WARN_UNUSED_RESULT
1332     bool initTwoByte(JSContext* cx, JSString* s);
1333 
isLatin1()1334     bool isLatin1() const { return state_ == Latin1; }
isTwoByte()1335     bool isTwoByte() const { return state_ == TwoByte; }
1336 
twoByteChars()1337     const char16_t* twoByteChars() const {
1338         MOZ_ASSERT(state_ == TwoByte);
1339         return twoByteChars_;
1340     }
1341 
latin1Range()1342     mozilla::Range<const JS::Latin1Char> latin1Range() const {
1343         MOZ_ASSERT(state_ == Latin1);
1344         return mozilla::Range<const JS::Latin1Char>(latin1Chars_,
1345                                                     GetStringLength(s_));
1346     }
1347 
twoByteRange()1348     mozilla::Range<const char16_t> twoByteRange() const {
1349         MOZ_ASSERT(state_ == TwoByte);
1350         return mozilla::Range<const char16_t>(twoByteChars_,
1351                                             GetStringLength(s_));
1352     }
1353 
1354     /* If we own the chars, transfer ownership to the caller. */
maybeGiveOwnershipToCaller()1355     bool maybeGiveOwnershipToCaller() {
1356         MOZ_ASSERT(state_ != Uninitialized);
1357         if (!ownsChars_)
1358             return false;
1359         state_ = Uninitialized;
1360         ownsChars_ = false;
1361         return true;
1362     }
1363 
1364   private:
1365     AutoStableStringChars(const AutoStableStringChars& other) = delete;
1366     void operator=(const AutoStableStringChars& other) = delete;
1367 };
1368 
1369 /**
1370  * Creates a string of the form |ErrorType: ErrorMessage| for a JSErrorReport,
1371  * which generally matches the toString() behavior of an ErrorObject.
1372  */
1373 extern JS_FRIEND_API(JSString*)
1374 ErrorReportToString(JSContext* cx, JSErrorReport* reportp);
1375 
JS_FRIEND_API(ErrorReport)1376 struct MOZ_STACK_CLASS JS_FRIEND_API(ErrorReport)
1377 {
1378     explicit ErrorReport(JSContext* cx);
1379     ~ErrorReport();
1380 
1381     bool init(JSContext* cx, JS::HandleValue exn);
1382 
1383     JSErrorReport* report()
1384     {
1385         return reportp;
1386     }
1387 
1388     const char* message()
1389     {
1390         return message_;
1391     }
1392 
1393   private:
1394     // More or less an equivalent of JS_ReportErrorNumber/js::ReportErrorNumberVA
1395     // but fills in an ErrorReport instead of reporting it.  Uses varargs to
1396     // make it simpler to call js::ExpandErrorArgumentsVA.
1397     //
1398     // Returns false if we fail to actually populate the ErrorReport
1399     // for some reason (probably out of memory).
1400     bool populateUncaughtExceptionReport(JSContext* cx, ...);
1401     bool populateUncaughtExceptionReportVA(JSContext* cx, va_list ap);
1402 
1403     // Reports exceptions from add-on scopes to telementry.
1404     void ReportAddonExceptionToTelementry(JSContext* cx);
1405 
1406     // We may have a provided JSErrorReport, so need a way to represent that.
1407     JSErrorReport* reportp;
1408 
1409     // And we may have a message.
1410     const char* message_;
1411 
1412     // Or we may need to synthesize a JSErrorReport one of our own.
1413     JSErrorReport ownedReport;
1414 
1415     // Or a message of our own.  If this is non-null, we need to clean up both
1416     // it and ownedReport.
1417     char* ownedMessage;
1418 
1419     // And we have a string to maybe keep alive that has pointers into
1420     // it from ownedReport.
1421     JS::RootedString str;
1422 
1423     // And keep its chars alive too.
1424     AutoStableStringChars strChars;
1425 
1426     // And we need to root our exception value.
1427     JS::RootedObject exnObject;
1428 
1429     // And possibly some byte storage for our message_.
1430     JSAutoByteString bytesStorage;
1431 
1432     // And for our filename.
1433     JSAutoByteString filename;
1434 
1435     // True if we need to free message_ and the stuff in ownedReport
1436     bool ownsMessageAndReport;
1437 };
1438 
1439 /* Implemented in vm/StructuredClone.cpp. */
1440 extern JS_FRIEND_API(uint64_t)
1441 GetSCOffset(JSStructuredCloneWriter* writer);
1442 
1443 namespace Scalar {
1444 
1445 /**
1446  * Scalar types that can appear in typed arrays and typed objects.  The enum
1447  * values must to be kept in sync with the JS_SCALARTYPEREPR_ constants, as
1448  * well as the TypedArrayObject::classes and TypedArrayObject::protoClasses
1449  * definitions.
1450  */
1451 enum Type {
1452     Int8 = 0,
1453     Uint8,
1454     Int16,
1455     Uint16,
1456     Int32,
1457     Uint32,
1458     Float32,
1459     Float64,
1460 
1461     /**
1462      * Special type that is a uint8_t, but assignments are clamped to [0, 256).
1463      * Treat the raw data type as a uint8_t.
1464      */
1465     Uint8Clamped,
1466 
1467     /**
1468      * SIMD types don't have their own TypedArray equivalent, for now.
1469      */
1470     MaxTypedArrayViewType,
1471 
1472     Float32x4,
1473     Int32x4
1474 };
1475 
1476 static inline size_t
byteSize(Type atype)1477 byteSize(Type atype)
1478 {
1479     switch (atype) {
1480       case Int8:
1481       case Uint8:
1482       case Uint8Clamped:
1483         return 1;
1484       case Int16:
1485       case Uint16:
1486         return 2;
1487       case Int32:
1488       case Uint32:
1489       case Float32:
1490         return 4;
1491       case Float64:
1492         return 8;
1493       case Int32x4:
1494       case Float32x4:
1495         return 16;
1496       default:
1497         MOZ_CRASH("invalid scalar type");
1498     }
1499 }
1500 
1501 static inline bool
isSignedIntType(Type atype)1502 isSignedIntType(Type atype) {
1503     switch (atype) {
1504       case Int8:
1505       case Int16:
1506       case Int32:
1507       case Int32x4:
1508         return true;
1509       case Uint8:
1510       case Uint8Clamped:
1511       case Uint16:
1512       case Uint32:
1513       case Float32:
1514       case Float64:
1515       case Float32x4:
1516         return false;
1517       default:
1518         MOZ_CRASH("invalid scalar type");
1519     }
1520 }
1521 
1522 static inline bool
isSimdType(Type atype)1523 isSimdType(Type atype) {
1524     switch (atype) {
1525       case Int8:
1526       case Uint8:
1527       case Uint8Clamped:
1528       case Int16:
1529       case Uint16:
1530       case Int32:
1531       case Uint32:
1532       case Float32:
1533       case Float64:
1534         return false;
1535       case Int32x4:
1536       case Float32x4:
1537         return true;
1538       case MaxTypedArrayViewType:
1539         break;
1540     }
1541     MOZ_CRASH("invalid scalar type");
1542 }
1543 
1544 static inline size_t
scalarByteSize(Type atype)1545 scalarByteSize(Type atype) {
1546     switch (atype) {
1547       case Int32x4:
1548       case Float32x4:
1549         return 4;
1550       case Int8:
1551       case Uint8:
1552       case Uint8Clamped:
1553       case Int16:
1554       case Uint16:
1555       case Int32:
1556       case Uint32:
1557       case Float32:
1558       case Float64:
1559       case MaxTypedArrayViewType:
1560         break;
1561     }
1562     MOZ_CRASH("invalid simd type");
1563 }
1564 
1565 } /* namespace Scalar */
1566 } /* namespace js */
1567 
1568 /*
1569  * Create a new typed array with nelements elements.
1570  *
1571  * These functions (except the WithBuffer variants) fill in the array with zeros.
1572  */
1573 
1574 extern JS_FRIEND_API(JSObject*)
1575 JS_NewInt8Array(JSContext* cx, uint32_t nelements);
1576 extern JS_FRIEND_API(JSObject*)
1577 JS_NewUint8Array(JSContext* cx, uint32_t nelements);
1578 extern JS_FRIEND_API(JSObject*)
1579 JS_NewUint8ClampedArray(JSContext* cx, uint32_t nelements);
1580 extern JS_FRIEND_API(JSObject*)
1581 JS_NewInt16Array(JSContext* cx, uint32_t nelements);
1582 extern JS_FRIEND_API(JSObject*)
1583 JS_NewUint16Array(JSContext* cx, uint32_t nelements);
1584 extern JS_FRIEND_API(JSObject*)
1585 JS_NewInt32Array(JSContext* cx, uint32_t nelements);
1586 extern JS_FRIEND_API(JSObject*)
1587 JS_NewUint32Array(JSContext* cx, uint32_t nelements);
1588 extern JS_FRIEND_API(JSObject*)
1589 JS_NewFloat32Array(JSContext* cx, uint32_t nelements);
1590 extern JS_FRIEND_API(JSObject*)
1591 JS_NewFloat64Array(JSContext* cx, uint32_t nelements);
1592 
1593 /*
1594  * Create a new typed array and copy in values from the given object. The
1595  * object is used as if it were an array; that is, the new array (if
1596  * successfully created) will have length given by array.length, and its
1597  * elements will be those specified by array[0], array[1], and so on, after
1598  * conversion to the typed array element type.
1599  */
1600 
1601 extern JS_FRIEND_API(JSObject*)
1602 JS_NewInt8ArrayFromArray(JSContext* cx, JS::HandleObject array);
1603 extern JS_FRIEND_API(JSObject*)
1604 JS_NewUint8ArrayFromArray(JSContext* cx, JS::HandleObject array);
1605 extern JS_FRIEND_API(JSObject*)
1606 JS_NewUint8ClampedArrayFromArray(JSContext* cx, JS::HandleObject array);
1607 extern JS_FRIEND_API(JSObject*)
1608 JS_NewInt16ArrayFromArray(JSContext* cx, JS::HandleObject array);
1609 extern JS_FRIEND_API(JSObject*)
1610 JS_NewUint16ArrayFromArray(JSContext* cx, JS::HandleObject array);
1611 extern JS_FRIEND_API(JSObject*)
1612 JS_NewInt32ArrayFromArray(JSContext* cx, JS::HandleObject array);
1613 extern JS_FRIEND_API(JSObject*)
1614 JS_NewUint32ArrayFromArray(JSContext* cx, JS::HandleObject array);
1615 extern JS_FRIEND_API(JSObject*)
1616 JS_NewFloat32ArrayFromArray(JSContext* cx, JS::HandleObject array);
1617 extern JS_FRIEND_API(JSObject*)
1618 JS_NewFloat64ArrayFromArray(JSContext* cx, JS::HandleObject array);
1619 
1620 /*
1621  * Create a new typed array using the given ArrayBuffer or
1622  * SharedArrayBuffer for storage.  The length value is optional; if -1
1623  * is passed, enough elements to use up the remainder of the byte
1624  * array is used as the default value.
1625  */
1626 
1627 extern JS_FRIEND_API(JSObject*)
1628 JS_NewInt8ArrayWithBuffer(JSContext* cx, JS::HandleObject arrayBuffer,
1629                           uint32_t byteOffset, int32_t length);
1630 extern JS_FRIEND_API(JSObject*)
1631 JS_NewUint8ArrayWithBuffer(JSContext* cx, JS::HandleObject arrayBuffer,
1632                            uint32_t byteOffset, int32_t length);
1633 extern JS_FRIEND_API(JSObject*)
1634 JS_NewUint8ClampedArrayWithBuffer(JSContext* cx, JS::HandleObject arrayBuffer,
1635                                   uint32_t byteOffset, int32_t length);
1636 extern JS_FRIEND_API(JSObject*)
1637 JS_NewInt16ArrayWithBuffer(JSContext* cx, JS::HandleObject arrayBuffer,
1638                            uint32_t byteOffset, int32_t length);
1639 extern JS_FRIEND_API(JSObject*)
1640 JS_NewUint16ArrayWithBuffer(JSContext* cx, JS::HandleObject arrayBuffer,
1641                             uint32_t byteOffset, int32_t length);
1642 extern JS_FRIEND_API(JSObject*)
1643 JS_NewInt32ArrayWithBuffer(JSContext* cx, JS::HandleObject arrayBuffer,
1644                            uint32_t byteOffset, int32_t length);
1645 extern JS_FRIEND_API(JSObject*)
1646 JS_NewUint32ArrayWithBuffer(JSContext* cx, JS::HandleObject arrayBuffer,
1647                             uint32_t byteOffset, int32_t length);
1648 extern JS_FRIEND_API(JSObject*)
1649 JS_NewFloat32ArrayWithBuffer(JSContext* cx, JS::HandleObject arrayBuffer,
1650                              uint32_t byteOffset, int32_t length);
1651 extern JS_FRIEND_API(JSObject*)
1652 JS_NewFloat64ArrayWithBuffer(JSContext* cx, JS::HandleObject arrayBuffer,
1653                              uint32_t byteOffset, int32_t length);
1654 
1655 /**
1656  * Create a new SharedArrayBuffer with the given byte length.
1657  */
1658 extern JS_FRIEND_API(JSObject*)
1659 JS_NewSharedArrayBuffer(JSContext* cx, uint32_t nbytes);
1660 
1661 /**
1662  * Create a new ArrayBuffer with the given byte length.
1663  */
1664 extern JS_FRIEND_API(JSObject*)
1665 JS_NewArrayBuffer(JSContext* cx, uint32_t nbytes);
1666 
1667 /**
1668  * Check whether obj supports JS_GetTypedArray* APIs. Note that this may return
1669  * false if a security wrapper is encountered that denies the unwrapping. If
1670  * this test or one of the JS_Is*Array tests succeeds, then it is safe to call
1671  * the various accessor JSAPI calls defined below.
1672  */
1673 extern JS_FRIEND_API(bool)
1674 JS_IsTypedArrayObject(JSObject* obj);
1675 
1676 /**
1677  * Check whether obj supports JS_GetArrayBufferView* APIs. Note that this may
1678  * return false if a security wrapper is encountered that denies the
1679  * unwrapping. If this test or one of the more specific tests succeeds, then it
1680  * is safe to call the various ArrayBufferView accessor JSAPI calls defined
1681  * below.
1682  */
1683 extern JS_FRIEND_API(bool)
1684 JS_IsArrayBufferViewObject(JSObject* obj);
1685 
1686 /*
1687  * Test for specific typed array types (ArrayBufferView subtypes)
1688  */
1689 
1690 extern JS_FRIEND_API(bool)
1691 JS_IsInt8Array(JSObject* obj);
1692 extern JS_FRIEND_API(bool)
1693 JS_IsUint8Array(JSObject* obj);
1694 extern JS_FRIEND_API(bool)
1695 JS_IsUint8ClampedArray(JSObject* obj);
1696 extern JS_FRIEND_API(bool)
1697 JS_IsInt16Array(JSObject* obj);
1698 extern JS_FRIEND_API(bool)
1699 JS_IsUint16Array(JSObject* obj);
1700 extern JS_FRIEND_API(bool)
1701 JS_IsInt32Array(JSObject* obj);
1702 extern JS_FRIEND_API(bool)
1703 JS_IsUint32Array(JSObject* obj);
1704 extern JS_FRIEND_API(bool)
1705 JS_IsFloat32Array(JSObject* obj);
1706 extern JS_FRIEND_API(bool)
1707 JS_IsFloat64Array(JSObject* obj);
1708 
1709 /**
1710  * Return the isShared flag of a typed array, which denotes whether
1711  * the underlying buffer is a SharedArrayBuffer.
1712  *
1713  * |obj| must have passed a JS_IsTypedArrayObject/JS_Is*Array test, or somehow
1714  * be known that it would pass such a test: it is a typed array or a wrapper of
1715  * a typed array, and the unwrapping will succeed.
1716  */
1717 extern JS_FRIEND_API(bool)
1718 JS_GetTypedArraySharedness(JSObject* obj);
1719 
1720 /*
1721  * Test for specific typed array types (ArrayBufferView subtypes) and return
1722  * the unwrapped object if so, else nullptr.  Never throws.
1723  */
1724 
1725 namespace js {
1726 
1727 extern JS_FRIEND_API(JSObject*)
1728 UnwrapInt8Array(JSObject* obj);
1729 extern JS_FRIEND_API(JSObject*)
1730 UnwrapUint8Array(JSObject* obj);
1731 extern JS_FRIEND_API(JSObject*)
1732 UnwrapUint8ClampedArray(JSObject* obj);
1733 extern JS_FRIEND_API(JSObject*)
1734 UnwrapInt16Array(JSObject* obj);
1735 extern JS_FRIEND_API(JSObject*)
1736 UnwrapUint16Array(JSObject* obj);
1737 extern JS_FRIEND_API(JSObject*)
1738 UnwrapInt32Array(JSObject* obj);
1739 extern JS_FRIEND_API(JSObject*)
1740 UnwrapUint32Array(JSObject* obj);
1741 extern JS_FRIEND_API(JSObject*)
1742 UnwrapFloat32Array(JSObject* obj);
1743 extern JS_FRIEND_API(JSObject*)
1744 UnwrapFloat64Array(JSObject* obj);
1745 
1746 extern JS_FRIEND_API(JSObject*)
1747 UnwrapArrayBuffer(JSObject* obj);
1748 
1749 extern JS_FRIEND_API(JSObject*)
1750 UnwrapArrayBufferView(JSObject* obj);
1751 
1752 extern JS_FRIEND_API(JSObject*)
1753 UnwrapSharedArrayBuffer(JSObject* obj);
1754 
1755 
1756 namespace detail {
1757 
1758 extern JS_FRIEND_DATA(const Class* const) Int8ArrayClassPtr;
1759 extern JS_FRIEND_DATA(const Class* const) Uint8ArrayClassPtr;
1760 extern JS_FRIEND_DATA(const Class* const) Uint8ClampedArrayClassPtr;
1761 extern JS_FRIEND_DATA(const Class* const) Int16ArrayClassPtr;
1762 extern JS_FRIEND_DATA(const Class* const) Uint16ArrayClassPtr;
1763 extern JS_FRIEND_DATA(const Class* const) Int32ArrayClassPtr;
1764 extern JS_FRIEND_DATA(const Class* const) Uint32ArrayClassPtr;
1765 extern JS_FRIEND_DATA(const Class* const) Float32ArrayClassPtr;
1766 extern JS_FRIEND_DATA(const Class* const) Float64ArrayClassPtr;
1767 
1768 const size_t TypedArrayLengthSlot = 1;
1769 
1770 } // namespace detail
1771 
1772 #define JS_DEFINE_DATA_AND_LENGTH_ACCESSOR(Type, type) \
1773 inline void \
1774 Get ## Type ## ArrayLengthAndData(JSObject* obj, uint32_t* length, bool* isSharedMemory, type** data) \
1775 { \
1776     MOZ_ASSERT(GetObjectClass(obj) == detail::Type ## ArrayClassPtr); \
1777     const JS::Value& lenSlot = GetReservedSlot(obj, detail::TypedArrayLengthSlot); \
1778     *length = mozilla::AssertedCast<uint32_t>(lenSlot.toInt32()); \
1779     *isSharedMemory = JS_GetTypedArraySharedness(obj); \
1780     *data = static_cast<type*>(GetObjectPrivate(obj)); \
1781 }
1782 
1783 JS_DEFINE_DATA_AND_LENGTH_ACCESSOR(Int8, int8_t)
1784 JS_DEFINE_DATA_AND_LENGTH_ACCESSOR(Uint8, uint8_t)
1785 JS_DEFINE_DATA_AND_LENGTH_ACCESSOR(Uint8Clamped, uint8_t)
1786 JS_DEFINE_DATA_AND_LENGTH_ACCESSOR(Int16, int16_t)
1787 JS_DEFINE_DATA_AND_LENGTH_ACCESSOR(Uint16, uint16_t)
1788 JS_DEFINE_DATA_AND_LENGTH_ACCESSOR(Int32, int32_t)
1789 JS_DEFINE_DATA_AND_LENGTH_ACCESSOR(Uint32, uint32_t)
1790 JS_DEFINE_DATA_AND_LENGTH_ACCESSOR(Float32, float)
1791 JS_DEFINE_DATA_AND_LENGTH_ACCESSOR(Float64, double)
1792 
1793 #undef JS_DEFINE_DATA_AND_LENGTH_ACCESSOR
1794 
1795 // This one isn't inlined because it's rather tricky (by dint of having to deal
1796 // with a dozen-plus classes and varying slot layouts.
1797 extern JS_FRIEND_API(void)
1798 GetArrayBufferViewLengthAndData(JSObject* obj, uint32_t* length, bool* isSharedMemory, uint8_t** data);
1799 
1800 // This one isn't inlined because there are a bunch of different ArrayBuffer
1801 // classes that would have to be individually handled here.
1802 //
1803 // There is an isShared out argument for API consistency (eases use from DOM).
1804 // It will always be set to false.
1805 extern JS_FRIEND_API(void)
1806 GetArrayBufferLengthAndData(JSObject* obj, uint32_t* length, bool* isSharedMemory, uint8_t** data);
1807 
1808 // Ditto for SharedArrayBuffer.
1809 //
1810 // There is an isShared out argument for API consistency (eases use from DOM).
1811 // It will always be set to true.
1812 extern JS_FRIEND_API(void)
1813 GetSharedArrayBufferLengthAndData(JSObject* obj, uint32_t* length, bool* isSharedMemory, uint8_t** data);
1814 
1815 } // namespace js
1816 
1817 JS_FRIEND_API(uint8_t*)
1818 JS_GetSharedArrayBufferData(JSObject* obj, bool* isSharedMemory, const JS::AutoCheckCannotGC&);
1819 
1820 /*
1821  * Unwrap Typed arrays all at once. Return nullptr without throwing if the
1822  * object cannot be viewed as the correct typed array, or the typed array
1823  * object on success, filling both outparameters.
1824  */
1825 extern JS_FRIEND_API(JSObject*)
1826 JS_GetObjectAsInt8Array(JSObject* obj, uint32_t* length, bool* isSharedMemory, int8_t** data);
1827 extern JS_FRIEND_API(JSObject*)
1828 JS_GetObjectAsUint8Array(JSObject* obj, uint32_t* length, bool* isSharedMemory, uint8_t** data);
1829 extern JS_FRIEND_API(JSObject*)
1830 JS_GetObjectAsUint8ClampedArray(JSObject* obj, uint32_t* length, bool* isSharedMemory, uint8_t** data);
1831 extern JS_FRIEND_API(JSObject*)
1832 JS_GetObjectAsInt16Array(JSObject* obj, uint32_t* length, bool* isSharedMemory, int16_t** data);
1833 extern JS_FRIEND_API(JSObject*)
1834 JS_GetObjectAsUint16Array(JSObject* obj, uint32_t* length, bool* isSharedMemory, uint16_t** data);
1835 extern JS_FRIEND_API(JSObject*)
1836 JS_GetObjectAsInt32Array(JSObject* obj, uint32_t* length, bool* isSharedMemory, int32_t** data);
1837 extern JS_FRIEND_API(JSObject*)
1838 JS_GetObjectAsUint32Array(JSObject* obj, uint32_t* length, bool* isSharedMemory, uint32_t** data);
1839 extern JS_FRIEND_API(JSObject*)
1840 JS_GetObjectAsFloat32Array(JSObject* obj, uint32_t* length, bool* isSharedMemory, float** data);
1841 extern JS_FRIEND_API(JSObject*)
1842 JS_GetObjectAsFloat64Array(JSObject* obj, uint32_t* length, bool* isSharedMemory, double** data);
1843 extern JS_FRIEND_API(JSObject*)
1844 JS_GetObjectAsArrayBufferView(JSObject* obj, uint32_t* length, bool* isSharedMemory, uint8_t** data);
1845 
1846 /*
1847  * Unwrap an ArrayBuffer, return nullptr if it's a different type.
1848  */
1849 extern JS_FRIEND_API(JSObject*)
1850 JS_GetObjectAsArrayBuffer(JSObject* obj, uint32_t* length, uint8_t** data);
1851 
1852 /*
1853  * Get the type of elements in a typed array, or MaxTypedArrayViewType if a DataView.
1854  *
1855  * |obj| must have passed a JS_IsArrayBufferView/JS_Is*Array test, or somehow
1856  * be known that it would pass such a test: it is an ArrayBufferView or a
1857  * wrapper of an ArrayBufferView, and the unwrapping will succeed.
1858  */
1859 extern JS_FRIEND_API(js::Scalar::Type)
1860 JS_GetArrayBufferViewType(JSObject* obj);
1861 
1862 extern JS_FRIEND_API(js::Scalar::Type)
1863 JS_GetSharedArrayBufferViewType(JSObject* obj);
1864 
1865 /*
1866  * Check whether obj supports the JS_GetArrayBuffer* APIs. Note that this may
1867  * return false if a security wrapper is encountered that denies the
1868  * unwrapping. If this test succeeds, then it is safe to call the various
1869  * accessor JSAPI calls defined below.
1870  */
1871 extern JS_FRIEND_API(bool)
1872 JS_IsArrayBufferObject(JSObject* obj);
1873 
1874 extern JS_FRIEND_API(bool)
1875 JS_IsSharedArrayBufferObject(JSObject* obj);
1876 
1877 /**
1878  * Return the available byte length of an array buffer.
1879  *
1880  * |obj| must have passed a JS_IsArrayBufferObject test, or somehow be known
1881  * that it would pass such a test: it is an ArrayBuffer or a wrapper of an
1882  * ArrayBuffer, and the unwrapping will succeed.
1883  */
1884 extern JS_FRIEND_API(uint32_t)
1885 JS_GetArrayBufferByteLength(JSObject* obj);
1886 
1887 extern JS_FRIEND_API(uint32_t)
1888 JS_GetSharedArrayBufferByteLength(JSObject* obj);
1889 
1890 /**
1891  * Return true if the arrayBuffer contains any data. This will return false for
1892  * ArrayBuffer.prototype and neutered ArrayBuffers.
1893  *
1894  * |obj| must have passed a JS_IsArrayBufferObject test, or somehow be known
1895  * that it would pass such a test: it is an ArrayBuffer or a wrapper of an
1896  * ArrayBuffer, and the unwrapping will succeed.
1897  */
1898 extern JS_FRIEND_API(bool)
1899 JS_ArrayBufferHasData(JSObject* obj);
1900 
1901 /**
1902  * Return a pointer to the start of the data referenced by a typed array. The
1903  * data is still owned by the typed array, and should not be modified on
1904  * another thread. Furthermore, the pointer can become invalid on GC (if the
1905  * data is small and fits inside the array's GC header), so callers must take
1906  * care not to hold on across anything that could GC.
1907  *
1908  * |obj| must have passed a JS_IsArrayBufferObject test, or somehow be known
1909  * that it would pass such a test: it is an ArrayBuffer or a wrapper of an
1910  * ArrayBuffer, and the unwrapping will succeed.
1911  *
1912  * *isSharedMemory will be set to false, the argument is present to simplify
1913  * its use from code that also interacts with SharedArrayBuffer.
1914  */
1915 extern JS_FRIEND_API(uint8_t*)
1916 JS_GetArrayBufferData(JSObject* obj, bool* isSharedMemory, const JS::AutoCheckCannotGC&);
1917 
1918 /**
1919  * Check whether the obj is ArrayBufferObject and memory mapped. Note that this
1920  * may return false if a security wrapper is encountered that denies the
1921  * unwrapping.
1922  */
1923 extern JS_FRIEND_API(bool)
1924 JS_IsMappedArrayBufferObject(JSObject* obj);
1925 
1926 /**
1927  * Return the number of elements in a typed array.
1928  *
1929  * |obj| must have passed a JS_IsTypedArrayObject/JS_Is*Array test, or somehow
1930  * be known that it would pass such a test: it is a typed array or a wrapper of
1931  * a typed array, and the unwrapping will succeed.
1932  */
1933 extern JS_FRIEND_API(uint32_t)
1934 JS_GetTypedArrayLength(JSObject* obj);
1935 
1936 /**
1937  * Return the byte offset from the start of an array buffer to the start of a
1938  * typed array view.
1939  *
1940  * |obj| must have passed a JS_IsTypedArrayObject/JS_Is*Array test, or somehow
1941  * be known that it would pass such a test: it is a typed array or a wrapper of
1942  * a typed array, and the unwrapping will succeed.
1943  */
1944 extern JS_FRIEND_API(uint32_t)
1945 JS_GetTypedArrayByteOffset(JSObject* obj);
1946 
1947 /**
1948  * Return the byte length of a typed array.
1949  *
1950  * |obj| must have passed a JS_IsTypedArrayObject/JS_Is*Array test, or somehow
1951  * be known that it would pass such a test: it is a typed array or a wrapper of
1952  * a typed array, and the unwrapping will succeed.
1953  */
1954 extern JS_FRIEND_API(uint32_t)
1955 JS_GetTypedArrayByteLength(JSObject* obj);
1956 
1957 /**
1958  * Check whether obj supports JS_ArrayBufferView* APIs. Note that this may
1959  * return false if a security wrapper is encountered that denies the
1960  * unwrapping.
1961  */
1962 extern JS_FRIEND_API(bool)
1963 JS_IsArrayBufferViewObject(JSObject* obj);
1964 
1965 /**
1966  * More generic name for JS_GetTypedArrayByteLength to cover DataViews as well
1967  */
1968 extern JS_FRIEND_API(uint32_t)
1969 JS_GetArrayBufferViewByteLength(JSObject* obj);
1970 
1971 /*
1972  * Return a pointer to the start of the data referenced by a typed array. The
1973  * data is still owned by the typed array, and should not be modified on
1974  * another thread. Furthermore, the pointer can become invalid on GC (if the
1975  * data is small and fits inside the array's GC header), so callers must take
1976  * care not to hold on across anything that could GC.
1977  *
1978  * |obj| must have passed a JS_Is*Array test, or somehow be known that it would
1979  * pass such a test: it is a typed array or a wrapper of a typed array, and the
1980  * unwrapping will succeed.
1981  *
1982  * *isSharedMemory will be set to true if the typed array maps a
1983  * SharedArrayBuffer, otherwise to false.
1984  */
1985 
1986 extern JS_FRIEND_API(int8_t*)
1987 JS_GetInt8ArrayData(JSObject* obj, bool* isSharedMemory, const JS::AutoCheckCannotGC&);
1988 extern JS_FRIEND_API(uint8_t*)
1989 JS_GetUint8ArrayData(JSObject* obj, bool* isSharedMemory, const JS::AutoCheckCannotGC&);
1990 extern JS_FRIEND_API(uint8_t*)
1991 JS_GetUint8ClampedArrayData(JSObject* obj, bool* isSharedMemory, const JS::AutoCheckCannotGC&);
1992 extern JS_FRIEND_API(int16_t*)
1993 JS_GetInt16ArrayData(JSObject* obj, bool* isSharedMemory, const JS::AutoCheckCannotGC&);
1994 extern JS_FRIEND_API(uint16_t*)
1995 JS_GetUint16ArrayData(JSObject* obj, bool* isSharedMemory, const JS::AutoCheckCannotGC&);
1996 extern JS_FRIEND_API(int32_t*)
1997 JS_GetInt32ArrayData(JSObject* obj, bool* isSharedMemory, const JS::AutoCheckCannotGC&);
1998 extern JS_FRIEND_API(uint32_t*)
1999 JS_GetUint32ArrayData(JSObject* obj, bool* isSharedMemory, const JS::AutoCheckCannotGC&);
2000 extern JS_FRIEND_API(float*)
2001 JS_GetFloat32ArrayData(JSObject* obj, bool* isSharedMemory, const JS::AutoCheckCannotGC&);
2002 extern JS_FRIEND_API(double*)
2003 JS_GetFloat64ArrayData(JSObject* obj, bool* isSharedMemory, const JS::AutoCheckCannotGC&);
2004 
2005 /**
2006  * Same as above, but for any kind of ArrayBufferView. Prefer the type-specific
2007  * versions when possible.
2008  */
2009 extern JS_FRIEND_API(void*)
2010 JS_GetArrayBufferViewData(JSObject* obj, bool* isSharedMemory, const JS::AutoCheckCannotGC&);
2011 
2012 /**
2013  * Return the ArrayBuffer or SharedArrayBuffer underlying an
2014  * ArrayBufferView. If the buffer has been neutered, this will still
2015  * return the neutered buffer. |obj| must be an object that would
2016  * return true for JS_IsArrayBufferViewObject().
2017  */
2018 extern JS_FRIEND_API(JSObject*)
2019 JS_GetArrayBufferViewBuffer(JSContext* cx, JS::HandleObject obj, bool* isSharedMemory);
2020 
2021 typedef enum {
2022     ChangeData,
2023     KeepData
2024 } NeuterDataDisposition;
2025 
2026 /**
2027  * Set an ArrayBuffer's length to 0 and neuter all of its views.
2028  *
2029  * The |changeData| argument is a hint to inform internal behavior with respect
2030  * to the internal pointer to the ArrayBuffer's data after being neutered.
2031  * There is no guarantee it will be respected.  But if it is respected, the
2032  * ArrayBuffer's internal data pointer will, or will not, have changed
2033  * accordingly.
2034  */
2035 extern JS_FRIEND_API(bool)
2036 JS_NeuterArrayBuffer(JSContext* cx, JS::HandleObject obj,
2037                      NeuterDataDisposition changeData);
2038 
2039 /**
2040  * Check whether the obj is ArrayBufferObject and neutered. Note that this
2041  * may return false if a security wrapper is encountered that denies the
2042  * unwrapping.
2043  */
2044 extern JS_FRIEND_API(bool)
2045 JS_IsNeuteredArrayBufferObject(JSObject* obj);
2046 
2047 /**
2048  * Check whether obj supports JS_GetDataView* APIs.
2049  */
2050 JS_FRIEND_API(bool)
2051 JS_IsDataViewObject(JSObject* obj);
2052 
2053 /**
2054  * Create a new DataView using the given ArrayBuffer for storage. The given
2055  * buffer must be an ArrayBuffer (or a cross-compartment wrapper of an
2056  * ArrayBuffer), and the offset and length must fit within the bounds of the
2057  * arrayBuffer. Currently, nullptr will be returned and an exception will be
2058  * thrown if these conditions do not hold, but do not depend on that behavior.
2059  */
2060 JS_FRIEND_API(JSObject*)
2061 JS_NewDataView(JSContext* cx, JS::HandleObject arrayBuffer, uint32_t byteOffset, int32_t byteLength);
2062 
2063 /**
2064  * Return the byte offset of a data view into its array buffer. |obj| must be a
2065  * DataView.
2066  *
2067  * |obj| must have passed a JS_IsDataViewObject test, or somehow be known that
2068  * it would pass such a test: it is a data view or a wrapper of a data view,
2069  * and the unwrapping will succeed.
2070  */
2071 JS_FRIEND_API(uint32_t)
2072 JS_GetDataViewByteOffset(JSObject* obj);
2073 
2074 /**
2075  * Return the byte length of a data view.
2076  *
2077  * |obj| must have passed a JS_IsDataViewObject test, or somehow be known that
2078  * it would pass such a test: it is a data view or a wrapper of a data view,
2079  * and the unwrapping will succeed. If cx is nullptr, then DEBUG builds may be
2080  * unable to assert when unwrapping should be disallowed.
2081  */
2082 JS_FRIEND_API(uint32_t)
2083 JS_GetDataViewByteLength(JSObject* obj);
2084 
2085 /**
2086  * Return a pointer to the beginning of the data referenced by a DataView.
2087  *
2088  * |obj| must have passed a JS_IsDataViewObject test, or somehow be known that
2089  * it would pass such a test: it is a data view or a wrapper of a data view,
2090  * and the unwrapping will succeed. If cx is nullptr, then DEBUG builds may be
2091  * unable to assert when unwrapping should be disallowed.
2092  */
2093 JS_FRIEND_API(void*)
2094 JS_GetDataViewData(JSObject* obj, const JS::AutoCheckCannotGC&);
2095 
2096 namespace js {
2097 
2098 /**
2099  * Add a watchpoint -- in the Object.prototype.watch sense -- to |obj| for the
2100  * property |id|, using the callable object |callable| as the function to be
2101  * called for notifications.
2102  *
2103  * This is an internal function exposed -- temporarily -- only so that DOM
2104  * proxies can be watchable.  Don't use it!  We'll soon kill off the
2105  * Object.prototype.{,un}watch functions, at which point this will go too.
2106  */
2107 extern JS_FRIEND_API(bool)
2108 WatchGuts(JSContext* cx, JS::HandleObject obj, JS::HandleId id, JS::HandleObject callable);
2109 
2110 /**
2111  * Remove a watchpoint -- in the Object.prototype.watch sense -- from |obj| for
2112  * the property |id|.
2113  *
2114  * This is an internal function exposed -- temporarily -- only so that DOM
2115  * proxies can be watchable.  Don't use it!  We'll soon kill off the
2116  * Object.prototype.{,un}watch functions, at which point this will go too.
2117  */
2118 extern JS_FRIEND_API(bool)
2119 UnwatchGuts(JSContext* cx, JS::HandleObject obj, JS::HandleId id);
2120 
2121 namespace jit {
2122 
2123 enum class InlinableNative : uint16_t;
2124 
2125 } // namespace jit
2126 
2127 } // namespace js
2128 
2129 /**
2130  * A class, expected to be passed by value, which represents the CallArgs for a
2131  * JSJitGetterOp.
2132  */
2133 class JSJitGetterCallArgs : protected JS::MutableHandleValue
2134 {
2135   public:
JSJitGetterCallArgs(const JS::CallArgs & args)2136     explicit JSJitGetterCallArgs(const JS::CallArgs& args)
2137       : JS::MutableHandleValue(args.rval())
2138     {}
2139 
JSJitGetterCallArgs(JS::RootedValue * rooted)2140     explicit JSJitGetterCallArgs(JS::RootedValue* rooted)
2141       : JS::MutableHandleValue(rooted)
2142     {}
2143 
rval()2144     JS::MutableHandleValue rval() {
2145         return *this;
2146     }
2147 };
2148 
2149 /**
2150  * A class, expected to be passed by value, which represents the CallArgs for a
2151  * JSJitSetterOp.
2152  */
2153 class JSJitSetterCallArgs : protected JS::MutableHandleValue
2154 {
2155   public:
JSJitSetterCallArgs(const JS::CallArgs & args)2156     explicit JSJitSetterCallArgs(const JS::CallArgs& args)
2157       : JS::MutableHandleValue(args[0])
2158     {}
2159 
2160     JS::MutableHandleValue operator[](unsigned i) {
2161         MOZ_ASSERT(i == 0);
2162         return *this;
2163     }
2164 
length()2165     unsigned length() const { return 1; }
2166 
2167     // Add get() or maybe hasDefined() as needed
2168 };
2169 
2170 struct JSJitMethodCallArgsTraits;
2171 
2172 /**
2173  * A class, expected to be passed by reference, which represents the CallArgs
2174  * for a JSJitMethodOp.
2175  */
2176 class JSJitMethodCallArgs : protected JS::detail::CallArgsBase<JS::detail::NoUsedRval>
2177 {
2178   private:
2179     typedef JS::detail::CallArgsBase<JS::detail::NoUsedRval> Base;
2180     friend struct JSJitMethodCallArgsTraits;
2181 
2182   public:
JSJitMethodCallArgs(const JS::CallArgs & args)2183     explicit JSJitMethodCallArgs(const JS::CallArgs& args) {
2184         argv_ = args.array();
2185         argc_ = args.length();
2186     }
2187 
rval()2188     JS::MutableHandleValue rval() const {
2189         return Base::rval();
2190     }
2191 
length()2192     unsigned length() const { return Base::length(); }
2193 
2194     JS::MutableHandleValue operator[](unsigned i) const {
2195         return Base::operator[](i);
2196     }
2197 
hasDefined(unsigned i)2198     bool hasDefined(unsigned i) const {
2199         return Base::hasDefined(i);
2200     }
2201 
callee()2202     JSObject& callee() const {
2203         // We can't use Base::callee() because that will try to poke at
2204         // this->usedRval_, which we don't have.
2205         return argv_[-2].toObject();
2206     }
2207 
get(unsigned i)2208     JS::HandleValue get(unsigned i) const {
2209         return Base::get(i);
2210     }
2211 };
2212 
2213 struct JSJitMethodCallArgsTraits
2214 {
2215     static const size_t offsetOfArgv = offsetof(JSJitMethodCallArgs, argv_);
2216     static const size_t offsetOfArgc = offsetof(JSJitMethodCallArgs, argc_);
2217 };
2218 
2219 typedef bool
2220 (* JSJitGetterOp)(JSContext* cx, JS::HandleObject thisObj,
2221                   void* specializedThis, JSJitGetterCallArgs args);
2222 typedef bool
2223 (* JSJitSetterOp)(JSContext* cx, JS::HandleObject thisObj,
2224                   void* specializedThis, JSJitSetterCallArgs args);
2225 typedef bool
2226 (* JSJitMethodOp)(JSContext* cx, JS::HandleObject thisObj,
2227                   void* specializedThis, const JSJitMethodCallArgs& args);
2228 
2229 /**
2230  * This struct contains metadata passed from the DOM to the JS Engine for JIT
2231  * optimizations on DOM property accessors. Eventually, this should be made
2232  * available to general JSAPI users, but we are not currently ready to do so.
2233  */
2234 struct JSJitInfo {
2235     enum OpType {
2236         Getter,
2237         Setter,
2238         Method,
2239         StaticMethod,
2240         InlinableNative,
2241         // Must be last
2242         OpTypeCount
2243     };
2244 
2245     enum ArgType {
2246         // Basic types
2247         String = (1 << 0),
2248         Integer = (1 << 1), // Only 32-bit or less
2249         Double = (1 << 2), // Maybe we want to add Float sometime too
2250         Boolean = (1 << 3),
2251         Object = (1 << 4),
2252         Null = (1 << 5),
2253 
2254         // And derived types
2255         Numeric = Integer | Double,
2256         // Should "Primitive" use the WebIDL definition, which
2257         // excludes string and null, or the typical JS one that includes them?
2258         Primitive = Numeric | Boolean | Null | String,
2259         ObjectOrNull = Object | Null,
2260         Any = ObjectOrNull | Primitive,
2261 
2262         // Our sentinel value.
2263         ArgTypeListEnd = (1 << 31)
2264     };
2265 
2266     static_assert(Any & String, "Any must include String.");
2267     static_assert(Any & Integer, "Any must include Integer.");
2268     static_assert(Any & Double, "Any must include Double.");
2269     static_assert(Any & Boolean, "Any must include Boolean.");
2270     static_assert(Any & Object, "Any must include Object.");
2271     static_assert(Any & Null, "Any must include Null.");
2272 
2273     /**
2274      * An enum that describes what this getter/setter/method aliases.  This
2275      * determines what things can be hoisted past this call, and if this
2276      * call is movable what it can be hoisted past.
2277      */
2278     enum AliasSet {
2279         /**
2280          * Alias nothing: a constant value, getting it can't affect any other
2281          * values, nothing can affect it.
2282          */
2283         AliasNone,
2284 
2285         /**
2286          * Alias things that can modify the DOM but nothing else.  Doing the
2287          * call can't affect the behavior of any other function.
2288          */
2289         AliasDOMSets,
2290 
2291         /**
2292          * Alias the world.  Calling this can change arbitrary values anywhere
2293          * in the system.  Most things fall in this bucket.
2294          */
2295         AliasEverything,
2296 
2297         /** Must be last. */
2298         AliasSetCount
2299     };
2300 
needsOuterizedThisObjectJSJitInfo2301     bool needsOuterizedThisObject() const
2302     {
2303         return type() != Getter && type() != Setter;
2304     }
2305 
isTypedMethodJitInfoJSJitInfo2306     bool isTypedMethodJitInfo() const
2307     {
2308         return isTypedMethod;
2309     }
2310 
typeJSJitInfo2311     OpType type() const
2312     {
2313         return OpType(type_);
2314     }
2315 
aliasSetJSJitInfo2316     AliasSet aliasSet() const
2317     {
2318         return AliasSet(aliasSet_);
2319     }
2320 
returnTypeJSJitInfo2321     JSValueType returnType() const
2322     {
2323         return JSValueType(returnType_);
2324     }
2325 
2326     union {
2327         JSJitGetterOp getter;
2328         JSJitSetterOp setter;
2329         JSJitMethodOp method;
2330         /** A DOM static method, used for Promise wrappers */
2331         JSNative staticMethod;
2332     };
2333 
2334     union {
2335         uint16_t protoID;
2336         js::jit::InlinableNative inlinableNative;
2337     };
2338 
2339     uint16_t depth;
2340 
2341     // These fields are carefully packed to take up 4 bytes.  If you need more
2342     // bits for whatever reason, please see if you can steal bits from existing
2343     // fields before adding more members to this structure.
2344 
2345 #define JITINFO_OP_TYPE_BITS 4
2346 #define JITINFO_ALIAS_SET_BITS 4
2347 #define JITINFO_RETURN_TYPE_BITS 8
2348 #define JITINFO_SLOT_INDEX_BITS 10
2349 
2350     /** The OpType that says what sort of function we are. */
2351     uint32_t type_ : JITINFO_OP_TYPE_BITS;
2352 
2353     /**
2354      * The alias set for this op.  This is a _minimal_ alias set; in
2355      * particular for a method it does not include whatever argument
2356      * conversions might do.  That's covered by argTypes and runtime
2357      * analysis of the actual argument types being passed in.
2358      */
2359     uint32_t aliasSet_ : JITINFO_ALIAS_SET_BITS;
2360 
2361     /** The return type tag.  Might be JSVAL_TYPE_UNKNOWN. */
2362     uint32_t returnType_ : JITINFO_RETURN_TYPE_BITS;
2363 
2364     static_assert(OpTypeCount <= (1 << JITINFO_OP_TYPE_BITS),
2365                   "Not enough space for OpType");
2366     static_assert(AliasSetCount <= (1 << JITINFO_ALIAS_SET_BITS),
2367                   "Not enough space for AliasSet");
2368     static_assert((sizeof(JSValueType) * 8) <= JITINFO_RETURN_TYPE_BITS,
2369                   "Not enough space for JSValueType");
2370 
2371 #undef JITINFO_RETURN_TYPE_BITS
2372 #undef JITINFO_ALIAS_SET_BITS
2373 #undef JITINFO_OP_TYPE_BITS
2374 
2375     /** Is op fallible? False in setters. */
2376     uint32_t isInfallible : 1;
2377 
2378     /**
2379      * Is op movable?  To be movable the op must
2380      * not AliasEverything, but even that might
2381      * not be enough (e.g. in cases when it can
2382      * throw or is explicitly not movable).
2383      */
2384     uint32_t isMovable : 1;
2385 
2386     /**
2387      * Can op be dead-code eliminated? Again, this
2388      * depends on whether the op can throw, in
2389      * addition to the alias set.
2390      */
2391     uint32_t isEliminatable : 1;
2392 
2393     // XXXbz should we have a JSValueType for the type of the member?
2394     /**
2395      * True if this is a getter that can always
2396      * get the value from a slot of the "this" object.
2397      */
2398     uint32_t isAlwaysInSlot : 1;
2399 
2400     /**
2401      * True if this is a getter that can sometimes (if the slot doesn't contain
2402      * UndefinedValue()) get the value from a slot of the "this" object.
2403      */
2404     uint32_t isLazilyCachedInSlot : 1;
2405 
2406     /** True if this is an instance of JSTypedMethodJitInfo. */
2407     uint32_t isTypedMethod : 1;
2408 
2409     /**
2410      * If isAlwaysInSlot or isSometimesInSlot is true,
2411      * the index of the slot to get the value from.
2412      * Otherwise 0.
2413      */
2414     uint32_t slotIndex : JITINFO_SLOT_INDEX_BITS;
2415 
2416     static const size_t maxSlotIndex = (1 << JITINFO_SLOT_INDEX_BITS) - 1;
2417 
2418 #undef JITINFO_SLOT_INDEX_BITS
2419 };
2420 
2421 static_assert(sizeof(JSJitInfo) == (sizeof(void*) + 2 * sizeof(uint32_t)),
2422               "There are several thousand instances of JSJitInfo stored in "
2423               "a binary. Please don't increase its space requirements without "
2424               "verifying that there is no other way forward (better packing, "
2425               "smaller datatypes for fields, subclassing, etc.).");
2426 
2427 struct JSTypedMethodJitInfo
2428 {
2429     // We use C-style inheritance here, rather than C++ style inheritance
2430     // because not all compilers support brace-initialization for non-aggregate
2431     // classes. Using C++ style inheritance and constructors instead of
2432     // brace-initialization would also force the creation of static
2433     // constructors (on some compilers) when JSJitInfo and JSTypedMethodJitInfo
2434     // structures are declared. Since there can be several thousand of these
2435     // structures present and we want to have roughly equivalent performance
2436     // across a range of compilers, we do things manually.
2437     JSJitInfo base;
2438 
2439     const JSJitInfo::ArgType* const argTypes; /* For a method, a list of sets of
2440                                                  types that the function
2441                                                  expects.  This can be used,
2442                                                  for example, to figure out
2443                                                  when argument coercions can
2444                                                  have side-effects. */
2445 };
2446 
2447 namespace js {
2448 
2449 static MOZ_ALWAYS_INLINE shadow::Function*
FunctionObjectToShadowFunction(JSObject * fun)2450 FunctionObjectToShadowFunction(JSObject* fun)
2451 {
2452     MOZ_ASSERT(GetObjectClass(fun) == FunctionClassPtr);
2453     return reinterpret_cast<shadow::Function*>(fun);
2454 }
2455 
2456 /* Statically asserted in jsfun.h. */
2457 static const unsigned JS_FUNCTION_INTERPRETED_BITS = 0x0201;
2458 
2459 // Return whether the given function object is native.
2460 static MOZ_ALWAYS_INLINE bool
FunctionObjectIsNative(JSObject * fun)2461 FunctionObjectIsNative(JSObject* fun)
2462 {
2463     return !(FunctionObjectToShadowFunction(fun)->flags & JS_FUNCTION_INTERPRETED_BITS);
2464 }
2465 
2466 static MOZ_ALWAYS_INLINE JSNative
GetFunctionObjectNative(JSObject * fun)2467 GetFunctionObjectNative(JSObject* fun)
2468 {
2469     MOZ_ASSERT(FunctionObjectIsNative(fun));
2470     return FunctionObjectToShadowFunction(fun)->native;
2471 }
2472 
2473 } // namespace js
2474 
2475 static MOZ_ALWAYS_INLINE const JSJitInfo*
FUNCTION_VALUE_TO_JITINFO(const JS::Value & v)2476 FUNCTION_VALUE_TO_JITINFO(const JS::Value& v)
2477 {
2478     MOZ_ASSERT(js::FunctionObjectIsNative(&v.toObject()));
2479     return js::FunctionObjectToShadowFunction(&v.toObject())->jitinfo;
2480 }
2481 
2482 static MOZ_ALWAYS_INLINE void
SET_JITINFO(JSFunction * func,const JSJitInfo * info)2483 SET_JITINFO(JSFunction * func, const JSJitInfo* info)
2484 {
2485     js::shadow::Function* fun = reinterpret_cast<js::shadow::Function*>(func);
2486     MOZ_ASSERT(!(fun->flags & js::JS_FUNCTION_INTERPRETED_BITS));
2487     fun->jitinfo = info;
2488 }
2489 
2490 /*
2491  * Engine-internal extensions of jsid.  This code is here only until we
2492  * eliminate Gecko's dependencies on it!
2493  */
2494 
2495 static MOZ_ALWAYS_INLINE jsid
JSID_FROM_BITS(size_t bits)2496 JSID_FROM_BITS(size_t bits)
2497 {
2498     jsid id;
2499     JSID_BITS(id) = bits;
2500     return id;
2501 }
2502 
2503 namespace js {
2504 namespace detail {
2505 bool IdMatchesAtom(jsid id, JSAtom* atom);
2506 } // namespace detail
2507 } // namespace js
2508 
2509 /**
2510  * Must not be used on atoms that are representable as integer jsids.
2511  * Prefer NameToId or AtomToId over this function:
2512  *
2513  * A PropertyName is an atom that does not contain an integer in the range
2514  * [0, UINT32_MAX]. However, jsid can only hold an integer in the range
2515  * [0, JSID_INT_MAX] (where JSID_INT_MAX == 2^31-1).  Thus, for the range of
2516  * integers (JSID_INT_MAX, UINT32_MAX], to represent as a jsid 'id', it must be
2517  * the case JSID_IS_ATOM(id) and !JSID_TO_ATOM(id)->isPropertyName().  In most
2518  * cases when creating a jsid, code does not have to care about this corner
2519  * case because:
2520  *
2521  * - When given an arbitrary JSAtom*, AtomToId must be used, which checks for
2522  *   integer atoms representable as integer jsids, and does this conversion.
2523  *
2524  * - When given a PropertyName*, NameToId can be used which which does not need
2525  *   to do any dynamic checks.
2526  *
2527  * Thus, it is only the rare third case which needs this function, which
2528  * handles any JSAtom* that is known not to be representable with an int jsid.
2529  */
2530 static MOZ_ALWAYS_INLINE jsid
NON_INTEGER_ATOM_TO_JSID(JSAtom * atom)2531 NON_INTEGER_ATOM_TO_JSID(JSAtom* atom)
2532 {
2533     MOZ_ASSERT(((size_t)atom & 0x7) == 0);
2534     jsid id = JSID_FROM_BITS((size_t)atom);
2535     MOZ_ASSERT(js::detail::IdMatchesAtom(id, atom));
2536     return id;
2537 }
2538 
2539 /* All strings stored in jsids are atomized, but are not necessarily property names. */
2540 static MOZ_ALWAYS_INLINE bool
JSID_IS_ATOM(jsid id)2541 JSID_IS_ATOM(jsid id)
2542 {
2543     return JSID_IS_STRING(id);
2544 }
2545 
2546 static MOZ_ALWAYS_INLINE bool
JSID_IS_ATOM(jsid id,JSAtom * atom)2547 JSID_IS_ATOM(jsid id, JSAtom* atom)
2548 {
2549     return id == JSID_FROM_BITS((size_t)atom);
2550 }
2551 
2552 static MOZ_ALWAYS_INLINE JSAtom*
JSID_TO_ATOM(jsid id)2553 JSID_TO_ATOM(jsid id)
2554 {
2555     return (JSAtom*)JSID_TO_STRING(id);
2556 }
2557 
2558 JS_STATIC_ASSERT(sizeof(jsid) == sizeof(void*));
2559 
2560 namespace js {
2561 
2562 static MOZ_ALWAYS_INLINE JS::Value
IdToValue(jsid id)2563 IdToValue(jsid id)
2564 {
2565     if (JSID_IS_STRING(id))
2566         return JS::StringValue(JSID_TO_STRING(id));
2567     if (JSID_IS_INT(id))
2568         return JS::Int32Value(JSID_TO_INT(id));
2569     if (JSID_IS_SYMBOL(id))
2570         return JS::SymbolValue(JSID_TO_SYMBOL(id));
2571     MOZ_ASSERT(JSID_IS_VOID(id));
2572     return JS::UndefinedValue();
2573 }
2574 
2575 /**
2576  * If the embedder has registered a ScriptEnvironmentPreparer,
2577  * PrepareScriptEnvironmentAndInvoke will call the preparer's 'invoke' method
2578  * with the given |closure|, with the assumption that the preparer will set up
2579  * any state necessary to run script in |scope|, invoke |closure| with a valid
2580  * JSContext*, report any exceptions thrown from the closure, and return.
2581  *
2582  * If no preparer is registered, PrepareScriptEnvironmentAndInvoke will assert
2583  * that |rt| has exactly one JSContext associated with it, enter the compartment
2584  * of |scope| on that context, and invoke |closure|.
2585  *
2586  * In both cases, PrepareScriptEnvironmentAndInvoke will report any exceptions
2587  * that are thrown by the closure.  Consumers who want to propagate back
2588  * whether the closure succeeded should do so via members of the closure
2589  * itself.
2590  */
2591 
2592 struct ScriptEnvironmentPreparer {
2593     struct Closure {
2594         virtual bool operator()(JSContext* cx) = 0;
2595     };
2596 
2597     virtual void invoke(JS::HandleObject scope, Closure& closure) = 0;
2598 };
2599 
2600 extern JS_FRIEND_API(void)
2601 PrepareScriptEnvironmentAndInvoke(JSContext* cx, JS::HandleObject scope,
2602                                   ScriptEnvironmentPreparer::Closure& closure);
2603 
2604 JS_FRIEND_API(void)
2605 SetScriptEnvironmentPreparer(JSRuntime* rt, ScriptEnvironmentPreparer*
2606 preparer);
2607 
2608 /**
2609  * To help embedders enforce their invariants, we allow them to specify in
2610  * advance which JSContext should be passed to JSAPI calls. If this is set
2611  * to a non-null value, the assertSameCompartment machinery does double-
2612  * duty (in debug builds) to verify that it matches the cx being used.
2613  */
2614 #ifdef DEBUG
2615 JS_FRIEND_API(void)
2616 Debug_SetActiveJSContext(JSRuntime* rt, JSContext* cx);
2617 #else
2618 inline void
Debug_SetActiveJSContext(JSRuntime * rt,JSContext * cx)2619 Debug_SetActiveJSContext(JSRuntime* rt, JSContext* cx) {}
2620 #endif
2621 
2622 enum CTypesActivityType {
2623     CTYPES_CALL_BEGIN,
2624     CTYPES_CALL_END,
2625     CTYPES_CALLBACK_BEGIN,
2626     CTYPES_CALLBACK_END
2627 };
2628 
2629 typedef void
2630 (* CTypesActivityCallback)(JSContext* cx, CTypesActivityType type);
2631 
2632 /**
2633  * Sets a callback that is run whenever js-ctypes is about to be used when
2634  * calling into C.
2635  */
2636 JS_FRIEND_API(void)
2637 SetCTypesActivityCallback(JSRuntime* rt, CTypesActivityCallback cb);
2638 
JS_FRIEND_API(AutoCTypesActivityCallback)2639 class MOZ_RAII JS_FRIEND_API(AutoCTypesActivityCallback) {
2640   private:
2641     JSContext* cx;
2642     CTypesActivityCallback callback;
2643     CTypesActivityType endType;
2644     MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
2645 
2646   public:
2647     AutoCTypesActivityCallback(JSContext* cx, CTypesActivityType beginType,
2648                                CTypesActivityType endType
2649                                MOZ_GUARD_OBJECT_NOTIFIER_PARAM);
2650     ~AutoCTypesActivityCallback() {
2651         DoEndCallback();
2652     }
2653     void DoEndCallback() {
2654         if (callback) {
2655             callback(cx, endType);
2656             callback = nullptr;
2657         }
2658     }
2659 };
2660 
2661 typedef JSObject*
2662 (* ObjectMetadataCallback)(JSContext* cx, JSObject* obj);
2663 
2664 /**
2665  * Specify a callback to invoke when creating each JS object in the current
2666  * compartment, which may return a metadata object to associate with the
2667  * object.
2668  */
2669 JS_FRIEND_API(void)
2670 SetObjectMetadataCallback(JSContext* cx, ObjectMetadataCallback callback);
2671 
2672 /** Get the metadata associated with an object. */
2673 JS_FRIEND_API(JSObject*)
2674 GetObjectMetadata(JSObject* obj);
2675 
2676 JS_FRIEND_API(bool)
2677 GetElementsWithAdder(JSContext* cx, JS::HandleObject obj, JS::HandleObject receiver,
2678                      uint32_t begin, uint32_t end, js::ElementAdder* adder);
2679 
2680 JS_FRIEND_API(bool)
2681 ForwardToNative(JSContext* cx, JSNative native, const JS::CallArgs& args);
2682 
2683 /**
2684  * Helper function for HTMLDocument and HTMLFormElement.
2685  *
2686  * These are the only two interfaces that have [OverrideBuiltins], a named
2687  * getter, and no named setter. They're implemented as proxies with a custom
2688  * getOwnPropertyDescriptor() method. Unfortunately, overriding
2689  * getOwnPropertyDescriptor() automatically affects the behavior of set(),
2690  * which normally is just common sense but is *not* desired for these two
2691  * interfaces.
2692  *
2693  * The fix is for these two interfaces to override set() to ignore the
2694  * getOwnPropertyDescriptor() override.
2695  *
2696  * SetPropertyIgnoringNamedGetter is exposed to make it easier to override
2697  * set() in this way.  It carries out all the steps of BaseProxyHandler::set()
2698  * except the initial getOwnPropertyDescriptor() call.  The caller must supply
2699  * that descriptor as the 'ownDesc' parameter.
2700  *
2701  * Implemented in proxy/BaseProxyHandler.cpp.
2702  */
2703 JS_FRIEND_API(bool)
2704 SetPropertyIgnoringNamedGetter(JSContext* cx, JS::HandleObject obj, JS::HandleId id,
2705                                JS::HandleValue v, JS::HandleValue receiver,
2706                                JS::Handle<JSPropertyDescriptor> ownDesc,
2707                                JS::ObjectOpResult& result);
2708 
2709 JS_FRIEND_API(void)
2710 ReportErrorWithId(JSContext* cx, const char* msg, JS::HandleId id);
2711 
2712 // This function is for one specific use case, please don't use this for anything else!
2713 extern JS_FRIEND_API(bool)
2714 ExecuteInGlobalAndReturnScope(JSContext* cx, JS::HandleObject obj, JS::HandleScript script,
2715                               JS::MutableHandleObject scope);
2716 
2717 #if defined(XP_WIN) && defined(_WIN64)
2718 // Parameters use void* types to avoid #including windows.h. The return value of
2719 // this function is returned from the exception handler.
2720 typedef long
2721 (*JitExceptionHandler)(void* exceptionRecord,  // PEXECTION_RECORD
2722                        void* context);         // PCONTEXT
2723 
2724 /**
2725  * Windows uses "structured exception handling" to handle faults. When a fault
2726  * occurs, the stack is searched for a handler (similar to C++ exception
2727  * handling). If the search does not find a handler, the "unhandled exception
2728  * filter" is called. Breakpad uses the unhandled exception filter to do crash
2729  * reporting. Unfortunately, on Win64, JIT code on the stack completely throws
2730  * off this unwinding process and prevents the unhandled exception filter from
2731  * being called. The reason is that Win64 requires unwind information be
2732  * registered for all code regions and JIT code has none. While it is possible
2733  * to register full unwind information for JIT code, this is a lot of work (one
2734  * has to be able to recover the frame pointer at any PC) so instead we register
2735  * a handler for all JIT code that simply calls breakpad's unhandled exception
2736  * filter (which will perform crash reporting and then terminate the process).
2737  * This would be wrong if there was an outer __try block that expected to handle
2738  * the fault, but this is not generally allowed.
2739  *
2740  * Gecko must call SetJitExceptionFilter before any JIT code is compiled and
2741  * only once per process.
2742  */
2743 extern JS_FRIEND_API(void)
2744 SetJitExceptionHandler(JitExceptionHandler handler);
2745 #endif
2746 
2747 /**
2748  * Get the nearest enclosing with scope object for a given function. If the
2749  * function is not scripted or is not enclosed by a with scope, returns the
2750  * global.
2751  */
2752 extern JS_FRIEND_API(JSObject*)
2753 GetNearestEnclosingWithScopeObjectForFunction(JSFunction* fun);
2754 
2755 /**
2756  * Get the first SavedFrame object in this SavedFrame stack whose principals are
2757  * subsumed by the cx's principals. If there is no such frame, return nullptr.
2758  *
2759  * Do NOT pass a non-SavedFrame object here.
2760  *
2761  * The savedFrame and cx do not need to be in the same compartment.
2762  */
2763 extern JS_FRIEND_API(JSObject*)
2764 GetFirstSubsumedSavedFrame(JSContext* cx, JS::HandleObject savedFrame, JS::SavedFrameSelfHosted selfHosted);
2765 
2766 extern JS_FRIEND_API(bool)
2767 ReportIsNotFunction(JSContext* cx, JS::HandleValue v);
2768 
2769 extern JS_FRIEND_API(JSObject*)
2770 ConvertArgsToArray(JSContext* cx, const JS::CallArgs& args);
2771 
2772 /**
2773  * Window and WindowProxy
2774  *
2775  * The functions below have to do with Windows and WindowProxies. There's an
2776  * invariant that actual Window objects (the global objects of web pages) are
2777  * never directly exposed to script. Instead we often substitute a WindowProxy.
2778  *
2779  * The scope chain, on the other hand, contains the Window and never its
2780  * WindowProxy.
2781  *
2782  * As a result, we have calls to these "substitute-this-object-for-that-object"
2783  * functions sprinkled at apparently arbitrary (but actually *very* carefully
2784  * and nervously selected) places throughout the engine and indeed the
2785  * universe.
2786  */
2787 
2788 /**
2789  * Tell the JS engine which Class is used for WindowProxy objects. Used by the
2790  * functions below.
2791  */
2792 extern JS_FRIEND_API(void)
2793 SetWindowProxyClass(JSRuntime* rt, const Class* clasp);
2794 
2795 /**
2796  * Associates a WindowProxy with a Window (global object). `windowProxy` must
2797  * have the Class set by SetWindowProxyClass.
2798  */
2799 extern JS_FRIEND_API(void)
2800 SetWindowProxy(JSContext* cx, JS::HandleObject global, JS::HandleObject windowProxy);
2801 
2802 namespace detail {
2803 
2804 JS_FRIEND_API(bool)
2805 IsWindowSlow(JSObject* obj);
2806 
2807 } // namespace detail
2808 
2809 /**
2810  * Returns true iff `obj` is a global object with an associated WindowProxy,
2811  * see SetWindowProxy.
2812  */
2813 inline bool
IsWindow(JSObject * obj)2814 IsWindow(JSObject* obj)
2815 {
2816     if (GetObjectClass(obj)->flags & JSCLASS_IS_GLOBAL)
2817         return detail::IsWindowSlow(obj);
2818     return false;
2819 }
2820 
2821 /**
2822  * Returns true iff `obj` has the WindowProxy Class (see SetWindowProxyClass).
2823  */
2824 JS_FRIEND_API(bool)
2825 IsWindowProxy(JSObject* obj);
2826 
2827 /**
2828  * If `obj` is a Window, get its associated WindowProxy (or a CCW or dead
2829  * wrapper if the page was navigated away from), else return `obj`. This
2830  * function is infallible and never returns nullptr.
2831  */
2832 extern JS_FRIEND_API(JSObject*)
2833 ToWindowProxyIfWindow(JSObject* obj);
2834 
2835 /**
2836  * If `obj` is a WindowProxy, get its associated Window (the compartment's
2837  * global), else return `obj`. This function is infallible and never returns
2838  * nullptr.
2839  */
2840 extern JS_FRIEND_API(JSObject*)
2841 ToWindowIfWindowProxy(JSObject* obj);
2842 
2843 } /* namespace js */
2844 
2845 extern JS_FRIEND_API(void)
2846 JS_StoreObjectPostBarrierCallback(JSContext* cx,
2847                                   void (*callback)(JSTracer* trc, JSObject* key, void* data),
2848                                   JSObject* key, void* data);
2849 
2850 extern JS_FRIEND_API(void)
2851 JS_StoreStringPostBarrierCallback(JSContext* cx,
2852                                   void (*callback)(JSTracer* trc, JSString* key, void* data),
2853                                   JSString* key, void* data);
2854 
2855 /**
2856  * Forcibly clear postbarrier callbacks queued by the previous two methods.
2857  * This should be used when the object owning the postbarriered pointers is
2858  * being destroyed outside of a garbage collection.
2859  *
2860  * This currently works by performing a minor GC.
2861  */
2862 extern JS_FRIEND_API(void)
2863 JS_ClearAllPostBarrierCallbacks(JSRuntime *rt);
2864 
2865 class NativeProfiler
2866 {
2867   public:
~NativeProfiler()2868     virtual ~NativeProfiler() {};
2869     virtual void sampleNative(void* addr, uint32_t size) = 0;
2870     virtual void removeNative(void* addr) = 0;
2871     virtual void reset() = 0;
2872 };
2873 
2874 class GCHeapProfiler
2875 {
2876   public:
~GCHeapProfiler()2877     virtual ~GCHeapProfiler() {};
2878     virtual void sampleTenured(void* addr, uint32_t size) = 0;
2879     virtual void sampleNursery(void* addr, uint32_t size) = 0;
2880     virtual void markTenuredStart() = 0;
2881     virtual void markTenured(void* addr) = 0;
2882     virtual void sweepTenured() = 0;
2883     virtual void sweepNursery() = 0;
2884     virtual void moveNurseryToTenured(void* addrOld, void* addrNew) = 0;
2885     virtual void reset() = 0;
2886 };
2887 
2888 class MemProfiler
2889 {
2890     static mozilla::Atomic<uint32_t, mozilla::Relaxed> sActiveProfilerCount;
2891     static NativeProfiler* sNativeProfiler;
2892 
2893     static GCHeapProfiler* GetGCHeapProfiler(void* addr);
2894     static GCHeapProfiler* GetGCHeapProfiler(JSRuntime* runtime);
2895 
GetNativeProfiler()2896     static NativeProfiler* GetNativeProfiler() {
2897         return sNativeProfiler;
2898     }
2899 
2900     GCHeapProfiler* mGCHeapProfiler;
2901     JSRuntime* mRuntime;
2902 
2903   public:
MemProfiler(JSRuntime * aRuntime)2904     explicit MemProfiler(JSRuntime* aRuntime) : mGCHeapProfiler(nullptr), mRuntime(aRuntime) {}
2905 
2906     void start(GCHeapProfiler* aGCHeapProfiler);
2907     void stop();
2908 
getGCHeapProfiler()2909     GCHeapProfiler* getGCHeapProfiler() const {
2910         return mGCHeapProfiler;
2911     }
2912 
enabled()2913     static MOZ_ALWAYS_INLINE bool enabled() {
2914         return sActiveProfilerCount > 0;
2915     }
2916 
2917     static MemProfiler* GetMemProfiler(JSRuntime* runtime);
2918 
SetNativeProfiler(NativeProfiler * aProfiler)2919     static void SetNativeProfiler(NativeProfiler* aProfiler) {
2920         sNativeProfiler = aProfiler;
2921     }
2922 
SampleNative(void * addr,uint32_t size)2923     static MOZ_ALWAYS_INLINE void SampleNative(void* addr, uint32_t size) {
2924         JS::AutoSuppressGCAnalysis nogc;
2925 
2926         if (MOZ_LIKELY(!enabled()))
2927             return;
2928 
2929         NativeProfiler* profiler = GetNativeProfiler();
2930         if (profiler)
2931             profiler->sampleNative(addr, size);
2932     }
2933 
SampleTenured(void * addr,uint32_t size)2934     static MOZ_ALWAYS_INLINE void SampleTenured(void* addr, uint32_t size) {
2935         JS::AutoSuppressGCAnalysis nogc;
2936 
2937         if (MOZ_LIKELY(!enabled()))
2938             return;
2939 
2940         GCHeapProfiler* profiler = GetGCHeapProfiler(addr);
2941         if (profiler)
2942             profiler->sampleTenured(addr, size);
2943     }
2944 
SampleNursery(void * addr,uint32_t size)2945     static MOZ_ALWAYS_INLINE void SampleNursery(void* addr, uint32_t size) {
2946         JS::AutoSuppressGCAnalysis nogc;
2947 
2948         if (MOZ_LIKELY(!enabled()))
2949             return;
2950 
2951         GCHeapProfiler* profiler = GetGCHeapProfiler(addr);
2952         if (profiler)
2953             profiler->sampleNursery(addr, size);
2954     }
2955 
RemoveNative(void * addr)2956     static MOZ_ALWAYS_INLINE void RemoveNative(void* addr) {
2957         JS::AutoSuppressGCAnalysis nogc;
2958 
2959         if (MOZ_LIKELY(!enabled()))
2960             return;
2961 
2962         NativeProfiler* profiler = GetNativeProfiler();
2963         if (profiler)
2964             profiler->removeNative(addr);
2965     }
2966 
MarkTenuredStart(JSRuntime * runtime)2967     static MOZ_ALWAYS_INLINE void MarkTenuredStart(JSRuntime* runtime) {
2968         JS::AutoSuppressGCAnalysis nogc;
2969 
2970         if (MOZ_LIKELY(!enabled()))
2971             return;
2972 
2973         GCHeapProfiler* profiler = GetGCHeapProfiler(runtime);
2974         if (profiler)
2975             profiler->markTenuredStart();
2976     }
2977 
MarkTenured(void * addr)2978     static MOZ_ALWAYS_INLINE void MarkTenured(void* addr) {
2979         JS::AutoSuppressGCAnalysis nogc;
2980 
2981         if (MOZ_LIKELY(!enabled()))
2982             return;
2983 
2984         GCHeapProfiler* profiler = GetGCHeapProfiler(addr);
2985         if (profiler)
2986             profiler->markTenured(addr);
2987     }
2988 
SweepTenured(JSRuntime * runtime)2989     static MOZ_ALWAYS_INLINE void SweepTenured(JSRuntime* runtime) {
2990         JS::AutoSuppressGCAnalysis nogc;
2991 
2992         if (MOZ_LIKELY(!enabled()))
2993             return;
2994 
2995         GCHeapProfiler* profiler = GetGCHeapProfiler(runtime);
2996         if (profiler)
2997             profiler->sweepTenured();
2998     }
2999 
SweepNursery(JSRuntime * runtime)3000     static MOZ_ALWAYS_INLINE void SweepNursery(JSRuntime* runtime) {
3001         JS::AutoSuppressGCAnalysis nogc;
3002 
3003         if (MOZ_LIKELY(!enabled()))
3004             return;
3005 
3006         GCHeapProfiler* profiler = GetGCHeapProfiler(runtime);
3007         if (profiler)
3008             profiler->sweepNursery();
3009     }
3010 
MoveNurseryToTenured(void * addrOld,void * addrNew)3011     static MOZ_ALWAYS_INLINE void MoveNurseryToTenured(void* addrOld, void* addrNew) {
3012         JS::AutoSuppressGCAnalysis nogc;
3013 
3014         if (MOZ_LIKELY(!enabled()))
3015             return;
3016 
3017         GCHeapProfiler* profiler = GetGCHeapProfiler(addrOld);
3018         if (profiler)
3019             profiler->moveNurseryToTenured(addrOld, addrNew);
3020     }
3021 };
3022 
3023 #endif /* jsfriendapi_h */
3024