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