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