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