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