1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
2  * vim: set ts=8 sts=2 et sw=2 tw=80:
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 #include "jit/VMFunctions.h"
8 
9 #include "mozilla/FloatingPoint.h"
10 
11 #include "builtin/String.h"
12 #include "frontend/BytecodeCompiler.h"
13 #include "gc/Cell.h"
14 #include "jit/arm/Simulator-arm.h"
15 #include "jit/AtomicOperations.h"
16 #include "jit/BaselineIC.h"
17 #include "jit/CalleeToken.h"
18 #include "jit/Invalidation.h"
19 #include "jit/JitFrames.h"
20 #include "jit/JitRuntime.h"
21 #include "jit/mips32/Simulator-mips32.h"
22 #include "jit/mips64/Simulator-mips64.h"
23 #include "js/friend/ErrorMessages.h"  // js::GetErrorMessage, JSMSG_*
24 #include "js/friend/StackLimits.h"    // js::AutoCheckRecursionLimit
25 #include "js/friend/WindowProxy.h"    // js::IsWindow
26 #include "js/Printf.h"
27 #include "vm/ArrayObject.h"
28 #include "vm/Interpreter.h"
29 #include "vm/PlainObject.h"  // js::PlainObject
30 #include "vm/SelfHosting.h"
31 #include "vm/TraceLogging.h"
32 #include "vm/TypedArrayObject.h"
33 #include "wasm/TypedObject.h"
34 
35 #include "debugger/DebugAPI-inl.h"
36 #include "jit/BaselineFrame-inl.h"
37 #include "jit/VMFunctionList-inl.h"
38 #include "vm/Interpreter-inl.h"
39 #include "vm/JSScript-inl.h"
40 #include "vm/NativeObject-inl.h"
41 #include "vm/PlainObject-inl.h"  // js::CreateThis
42 #include "vm/StringObject-inl.h"
43 
44 using namespace js;
45 using namespace js::jit;
46 
47 namespace js {
48 
49 class ArgumentsObject;
50 class NamedLambdaObject;
51 class AsyncFunctionGeneratorObject;
52 class RegExpObject;
53 
54 namespace jit {
55 
56 struct IonOsrTempData;
57 
58 struct PopValues {
59   uint8_t numValues;
60 
PopValuesjs::jit::PopValues61   explicit constexpr PopValues(uint8_t numValues) : numValues(numValues) {}
62 };
63 
64 template <class>
65 struct TypeToDataType { /* Unexpected return type for a VMFunction. */
66 };
67 template <>
68 struct TypeToDataType<void> {
69   static const DataType result = Type_Void;
70 };
71 template <>
72 struct TypeToDataType<bool> {
73   static const DataType result = Type_Bool;
74 };
75 template <>
76 struct TypeToDataType<JSObject*> {
77   static const DataType result = Type_Object;
78 };
79 template <>
80 struct TypeToDataType<JSFunction*> {
81   static const DataType result = Type_Object;
82 };
83 template <>
84 struct TypeToDataType<NativeObject*> {
85   static const DataType result = Type_Object;
86 };
87 template <>
88 struct TypeToDataType<PlainObject*> {
89   static const DataType result = Type_Object;
90 };
91 template <>
92 struct TypeToDataType<InlineTypedObject*> {
93   static const DataType result = Type_Object;
94 };
95 template <>
96 struct TypeToDataType<NamedLambdaObject*> {
97   static const DataType result = Type_Object;
98 };
99 template <>
100 struct TypeToDataType<BlockLexicalEnvironmentObject*> {
101   static const DataType result = Type_Object;
102 };
103 template <>
104 struct TypeToDataType<ClassBodyLexicalEnvironmentObject*> {
105   static const DataType result = Type_Object;
106 };
107 template <>
108 struct TypeToDataType<ArgumentsObject*> {
109   static const DataType result = Type_Object;
110 };
111 template <>
112 struct TypeToDataType<ArrayObject*> {
113   static const DataType result = Type_Object;
114 };
115 template <>
116 struct TypeToDataType<TypedArrayObject*> {
117   static const DataType result = Type_Object;
118 };
119 template <>
120 struct TypeToDataType<ArrayIteratorObject*> {
121   static const DataType result = Type_Object;
122 };
123 template <>
124 struct TypeToDataType<StringIteratorObject*> {
125   static const DataType result = Type_Object;
126 };
127 template <>
128 struct TypeToDataType<RegExpStringIteratorObject*> {
129   static const DataType result = Type_Object;
130 };
131 template <>
132 struct TypeToDataType<JSString*> {
133   static const DataType result = Type_Object;
134 };
135 template <>
136 struct TypeToDataType<JSLinearString*> {
137   static const DataType result = Type_Object;
138 };
139 
140 template <>
141 struct TypeToDataType<BigInt*> {
142   static const DataType result = Type_Object;
143 };
144 template <>
145 struct TypeToDataType<HandleObject> {
146   static const DataType result = Type_Handle;
147 };
148 template <>
149 struct TypeToDataType<HandleString> {
150   static const DataType result = Type_Handle;
151 };
152 template <>
153 struct TypeToDataType<HandlePropertyName> {
154   static const DataType result = Type_Handle;
155 };
156 template <>
157 struct TypeToDataType<HandleFunction> {
158   static const DataType result = Type_Handle;
159 };
160 template <>
161 struct TypeToDataType<Handle<NativeObject*> > {
162   static const DataType result = Type_Handle;
163 };
164 template <>
165 struct TypeToDataType<Handle<InlineTypedObject*> > {
166   static const DataType result = Type_Handle;
167 };
168 template <>
169 struct TypeToDataType<Handle<ArrayObject*> > {
170   static const DataType result = Type_Handle;
171 };
172 template <>
173 struct TypeToDataType<Handle<AbstractGeneratorObject*> > {
174   static const DataType result = Type_Handle;
175 };
176 template <>
177 struct TypeToDataType<Handle<AsyncFunctionGeneratorObject*> > {
178   static const DataType result = Type_Handle;
179 };
180 template <>
181 struct TypeToDataType<Handle<PlainObject*> > {
182   static const DataType result = Type_Handle;
183 };
184 template <>
185 struct TypeToDataType<Handle<WithScope*> > {
186   static const DataType result = Type_Handle;
187 };
188 template <>
189 struct TypeToDataType<Handle<LexicalScope*> > {
190   static const DataType result = Type_Handle;
191 };
192 template <>
193 struct TypeToDataType<Handle<ClassBodyScope*> > {
194   static const DataType result = Type_Handle;
195 };
196 template <>
197 struct TypeToDataType<Handle<Scope*> > {
198   static const DataType result = Type_Handle;
199 };
200 template <>
201 struct TypeToDataType<HandleScript> {
202   static const DataType result = Type_Handle;
203 };
204 template <>
205 struct TypeToDataType<HandleValue> {
206   static const DataType result = Type_Handle;
207 };
208 template <>
209 struct TypeToDataType<MutableHandleValue> {
210   static const DataType result = Type_Handle;
211 };
212 template <>
213 struct TypeToDataType<HandleId> {
214   static const DataType result = Type_Handle;
215 };
216 template <>
217 struct TypeToDataType<HandleBigInt> {
218   static const DataType result = Type_Handle;
219 };
220 
221 // Convert argument types to properties of the argument known by the jit.
222 template <class T>
223 struct TypeToArgProperties {
224   static const uint32_t result =
225       (sizeof(T) <= sizeof(void*) ? VMFunctionData::Word
226                                   : VMFunctionData::Double);
227 };
228 template <>
229 struct TypeToArgProperties<const Value&> {
230   static const uint32_t result =
231       TypeToArgProperties<Value>::result | VMFunctionData::ByRef;
232 };
233 template <>
234 struct TypeToArgProperties<HandleObject> {
235   static const uint32_t result =
236       TypeToArgProperties<JSObject*>::result | VMFunctionData::ByRef;
237 };
238 template <>
239 struct TypeToArgProperties<HandleString> {
240   static const uint32_t result =
241       TypeToArgProperties<JSString*>::result | VMFunctionData::ByRef;
242 };
243 template <>
244 struct TypeToArgProperties<HandlePropertyName> {
245   static const uint32_t result =
246       TypeToArgProperties<PropertyName*>::result | VMFunctionData::ByRef;
247 };
248 template <>
249 struct TypeToArgProperties<HandleFunction> {
250   static const uint32_t result =
251       TypeToArgProperties<JSFunction*>::result | VMFunctionData::ByRef;
252 };
253 template <>
254 struct TypeToArgProperties<Handle<NativeObject*> > {
255   static const uint32_t result =
256       TypeToArgProperties<NativeObject*>::result | VMFunctionData::ByRef;
257 };
258 template <>
259 struct TypeToArgProperties<Handle<InlineTypedObject*> > {
260   static const uint32_t result =
261       TypeToArgProperties<InlineTypedObject*>::result | VMFunctionData::ByRef;
262 };
263 template <>
264 struct TypeToArgProperties<Handle<ArrayObject*> > {
265   static const uint32_t result =
266       TypeToArgProperties<ArrayObject*>::result | VMFunctionData::ByRef;
267 };
268 template <>
269 struct TypeToArgProperties<Handle<AbstractGeneratorObject*> > {
270   static const uint32_t result =
271       TypeToArgProperties<AbstractGeneratorObject*>::result |
272       VMFunctionData::ByRef;
273 };
274 template <>
275 struct TypeToArgProperties<Handle<AsyncFunctionGeneratorObject*> > {
276   static const uint32_t result =
277       TypeToArgProperties<AsyncFunctionGeneratorObject*>::result |
278       VMFunctionData::ByRef;
279 };
280 template <>
281 struct TypeToArgProperties<Handle<PlainObject*> > {
282   static const uint32_t result =
283       TypeToArgProperties<PlainObject*>::result | VMFunctionData::ByRef;
284 };
285 template <>
286 struct TypeToArgProperties<Handle<RegExpObject*> > {
287   static const uint32_t result =
288       TypeToArgProperties<RegExpObject*>::result | VMFunctionData::ByRef;
289 };
290 template <>
291 struct TypeToArgProperties<Handle<WithScope*> > {
292   static const uint32_t result =
293       TypeToArgProperties<WithScope*>::result | VMFunctionData::ByRef;
294 };
295 template <>
296 struct TypeToArgProperties<Handle<LexicalScope*> > {
297   static const uint32_t result =
298       TypeToArgProperties<LexicalScope*>::result | VMFunctionData::ByRef;
299 };
300 template <>
301 struct TypeToArgProperties<Handle<ClassBodyScope*> > {
302   static const uint32_t result =
303       TypeToArgProperties<ClassBodyScope*>::result | VMFunctionData::ByRef;
304 };
305 template <>
306 struct TypeToArgProperties<Handle<Scope*> > {
307   static const uint32_t result =
308       TypeToArgProperties<Scope*>::result | VMFunctionData::ByRef;
309 };
310 template <>
311 struct TypeToArgProperties<HandleScript> {
312   static const uint32_t result =
313       TypeToArgProperties<JSScript*>::result | VMFunctionData::ByRef;
314 };
315 template <>
316 struct TypeToArgProperties<HandleValue> {
317   static const uint32_t result =
318       TypeToArgProperties<Value>::result | VMFunctionData::ByRef;
319 };
320 template <>
321 struct TypeToArgProperties<MutableHandleValue> {
322   static const uint32_t result =
323       TypeToArgProperties<Value>::result | VMFunctionData::ByRef;
324 };
325 template <>
326 struct TypeToArgProperties<HandleId> {
327   static const uint32_t result =
328       TypeToArgProperties<jsid>::result | VMFunctionData::ByRef;
329 };
330 template <>
331 struct TypeToArgProperties<HandleShape> {
332   static const uint32_t result =
333       TypeToArgProperties<Shape*>::result | VMFunctionData::ByRef;
334 };
335 template <>
336 struct TypeToArgProperties<HandleBigInt> {
337   static const uint32_t result =
338       TypeToArgProperties<BigInt*>::result | VMFunctionData::ByRef;
339 };
340 
341 // Convert argument type to whether or not it should be passed in a float
342 // register on platforms that have them, like x64.
343 template <class T>
344 struct TypeToPassInFloatReg {
345   static const uint32_t result = 0;
346 };
347 template <>
348 struct TypeToPassInFloatReg<double> {
349   static const uint32_t result = 1;
350 };
351 
352 // Convert argument types to root types used by the gc, see MarkJitExitFrame.
353 template <class T>
354 struct TypeToRootType {
355   static const uint32_t result = VMFunctionData::RootNone;
356 };
357 template <>
358 struct TypeToRootType<HandleObject> {
359   static const uint32_t result = VMFunctionData::RootObject;
360 };
361 template <>
362 struct TypeToRootType<HandleString> {
363   static const uint32_t result = VMFunctionData::RootString;
364 };
365 template <>
366 struct TypeToRootType<HandlePropertyName> {
367   static const uint32_t result = VMFunctionData::RootString;
368 };
369 template <>
370 struct TypeToRootType<HandleFunction> {
371   static const uint32_t result = VMFunctionData::RootFunction;
372 };
373 template <>
374 struct TypeToRootType<HandleValue> {
375   static const uint32_t result = VMFunctionData::RootValue;
376 };
377 template <>
378 struct TypeToRootType<MutableHandleValue> {
379   static const uint32_t result = VMFunctionData::RootValue;
380 };
381 template <>
382 struct TypeToRootType<HandleId> {
383   static const uint32_t result = VMFunctionData::RootId;
384 };
385 template <>
386 struct TypeToRootType<HandleShape> {
387   static const uint32_t result = VMFunctionData::RootCell;
388 };
389 template <>
390 struct TypeToRootType<HandleScript> {
391   static const uint32_t result = VMFunctionData::RootCell;
392 };
393 template <>
394 struct TypeToRootType<Handle<NativeObject*> > {
395   static const uint32_t result = VMFunctionData::RootObject;
396 };
397 template <>
398 struct TypeToRootType<Handle<InlineTypedObject*> > {
399   static const uint32_t result = VMFunctionData::RootObject;
400 };
401 template <>
402 struct TypeToRootType<Handle<ArrayObject*> > {
403   static const uint32_t result = VMFunctionData::RootObject;
404 };
405 template <>
406 struct TypeToRootType<Handle<AbstractGeneratorObject*> > {
407   static const uint32_t result = VMFunctionData::RootObject;
408 };
409 template <>
410 struct TypeToRootType<Handle<AsyncFunctionGeneratorObject*> > {
411   static const uint32_t result = VMFunctionData::RootObject;
412 };
413 template <>
414 struct TypeToRootType<Handle<PlainObject*> > {
415   static const uint32_t result = VMFunctionData::RootObject;
416 };
417 template <>
418 struct TypeToRootType<Handle<RegExpObject*> > {
419   static const uint32_t result = VMFunctionData::RootObject;
420 };
421 template <>
422 struct TypeToRootType<Handle<LexicalScope*> > {
423   static const uint32_t result = VMFunctionData::RootCell;
424 };
425 template <>
426 struct TypeToRootType<Handle<ClassBodyScope*> > {
427   static const uint32_t result = VMFunctionData::RootCell;
428 };
429 template <>
430 struct TypeToRootType<Handle<WithScope*> > {
431   static const uint32_t result = VMFunctionData::RootCell;
432 };
433 template <>
434 struct TypeToRootType<Handle<Scope*> > {
435   static const uint32_t result = VMFunctionData::RootCell;
436 };
437 template <>
438 struct TypeToRootType<HandleBigInt> {
439   static const uint32_t result = VMFunctionData::RootBigInt;
440 };
441 template <class T>
442 struct TypeToRootType<Handle<T> > {
443   // Fail for Handle types that aren't specialized above.
444 };
445 
446 template <class>
447 struct OutParamToDataType {
448   static const DataType result = Type_Void;
449 };
450 template <>
451 struct OutParamToDataType<Value*> {
452   static const DataType result = Type_Value;
453 };
454 template <>
455 struct OutParamToDataType<int*> {
456   static const DataType result = Type_Int32;
457 };
458 template <>
459 struct OutParamToDataType<uint32_t*> {
460   static const DataType result = Type_Int32;
461 };
462 template <>
463 struct OutParamToDataType<uint8_t**> {
464   static const DataType result = Type_Pointer;
465 };
466 template <>
467 struct OutParamToDataType<IonOsrTempData**> {
468   static const DataType result = Type_Pointer;
469 };
470 template <>
471 struct OutParamToDataType<bool*> {
472   static const DataType result = Type_Bool;
473 };
474 template <>
475 struct OutParamToDataType<double*> {
476   static const DataType result = Type_Double;
477 };
478 template <>
479 struct OutParamToDataType<MutableHandleValue> {
480   static const DataType result = Type_Handle;
481 };
482 template <>
483 struct OutParamToDataType<MutableHandleObject> {
484   static const DataType result = Type_Handle;
485 };
486 template <>
487 struct OutParamToDataType<MutableHandleString> {
488   static const DataType result = Type_Handle;
489 };
490 template <>
491 struct OutParamToDataType<MutableHandleBigInt> {
492   static const DataType result = Type_Handle;
493 };
494 
495 template <class>
496 struct OutParamToRootType {
497   static const VMFunctionData::RootType result = VMFunctionData::RootNone;
498 };
499 template <>
500 struct OutParamToRootType<MutableHandleValue> {
501   static const VMFunctionData::RootType result = VMFunctionData::RootValue;
502 };
503 template <>
504 struct OutParamToRootType<MutableHandleObject> {
505   static const VMFunctionData::RootType result = VMFunctionData::RootObject;
506 };
507 template <>
508 struct OutParamToRootType<MutableHandleString> {
509   static const VMFunctionData::RootType result = VMFunctionData::RootString;
510 };
511 template <>
512 struct OutParamToRootType<MutableHandleBigInt> {
513   static const VMFunctionData::RootType result = VMFunctionData::RootBigInt;
514 };
515 
516 // Construct a bit mask from a list of types.  The mask is constructed as an OR
517 // of the mask produced for each argument. The result of each argument is
518 // shifted by its index, such that the result of the first argument is on the
519 // low bits of the mask, and the result of the last argument in part of the
520 // high bits of the mask.
521 template <template <typename> class Each, typename ResultType, size_t Shift,
522           typename... Args>
523 struct BitMask;
524 
525 template <template <typename> class Each, typename ResultType, size_t Shift>
526 struct BitMask<Each, ResultType, Shift> {
527   static constexpr ResultType result = ResultType();
528 };
529 
530 template <template <typename> class Each, typename ResultType, size_t Shift,
531           typename HeadType, typename... TailTypes>
532 struct BitMask<Each, ResultType, Shift, HeadType, TailTypes...> {
533   static_assert(ResultType(Each<HeadType>::result) < (1 << Shift),
534                 "not enough bits reserved by the shift for individual results");
535   static_assert(sizeof...(TailTypes) < (8 * sizeof(ResultType) / Shift),
536                 "not enough bits in the result type to store all bit masks");
537 
538   static constexpr ResultType result =
539       ResultType(Each<HeadType>::result) |
540       (BitMask<Each, ResultType, Shift, TailTypes...>::result << Shift);
541 };
542 
543 // Helper template to build the VMFunctionData for a function.
544 template <typename... Args>
545 struct VMFunctionDataHelper;
546 
547 template <class R, typename... Args>
548 struct VMFunctionDataHelper<R (*)(JSContext*, Args...)>
549     : public VMFunctionData {
550   using Fun = R (*)(JSContext*, Args...);
551 
returnTypejs::jit::VMFunctionDataHelper552   static constexpr DataType returnType() { return TypeToDataType<R>::result; }
outParamjs::jit::VMFunctionDataHelper553   static constexpr DataType outParam() {
554     return OutParamToDataType<typename LastArg<Args...>::Type>::result;
555   }
outParamRootTypejs::jit::VMFunctionDataHelper556   static constexpr RootType outParamRootType() {
557     return OutParamToRootType<typename LastArg<Args...>::Type>::result;
558   }
NbArgsjs::jit::VMFunctionDataHelper559   static constexpr size_t NbArgs() { return sizeof...(Args); }
explicitArgsjs::jit::VMFunctionDataHelper560   static constexpr size_t explicitArgs() {
561     return NbArgs() - (outParam() != Type_Void ? 1 : 0);
562   }
argumentPropertiesjs::jit::VMFunctionDataHelper563   static constexpr uint32_t argumentProperties() {
564     return BitMask<TypeToArgProperties, uint32_t, 2, Args...>::result;
565   }
argumentPassedInFloatRegsjs::jit::VMFunctionDataHelper566   static constexpr uint32_t argumentPassedInFloatRegs() {
567     return BitMask<TypeToPassInFloatReg, uint32_t, 2, Args...>::result;
568   }
argumentRootTypesjs::jit::VMFunctionDataHelper569   static constexpr uint64_t argumentRootTypes() {
570     return BitMask<TypeToRootType, uint64_t, 3, Args...>::result;
571   }
VMFunctionDataHelperjs::jit::VMFunctionDataHelper572   constexpr explicit VMFunctionDataHelper(const char* name)
573       : VMFunctionData(name, explicitArgs(), argumentProperties(),
574                        argumentPassedInFloatRegs(), argumentRootTypes(),
575                        outParam(), outParamRootType(), returnType(),
576                        /* extraValuesToPop = */ 0, NonTailCall) {}
VMFunctionDataHelperjs::jit::VMFunctionDataHelper577   constexpr explicit VMFunctionDataHelper(const char* name,
578                                           MaybeTailCall expectTailCall,
579                                           PopValues extraValuesToPop)
580       : VMFunctionData(name, explicitArgs(), argumentProperties(),
581                        argumentPassedInFloatRegs(), argumentRootTypes(),
582                        outParam(), outParamRootType(), returnType(),
583                        extraValuesToPop.numValues, expectTailCall) {}
584 };
585 
586 // GCC warns when the signature does not have matching attributes (for example
587 // [[nodiscard]]). Squelch this warning to avoid a GCC-only footgun.
588 #if MOZ_IS_GCC
589 #  pragma GCC diagnostic push
590 #  pragma GCC diagnostic ignored "-Wignored-attributes"
591 #endif
592 
593 // Generate VMFunctionData array.
594 static constexpr VMFunctionData vmFunctions[] = {
595 #define DEF_VMFUNCTION(name, fp) VMFunctionDataHelper<decltype(&(::fp))>(#name),
596     VMFUNCTION_LIST(DEF_VMFUNCTION)
597 #undef DEF_VMFUNCTION
598 };
599 static constexpr VMFunctionData tailCallVMFunctions[] = {
600 #define DEF_VMFUNCTION(name, fp, valuesToPop)              \
601   VMFunctionDataHelper<decltype(&(::fp))>(#name, TailCall, \
602                                           PopValues(valuesToPop)),
603     TAIL_CALL_VMFUNCTION_LIST(DEF_VMFUNCTION)
604 #undef DEF_VMFUNCTION
605 };
606 
607 #if MOZ_IS_GCC
608 #  pragma GCC diagnostic pop
609 #endif
610 
611 // Generate arrays storing C++ function pointers. These pointers are not stored
612 // in VMFunctionData because there's no good way to cast them to void* in
613 // constexpr code. Compilers are smart enough to treat the const array below as
614 // constexpr.
615 #define DEF_VMFUNCTION(name, fp, ...) (void*)(::fp),
616 static void* const vmFunctionTargets[] = {VMFUNCTION_LIST(DEF_VMFUNCTION)};
617 static void* const tailCallVMFunctionTargets[] = {
618     TAIL_CALL_VMFUNCTION_LIST(DEF_VMFUNCTION)};
619 #undef DEF_VMFUNCTION
620 
GetVMFunction(VMFunctionId id)621 const VMFunctionData& GetVMFunction(VMFunctionId id) {
622   return vmFunctions[size_t(id)];
623 }
GetVMFunction(TailCallVMFunctionId id)624 const VMFunctionData& GetVMFunction(TailCallVMFunctionId id) {
625   return tailCallVMFunctions[size_t(id)];
626 }
627 
GetVMFunctionTarget(VMFunctionId id)628 static DynFn GetVMFunctionTarget(VMFunctionId id) {
629   return DynFn{vmFunctionTargets[size_t(id)]};
630 }
631 
GetVMFunctionTarget(TailCallVMFunctionId id)632 static DynFn GetVMFunctionTarget(TailCallVMFunctionId id) {
633   return DynFn{tailCallVMFunctionTargets[size_t(id)]};
634 }
635 
636 template <typename IdT>
generateVMWrappers(JSContext * cx,MacroAssembler & masm,VMWrapperOffsets & offsets)637 bool JitRuntime::generateVMWrappers(JSContext* cx, MacroAssembler& masm,
638                                     VMWrapperOffsets& offsets) {
639   // Generate all VM function wrappers.
640 
641   static constexpr size_t NumVMFunctions = size_t(IdT::Count);
642 
643   if (!offsets.reserve(NumVMFunctions)) {
644     return false;
645   }
646 
647 #ifdef DEBUG
648   const char* lastName = nullptr;
649 #endif
650 
651   for (size_t i = 0; i < NumVMFunctions; i++) {
652     IdT id = IdT(i);
653     const VMFunctionData& fun = GetVMFunction(id);
654 
655 #ifdef DEBUG
656     // Assert the list is sorted by name.
657     if (lastName) {
658       MOZ_ASSERT(strcmp(lastName, fun.name()) < 0,
659                  "VM function list must be sorted by name");
660     }
661     lastName = fun.name();
662 #endif
663 
664     JitSpew(JitSpew_Codegen, "# VM function wrapper (%s)", fun.name());
665 
666     uint32_t offset;
667     if (!generateVMWrapper(cx, masm, fun, GetVMFunctionTarget(id), &offset)) {
668       return false;
669     }
670 
671     MOZ_ASSERT(offsets.length() == size_t(id));
672     offsets.infallibleAppend(offset);
673   }
674 
675   return true;
676 };
677 
generateVMWrappers(JSContext * cx,MacroAssembler & masm)678 bool JitRuntime::generateVMWrappers(JSContext* cx, MacroAssembler& masm) {
679   if (!generateVMWrappers<VMFunctionId>(cx, masm, functionWrapperOffsets_)) {
680     return false;
681   }
682 
683   if (!generateVMWrappers<TailCallVMFunctionId>(
684           cx, masm, tailCallFunctionWrapperOffsets_)) {
685     return false;
686   }
687 
688   return true;
689 }
690 
InvokeFunction(JSContext * cx,HandleObject obj,bool constructing,bool ignoresReturnValue,uint32_t argc,Value * argv,MutableHandleValue rval)691 bool InvokeFunction(JSContext* cx, HandleObject obj, bool constructing,
692                     bool ignoresReturnValue, uint32_t argc, Value* argv,
693                     MutableHandleValue rval) {
694   TraceLoggerThread* logger = TraceLoggerForCurrentThread(cx);
695   TraceLogStartEvent(logger, TraceLogger_Call);
696 
697   RootedExternalValueArray argvRoot(cx, argc + 1 + constructing, argv);
698 
699   // Data in the argument vector is arranged for a JIT -> JIT call.
700   RootedValue thisv(cx, argv[0]);
701   Value* argvWithoutThis = argv + 1;
702 
703   RootedValue fval(cx, ObjectValue(*obj));
704   if (constructing) {
705     if (!IsConstructor(fval)) {
706       ReportValueError(cx, JSMSG_NOT_CONSTRUCTOR, JSDVG_IGNORE_STACK, fval,
707                        nullptr);
708       return false;
709     }
710 
711     ConstructArgs cargs(cx);
712     if (!cargs.init(cx, argc)) {
713       return false;
714     }
715 
716     for (uint32_t i = 0; i < argc; i++) {
717       cargs[i].set(argvWithoutThis[i]);
718     }
719 
720     RootedValue newTarget(cx, argvWithoutThis[argc]);
721 
722     // See CreateThisFromIon for why this can be NullValue.
723     if (thisv.isNull()) {
724       thisv.setMagic(JS_IS_CONSTRUCTING);
725     }
726 
727     // If |this| hasn't been created, or is JS_UNINITIALIZED_LEXICAL,
728     // we can use normal construction code without creating an extraneous
729     // object.
730     if (thisv.isMagic()) {
731       MOZ_ASSERT(thisv.whyMagic() == JS_IS_CONSTRUCTING ||
732                  thisv.whyMagic() == JS_UNINITIALIZED_LEXICAL);
733 
734       RootedObject obj(cx);
735       if (!Construct(cx, fval, cargs, newTarget, &obj)) {
736         return false;
737       }
738 
739       rval.setObject(*obj);
740       return true;
741     }
742 
743     // Otherwise the default |this| has already been created.  We could
744     // almost perform a *call* at this point, but we'd break |new.target|
745     // in the function.  So in this one weird case we call a one-off
746     // construction path that *won't* set |this| to JS_IS_CONSTRUCTING.
747     return InternalConstructWithProvidedThis(cx, fval, thisv, cargs, newTarget,
748                                              rval);
749   }
750 
751   InvokeArgsMaybeIgnoresReturnValue args(cx);
752   if (!args.init(cx, argc, ignoresReturnValue)) {
753     return false;
754   }
755 
756   for (size_t i = 0; i < argc; i++) {
757     args[i].set(argvWithoutThis[i]);
758   }
759 
760   return Call(cx, fval, thisv, args, rval);
761 }
762 
GetContextSensitiveInterpreterStub()763 void* GetContextSensitiveInterpreterStub() {
764   return TlsContext.get()->runtime()->jitRuntime()->interpreterStub().value;
765 }
766 
InvokeFromInterpreterStub(JSContext * cx,InterpreterStubExitFrameLayout * frame)767 bool InvokeFromInterpreterStub(JSContext* cx,
768                                InterpreterStubExitFrameLayout* frame) {
769   JitFrameLayout* jsFrame = frame->jsFrame();
770   CalleeToken token = jsFrame->calleeToken();
771 
772   Value* argv = jsFrame->argv();
773   uint32_t numActualArgs = jsFrame->numActualArgs();
774   bool constructing = CalleeTokenIsConstructing(token);
775   RootedFunction fun(cx, CalleeTokenToFunction(token));
776 
777   // Ensure new.target immediately follows the actual arguments (the arguments
778   // rectifier added padding).
779   if (constructing && numActualArgs < fun->nargs()) {
780     argv[1 + numActualArgs] = argv[1 + fun->nargs()];
781   }
782 
783   RootedValue rval(cx);
784   if (!InvokeFunction(cx, fun, constructing,
785                       /* ignoresReturnValue = */ false, numActualArgs, argv,
786                       &rval)) {
787     return false;
788   }
789 
790   // Overwrite |this| with the return value.
791   argv[0] = rval;
792   return true;
793 }
794 
CheckOverRecursedImpl(JSContext * cx,size_t extra)795 static bool CheckOverRecursedImpl(JSContext* cx, size_t extra) {
796   // We just failed the jitStackLimit check. There are two possible reasons:
797   //  1) jitStackLimit was the real stack limit and we're over-recursed
798   //  2) jitStackLimit was set to UINTPTR_MAX by JSContext::requestInterrupt
799   //     and we need to call JSContext::handleInterrupt.
800 
801   // This handles 1).
802 #ifdef JS_SIMULATOR
803   if (cx->simulator()->overRecursedWithExtra(extra)) {
804     ReportOverRecursed(cx);
805     return false;
806   }
807 #else
808   AutoCheckRecursionLimit recursion(cx);
809   if (!recursion.checkWithExtra(cx, extra)) {
810     return false;
811   }
812 #endif
813 
814   // This handles 2).
815   gc::MaybeVerifyBarriers(cx);
816   return cx->handleInterrupt();
817 }
818 
CheckOverRecursed(JSContext * cx)819 bool CheckOverRecursed(JSContext* cx) { return CheckOverRecursedImpl(cx, 0); }
820 
CheckOverRecursedBaseline(JSContext * cx,BaselineFrame * frame)821 bool CheckOverRecursedBaseline(JSContext* cx, BaselineFrame* frame) {
822   // The stack check in Baseline happens before pushing locals so we have to
823   // account for that by including script->nslots() in the C++ recursion check.
824   size_t extra = frame->script()->nslots() * sizeof(Value);
825   return CheckOverRecursedImpl(cx, extra);
826 }
827 
MutatePrototype(JSContext * cx,HandlePlainObject obj,HandleValue value)828 bool MutatePrototype(JSContext* cx, HandlePlainObject obj, HandleValue value) {
829   if (!value.isObjectOrNull()) {
830     return true;
831   }
832 
833   RootedObject newProto(cx, value.toObjectOrNull());
834   return SetPrototype(cx, obj, newProto);
835 }
836 
837 template <EqualityKind Kind>
StringsEqual(JSContext * cx,HandleString lhs,HandleString rhs,bool * res)838 bool StringsEqual(JSContext* cx, HandleString lhs, HandleString rhs,
839                   bool* res) {
840   if (!js::EqualStrings(cx, lhs, rhs, res)) {
841     return false;
842   }
843   if (Kind != EqualityKind::Equal) {
844     *res = !*res;
845   }
846   return true;
847 }
848 
849 template bool StringsEqual<EqualityKind::Equal>(JSContext* cx, HandleString lhs,
850                                                 HandleString rhs, bool* res);
851 template bool StringsEqual<EqualityKind::NotEqual>(JSContext* cx,
852                                                    HandleString lhs,
853                                                    HandleString rhs, bool* res);
854 
855 template <ComparisonKind Kind>
StringsCompare(JSContext * cx,HandleString lhs,HandleString rhs,bool * res)856 bool StringsCompare(JSContext* cx, HandleString lhs, HandleString rhs,
857                     bool* res) {
858   int32_t result;
859   if (!js::CompareStrings(cx, lhs, rhs, &result)) {
860     return false;
861   }
862   if (Kind == ComparisonKind::LessThan) {
863     *res = result < 0;
864   } else {
865     *res = result >= 0;
866   }
867   return true;
868 }
869 
870 template bool StringsCompare<ComparisonKind::LessThan>(JSContext* cx,
871                                                        HandleString lhs,
872                                                        HandleString rhs,
873                                                        bool* res);
874 template bool StringsCompare<ComparisonKind::GreaterThanOrEqual>(
875     JSContext* cx, HandleString lhs, HandleString rhs, bool* res);
876 
ArrayPushDense(JSContext * cx,HandleArrayObject arr,HandleValue v,uint32_t * length)877 bool ArrayPushDense(JSContext* cx, HandleArrayObject arr, HandleValue v,
878                     uint32_t* length) {
879   *length = arr->length();
880   DenseElementResult result =
881       arr->setOrExtendDenseElements(cx, *length, v.address(), 1);
882   if (result != DenseElementResult::Incomplete) {
883     (*length)++;
884     return result == DenseElementResult::Success;
885   }
886 
887   JS::RootedValueArray<3> argv(cx);
888   argv[0].setUndefined();
889   argv[1].setObject(*arr);
890   argv[2].set(v);
891   if (!js::array_push(cx, 1, argv.begin())) {
892     return false;
893   }
894 
895   // Length must fit in an int32 because we guard against overflow before
896   // calling this VM function.
897   *length = argv[0].toInt32();
898   return true;
899 }
900 
ArrayJoin(JSContext * cx,HandleObject array,HandleString sep)901 JSString* ArrayJoin(JSContext* cx, HandleObject array, HandleString sep) {
902   JS::RootedValueArray<3> argv(cx);
903   argv[0].setUndefined();
904   argv[1].setObject(*array);
905   argv[2].setString(sep);
906   if (!js::array_join(cx, 1, argv.begin())) {
907     return nullptr;
908   }
909   return argv[0].toString();
910 }
911 
SetArrayLength(JSContext * cx,HandleObject obj,HandleValue value,bool strict)912 bool SetArrayLength(JSContext* cx, HandleObject obj, HandleValue value,
913                     bool strict) {
914   Handle<ArrayObject*> array = obj.as<ArrayObject>();
915 
916   RootedId id(cx, NameToId(cx->names().length));
917   ObjectOpResult result;
918 
919   // SetArrayLength is called by IC stubs for SetProp and SetElem on arrays'
920   // "length" property.
921   //
922   // ArraySetLength below coerces |value| before checking for length being
923   // writable, and in the case of illegal values, will throw RangeError even
924   // when "length" is not writable. This is incorrect observable behavior,
925   // as a regular [[Set]] operation will check for "length" being
926   // writable before attempting any assignment.
927   //
928   // So, perform ArraySetLength if and only if "length" is writable.
929   if (array->lengthIsWritable()) {
930     Rooted<PropertyDescriptor> desc(
931         cx, PropertyDescriptor::Data(value, JS::PropertyAttribute::Writable));
932     if (!ArraySetLength(cx, array, id, desc, result)) {
933       return false;
934     }
935   } else {
936     MOZ_ALWAYS_TRUE(result.fail(JSMSG_READ_ONLY));
937   }
938 
939   return result.checkStrictModeError(cx, obj, id, strict);
940 }
941 
CharCodeAt(JSContext * cx,HandleString str,int32_t index,uint32_t * code)942 bool CharCodeAt(JSContext* cx, HandleString str, int32_t index,
943                 uint32_t* code) {
944   char16_t c;
945   if (!str->getChar(cx, index, &c)) {
946     return false;
947   }
948   *code = c;
949   return true;
950 }
951 
StringFromCharCode(JSContext * cx,int32_t code)952 JSLinearString* StringFromCharCode(JSContext* cx, int32_t code) {
953   char16_t c = char16_t(code);
954 
955   if (StaticStrings::hasUnit(c)) {
956     return cx->staticStrings().getUnit(c);
957   }
958 
959   return NewStringCopyNDontDeflate<CanGC>(cx, &c, 1);
960 }
961 
StringFromCharCodeNoGC(JSContext * cx,int32_t code)962 JSLinearString* StringFromCharCodeNoGC(JSContext* cx, int32_t code) {
963   AutoUnsafeCallWithABI unsafe;
964 
965   char16_t c = char16_t(code);
966 
967   if (StaticStrings::hasUnit(c)) {
968     return cx->staticStrings().getUnit(c);
969   }
970 
971   return NewStringCopyNDontDeflate<NoGC>(cx, &c, 1);
972 }
973 
StringFromCodePoint(JSContext * cx,int32_t codePoint)974 JSString* StringFromCodePoint(JSContext* cx, int32_t codePoint) {
975   RootedValue rval(cx, Int32Value(codePoint));
976   if (!str_fromCodePoint_one_arg(cx, rval, &rval)) {
977     return nullptr;
978   }
979 
980   return rval.toString();
981 }
982 
SetProperty(JSContext * cx,HandleObject obj,HandlePropertyName name,HandleValue value,bool strict,jsbytecode * pc)983 bool SetProperty(JSContext* cx, HandleObject obj, HandlePropertyName name,
984                  HandleValue value, bool strict, jsbytecode* pc) {
985   RootedId id(cx, NameToId(name));
986 
987   RootedValue receiver(cx, ObjectValue(*obj));
988   ObjectOpResult result;
989   if (MOZ_LIKELY(!obj->getOpsSetProperty())) {
990     JSOp op = JSOp(*pc);
991     if (op == JSOp::SetName || op == JSOp::StrictSetName ||
992         op == JSOp::SetGName || op == JSOp::StrictSetGName) {
993       if (!NativeSetProperty<Unqualified>(cx, obj.as<NativeObject>(), id, value,
994                                           receiver, result)) {
995         return false;
996       }
997     } else {
998       if (!NativeSetProperty<Qualified>(cx, obj.as<NativeObject>(), id, value,
999                                         receiver, result)) {
1000         return false;
1001       }
1002     }
1003   } else {
1004     if (!SetProperty(cx, obj, id, value, receiver, result)) {
1005       return false;
1006     }
1007   }
1008   return result.checkStrictModeError(cx, obj, id, strict);
1009 }
1010 
InterruptCheck(JSContext * cx)1011 bool InterruptCheck(JSContext* cx) {
1012   gc::MaybeVerifyBarriers(cx);
1013 
1014   return CheckForInterrupt(cx);
1015 }
1016 
NewCallObject(JSContext * cx,HandleShape shape)1017 JSObject* NewCallObject(JSContext* cx, HandleShape shape) {
1018   JSObject* obj = CallObject::create(cx, shape);
1019   if (!obj) {
1020     return nullptr;
1021   }
1022 
1023   // The JIT creates call objects in the nursery, so elides barriers for
1024   // the initializing writes. The interpreter, however, may have allocated
1025   // the call object tenured, so barrier as needed before re-entering.
1026   if (!IsInsideNursery(obj)) {
1027     cx->runtime()->gc.storeBuffer().putWholeCell(obj);
1028   }
1029 
1030   return obj;
1031 }
1032 
NewStringObject(JSContext * cx,HandleString str)1033 JSObject* NewStringObject(JSContext* cx, HandleString str) {
1034   return StringObject::create(cx, str);
1035 }
1036 
OperatorIn(JSContext * cx,HandleValue key,HandleObject obj,bool * out)1037 bool OperatorIn(JSContext* cx, HandleValue key, HandleObject obj, bool* out) {
1038   RootedId id(cx);
1039   return ToPropertyKey(cx, key, &id) && HasProperty(cx, obj, id, out);
1040 }
1041 
GetIntrinsicValue(JSContext * cx,HandlePropertyName name,MutableHandleValue rval)1042 bool GetIntrinsicValue(JSContext* cx, HandlePropertyName name,
1043                        MutableHandleValue rval) {
1044   return GlobalObject::getIntrinsicValue(cx, cx->global(), name, rval);
1045 }
1046 
CreateThisFromIC(JSContext * cx,HandleObject callee,HandleObject newTarget,MutableHandleValue rval)1047 bool CreateThisFromIC(JSContext* cx, HandleObject callee,
1048                       HandleObject newTarget, MutableHandleValue rval) {
1049   HandleFunction fun = callee.as<JSFunction>();
1050   MOZ_ASSERT(fun->isInterpreted());
1051   MOZ_ASSERT(fun->isConstructor());
1052   MOZ_ASSERT(cx->realm() == fun->realm(),
1053              "Realm switching happens before creating this");
1054 
1055   // CreateThis expects rval to be this magic value.
1056   rval.set(MagicValue(JS_IS_CONSTRUCTING));
1057 
1058   if (!js::CreateThis(cx, fun, newTarget, GenericObject, rval)) {
1059     return false;
1060   }
1061 
1062   MOZ_ASSERT_IF(rval.isObject(), fun->realm() == rval.toObject().nonCCWRealm());
1063   return true;
1064 }
1065 
CreateThisFromIon(JSContext * cx,HandleObject callee,HandleObject newTarget,MutableHandleValue rval)1066 bool CreateThisFromIon(JSContext* cx, HandleObject callee,
1067                        HandleObject newTarget, MutableHandleValue rval) {
1068   // Return JS_IS_CONSTRUCTING for cases not supported by the inline call path.
1069   rval.set(MagicValue(JS_IS_CONSTRUCTING));
1070 
1071   if (!callee->is<JSFunction>()) {
1072     return true;
1073   }
1074 
1075   HandleFunction fun = callee.as<JSFunction>();
1076   if (!fun->isInterpreted() || !fun->isConstructor()) {
1077     return true;
1078   }
1079 
1080   // If newTarget is not a function or is a function with a possibly-getter
1081   // .prototype property, return NullValue to signal to LCallGeneric that it has
1082   // to take the slow path. Note that we return NullValue instead of a
1083   // MagicValue only because it's easier and faster to check for in JIT code
1084   // (if we returned a MagicValue, JIT code would have to check both the type
1085   // tag and the JSWhyMagic payload).
1086   if (!fun->constructorNeedsUninitializedThis()) {
1087     if (!newTarget->is<JSFunction>()) {
1088       rval.setNull();
1089       return true;
1090     }
1091     JSFunction* newTargetFun = &newTarget->as<JSFunction>();
1092     if (!newTargetFun->hasNonConfigurablePrototypeDataProperty()) {
1093       rval.setNull();
1094       return true;
1095     }
1096   }
1097 
1098   AutoRealm ar(cx, fun);
1099   if (!js::CreateThis(cx, fun, newTarget, GenericObject, rval)) {
1100     return false;
1101   }
1102 
1103   MOZ_ASSERT_IF(rval.isObject(), fun->realm() == rval.toObject().nonCCWRealm());
1104   return true;
1105 }
1106 
PostWriteBarrier(JSRuntime * rt,js::gc::Cell * cell)1107 void PostWriteBarrier(JSRuntime* rt, js::gc::Cell* cell) {
1108   AutoUnsafeCallWithABI unsafe;
1109   MOZ_ASSERT(!IsInsideNursery(cell));
1110   rt->gc.storeBuffer().putWholeCell(cell);
1111 }
1112 
1113 static const size_t MAX_WHOLE_CELL_BUFFER_SIZE = 4096;
1114 
1115 template <IndexInBounds InBounds>
PostWriteElementBarrier(JSRuntime * rt,JSObject * obj,int32_t index)1116 void PostWriteElementBarrier(JSRuntime* rt, JSObject* obj, int32_t index) {
1117   AutoUnsafeCallWithABI unsafe;
1118 
1119   MOZ_ASSERT(!IsInsideNursery(obj));
1120 
1121   if (InBounds == IndexInBounds::Yes) {
1122     MOZ_ASSERT(uint32_t(index) <
1123                obj->as<NativeObject>().getDenseInitializedLength());
1124   } else {
1125     if (MOZ_UNLIKELY(!obj->is<NativeObject>() || index < 0 ||
1126                      uint32_t(index) >=
1127                          NativeObject::MAX_DENSE_ELEMENTS_COUNT)) {
1128       rt->gc.storeBuffer().putWholeCell(obj);
1129       return;
1130     }
1131   }
1132 
1133   NativeObject* nobj = &obj->as<NativeObject>();
1134   if (nobj->isInWholeCellBuffer()) {
1135     return;
1136   }
1137 
1138   if (nobj->getDenseInitializedLength() > MAX_WHOLE_CELL_BUFFER_SIZE
1139 #ifdef JS_GC_ZEAL
1140       || rt->hasZealMode(gc::ZealMode::ElementsBarrier)
1141 #endif
1142   ) {
1143     rt->gc.storeBuffer().putSlot(nobj, HeapSlot::Element,
1144                                  nobj->unshiftedIndex(index), 1);
1145     return;
1146   }
1147 
1148   rt->gc.storeBuffer().putWholeCell(obj);
1149 }
1150 
1151 template void PostWriteElementBarrier<IndexInBounds::Yes>(JSRuntime* rt,
1152                                                           JSObject* obj,
1153                                                           int32_t index);
1154 
1155 template void PostWriteElementBarrier<IndexInBounds::Maybe>(JSRuntime* rt,
1156                                                             JSObject* obj,
1157                                                             int32_t index);
1158 
PostGlobalWriteBarrier(JSRuntime * rt,GlobalObject * obj)1159 void PostGlobalWriteBarrier(JSRuntime* rt, GlobalObject* obj) {
1160   MOZ_ASSERT(obj->JSObject::is<GlobalObject>());
1161 
1162   if (!obj->realm()->globalWriteBarriered) {
1163     PostWriteBarrier(rt, obj);
1164     obj->realm()->globalWriteBarriered = 1;
1165   }
1166 }
1167 
GetInt32FromStringPure(JSContext * cx,JSString * str,int32_t * result)1168 bool GetInt32FromStringPure(JSContext* cx, JSString* str, int32_t* result) {
1169   // We shouldn't GC here as this is called directly from IC code.
1170   AutoUnsafeCallWithABI unsafe;
1171 
1172   double d;
1173   if (!StringToNumberPure(cx, str, &d)) {
1174     return false;
1175   }
1176 
1177   return mozilla::NumberIsInt32(d, result);
1178 }
1179 
GetIndexFromString(JSString * str)1180 int32_t GetIndexFromString(JSString* str) {
1181   // We shouldn't GC here as this is called directly from IC code.
1182   AutoUnsafeCallWithABI unsafe;
1183 
1184   if (!str->isLinear()) {
1185     return -1;
1186   }
1187 
1188   uint32_t index = UINT32_MAX;  // Initialize this to appease Valgrind.
1189   if (!str->asLinear().isIndex(&index) || index > INT32_MAX) {
1190     return -1;
1191   }
1192 
1193   return int32_t(index);
1194 }
1195 
WrapObjectPure(JSContext * cx,JSObject * obj)1196 JSObject* WrapObjectPure(JSContext* cx, JSObject* obj) {
1197   // IC code calls this directly so we shouldn't GC.
1198   AutoUnsafeCallWithABI unsafe;
1199 
1200   MOZ_ASSERT(obj);
1201   MOZ_ASSERT(cx->compartment() != obj->compartment());
1202 
1203   // From: Compartment::getNonWrapperObjectForCurrentCompartment
1204   // Note that if the object is same-compartment, but has been wrapped into a
1205   // different compartment, we need to unwrap it and return the bare same-
1206   // compartment object. Note again that windows are always wrapped by a
1207   // WindowProxy even when same-compartment so take care not to strip this
1208   // particular wrapper.
1209   obj = UncheckedUnwrap(obj, /* stopAtWindowProxy = */ true);
1210   if (cx->compartment() == obj->compartment()) {
1211     MOZ_ASSERT(!IsWindow(obj));
1212     JS::ExposeObjectToActiveJS(obj);
1213     return obj;
1214   }
1215 
1216   // Try to Lookup an existing wrapper for this object. We assume that
1217   // if we can find such a wrapper, not calling preWrap is correct.
1218   if (ObjectWrapperMap::Ptr p = cx->compartment()->lookupWrapper(obj)) {
1219     JSObject* wrapped = p->value().get();
1220 
1221     // Ensure the wrapper is still exposed.
1222     JS::ExposeObjectToActiveJS(wrapped);
1223     return wrapped;
1224   }
1225 
1226   return nullptr;
1227 }
1228 
DebugPrologue(JSContext * cx,BaselineFrame * frame)1229 bool DebugPrologue(JSContext* cx, BaselineFrame* frame) {
1230   return DebugAPI::onEnterFrame(cx, frame);
1231 }
1232 
DebugEpilogueOnBaselineReturn(JSContext * cx,BaselineFrame * frame,jsbytecode * pc)1233 bool DebugEpilogueOnBaselineReturn(JSContext* cx, BaselineFrame* frame,
1234                                    jsbytecode* pc) {
1235   if (!DebugEpilogue(cx, frame, pc, true)) {
1236     // DebugEpilogue popped the frame by updating packedExitFP, so run the
1237     // stop event here before we enter the exception handler.
1238     TraceLoggerThread* logger = TraceLoggerForCurrentThread(cx);
1239     TraceLogStopEvent(logger, TraceLogger_Baseline);
1240     TraceLogStopEvent(logger, TraceLogger_Scripts);
1241     return false;
1242   }
1243 
1244   return true;
1245 }
1246 
DebugEpilogue(JSContext * cx,BaselineFrame * frame,jsbytecode * pc,bool ok)1247 bool DebugEpilogue(JSContext* cx, BaselineFrame* frame, jsbytecode* pc,
1248                    bool ok) {
1249   // If DebugAPI::onLeaveFrame returns |true| we have to return the frame's
1250   // return value. If it returns |false|, the debugger threw an exception.
1251   // In both cases we have to pop debug scopes.
1252   ok = DebugAPI::onLeaveFrame(cx, frame, pc, ok);
1253 
1254   // Unwind to the outermost environment.
1255   EnvironmentIter ei(cx, frame, pc);
1256   UnwindAllEnvironmentsInFrame(cx, ei);
1257 
1258   if (!ok) {
1259     // Pop this frame by updating packedExitFP, so that the exception
1260     // handling code will start at the previous frame.
1261     JitFrameLayout* prefix = frame->framePrefix();
1262     EnsureBareExitFrame(cx->activation()->asJit(), prefix);
1263     return false;
1264   }
1265 
1266   return true;
1267 }
1268 
FrameIsDebuggeeCheck(BaselineFrame * frame)1269 void FrameIsDebuggeeCheck(BaselineFrame* frame) {
1270   AutoUnsafeCallWithABI unsafe;
1271   if (frame->script()->isDebuggee()) {
1272     frame->setIsDebuggee();
1273   }
1274 }
1275 
CreateGeneratorFromFrame(JSContext * cx,BaselineFrame * frame)1276 JSObject* CreateGeneratorFromFrame(JSContext* cx, BaselineFrame* frame) {
1277   return AbstractGeneratorObject::createFromFrame(cx, frame);
1278 }
1279 
CreateGenerator(JSContext * cx,HandleFunction callee,HandleScript script,HandleObject environmentChain,HandleObject args)1280 JSObject* CreateGenerator(JSContext* cx, HandleFunction callee,
1281                           HandleScript script, HandleObject environmentChain,
1282                           HandleObject args) {
1283   Rooted<ArgumentsObject*> argsObj(
1284       cx, args ? &args->as<ArgumentsObject>() : nullptr);
1285   return AbstractGeneratorObject::create(cx, callee, script, environmentChain,
1286                                          argsObj);
1287 }
1288 
NormalSuspend(JSContext * cx,HandleObject obj,BaselineFrame * frame,uint32_t frameSize,jsbytecode * pc)1289 bool NormalSuspend(JSContext* cx, HandleObject obj, BaselineFrame* frame,
1290                    uint32_t frameSize, jsbytecode* pc) {
1291   MOZ_ASSERT(JSOp(*pc) == JSOp::InitialYield || JSOp(*pc) == JSOp::Yield ||
1292              JSOp(*pc) == JSOp::Await);
1293 
1294   // Minus one because we don't want to include the return value.
1295   uint32_t numSlots = frame->numValueSlots(frameSize) - 1;
1296   MOZ_ASSERT(numSlots >= frame->script()->nfixed());
1297   return AbstractGeneratorObject::suspend(cx, obj, frame, pc, numSlots);
1298 }
1299 
FinalSuspend(JSContext * cx,HandleObject obj,jsbytecode * pc)1300 bool FinalSuspend(JSContext* cx, HandleObject obj, jsbytecode* pc) {
1301   MOZ_ASSERT(JSOp(*pc) == JSOp::FinalYieldRval);
1302   AbstractGeneratorObject::finalSuspend(obj);
1303   return true;
1304 }
1305 
InterpretResume(JSContext * cx,HandleObject obj,Value * stackValues,MutableHandleValue rval)1306 bool InterpretResume(JSContext* cx, HandleObject obj, Value* stackValues,
1307                      MutableHandleValue rval) {
1308   MOZ_ASSERT(obj->is<AbstractGeneratorObject>());
1309 
1310   // The |stackValues| argument points to the JSOp::Resume operands on the
1311   // native stack. Because the stack grows down, these values are:
1312   //
1313   //   [resumeKind, argument, generator, ..]
1314 
1315   MOZ_ASSERT(stackValues[2].toObject() == *obj);
1316 
1317   GeneratorResumeKind resumeKind = IntToResumeKind(stackValues[0].toInt32());
1318   JSAtom* kind = ResumeKindToAtom(cx, resumeKind);
1319 
1320   FixedInvokeArgs<3> args(cx);
1321 
1322   args[0].setObject(*obj);
1323   args[1].set(stackValues[1]);
1324   args[2].setString(kind);
1325 
1326   return CallSelfHostedFunction(cx, cx->names().InterpretGeneratorResume,
1327                                 UndefinedHandleValue, args, rval);
1328 }
1329 
DebugAfterYield(JSContext * cx,BaselineFrame * frame)1330 bool DebugAfterYield(JSContext* cx, BaselineFrame* frame) {
1331   // The BaselineFrame has just been constructed by JSOp::Resume in the
1332   // caller. We need to set its debuggee flag as necessary.
1333   //
1334   // If a breakpoint is set on JSOp::AfterYield, or stepping is enabled,
1335   // we may already have done this work. Don't fire onEnterFrame again.
1336   if (frame->script()->isDebuggee() && !frame->isDebuggee()) {
1337     frame->setIsDebuggee();
1338     return DebugAPI::onResumeFrame(cx, frame);
1339   }
1340 
1341   return true;
1342 }
1343 
GeneratorThrowOrReturn(JSContext * cx,BaselineFrame * frame,Handle<AbstractGeneratorObject * > genObj,HandleValue arg,int32_t resumeKindArg)1344 bool GeneratorThrowOrReturn(JSContext* cx, BaselineFrame* frame,
1345                             Handle<AbstractGeneratorObject*> genObj,
1346                             HandleValue arg, int32_t resumeKindArg) {
1347   GeneratorResumeKind resumeKind = IntToResumeKind(resumeKindArg);
1348   MOZ_ALWAYS_FALSE(
1349       js::GeneratorThrowOrReturn(cx, frame, genObj, arg, resumeKind));
1350   return false;
1351 }
1352 
GlobalDeclInstantiationFromIon(JSContext * cx,HandleScript script,jsbytecode * pc)1353 bool GlobalDeclInstantiationFromIon(JSContext* cx, HandleScript script,
1354                                     jsbytecode* pc) {
1355   MOZ_ASSERT(!script->hasNonSyntacticScope());
1356 
1357   RootedObject envChain(cx, &cx->global()->lexicalEnvironment());
1358   GCThingIndex lastFun = GET_GCTHING_INDEX(pc);
1359 
1360   return GlobalOrEvalDeclInstantiation(cx, envChain, script, lastFun);
1361 }
1362 
InitFunctionEnvironmentObjects(JSContext * cx,BaselineFrame * frame)1363 bool InitFunctionEnvironmentObjects(JSContext* cx, BaselineFrame* frame) {
1364   return frame->initFunctionEnvironmentObjects(cx);
1365 }
1366 
NewArgumentsObject(JSContext * cx,BaselineFrame * frame,MutableHandleValue res)1367 bool NewArgumentsObject(JSContext* cx, BaselineFrame* frame,
1368                         MutableHandleValue res) {
1369   ArgumentsObject* obj = ArgumentsObject::createExpected(cx, frame);
1370   if (!obj) {
1371     return false;
1372   }
1373   res.setObject(*obj);
1374   return true;
1375 }
1376 
CopyLexicalEnvironmentObject(JSContext * cx,HandleObject env,bool copySlots)1377 JSObject* CopyLexicalEnvironmentObject(JSContext* cx, HandleObject env,
1378                                        bool copySlots) {
1379   Handle<BlockLexicalEnvironmentObject*> lexicalEnv =
1380       env.as<BlockLexicalEnvironmentObject>();
1381 
1382   if (copySlots) {
1383     return BlockLexicalEnvironmentObject::clone(cx, lexicalEnv);
1384   }
1385 
1386   return BlockLexicalEnvironmentObject::recreate(cx, lexicalEnv);
1387 }
1388 
InitRestParameter(JSContext * cx,uint32_t length,Value * rest,HandleObject objRes)1389 JSObject* InitRestParameter(JSContext* cx, uint32_t length, Value* rest,
1390                             HandleObject objRes) {
1391   if (objRes) {
1392     Handle<ArrayObject*> arrRes = objRes.as<ArrayObject>();
1393     MOZ_ASSERT(arrRes->getDenseInitializedLength() == 0);
1394 
1395     // Fast path: we managed to allocate the array inline; initialize the
1396     // slots.
1397     if (length > 0) {
1398       if (!arrRes->ensureElements(cx, length)) {
1399         return nullptr;
1400       }
1401       arrRes->initDenseElements(rest, length);
1402       arrRes->setLength(length);
1403     }
1404     return arrRes;
1405   }
1406 
1407   return NewDenseCopiedArray(cx, length, rest);
1408 }
1409 
HandleDebugTrap(JSContext * cx,BaselineFrame * frame,uint8_t * retAddr)1410 bool HandleDebugTrap(JSContext* cx, BaselineFrame* frame, uint8_t* retAddr) {
1411   RootedScript script(cx, frame->script());
1412   jsbytecode* pc;
1413   if (frame->runningInInterpreter()) {
1414     pc = frame->interpreterPC();
1415   } else {
1416     BaselineScript* blScript = script->baselineScript();
1417     pc = blScript->retAddrEntryFromReturnAddress(retAddr).pc(script);
1418   }
1419 
1420   // The Baseline Interpreter calls HandleDebugTrap for every op when the script
1421   // is in step mode or has breakpoints. The Baseline Compiler can toggle
1422   // breakpoints more granularly for specific bytecode PCs.
1423   if (frame->runningInInterpreter()) {
1424     MOZ_ASSERT(DebugAPI::hasAnyBreakpointsOrStepMode(script));
1425   } else {
1426     MOZ_ASSERT(DebugAPI::stepModeEnabled(script) ||
1427                DebugAPI::hasBreakpointsAt(script, pc));
1428   }
1429 
1430   if (JSOp(*pc) == JSOp::AfterYield) {
1431     // JSOp::AfterYield will set the frame's debuggee flag and call the
1432     // onEnterFrame handler, but if we set a breakpoint there we have to do
1433     // it now.
1434     MOZ_ASSERT(!frame->isDebuggee());
1435 
1436     if (!DebugAfterYield(cx, frame)) {
1437       return false;
1438     }
1439 
1440     // If the frame is not a debuggee we're done. This can happen, for instance,
1441     // if the onEnterFrame hook called removeDebuggee.
1442     if (!frame->isDebuggee()) {
1443       return true;
1444     }
1445   }
1446 
1447   MOZ_ASSERT(frame->isDebuggee());
1448 
1449   if (DebugAPI::stepModeEnabled(script) && !DebugAPI::onSingleStep(cx)) {
1450     return false;
1451   }
1452 
1453   if (DebugAPI::hasBreakpointsAt(script, pc) && !DebugAPI::onTrap(cx)) {
1454     return false;
1455   }
1456 
1457   return true;
1458 }
1459 
OnDebuggerStatement(JSContext * cx,BaselineFrame * frame)1460 bool OnDebuggerStatement(JSContext* cx, BaselineFrame* frame) {
1461   return DebugAPI::onDebuggerStatement(cx, frame);
1462 }
1463 
GlobalHasLiveOnDebuggerStatement(JSContext * cx)1464 bool GlobalHasLiveOnDebuggerStatement(JSContext* cx) {
1465   AutoUnsafeCallWithABI unsafe;
1466   return cx->realm()->isDebuggee() &&
1467          DebugAPI::hasDebuggerStatementHook(cx->global());
1468 }
1469 
PushLexicalEnv(JSContext * cx,BaselineFrame * frame,Handle<LexicalScope * > scope)1470 bool PushLexicalEnv(JSContext* cx, BaselineFrame* frame,
1471                     Handle<LexicalScope*> scope) {
1472   return frame->pushLexicalEnvironment(cx, scope);
1473 }
1474 
PopLexicalEnv(JSContext * cx,BaselineFrame * frame)1475 bool PopLexicalEnv(JSContext* cx, BaselineFrame* frame) {
1476   frame->popOffEnvironmentChain<ScopedLexicalEnvironmentObject>();
1477   return true;
1478 }
1479 
DebugLeaveThenPopLexicalEnv(JSContext * cx,BaselineFrame * frame,jsbytecode * pc)1480 bool DebugLeaveThenPopLexicalEnv(JSContext* cx, BaselineFrame* frame,
1481                                  jsbytecode* pc) {
1482   MOZ_ALWAYS_TRUE(DebugLeaveLexicalEnv(cx, frame, pc));
1483   frame->popOffEnvironmentChain<ScopedLexicalEnvironmentObject>();
1484   return true;
1485 }
1486 
FreshenLexicalEnv(JSContext * cx,BaselineFrame * frame)1487 bool FreshenLexicalEnv(JSContext* cx, BaselineFrame* frame) {
1488   return frame->freshenLexicalEnvironment(cx);
1489 }
1490 
DebugLeaveThenFreshenLexicalEnv(JSContext * cx,BaselineFrame * frame,jsbytecode * pc)1491 bool DebugLeaveThenFreshenLexicalEnv(JSContext* cx, BaselineFrame* frame,
1492                                      jsbytecode* pc) {
1493   MOZ_ALWAYS_TRUE(DebugLeaveLexicalEnv(cx, frame, pc));
1494   return frame->freshenLexicalEnvironment(cx);
1495 }
1496 
RecreateLexicalEnv(JSContext * cx,BaselineFrame * frame)1497 bool RecreateLexicalEnv(JSContext* cx, BaselineFrame* frame) {
1498   return frame->recreateLexicalEnvironment(cx);
1499 }
1500 
DebugLeaveThenRecreateLexicalEnv(JSContext * cx,BaselineFrame * frame,jsbytecode * pc)1501 bool DebugLeaveThenRecreateLexicalEnv(JSContext* cx, BaselineFrame* frame,
1502                                       jsbytecode* pc) {
1503   MOZ_ALWAYS_TRUE(DebugLeaveLexicalEnv(cx, frame, pc));
1504   return frame->recreateLexicalEnvironment(cx);
1505 }
1506 
DebugLeaveLexicalEnv(JSContext * cx,BaselineFrame * frame,jsbytecode * pc)1507 bool DebugLeaveLexicalEnv(JSContext* cx, BaselineFrame* frame, jsbytecode* pc) {
1508   MOZ_ASSERT_IF(!frame->runningInInterpreter(),
1509                 frame->script()->baselineScript()->hasDebugInstrumentation());
1510   if (cx->realm()->isDebuggee()) {
1511     DebugEnvironments::onPopLexical(cx, frame, pc);
1512   }
1513   return true;
1514 }
1515 
PushClassBodyEnv(JSContext * cx,BaselineFrame * frame,Handle<ClassBodyScope * > scope)1516 bool PushClassBodyEnv(JSContext* cx, BaselineFrame* frame,
1517                       Handle<ClassBodyScope*> scope) {
1518   return frame->pushClassBodyEnvironment(cx, scope);
1519 }
1520 
PushVarEnv(JSContext * cx,BaselineFrame * frame,HandleScope scope)1521 bool PushVarEnv(JSContext* cx, BaselineFrame* frame, HandleScope scope) {
1522   return frame->pushVarEnvironment(cx, scope);
1523 }
1524 
EnterWith(JSContext * cx,BaselineFrame * frame,HandleValue val,Handle<WithScope * > templ)1525 bool EnterWith(JSContext* cx, BaselineFrame* frame, HandleValue val,
1526                Handle<WithScope*> templ) {
1527   return EnterWithOperation(cx, frame, val, templ);
1528 }
1529 
LeaveWith(JSContext * cx,BaselineFrame * frame)1530 bool LeaveWith(JSContext* cx, BaselineFrame* frame) {
1531   if (MOZ_UNLIKELY(frame->isDebuggee())) {
1532     DebugEnvironments::onPopWith(frame);
1533   }
1534   frame->popOffEnvironmentChain<WithEnvironmentObject>();
1535   return true;
1536 }
1537 
InitBaselineFrameForOsr(BaselineFrame * frame,InterpreterFrame * interpFrame,uint32_t numStackValues)1538 bool InitBaselineFrameForOsr(BaselineFrame* frame,
1539                              InterpreterFrame* interpFrame,
1540                              uint32_t numStackValues) {
1541   return frame->initForOsr(interpFrame, numStackValues);
1542 }
1543 
StringReplace(JSContext * cx,HandleString string,HandleString pattern,HandleString repl)1544 JSString* StringReplace(JSContext* cx, HandleString string,
1545                         HandleString pattern, HandleString repl) {
1546   MOZ_ASSERT(string);
1547   MOZ_ASSERT(pattern);
1548   MOZ_ASSERT(repl);
1549 
1550   return str_replace_string_raw(cx, string, pattern, repl);
1551 }
1552 
SetDenseElement(JSContext * cx,HandleNativeObject obj,int32_t index,HandleValue value,bool strict)1553 bool SetDenseElement(JSContext* cx, HandleNativeObject obj, int32_t index,
1554                      HandleValue value, bool strict) {
1555   // This function is called from Ion code for StoreElementHole's OOL path.
1556   // In this case we know the object is native.
1557 
1558   DenseElementResult result =
1559       obj->setOrExtendDenseElements(cx, index, value.address(), 1);
1560   if (result != DenseElementResult::Incomplete) {
1561     return result == DenseElementResult::Success;
1562   }
1563 
1564   RootedValue indexVal(cx, Int32Value(index));
1565   return SetObjectElement(cx, obj, indexVal, value, strict);
1566 }
1567 
AssertValidBigIntPtr(JSContext * cx,JS::BigInt * bi)1568 void AssertValidBigIntPtr(JSContext* cx, JS::BigInt* bi) {
1569   AutoUnsafeCallWithABI unsafe;
1570   // FIXME: check runtime?
1571   MOZ_ASSERT(cx->zone() == bi->zone());
1572   MOZ_ASSERT(bi->isAligned());
1573   MOZ_ASSERT(bi->getAllocKind() == gc::AllocKind::BIGINT);
1574 }
1575 
AssertValidObjectPtr(JSContext * cx,JSObject * obj)1576 void AssertValidObjectPtr(JSContext* cx, JSObject* obj) {
1577   AutoUnsafeCallWithABI unsafe;
1578 #ifdef DEBUG
1579   // Check what we can, so that we'll hopefully assert/crash if we get a
1580   // bogus object (pointer).
1581   MOZ_ASSERT(obj->compartment() == cx->compartment());
1582   MOZ_ASSERT(obj->zoneFromAnyThread() == cx->zone());
1583   MOZ_ASSERT(obj->runtimeFromMainThread() == cx->runtime());
1584 
1585   if (obj->isTenured()) {
1586     MOZ_ASSERT(obj->isAligned());
1587     gc::AllocKind kind = obj->asTenured().getAllocKind();
1588     MOZ_ASSERT(gc::IsObjectAllocKind(kind));
1589   }
1590 #endif
1591 }
1592 
AssertValidStringPtr(JSContext * cx,JSString * str)1593 void AssertValidStringPtr(JSContext* cx, JSString* str) {
1594   AutoUnsafeCallWithABI unsafe;
1595 #ifdef DEBUG
1596   // We can't closely inspect strings from another runtime.
1597   if (str->runtimeFromAnyThread() != cx->runtime()) {
1598     MOZ_ASSERT(str->isPermanentAtom());
1599     return;
1600   }
1601 
1602   if (str->isAtom()) {
1603     MOZ_ASSERT(str->zone()->isAtomsZone());
1604   } else {
1605     MOZ_ASSERT(str->zone() == cx->zone());
1606   }
1607 
1608   MOZ_ASSERT(str->isAligned());
1609   MOZ_ASSERT(str->length() <= JSString::MAX_LENGTH);
1610 
1611   gc::AllocKind kind = str->getAllocKind();
1612   if (str->isFatInline()) {
1613     MOZ_ASSERT(kind == gc::AllocKind::FAT_INLINE_STRING ||
1614                kind == gc::AllocKind::FAT_INLINE_ATOM);
1615   } else if (str->isExternal()) {
1616     MOZ_ASSERT(kind == gc::AllocKind::EXTERNAL_STRING);
1617   } else if (str->isAtom()) {
1618     MOZ_ASSERT(kind == gc::AllocKind::ATOM);
1619   } else if (str->isLinear()) {
1620     MOZ_ASSERT(kind == gc::AllocKind::STRING ||
1621                kind == gc::AllocKind::FAT_INLINE_STRING);
1622   } else {
1623     MOZ_ASSERT(kind == gc::AllocKind::STRING);
1624   }
1625 #endif
1626 }
1627 
AssertValidSymbolPtr(JSContext * cx,JS::Symbol * sym)1628 void AssertValidSymbolPtr(JSContext* cx, JS::Symbol* sym) {
1629   AutoUnsafeCallWithABI unsafe;
1630 
1631   // We can't closely inspect symbols from another runtime.
1632   if (sym->runtimeFromAnyThread() != cx->runtime()) {
1633     MOZ_ASSERT(sym->isWellKnownSymbol());
1634     return;
1635   }
1636 
1637   MOZ_ASSERT(sym->zone()->isAtomsZone());
1638   MOZ_ASSERT(sym->isAligned());
1639   if (JSAtom* desc = sym->description()) {
1640     AssertValidStringPtr(cx, desc);
1641   }
1642 
1643   MOZ_ASSERT(sym->getAllocKind() == gc::AllocKind::SYMBOL);
1644 }
1645 
AssertValidValue(JSContext * cx,Value * v)1646 void AssertValidValue(JSContext* cx, Value* v) {
1647   AutoUnsafeCallWithABI unsafe;
1648   if (v->isObject()) {
1649     AssertValidObjectPtr(cx, &v->toObject());
1650   } else if (v->isString()) {
1651     AssertValidStringPtr(cx, v->toString());
1652   } else if (v->isSymbol()) {
1653     AssertValidSymbolPtr(cx, v->toSymbol());
1654   } else if (v->isBigInt()) {
1655     AssertValidBigIntPtr(cx, v->toBigInt());
1656   }
1657 }
1658 
ObjectIsCallable(JSObject * obj)1659 bool ObjectIsCallable(JSObject* obj) {
1660   AutoUnsafeCallWithABI unsafe;
1661   return obj->isCallable();
1662 }
1663 
ObjectIsConstructor(JSObject * obj)1664 bool ObjectIsConstructor(JSObject* obj) {
1665   AutoUnsafeCallWithABI unsafe;
1666   return obj->isConstructor();
1667 }
1668 
JitValuePreWriteBarrier(JSRuntime * rt,Value * vp)1669 void JitValuePreWriteBarrier(JSRuntime* rt, Value* vp) {
1670   AutoUnsafeCallWithABI unsafe;
1671   MOZ_ASSERT(vp->isGCThing());
1672   MOZ_ASSERT(!vp->toGCThing()->isMarkedBlack());
1673   gc::ValuePreWriteBarrier(*vp);
1674 }
1675 
JitStringPreWriteBarrier(JSRuntime * rt,JSString ** stringp)1676 void JitStringPreWriteBarrier(JSRuntime* rt, JSString** stringp) {
1677   AutoUnsafeCallWithABI unsafe;
1678   MOZ_ASSERT(*stringp);
1679   MOZ_ASSERT(!(*stringp)->isMarkedBlack());
1680   gc::PreWriteBarrier(*stringp);
1681 }
1682 
JitObjectPreWriteBarrier(JSRuntime * rt,JSObject ** objp)1683 void JitObjectPreWriteBarrier(JSRuntime* rt, JSObject** objp) {
1684   AutoUnsafeCallWithABI unsafe;
1685   MOZ_ASSERT(*objp);
1686   MOZ_ASSERT(!(*objp)->isMarkedBlack());
1687   gc::PreWriteBarrier(*objp);
1688 }
1689 
JitShapePreWriteBarrier(JSRuntime * rt,Shape ** shapep)1690 void JitShapePreWriteBarrier(JSRuntime* rt, Shape** shapep) {
1691   AutoUnsafeCallWithABI unsafe;
1692   MOZ_ASSERT(!(*shapep)->isMarkedBlack());
1693   gc::PreWriteBarrier(*shapep);
1694 }
1695 
ThrowRuntimeLexicalError(JSContext * cx,unsigned errorNumber)1696 bool ThrowRuntimeLexicalError(JSContext* cx, unsigned errorNumber) {
1697   ScriptFrameIter iter(cx);
1698   RootedScript script(cx, iter.script());
1699   ReportRuntimeLexicalError(cx, errorNumber, script, iter.pc());
1700   return false;
1701 }
1702 
ThrowBadDerivedReturn(JSContext * cx,HandleValue v)1703 bool ThrowBadDerivedReturn(JSContext* cx, HandleValue v) {
1704   MOZ_ASSERT(!v.isObject() && !v.isUndefined());
1705   ReportValueError(cx, JSMSG_BAD_DERIVED_RETURN, JSDVG_IGNORE_STACK, v,
1706                    nullptr);
1707   return false;
1708 }
1709 
ThrowBadDerivedReturnOrUninitializedThis(JSContext * cx,HandleValue v)1710 bool ThrowBadDerivedReturnOrUninitializedThis(JSContext* cx, HandleValue v) {
1711   MOZ_ASSERT(!v.isObject());
1712   if (v.isUndefined()) {
1713     return js::ThrowUninitializedThis(cx);
1714   }
1715   return ThrowBadDerivedReturn(cx, v);
1716 }
1717 
BaselineGetFunctionThis(JSContext * cx,BaselineFrame * frame,MutableHandleValue res)1718 bool BaselineGetFunctionThis(JSContext* cx, BaselineFrame* frame,
1719                              MutableHandleValue res) {
1720   return GetFunctionThis(cx, frame, res);
1721 }
1722 
CallNativeGetter(JSContext * cx,HandleFunction callee,HandleValue receiver,MutableHandleValue result)1723 bool CallNativeGetter(JSContext* cx, HandleFunction callee,
1724                       HandleValue receiver, MutableHandleValue result) {
1725   AutoRealm ar(cx, callee);
1726 
1727   MOZ_ASSERT(callee->isNativeFun());
1728   JSNative natfun = callee->native();
1729 
1730   JS::RootedValueArray<2> vp(cx);
1731   vp[0].setObject(*callee.get());
1732   vp[1].set(receiver);
1733 
1734   if (!natfun(cx, 0, vp.begin())) {
1735     return false;
1736   }
1737 
1738   result.set(vp[0]);
1739   return true;
1740 }
1741 
CallDOMGetter(JSContext * cx,const JSJitInfo * info,HandleObject obj,MutableHandleValue result)1742 bool CallDOMGetter(JSContext* cx, const JSJitInfo* info, HandleObject obj,
1743                    MutableHandleValue result) {
1744   MOZ_ASSERT(info->type() == JSJitInfo::Getter);
1745   MOZ_ASSERT(obj->is<NativeObject>());
1746   MOZ_ASSERT(obj->getClass()->isDOMClass());
1747 
1748 #ifdef DEBUG
1749   DOMInstanceClassHasProtoAtDepth instanceChecker =
1750       cx->runtime()->DOMcallbacks->instanceClassMatchesProto;
1751   MOZ_ASSERT(instanceChecker(obj->getClass(), info->protoID, info->depth));
1752 #endif
1753 
1754   // Loading DOM_OBJECT_SLOT, which must be the first slot.
1755   JS::Value val = JS::GetReservedSlot(obj, 0);
1756   JSJitGetterOp getter = info->getter;
1757   return getter(cx, obj, val.toPrivate(), JSJitGetterCallArgs(result));
1758 }
1759 
CallNativeSetter(JSContext * cx,HandleFunction callee,HandleObject obj,HandleValue rhs)1760 bool CallNativeSetter(JSContext* cx, HandleFunction callee, HandleObject obj,
1761                       HandleValue rhs) {
1762   AutoRealm ar(cx, callee);
1763 
1764   MOZ_ASSERT(callee->isNativeFun());
1765   JSNative natfun = callee->native();
1766 
1767   JS::RootedValueArray<3> vp(cx);
1768   vp[0].setObject(*callee.get());
1769   vp[1].setObject(*obj.get());
1770   vp[2].set(rhs);
1771 
1772   return natfun(cx, 1, vp.begin());
1773 }
1774 
CallDOMSetter(JSContext * cx,const JSJitInfo * info,HandleObject obj,HandleValue value)1775 bool CallDOMSetter(JSContext* cx, const JSJitInfo* info, HandleObject obj,
1776                    HandleValue value) {
1777   MOZ_ASSERT(info->type() == JSJitInfo::Setter);
1778   MOZ_ASSERT(obj->is<NativeObject>());
1779   MOZ_ASSERT(obj->getClass()->isDOMClass());
1780 
1781 #ifdef DEBUG
1782   DOMInstanceClassHasProtoAtDepth instanceChecker =
1783       cx->runtime()->DOMcallbacks->instanceClassMatchesProto;
1784   MOZ_ASSERT(instanceChecker(obj->getClass(), info->protoID, info->depth));
1785 #endif
1786 
1787   // Loading DOM_OBJECT_SLOT, which must be the first slot.
1788   JS::Value val = JS::GetReservedSlot(obj, 0);
1789   JSJitSetterOp setter = info->setter;
1790 
1791   RootedValue v(cx, value);
1792   return setter(cx, obj, val.toPrivate(), JSJitSetterCallArgs(&v));
1793 }
1794 
EqualStringsHelperPure(JSString * str1,JSString * str2)1795 bool EqualStringsHelperPure(JSString* str1, JSString* str2) {
1796   // IC code calls this directly so we shouldn't GC.
1797   AutoUnsafeCallWithABI unsafe;
1798 
1799   MOZ_ASSERT(str1->isAtom());
1800   MOZ_ASSERT(!str2->isAtom());
1801   MOZ_ASSERT(str1->length() == str2->length());
1802 
1803   // ensureLinear is intentionally called with a nullptr to avoid OOM
1804   // reporting; if it fails, we will continue to the next stub.
1805   JSLinearString* str2Linear = str2->ensureLinear(nullptr);
1806   if (!str2Linear) {
1807     return false;
1808   }
1809 
1810   return EqualChars(&str1->asLinear(), str2Linear);
1811 }
1812 
MaybeTypedArrayIndexString(jsid id)1813 static bool MaybeTypedArrayIndexString(jsid id) {
1814   MOZ_ASSERT(id.isAtom() || id.isSymbol());
1815 
1816   if (MOZ_LIKELY(id.isAtom())) {
1817     JSAtom* str = id.toAtom();
1818     if (str->length() > 0) {
1819       // Only check the first character because we want this function to be
1820       // fast.
1821       return CanStartTypedArrayIndex(str->latin1OrTwoByteChar(0));
1822     }
1823   }
1824   return false;
1825 }
1826 
GetNativeDataPropertyPure(JSContext * cx,NativeObject * obj,jsid id,Value * vp)1827 static MOZ_ALWAYS_INLINE bool GetNativeDataPropertyPure(JSContext* cx,
1828                                                         NativeObject* obj,
1829                                                         jsid id, Value* vp) {
1830   // Fast path used by megamorphic IC stubs. Unlike our other property
1831   // lookup paths, this is optimized to be as fast as possible for simple
1832   // data property lookups.
1833 
1834   AutoUnsafeCallWithABI unsafe;
1835 
1836   MOZ_ASSERT(id.isAtom() || id.isSymbol());
1837 
1838   while (true) {
1839     uint32_t index;
1840     if (PropMap* map = obj->shape()->lookup(cx, id, &index)) {
1841       PropertyInfo prop = map->getPropertyInfo(index);
1842       if (!prop.isDataProperty()) {
1843         return false;
1844       }
1845 
1846       *vp = obj->getSlot(prop.slot());
1847       return true;
1848     }
1849 
1850     // Property not found. Watch out for Class hooks and TypedArrays.
1851     if (MOZ_UNLIKELY(!obj->is<PlainObject>())) {
1852       if (ClassMayResolveId(cx->names(), obj->getClass(), id, obj)) {
1853         return false;
1854       }
1855 
1856       // Don't skip past TypedArrayObjects if the id can be a TypedArray index.
1857       if (obj->is<TypedArrayObject>()) {
1858         if (MaybeTypedArrayIndexString(id)) {
1859           return false;
1860         }
1861       }
1862     }
1863 
1864     JSObject* proto = obj->staticPrototype();
1865     if (!proto) {
1866       vp->setUndefined();
1867       return true;
1868     }
1869 
1870     if (!proto->is<NativeObject>()) {
1871       return false;
1872     }
1873     obj = &proto->as<NativeObject>();
1874   }
1875 }
1876 
GetNativeDataPropertyPure(JSContext * cx,JSObject * obj,PropertyName * name,Value * vp)1877 bool GetNativeDataPropertyPure(JSContext* cx, JSObject* obj, PropertyName* name,
1878                                Value* vp) {
1879   // Condition checked by caller.
1880   MOZ_ASSERT(obj->is<NativeObject>());
1881   return GetNativeDataPropertyPure(cx, &obj->as<NativeObject>(), NameToId(name),
1882                                    vp);
1883 }
1884 
ValueToAtomOrSymbolPure(JSContext * cx,Value & idVal,jsid * id)1885 static MOZ_ALWAYS_INLINE bool ValueToAtomOrSymbolPure(JSContext* cx,
1886                                                       Value& idVal, jsid* id) {
1887   if (MOZ_LIKELY(idVal.isString())) {
1888     JSString* s = idVal.toString();
1889     JSAtom* atom;
1890     if (s->isAtom()) {
1891       atom = &s->asAtom();
1892     } else {
1893       atom = AtomizeString(cx, s);
1894       if (!atom) {
1895         cx->recoverFromOutOfMemory();
1896         return false;
1897       }
1898     }
1899     *id = AtomToId(atom);
1900   } else if (idVal.isSymbol()) {
1901     *id = SYMBOL_TO_JSID(idVal.toSymbol());
1902   } else {
1903     if (!ValueToIdPure(idVal, id)) {
1904       return false;
1905     }
1906   }
1907 
1908   // Watch out for ids that may be stored in dense elements.
1909   static_assert(NativeObject::MAX_DENSE_ELEMENTS_COUNT < JSID_INT_MAX,
1910                 "All dense elements must have integer jsids");
1911   if (MOZ_UNLIKELY(JSID_IS_INT(*id))) {
1912     return false;
1913   }
1914 
1915   return true;
1916 }
1917 
GetNativeDataPropertyByValuePure(JSContext * cx,JSObject * obj,Value * vp)1918 bool GetNativeDataPropertyByValuePure(JSContext* cx, JSObject* obj, Value* vp) {
1919   AutoUnsafeCallWithABI unsafe;
1920 
1921   // Condition checked by caller.
1922   MOZ_ASSERT(obj->is<NativeObject>());
1923 
1924   // vp[0] contains the id, result will be stored in vp[1].
1925   Value idVal = vp[0];
1926   jsid id;
1927   if (!ValueToAtomOrSymbolPure(cx, idVal, &id)) {
1928     return false;
1929   }
1930 
1931   Value* res = vp + 1;
1932   return GetNativeDataPropertyPure(cx, &obj->as<NativeObject>(), id, res);
1933 }
1934 
SetNativeDataPropertyPure(JSContext * cx,JSObject * obj,PropertyName * name,Value * val)1935 bool SetNativeDataPropertyPure(JSContext* cx, JSObject* obj, PropertyName* name,
1936                                Value* val) {
1937   AutoUnsafeCallWithABI unsafe;
1938 
1939   if (MOZ_UNLIKELY(!obj->is<NativeObject>())) {
1940     return false;
1941   }
1942 
1943   NativeObject* nobj = &obj->as<NativeObject>();
1944   uint32_t index;
1945   PropMap* map = nobj->shape()->lookup(cx, NameToId(name), &index);
1946   if (!map) {
1947     return false;
1948   }
1949 
1950   PropertyInfo prop = map->getPropertyInfo(index);
1951   if (!prop.isDataProperty() || !prop.writable()) {
1952     return false;
1953   }
1954 
1955   nobj->setSlot(prop.slot(), *val);
1956   return true;
1957 }
1958 
ObjectHasGetterSetterPure(JSContext * cx,JSObject * objArg,jsid id,GetterSetter * getterSetter)1959 bool ObjectHasGetterSetterPure(JSContext* cx, JSObject* objArg, jsid id,
1960                                GetterSetter* getterSetter) {
1961   AutoUnsafeCallWithABI unsafe;
1962 
1963   // Window objects may require outerizing (passing the WindowProxy to the
1964   // getter/setter), so we don't support them here.
1965   if (MOZ_UNLIKELY(!objArg->is<NativeObject>() || IsWindow(objArg))) {
1966     return false;
1967   }
1968 
1969   NativeObject* nobj = &objArg->as<NativeObject>();
1970 
1971   while (true) {
1972     uint32_t index;
1973     if (PropMap* map = nobj->shape()->lookup(cx, id, &index)) {
1974       PropertyInfo prop = map->getPropertyInfo(index);
1975       if (!prop.isAccessorProperty()) {
1976         return false;
1977       }
1978       GetterSetter* actualGetterSetter = nobj->getGetterSetter(prop);
1979       if (actualGetterSetter == getterSetter) {
1980         return true;
1981       }
1982       return (actualGetterSetter->getter() == getterSetter->getter() &&
1983               actualGetterSetter->setter() == getterSetter->setter());
1984     }
1985 
1986     // Property not found. Watch out for Class hooks.
1987     if (!nobj->is<PlainObject>()) {
1988       if (ClassMayResolveId(cx->names(), nobj->getClass(), id, nobj)) {
1989         return false;
1990       }
1991     }
1992 
1993     JSObject* proto = nobj->staticPrototype();
1994     if (!proto) {
1995       return false;
1996     }
1997 
1998     if (!proto->is<NativeObject>()) {
1999       return false;
2000     }
2001     nobj = &proto->as<NativeObject>();
2002   }
2003 }
2004 
2005 template <bool HasOwn>
HasNativeDataPropertyPure(JSContext * cx,JSObject * obj,Value * vp)2006 bool HasNativeDataPropertyPure(JSContext* cx, JSObject* obj, Value* vp) {
2007   AutoUnsafeCallWithABI unsafe;
2008 
2009   // vp[0] contains the id, result will be stored in vp[1].
2010   Value idVal = vp[0];
2011   jsid id;
2012   if (!ValueToAtomOrSymbolPure(cx, idVal, &id)) {
2013     return false;
2014   }
2015 
2016   do {
2017     if (obj->is<NativeObject>()) {
2018       uint32_t unused;
2019       if (obj->shape()->lookup(cx, id, &unused)) {
2020         vp[1].setBoolean(true);
2021         return true;
2022       }
2023 
2024       // Property not found. Watch out for Class hooks and TypedArrays.
2025       if (MOZ_UNLIKELY(!obj->is<PlainObject>())) {
2026         // Fail if there's a resolve hook, unless the mayResolve hook tells us
2027         // the resolve hook won't define a property with this id.
2028         if (ClassMayResolveId(cx->names(), obj->getClass(), id, obj)) {
2029           return false;
2030         }
2031 
2032         // Don't skip past TypedArrayObjects if the id can be a TypedArray
2033         // index.
2034         if (obj->is<TypedArrayObject>()) {
2035           if (MaybeTypedArrayIndexString(id)) {
2036             return false;
2037           }
2038         }
2039       }
2040     } else if (obj->is<TypedObject>()) {
2041       RootedTypedObject typedObj(cx, &obj->as<TypedObject>());
2042       if (typedObj->rttValue().hasProperty(cx, typedObj, id)) {
2043         vp[1].setBoolean(true);
2044         return true;
2045       }
2046     } else {
2047       return false;
2048     }
2049 
2050     // If implementing Object.hasOwnProperty, don't follow protochain.
2051     if (HasOwn) {
2052       break;
2053     }
2054 
2055     // Get prototype. Objects that may allow dynamic prototypes are already
2056     // filtered out above.
2057     obj = obj->staticPrototype();
2058   } while (obj);
2059 
2060   // Missing property.
2061   vp[1].setBoolean(false);
2062   return true;
2063 }
2064 
2065 template bool HasNativeDataPropertyPure<true>(JSContext* cx, JSObject* obj,
2066                                               Value* vp);
2067 
2068 template bool HasNativeDataPropertyPure<false>(JSContext* cx, JSObject* obj,
2069                                                Value* vp);
2070 
HasNativeElementPure(JSContext * cx,NativeObject * obj,int32_t index,Value * vp)2071 bool HasNativeElementPure(JSContext* cx, NativeObject* obj, int32_t index,
2072                           Value* vp) {
2073   AutoUnsafeCallWithABI unsafe;
2074 
2075   MOZ_ASSERT(obj->is<NativeObject>());
2076   MOZ_ASSERT(!obj->getOpsHasProperty());
2077   MOZ_ASSERT(!obj->getOpsLookupProperty());
2078   MOZ_ASSERT(!obj->getOpsGetOwnPropertyDescriptor());
2079 
2080   if (MOZ_UNLIKELY(index < 0)) {
2081     return false;
2082   }
2083 
2084   if (obj->containsDenseElement(index)) {
2085     vp[0].setBoolean(true);
2086     return true;
2087   }
2088 
2089   jsid id = INT_TO_JSID(index);
2090   uint32_t unused;
2091   if (obj->shape()->lookup(cx, id, &unused)) {
2092     vp[0].setBoolean(true);
2093     return true;
2094   }
2095 
2096   // Fail if there's a resolve hook, unless the mayResolve hook tells
2097   // us the resolve hook won't define a property with this id.
2098   if (MOZ_UNLIKELY(ClassMayResolveId(cx->names(), obj->getClass(), id, obj))) {
2099     return false;
2100   }
2101   // TypedArrayObject are also native and contain indexed properties.
2102   if (MOZ_UNLIKELY(obj->is<TypedArrayObject>())) {
2103     size_t length = obj->as<TypedArrayObject>().length();
2104     vp[0].setBoolean(uint32_t(index) < length);
2105     return true;
2106   }
2107 
2108   vp[0].setBoolean(false);
2109   return true;
2110 }
2111 
HandleCodeCoverageAtPC(BaselineFrame * frame,jsbytecode * pc)2112 void HandleCodeCoverageAtPC(BaselineFrame* frame, jsbytecode* pc) {
2113   AutoUnsafeCallWithABI unsafe(UnsafeABIStrictness::AllowPendingExceptions);
2114 
2115   MOZ_ASSERT(frame->runningInInterpreter());
2116 
2117   JSScript* script = frame->script();
2118   MOZ_ASSERT(pc == script->main() || BytecodeIsJumpTarget(JSOp(*pc)));
2119 
2120   if (!script->hasScriptCounts()) {
2121     if (!script->realm()->collectCoverageForDebug()) {
2122       return;
2123     }
2124     JSContext* cx = script->runtimeFromMainThread()->mainContextFromOwnThread();
2125     AutoEnterOOMUnsafeRegion oomUnsafe;
2126     if (!script->initScriptCounts(cx)) {
2127       oomUnsafe.crash("initScriptCounts");
2128     }
2129   }
2130 
2131   PCCounts* counts = script->maybeGetPCCounts(pc);
2132   MOZ_ASSERT(counts);
2133   counts->numExec()++;
2134 }
2135 
HandleCodeCoverageAtPrologue(BaselineFrame * frame)2136 void HandleCodeCoverageAtPrologue(BaselineFrame* frame) {
2137   AutoUnsafeCallWithABI unsafe;
2138 
2139   MOZ_ASSERT(frame->runningInInterpreter());
2140 
2141   JSScript* script = frame->script();
2142   jsbytecode* main = script->main();
2143   if (!BytecodeIsJumpTarget(JSOp(*main))) {
2144     HandleCodeCoverageAtPC(frame, main);
2145   }
2146 }
2147 
TypeOfObject(JSObject * obj,JSRuntime * rt)2148 JSString* TypeOfObject(JSObject* obj, JSRuntime* rt) {
2149   AutoUnsafeCallWithABI unsafe;
2150   JSType type = js::TypeOfObject(obj);
2151   return TypeName(type, *rt->commonNames);
2152 }
2153 
GetPrototypeOf(JSContext * cx,HandleObject target,MutableHandleValue rval)2154 bool GetPrototypeOf(JSContext* cx, HandleObject target,
2155                     MutableHandleValue rval) {
2156   MOZ_ASSERT(target->hasDynamicPrototype());
2157 
2158   RootedObject proto(cx);
2159   if (!GetPrototype(cx, target, &proto)) {
2160     return false;
2161   }
2162   rval.setObjectOrNull(proto);
2163   return true;
2164 }
2165 
ConvertObjectToStringForConcat(JSContext * cx,HandleValue obj)2166 static JSString* ConvertObjectToStringForConcat(JSContext* cx,
2167                                                 HandleValue obj) {
2168   MOZ_ASSERT(obj.isObject());
2169   RootedValue rootedObj(cx, obj);
2170   if (!ToPrimitive(cx, &rootedObj)) {
2171     return nullptr;
2172   }
2173   return ToString<CanGC>(cx, rootedObj);
2174 }
2175 
DoConcatStringObject(JSContext * cx,HandleValue lhs,HandleValue rhs,MutableHandleValue res)2176 bool DoConcatStringObject(JSContext* cx, HandleValue lhs, HandleValue rhs,
2177                           MutableHandleValue res) {
2178   JSString* lstr = nullptr;
2179   JSString* rstr = nullptr;
2180 
2181   if (lhs.isString()) {
2182     // Convert rhs first.
2183     MOZ_ASSERT(lhs.isString() && rhs.isObject());
2184     rstr = ConvertObjectToStringForConcat(cx, rhs);
2185     if (!rstr) {
2186       return false;
2187     }
2188 
2189     // lhs is already string.
2190     lstr = lhs.toString();
2191   } else {
2192     MOZ_ASSERT(rhs.isString() && lhs.isObject());
2193     // Convert lhs first.
2194     lstr = ConvertObjectToStringForConcat(cx, lhs);
2195     if (!lstr) {
2196       return false;
2197     }
2198 
2199     // rhs is already string.
2200     rstr = rhs.toString();
2201   }
2202 
2203   JSString* str = ConcatStrings<NoGC>(cx, lstr, rstr);
2204   if (!str) {
2205     RootedString nlstr(cx, lstr), nrstr(cx, rstr);
2206     str = ConcatStrings<CanGC>(cx, nlstr, nrstr);
2207     if (!str) {
2208       return false;
2209     }
2210   }
2211 
2212   res.setString(str);
2213   return true;
2214 }
2215 
IsPossiblyWrappedTypedArray(JSContext * cx,JSObject * obj,bool * result)2216 bool IsPossiblyWrappedTypedArray(JSContext* cx, JSObject* obj, bool* result) {
2217   JSObject* unwrapped = CheckedUnwrapDynamic(obj, cx);
2218   if (!unwrapped) {
2219     ReportAccessDenied(cx);
2220     return false;
2221   }
2222 
2223   *result = unwrapped->is<TypedArrayObject>();
2224   return true;
2225 }
2226 
2227 // Called from CreateDependentString::generateFallback.
AllocateString(JSContext * cx)2228 void* AllocateString(JSContext* cx) {
2229   AutoUnsafeCallWithABI unsafe;
2230   return js::AllocateString<JSString, NoGC>(cx, js::gc::DefaultHeap);
2231 }
AllocateFatInlineString(JSContext * cx)2232 void* AllocateFatInlineString(JSContext* cx) {
2233   AutoUnsafeCallWithABI unsafe;
2234   return js::AllocateString<JSFatInlineString, NoGC>(cx, js::gc::DefaultHeap);
2235 }
2236 
2237 // Called to allocate a BigInt if inline allocation failed.
AllocateBigIntNoGC(JSContext * cx,bool requestMinorGC)2238 void* AllocateBigIntNoGC(JSContext* cx, bool requestMinorGC) {
2239   AutoUnsafeCallWithABI unsafe;
2240 
2241   if (requestMinorGC) {
2242     cx->nursery().requestMinorGC(JS::GCReason::OUT_OF_NURSERY);
2243   }
2244 
2245   return js::AllocateBigInt<NoGC>(cx, gc::TenuredHeap);
2246 }
2247 
AllocateAndInitTypedArrayBuffer(JSContext * cx,TypedArrayObject * obj,int32_t count)2248 void AllocateAndInitTypedArrayBuffer(JSContext* cx, TypedArrayObject* obj,
2249                                      int32_t count) {
2250   AutoUnsafeCallWithABI unsafe;
2251 
2252   obj->initPrivate(nullptr);
2253 
2254   // Negative numbers or zero will bail out to the slow path, which in turn will
2255   // raise an invalid argument exception or create a correct object with zero
2256   // elements.
2257   const size_t maxByteLength = TypedArrayObject::maxByteLength();
2258   if (count <= 0 || size_t(count) > maxByteLength / obj->bytesPerElement()) {
2259     obj->setFixedSlot(TypedArrayObject::LENGTH_SLOT, PrivateValue(size_t(0)));
2260     return;
2261   }
2262 
2263   obj->setFixedSlot(TypedArrayObject::LENGTH_SLOT, PrivateValue(count));
2264 
2265   size_t nbytes = size_t(count) * obj->bytesPerElement();
2266   MOZ_ASSERT(nbytes <= maxByteLength);
2267   nbytes = RoundUp(nbytes, sizeof(Value));
2268 
2269   void* buf = cx->nursery().allocateZeroedBuffer(obj, nbytes,
2270                                                  js::ArrayBufferContentsArena);
2271   if (buf) {
2272     InitObjectPrivate(obj, buf, nbytes, MemoryUse::TypedArrayElements);
2273   }
2274 }
2275 
CreateMatchResultFallbackFunc(JSContext * cx,gc::AllocKind kind,size_t nDynamicSlots)2276 void* CreateMatchResultFallbackFunc(JSContext* cx, gc::AllocKind kind,
2277                                     size_t nDynamicSlots) {
2278   AutoUnsafeCallWithABI unsafe;
2279   return js::AllocateObject<NoGC>(cx, kind, nDynamicSlots, gc::DefaultHeap,
2280                                   &ArrayObject::class_);
2281 }
2282 
2283 #ifdef JS_GC_PROBES
TraceCreateObject(JSObject * obj)2284 void TraceCreateObject(JSObject* obj) {
2285   AutoUnsafeCallWithABI unsafe;
2286   js::gc::gcprobes::CreateObject(obj);
2287 }
2288 #endif
2289 
2290 #if JS_BITS_PER_WORD == 32
CreateBigIntFromInt64(JSContext * cx,uint32_t low,uint32_t high)2291 BigInt* CreateBigIntFromInt64(JSContext* cx, uint32_t low, uint32_t high) {
2292   uint64_t n = (static_cast<uint64_t>(high) << 32) + low;
2293   return js::BigInt::createFromInt64(cx, n);
2294 }
2295 
CreateBigIntFromUint64(JSContext * cx,uint32_t low,uint32_t high)2296 BigInt* CreateBigIntFromUint64(JSContext* cx, uint32_t low, uint32_t high) {
2297   uint64_t n = (static_cast<uint64_t>(high) << 32) + low;
2298   return js::BigInt::createFromUint64(cx, n);
2299 }
2300 #else
CreateBigIntFromInt64(JSContext * cx,uint64_t i64)2301 BigInt* CreateBigIntFromInt64(JSContext* cx, uint64_t i64) {
2302   return js::BigInt::createFromInt64(cx, i64);
2303 }
2304 
CreateBigIntFromUint64(JSContext * cx,uint64_t i64)2305 BigInt* CreateBigIntFromUint64(JSContext* cx, uint64_t i64) {
2306   return js::BigInt::createFromUint64(cx, i64);
2307 }
2308 #endif
2309 
DoStringToInt64(JSContext * cx,HandleString str,uint64_t * res)2310 bool DoStringToInt64(JSContext* cx, HandleString str, uint64_t* res) {
2311   BigInt* bi;
2312   JS_TRY_VAR_OR_RETURN_FALSE(cx, bi, js::StringToBigInt(cx, str));
2313 
2314   if (!bi) {
2315     JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
2316                               JSMSG_BIGINT_INVALID_SYNTAX);
2317     return false;
2318   }
2319 
2320   *res = js::BigInt::toUint64(bi);
2321   return true;
2322 }
2323 
2324 template <EqualityKind Kind>
BigIntEqual(BigInt * x,BigInt * y)2325 bool BigIntEqual(BigInt* x, BigInt* y) {
2326   AutoUnsafeCallWithABI unsafe;
2327   bool res = BigInt::equal(x, y);
2328   if (Kind != EqualityKind::Equal) {
2329     res = !res;
2330   }
2331   return res;
2332 }
2333 
2334 template bool BigIntEqual<EqualityKind::Equal>(BigInt* x, BigInt* y);
2335 template bool BigIntEqual<EqualityKind::NotEqual>(BigInt* x, BigInt* y);
2336 
2337 template <ComparisonKind Kind>
BigIntCompare(BigInt * x,BigInt * y)2338 bool BigIntCompare(BigInt* x, BigInt* y) {
2339   AutoUnsafeCallWithABI unsafe;
2340   bool res = BigInt::lessThan(x, y);
2341   if (Kind != ComparisonKind::LessThan) {
2342     res = !res;
2343   }
2344   return res;
2345 }
2346 
2347 template bool BigIntCompare<ComparisonKind::LessThan>(BigInt* x, BigInt* y);
2348 template bool BigIntCompare<ComparisonKind::GreaterThanOrEqual>(BigInt* x,
2349                                                                 BigInt* y);
2350 
2351 template <EqualityKind Kind>
BigIntNumberEqual(BigInt * x,double y)2352 bool BigIntNumberEqual(BigInt* x, double y) {
2353   AutoUnsafeCallWithABI unsafe;
2354   bool res = BigInt::equal(x, y);
2355   if (Kind != EqualityKind::Equal) {
2356     res = !res;
2357   }
2358   return res;
2359 }
2360 
2361 template bool BigIntNumberEqual<EqualityKind::Equal>(BigInt* x, double y);
2362 template bool BigIntNumberEqual<EqualityKind::NotEqual>(BigInt* x, double y);
2363 
2364 template <ComparisonKind Kind>
BigIntNumberCompare(BigInt * x,double y)2365 bool BigIntNumberCompare(BigInt* x, double y) {
2366   AutoUnsafeCallWithABI unsafe;
2367   mozilla::Maybe<bool> res = BigInt::lessThan(x, y);
2368   if (Kind == ComparisonKind::LessThan) {
2369     return res.valueOr(false);
2370   }
2371   return !res.valueOr(true);
2372 }
2373 
2374 template bool BigIntNumberCompare<ComparisonKind::LessThan>(BigInt* x,
2375                                                             double y);
2376 template bool BigIntNumberCompare<ComparisonKind::GreaterThanOrEqual>(BigInt* x,
2377                                                                       double y);
2378 
2379 template <ComparisonKind Kind>
NumberBigIntCompare(double x,BigInt * y)2380 bool NumberBigIntCompare(double x, BigInt* y) {
2381   AutoUnsafeCallWithABI unsafe;
2382   mozilla::Maybe<bool> res = BigInt::lessThan(x, y);
2383   if (Kind == ComparisonKind::LessThan) {
2384     return res.valueOr(false);
2385   }
2386   return !res.valueOr(true);
2387 }
2388 
2389 template bool NumberBigIntCompare<ComparisonKind::LessThan>(double x,
2390                                                             BigInt* y);
2391 template bool NumberBigIntCompare<ComparisonKind::GreaterThanOrEqual>(
2392     double x, BigInt* y);
2393 
2394 template <EqualityKind Kind>
BigIntStringEqual(JSContext * cx,HandleBigInt x,HandleString y,bool * res)2395 bool BigIntStringEqual(JSContext* cx, HandleBigInt x, HandleString y,
2396                        bool* res) {
2397   JS_TRY_VAR_OR_RETURN_FALSE(cx, *res, BigInt::equal(cx, x, y));
2398   if (Kind != EqualityKind::Equal) {
2399     *res = !*res;
2400   }
2401   return true;
2402 }
2403 
2404 template bool BigIntStringEqual<EqualityKind::Equal>(JSContext* cx,
2405                                                      HandleBigInt x,
2406                                                      HandleString y, bool* res);
2407 template bool BigIntStringEqual<EqualityKind::NotEqual>(JSContext* cx,
2408                                                         HandleBigInt x,
2409                                                         HandleString y,
2410                                                         bool* res);
2411 
2412 template <ComparisonKind Kind>
BigIntStringCompare(JSContext * cx,HandleBigInt x,HandleString y,bool * res)2413 bool BigIntStringCompare(JSContext* cx, HandleBigInt x, HandleString y,
2414                          bool* res) {
2415   mozilla::Maybe<bool> result;
2416   if (!BigInt::lessThan(cx, x, y, result)) {
2417     return false;
2418   }
2419   if (Kind == ComparisonKind::LessThan) {
2420     *res = result.valueOr(false);
2421   } else {
2422     *res = !result.valueOr(true);
2423   }
2424   return true;
2425 }
2426 
2427 template bool BigIntStringCompare<ComparisonKind::LessThan>(JSContext* cx,
2428                                                             HandleBigInt x,
2429                                                             HandleString y,
2430                                                             bool* res);
2431 template bool BigIntStringCompare<ComparisonKind::GreaterThanOrEqual>(
2432     JSContext* cx, HandleBigInt x, HandleString y, bool* res);
2433 
2434 template <ComparisonKind Kind>
StringBigIntCompare(JSContext * cx,HandleString x,HandleBigInt y,bool * res)2435 bool StringBigIntCompare(JSContext* cx, HandleString x, HandleBigInt y,
2436                          bool* res) {
2437   mozilla::Maybe<bool> result;
2438   if (!BigInt::lessThan(cx, x, y, result)) {
2439     return false;
2440   }
2441   if (Kind == ComparisonKind::LessThan) {
2442     *res = result.valueOr(false);
2443   } else {
2444     *res = !result.valueOr(true);
2445   }
2446   return true;
2447 }
2448 
2449 template bool StringBigIntCompare<ComparisonKind::LessThan>(JSContext* cx,
2450                                                             HandleString x,
2451                                                             HandleBigInt y,
2452                                                             bool* res);
2453 template bool StringBigIntCompare<ComparisonKind::GreaterThanOrEqual>(
2454     JSContext* cx, HandleString x, HandleBigInt y, bool* res);
2455 
BigIntAsIntN(JSContext * cx,HandleBigInt x,int32_t bits)2456 BigInt* BigIntAsIntN(JSContext* cx, HandleBigInt x, int32_t bits) {
2457   MOZ_ASSERT(bits >= 0);
2458   return BigInt::asIntN(cx, x, uint64_t(bits));
2459 }
2460 
BigIntAsUintN(JSContext * cx,HandleBigInt x,int32_t bits)2461 BigInt* BigIntAsUintN(JSContext* cx, HandleBigInt x, int32_t bits) {
2462   MOZ_ASSERT(bits >= 0);
2463   return BigInt::asUintN(cx, x, uint64_t(bits));
2464 }
2465 
2466 template <typename T>
AtomicsCompareExchange(TypedArrayObject * typedArray,size_t index,int32_t expected,int32_t replacement)2467 static int32_t AtomicsCompareExchange(TypedArrayObject* typedArray,
2468                                       size_t index, int32_t expected,
2469                                       int32_t replacement) {
2470   AutoUnsafeCallWithABI unsafe;
2471 
2472   MOZ_ASSERT(!typedArray->hasDetachedBuffer());
2473   MOZ_ASSERT(index < typedArray->length());
2474 
2475   SharedMem<T*> addr = typedArray->dataPointerEither().cast<T*>();
2476   return jit::AtomicOperations::compareExchangeSeqCst(addr + index, T(expected),
2477                                                       T(replacement));
2478 }
2479 
AtomicsCompareExchange(Scalar::Type elementType)2480 AtomicsCompareExchangeFn AtomicsCompareExchange(Scalar::Type elementType) {
2481   switch (elementType) {
2482     case Scalar::Int8:
2483       return AtomicsCompareExchange<int8_t>;
2484     case Scalar::Uint8:
2485       return AtomicsCompareExchange<uint8_t>;
2486     case Scalar::Int16:
2487       return AtomicsCompareExchange<int16_t>;
2488     case Scalar::Uint16:
2489       return AtomicsCompareExchange<uint16_t>;
2490     case Scalar::Int32:
2491       return AtomicsCompareExchange<int32_t>;
2492     case Scalar::Uint32:
2493       return AtomicsCompareExchange<uint32_t>;
2494     default:
2495       MOZ_CRASH("Unexpected TypedArray type");
2496   }
2497 }
2498 
2499 template <typename T>
AtomicsExchange(TypedArrayObject * typedArray,size_t index,int32_t value)2500 static int32_t AtomicsExchange(TypedArrayObject* typedArray, size_t index,
2501                                int32_t value) {
2502   AutoUnsafeCallWithABI unsafe;
2503 
2504   MOZ_ASSERT(!typedArray->hasDetachedBuffer());
2505   MOZ_ASSERT(index < typedArray->length());
2506 
2507   SharedMem<T*> addr = typedArray->dataPointerEither().cast<T*>();
2508   return jit::AtomicOperations::exchangeSeqCst(addr + index, T(value));
2509 }
2510 
AtomicsExchange(Scalar::Type elementType)2511 AtomicsReadWriteModifyFn AtomicsExchange(Scalar::Type elementType) {
2512   switch (elementType) {
2513     case Scalar::Int8:
2514       return AtomicsExchange<int8_t>;
2515     case Scalar::Uint8:
2516       return AtomicsExchange<uint8_t>;
2517     case Scalar::Int16:
2518       return AtomicsExchange<int16_t>;
2519     case Scalar::Uint16:
2520       return AtomicsExchange<uint16_t>;
2521     case Scalar::Int32:
2522       return AtomicsExchange<int32_t>;
2523     case Scalar::Uint32:
2524       return AtomicsExchange<uint32_t>;
2525     default:
2526       MOZ_CRASH("Unexpected TypedArray type");
2527   }
2528 }
2529 
2530 template <typename T>
AtomicsAdd(TypedArrayObject * typedArray,size_t index,int32_t value)2531 static int32_t AtomicsAdd(TypedArrayObject* typedArray, size_t index,
2532                           int32_t value) {
2533   AutoUnsafeCallWithABI unsafe;
2534 
2535   MOZ_ASSERT(!typedArray->hasDetachedBuffer());
2536   MOZ_ASSERT(index < typedArray->length());
2537 
2538   SharedMem<T*> addr = typedArray->dataPointerEither().cast<T*>();
2539   return jit::AtomicOperations::fetchAddSeqCst(addr + index, T(value));
2540 }
2541 
AtomicsAdd(Scalar::Type elementType)2542 AtomicsReadWriteModifyFn AtomicsAdd(Scalar::Type elementType) {
2543   switch (elementType) {
2544     case Scalar::Int8:
2545       return AtomicsAdd<int8_t>;
2546     case Scalar::Uint8:
2547       return AtomicsAdd<uint8_t>;
2548     case Scalar::Int16:
2549       return AtomicsAdd<int16_t>;
2550     case Scalar::Uint16:
2551       return AtomicsAdd<uint16_t>;
2552     case Scalar::Int32:
2553       return AtomicsAdd<int32_t>;
2554     case Scalar::Uint32:
2555       return AtomicsAdd<uint32_t>;
2556     default:
2557       MOZ_CRASH("Unexpected TypedArray type");
2558   }
2559 }
2560 
2561 template <typename T>
AtomicsSub(TypedArrayObject * typedArray,size_t index,int32_t value)2562 static int32_t AtomicsSub(TypedArrayObject* typedArray, size_t index,
2563                           int32_t value) {
2564   AutoUnsafeCallWithABI unsafe;
2565 
2566   MOZ_ASSERT(!typedArray->hasDetachedBuffer());
2567   MOZ_ASSERT(index < typedArray->length());
2568 
2569   SharedMem<T*> addr = typedArray->dataPointerEither().cast<T*>();
2570   return jit::AtomicOperations::fetchSubSeqCst(addr + index, T(value));
2571 }
2572 
AtomicsSub(Scalar::Type elementType)2573 AtomicsReadWriteModifyFn AtomicsSub(Scalar::Type elementType) {
2574   switch (elementType) {
2575     case Scalar::Int8:
2576       return AtomicsSub<int8_t>;
2577     case Scalar::Uint8:
2578       return AtomicsSub<uint8_t>;
2579     case Scalar::Int16:
2580       return AtomicsSub<int16_t>;
2581     case Scalar::Uint16:
2582       return AtomicsSub<uint16_t>;
2583     case Scalar::Int32:
2584       return AtomicsSub<int32_t>;
2585     case Scalar::Uint32:
2586       return AtomicsSub<uint32_t>;
2587     default:
2588       MOZ_CRASH("Unexpected TypedArray type");
2589   }
2590 }
2591 
2592 template <typename T>
AtomicsAnd(TypedArrayObject * typedArray,size_t index,int32_t value)2593 static int32_t AtomicsAnd(TypedArrayObject* typedArray, size_t index,
2594                           int32_t value) {
2595   AutoUnsafeCallWithABI unsafe;
2596 
2597   MOZ_ASSERT(!typedArray->hasDetachedBuffer());
2598   MOZ_ASSERT(index < typedArray->length());
2599 
2600   SharedMem<T*> addr = typedArray->dataPointerEither().cast<T*>();
2601   return jit::AtomicOperations::fetchAndSeqCst(addr + index, T(value));
2602 }
2603 
AtomicsAnd(Scalar::Type elementType)2604 AtomicsReadWriteModifyFn AtomicsAnd(Scalar::Type elementType) {
2605   switch (elementType) {
2606     case Scalar::Int8:
2607       return AtomicsAnd<int8_t>;
2608     case Scalar::Uint8:
2609       return AtomicsAnd<uint8_t>;
2610     case Scalar::Int16:
2611       return AtomicsAnd<int16_t>;
2612     case Scalar::Uint16:
2613       return AtomicsAnd<uint16_t>;
2614     case Scalar::Int32:
2615       return AtomicsAnd<int32_t>;
2616     case Scalar::Uint32:
2617       return AtomicsAnd<uint32_t>;
2618     default:
2619       MOZ_CRASH("Unexpected TypedArray type");
2620   }
2621 }
2622 
2623 template <typename T>
AtomicsOr(TypedArrayObject * typedArray,size_t index,int32_t value)2624 static int32_t AtomicsOr(TypedArrayObject* typedArray, size_t index,
2625                          int32_t value) {
2626   AutoUnsafeCallWithABI unsafe;
2627 
2628   MOZ_ASSERT(!typedArray->hasDetachedBuffer());
2629   MOZ_ASSERT(index < typedArray->length());
2630 
2631   SharedMem<T*> addr = typedArray->dataPointerEither().cast<T*>();
2632   return jit::AtomicOperations::fetchOrSeqCst(addr + index, T(value));
2633 }
2634 
AtomicsOr(Scalar::Type elementType)2635 AtomicsReadWriteModifyFn AtomicsOr(Scalar::Type elementType) {
2636   switch (elementType) {
2637     case Scalar::Int8:
2638       return AtomicsOr<int8_t>;
2639     case Scalar::Uint8:
2640       return AtomicsOr<uint8_t>;
2641     case Scalar::Int16:
2642       return AtomicsOr<int16_t>;
2643     case Scalar::Uint16:
2644       return AtomicsOr<uint16_t>;
2645     case Scalar::Int32:
2646       return AtomicsOr<int32_t>;
2647     case Scalar::Uint32:
2648       return AtomicsOr<uint32_t>;
2649     default:
2650       MOZ_CRASH("Unexpected TypedArray type");
2651   }
2652 }
2653 
2654 template <typename T>
AtomicsXor(TypedArrayObject * typedArray,size_t index,int32_t value)2655 static int32_t AtomicsXor(TypedArrayObject* typedArray, size_t index,
2656                           int32_t value) {
2657   AutoUnsafeCallWithABI unsafe;
2658 
2659   MOZ_ASSERT(!typedArray->hasDetachedBuffer());
2660   MOZ_ASSERT(index < typedArray->length());
2661 
2662   SharedMem<T*> addr = typedArray->dataPointerEither().cast<T*>();
2663   return jit::AtomicOperations::fetchXorSeqCst(addr + index, T(value));
2664 }
2665 
AtomicsXor(Scalar::Type elementType)2666 AtomicsReadWriteModifyFn AtomicsXor(Scalar::Type elementType) {
2667   switch (elementType) {
2668     case Scalar::Int8:
2669       return AtomicsXor<int8_t>;
2670     case Scalar::Uint8:
2671       return AtomicsXor<uint8_t>;
2672     case Scalar::Int16:
2673       return AtomicsXor<int16_t>;
2674     case Scalar::Uint16:
2675       return AtomicsXor<uint16_t>;
2676     case Scalar::Int32:
2677       return AtomicsXor<int32_t>;
2678     case Scalar::Uint32:
2679       return AtomicsXor<uint32_t>;
2680     default:
2681       MOZ_CRASH("Unexpected TypedArray type");
2682   }
2683 }
2684 
2685 template <typename AtomicOp, typename... Args>
AtomicAccess64(JSContext * cx,TypedArrayObject * typedArray,size_t index,AtomicOp op,Args...args)2686 static BigInt* AtomicAccess64(JSContext* cx, TypedArrayObject* typedArray,
2687                               size_t index, AtomicOp op, Args... args) {
2688   MOZ_ASSERT(Scalar::isBigIntType(typedArray->type()));
2689   MOZ_ASSERT(!typedArray->hasDetachedBuffer());
2690   MOZ_ASSERT(index < typedArray->length());
2691 
2692   if (typedArray->type() == Scalar::BigInt64) {
2693     SharedMem<int64_t*> addr = typedArray->dataPointerEither().cast<int64_t*>();
2694     int64_t v = op(addr + index, BigInt::toInt64(args)...);
2695     return BigInt::createFromInt64(cx, v);
2696   }
2697 
2698   SharedMem<uint64_t*> addr = typedArray->dataPointerEither().cast<uint64_t*>();
2699   uint64_t v = op(addr + index, BigInt::toUint64(args)...);
2700   return BigInt::createFromUint64(cx, v);
2701 }
2702 
2703 template <typename AtomicOp, typename... Args>
AtomicAccess64(TypedArrayObject * typedArray,size_t index,AtomicOp op,Args...args)2704 static auto AtomicAccess64(TypedArrayObject* typedArray, size_t index,
2705                            AtomicOp op, Args... args) {
2706   MOZ_ASSERT(Scalar::isBigIntType(typedArray->type()));
2707   MOZ_ASSERT(!typedArray->hasDetachedBuffer());
2708   MOZ_ASSERT(index < typedArray->length());
2709 
2710   if (typedArray->type() == Scalar::BigInt64) {
2711     SharedMem<int64_t*> addr = typedArray->dataPointerEither().cast<int64_t*>();
2712     return op(addr + index, BigInt::toInt64(args)...);
2713   }
2714 
2715   SharedMem<uint64_t*> addr = typedArray->dataPointerEither().cast<uint64_t*>();
2716   return op(addr + index, BigInt::toUint64(args)...);
2717 }
2718 
AtomicsLoad64(JSContext * cx,TypedArrayObject * typedArray,size_t index)2719 BigInt* AtomicsLoad64(JSContext* cx, TypedArrayObject* typedArray,
2720                       size_t index) {
2721   return AtomicAccess64(cx, typedArray, index, [](auto addr) {
2722     return jit::AtomicOperations::loadSeqCst(addr);
2723   });
2724 }
2725 
AtomicsStore64(TypedArrayObject * typedArray,size_t index,BigInt * value)2726 void AtomicsStore64(TypedArrayObject* typedArray, size_t index, BigInt* value) {
2727   AutoUnsafeCallWithABI unsafe;
2728 
2729   AtomicAccess64(
2730       typedArray, index,
2731       [](auto addr, auto val) {
2732         jit::AtomicOperations::storeSeqCst(addr, val);
2733       },
2734       value);
2735 }
2736 
AtomicsCompareExchange64(JSContext * cx,TypedArrayObject * typedArray,size_t index,BigInt * expected,BigInt * replacement)2737 BigInt* AtomicsCompareExchange64(JSContext* cx, TypedArrayObject* typedArray,
2738                                  size_t index, BigInt* expected,
2739                                  BigInt* replacement) {
2740   return AtomicAccess64(
2741       cx, typedArray, index,
2742       [](auto addr, auto oldval, auto newval) {
2743         return jit::AtomicOperations::compareExchangeSeqCst(addr, oldval,
2744                                                             newval);
2745       },
2746       expected, replacement);
2747 }
2748 
AtomicsExchange64(JSContext * cx,TypedArrayObject * typedArray,size_t index,BigInt * value)2749 BigInt* AtomicsExchange64(JSContext* cx, TypedArrayObject* typedArray,
2750                           size_t index, BigInt* value) {
2751   return AtomicAccess64(
2752       cx, typedArray, index,
2753       [](auto addr, auto val) {
2754         return jit::AtomicOperations::exchangeSeqCst(addr, val);
2755       },
2756       value);
2757 }
2758 
AtomicsAdd64(JSContext * cx,TypedArrayObject * typedArray,size_t index,BigInt * value)2759 BigInt* AtomicsAdd64(JSContext* cx, TypedArrayObject* typedArray, size_t index,
2760                      BigInt* value) {
2761   return AtomicAccess64(
2762       cx, typedArray, index,
2763       [](auto addr, auto val) {
2764         return jit::AtomicOperations::fetchAddSeqCst(addr, val);
2765       },
2766       value);
2767 }
2768 
AtomicsAnd64(JSContext * cx,TypedArrayObject * typedArray,size_t index,BigInt * value)2769 BigInt* AtomicsAnd64(JSContext* cx, TypedArrayObject* typedArray, size_t index,
2770                      BigInt* value) {
2771   return AtomicAccess64(
2772       cx, typedArray, index,
2773       [](auto addr, auto val) {
2774         return jit::AtomicOperations::fetchAndSeqCst(addr, val);
2775       },
2776       value);
2777 }
2778 
AtomicsOr64(JSContext * cx,TypedArrayObject * typedArray,size_t index,BigInt * value)2779 BigInt* AtomicsOr64(JSContext* cx, TypedArrayObject* typedArray, size_t index,
2780                     BigInt* value) {
2781   return AtomicAccess64(
2782       cx, typedArray, index,
2783       [](auto addr, auto val) {
2784         return jit::AtomicOperations::fetchOrSeqCst(addr, val);
2785       },
2786       value);
2787 }
2788 
AtomicsSub64(JSContext * cx,TypedArrayObject * typedArray,size_t index,BigInt * value)2789 BigInt* AtomicsSub64(JSContext* cx, TypedArrayObject* typedArray, size_t index,
2790                      BigInt* value) {
2791   return AtomicAccess64(
2792       cx, typedArray, index,
2793       [](auto addr, auto val) {
2794         return jit::AtomicOperations::fetchSubSeqCst(addr, val);
2795       },
2796       value);
2797 }
2798 
AtomicsXor64(JSContext * cx,TypedArrayObject * typedArray,size_t index,BigInt * value)2799 BigInt* AtomicsXor64(JSContext* cx, TypedArrayObject* typedArray, size_t index,
2800                      BigInt* value) {
2801   return AtomicAccess64(
2802       cx, typedArray, index,
2803       [](auto addr, auto val) {
2804         return jit::AtomicOperations::fetchXorSeqCst(addr, val);
2805       },
2806       value);
2807 }
2808 
AssumeUnreachable(const char * output)2809 void AssumeUnreachable(const char* output) {
2810   MOZ_ReportAssertionFailure(output, __FILE__, __LINE__);
2811 }
2812 
Printf0(const char * output)2813 void Printf0(const char* output) {
2814   AutoUnsafeCallWithABI unsafe;
2815 
2816   // Use stderr instead of stdout because this is only used for debug
2817   // output. stderr is less likely to interfere with the program's normal
2818   // output, and it's always unbuffered.
2819   fprintf(stderr, "%s", output);
2820 }
2821 
Printf1(const char * output,uintptr_t value)2822 void Printf1(const char* output, uintptr_t value) {
2823   AutoUnsafeCallWithABI unsafe;
2824   AutoEnterOOMUnsafeRegion oomUnsafe;
2825   js::UniqueChars line = JS_sprintf_append(nullptr, output, value);
2826   if (!line) {
2827     oomUnsafe.crash("OOM at masm.printf");
2828   }
2829   fprintf(stderr, "%s", line.get());
2830 }
2831 
2832 }  // namespace jit
2833 }  // namespace js
2834