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