From 36d22d82aa202bb199967e9512281e9a53db42c9 Mon Sep 17 00:00:00 2001
From: Daniel Baumann <daniel.baumann@progress-linux.org>
Date: Sun, 7 Apr 2024 21:33:14 +0200
Subject: Adding upstream version 115.7.0esr.

Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
---
 js/src/jit/CodeGenerator.h | 447 +++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 447 insertions(+)
 create mode 100644 js/src/jit/CodeGenerator.h

(limited to 'js/src/jit/CodeGenerator.h')

diff --git a/js/src/jit/CodeGenerator.h b/js/src/jit/CodeGenerator.h
new file mode 100644
index 0000000000..7240bc07b4
--- /dev/null
+++ b/js/src/jit/CodeGenerator.h
@@ -0,0 +1,447 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
+ * vim: set ts=8 sts=2 et sw=2 tw=80:
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef jit_CodeGenerator_h
+#define jit_CodeGenerator_h
+
+#include "jit/PerfSpewer.h"
+#include "js/ScalarType.h"  // js::Scalar::Type
+
+#if defined(JS_CODEGEN_X86)
+#  include "jit/x86/CodeGenerator-x86.h"
+#elif defined(JS_CODEGEN_X64)
+#  include "jit/x64/CodeGenerator-x64.h"
+#elif defined(JS_CODEGEN_ARM)
+#  include "jit/arm/CodeGenerator-arm.h"
+#elif defined(JS_CODEGEN_ARM64)
+#  include "jit/arm64/CodeGenerator-arm64.h"
+#elif defined(JS_CODEGEN_MIPS32)
+#  include "jit/mips32/CodeGenerator-mips32.h"
+#elif defined(JS_CODEGEN_MIPS64)
+#  include "jit/mips64/CodeGenerator-mips64.h"
+#elif defined(JS_CODEGEN_LOONG64)
+#  include "jit/loong64/CodeGenerator-loong64.h"
+#elif defined(JS_CODEGEN_RISCV64)
+#  include "jit/riscv64/CodeGenerator-riscv64.h"
+#elif defined(JS_CODEGEN_WASM32)
+#  include "jit/wasm32/CodeGenerator-wasm32.h"
+#elif defined(JS_CODEGEN_NONE)
+#  include "jit/none/CodeGenerator-none.h"
+#else
+#  error "Unknown architecture!"
+#endif
+
+namespace js {
+
+namespace wasm {
+class Decoder;
+class StackMaps;
+}  // namespace wasm
+
+namespace jit {
+
+class WarpSnapshot;
+
+template <typename Fn, Fn fn, class ArgSeq, class StoreOutputTo>
+class OutOfLineCallVM;
+
+enum class SwitchTableType { Inline, OutOfLine };
+
+template <SwitchTableType tableType>
+class OutOfLineSwitch;
+class OutOfLineTestObject;
+class OutOfLineNewArray;
+class OutOfLineNewObject;
+class CheckOverRecursedFailure;
+class OutOfLineUnboxFloatingPoint;
+class OutOfLineStoreElementHole;
+class OutOfLineTypeOfV;
+class OutOfLineTypeOfIsNonPrimitiveV;
+class OutOfLineTypeOfIsNonPrimitiveO;
+class OutOfLineUpdateCache;
+class OutOfLineICFallback;
+class OutOfLineCallPostWriteBarrier;
+class OutOfLineCallPostWriteElementBarrier;
+class OutOfLineElementPostWriteBarrier;
+class OutOfLineIsCallable;
+class OutOfLineIsConstructor;
+class OutOfLineRegExpMatcher;
+class OutOfLineRegExpSearcher;
+class OutOfLineRegExpExecMatch;
+class OutOfLineRegExpExecTest;
+class OutOfLineRegExpPrototypeOptimizable;
+class OutOfLineRegExpInstanceOptimizable;
+class OutOfLineNaNToZero;
+class OutOfLineResumableWasmTrap;
+class OutOfLineAbortingWasmTrap;
+class OutOfLineGuardNumberToIntPtrIndex;
+class OutOfLineBoxNonStrictThis;
+class OutOfLineArrayPush;
+class OutOfLineWasmCallPostWriteBarrier;
+
+class CodeGenerator final : public CodeGeneratorSpecific {
+  [[nodiscard]] bool generateBody();
+
+  ConstantOrRegister toConstantOrRegister(LInstruction* lir, size_t n,
+                                          MIRType type);
+
+#ifdef CHECK_OSIPOINT_REGISTERS
+  void resetOsiPointRegs(LSafepoint* safepoint);
+  bool shouldVerifyOsiPointRegs(LSafepoint* safepoint);
+  void verifyOsiPointRegs(LSafepoint* safepoint);
+#endif
+
+  void callVMInternal(VMFunctionId id, LInstruction* ins);
+
+  template <typename Fn, Fn fn>
+  void callVM(LInstruction* ins);
+
+  template <typename Fn, Fn fn, class ArgSeq, class StoreOutputTo>
+  inline OutOfLineCode* oolCallVM(LInstruction* ins, const ArgSeq& args,
+                                  const StoreOutputTo& out);
+
+  template <typename LCallIns>
+  void emitCallNative(LCallIns* call, JSNative native);
+
+ public:
+  CodeGenerator(MIRGenerator* gen, LIRGraph* graph,
+                MacroAssembler* masm = nullptr);
+  ~CodeGenerator();
+
+  [[nodiscard]] bool generate();
+  [[nodiscard]] bool generateWasm(
+      wasm::CallIndirectId callIndirectId, wasm::BytecodeOffset trapOffset,
+      const wasm::ArgTypeVector& argTys, const RegisterOffsets& trapExitLayout,
+      size_t trapExitLayoutNumWords, wasm::FuncOffsets* offsets,
+      wasm::StackMaps* stackMaps, wasm::Decoder* decoder);
+
+  [[nodiscard]] bool link(JSContext* cx, const WarpSnapshot* snapshot);
+
+  void emitOOLTestObject(Register objreg, Label* ifTruthy, Label* ifFalsy,
+                         Register scratch);
+  void emitIntToString(Register input, Register output, Label* ool);
+
+  void emitTypeOfCheck(JSValueType type, Register tag, Register output,
+                       Label* done, Label* oolObject);
+  void emitTypeOfJSType(JSValueType type, Register output);
+  void emitTypeOfObject(Register obj, Register output, Label* done);
+  void emitTypeOfIsObject(MTypeOfIs* mir, Register obj, Register output,
+                          Label* success, Label* fail, Label* slowCheck);
+  void emitTypeOfIsObjectOOL(MTypeOfIs* mir, Register obj, Register output);
+
+  template <typename Fn, Fn fn, class ArgSeq, class StoreOutputTo>
+  void visitOutOfLineCallVM(
+      OutOfLineCallVM<Fn, fn, ArgSeq, StoreOutputTo>* ool);
+
+  void visitOutOfLineRegExpMatcher(OutOfLineRegExpMatcher* ool);
+  void visitOutOfLineRegExpSearcher(OutOfLineRegExpSearcher* ool);
+  void visitOutOfLineRegExpExecMatch(OutOfLineRegExpExecMatch* ool);
+  void visitOutOfLineRegExpExecTest(OutOfLineRegExpExecTest* ool);
+  void visitOutOfLineRegExpPrototypeOptimizable(
+      OutOfLineRegExpPrototypeOptimizable* ool);
+  void visitOutOfLineRegExpInstanceOptimizable(
+      OutOfLineRegExpInstanceOptimizable* ool);
+
+  void visitOutOfLineTypeOfV(OutOfLineTypeOfV* ool);
+  void visitOutOfLineTypeOfIsNonPrimitiveV(OutOfLineTypeOfIsNonPrimitiveV* ool);
+  void visitOutOfLineTypeOfIsNonPrimitiveO(OutOfLineTypeOfIsNonPrimitiveO* ool);
+
+  template <SwitchTableType tableType>
+  void visitOutOfLineSwitch(OutOfLineSwitch<tableType>* ool);
+
+  void visitOutOfLineIsCallable(OutOfLineIsCallable* ool);
+  void visitOutOfLineIsConstructor(OutOfLineIsConstructor* ool);
+
+  void visitOutOfLineNaNToZero(OutOfLineNaNToZero* ool);
+
+  void visitOutOfLineResumableWasmTrap(OutOfLineResumableWasmTrap* ool);
+  void visitOutOfLineAbortingWasmTrap(OutOfLineAbortingWasmTrap* ool);
+  void visitCheckOverRecursedFailure(CheckOverRecursedFailure* ool);
+
+  void visitOutOfLineUnboxFloatingPoint(OutOfLineUnboxFloatingPoint* ool);
+  void visitOutOfLineStoreElementHole(OutOfLineStoreElementHole* ool);
+
+  void visitOutOfLineBoxNonStrictThis(OutOfLineBoxNonStrictThis* ool);
+
+  void visitOutOfLineICFallback(OutOfLineICFallback* ool);
+
+  void visitOutOfLineCallPostWriteBarrier(OutOfLineCallPostWriteBarrier* ool);
+  void visitOutOfLineCallPostWriteElementBarrier(
+      OutOfLineCallPostWriteElementBarrier* ool);
+
+  void visitOutOfLineElementPostWriteBarrier(
+      OutOfLineElementPostWriteBarrier* ool);
+
+  void visitOutOfLineNewArray(OutOfLineNewArray* ool);
+  void visitOutOfLineNewObject(OutOfLineNewObject* ool);
+
+  void visitOutOfLineGuardNumberToIntPtrIndex(
+      OutOfLineGuardNumberToIntPtrIndex* ool);
+
+  void visitOutOfLineArrayPush(OutOfLineArrayPush* ool);
+
+  void visitOutOfLineWasmCallPostWriteBarrier(
+      OutOfLineWasmCallPostWriteBarrier* ool);
+
+ private:
+  void emitPostWriteBarrier(const LAllocation* obj);
+  void emitPostWriteBarrier(Register objreg);
+  void emitPostWriteBarrierS(Address address, Register prev, Register next);
+
+  void emitElementPostWriteBarrier(MInstruction* mir,
+                                   const LiveRegisterSet& liveVolatileRegs,
+                                   Register obj, const LAllocation* index,
+                                   Register scratch,
+                                   const ConstantOrRegister& val,
+                                   int32_t indexDiff = 0);
+
+  template <class LPostBarrierType, MIRType nurseryType>
+  void visitPostWriteBarrierCommon(LPostBarrierType* lir, OutOfLineCode* ool);
+  template <class LPostBarrierType>
+  void visitPostWriteBarrierCommonV(LPostBarrierType* lir, OutOfLineCode* ool);
+
+  void emitCallInvokeFunction(LInstruction* call, Register callereg,
+                              bool isConstructing, bool ignoresReturnValue,
+                              uint32_t argc, uint32_t unusedStack);
+  template <typename T>
+  void emitApplyGeneric(T* apply);
+  template <typename T>
+  void emitCallInvokeFunction(T* apply);
+  void emitAllocateSpaceForApply(Register argcreg, Register scratch);
+  void emitAllocateSpaceForConstructAndPushNewTarget(
+      Register argcreg, Register newTargetAndScratch);
+  void emitCopyValuesForApply(Register argvSrcBase, Register argvIndex,
+                              Register copyreg, size_t argvSrcOffset,
+                              size_t argvDstOffset);
+  void emitRestoreStackPointerFromFP();
+  void emitPushArguments(Register argcreg, Register scratch, Register copyreg,
+                         uint32_t extraFormals);
+  void emitPushArrayAsArguments(Register tmpArgc, Register srcBaseAndArgc,
+                                Register scratch, size_t argvSrcOffset);
+  void emitPushArguments(LApplyArgsGeneric* apply, Register scratch);
+  void emitPushArguments(LApplyArgsObj* apply, Register scratch);
+  void emitPushArguments(LApplyArrayGeneric* apply, Register scratch);
+  void emitPushArguments(LConstructArgsGeneric* construct, Register scratch);
+  void emitPushArguments(LConstructArrayGeneric* construct, Register scratch);
+
+  template <class GetInlinedArgument>
+  void emitGetInlinedArgument(GetInlinedArgument* lir, Register index,
+                              ValueOperand output);
+
+  using RegisterOrInt32 = mozilla::Variant<Register, int32_t>;
+
+  static RegisterOrInt32 ToRegisterOrInt32(const LAllocation* allocation);
+
+#ifdef DEBUG
+  void emitAssertArgumentsSliceBounds(const RegisterOrInt32& begin,
+                                      const RegisterOrInt32& count,
+                                      Register numActualArgs);
+#endif
+
+  template <class ArgumentsSlice>
+  void emitNewArray(ArgumentsSlice* lir, const RegisterOrInt32& count,
+                    Register output, Register temp);
+
+  void visitNewArrayCallVM(LNewArray* lir);
+  void visitNewObjectVMCall(LNewObject* lir);
+
+  void emitConcat(LInstruction* lir, Register lhs, Register rhs,
+                  Register output);
+
+  void emitInstanceOf(LInstruction* ins, Register protoReg);
+
+  void loadJSScriptForBlock(MBasicBlock* block, Register reg);
+  void loadOutermostJSScript(Register reg);
+
+#ifdef DEBUG
+  void emitAssertResultV(const ValueOperand output, const MDefinition* mir);
+  void emitAssertGCThingResult(Register input, const MDefinition* mir);
+#endif
+
+#ifdef DEBUG
+  void emitDebugForceBailing(LInstruction* lir);
+#endif
+
+  IonScriptCounts* extractScriptCounts() {
+    IonScriptCounts* counts = scriptCounts_;
+    scriptCounts_ = nullptr;  // prevent delete in dtor
+    return counts;
+  }
+
+  void addGetPropertyCache(LInstruction* ins, LiveRegisterSet liveRegs,
+                           TypedOrValueRegister value,
+                           const ConstantOrRegister& id, ValueOperand output);
+  void addSetPropertyCache(LInstruction* ins, LiveRegisterSet liveRegs,
+                           Register objReg, Register temp,
+                           const ConstantOrRegister& id,
+                           const ConstantOrRegister& value, bool strict);
+
+  template <class IteratorObject, class OrderedHashTable>
+  void emitGetNextEntryForIterator(LGetNextEntryForIterator* lir);
+
+  template <class OrderedHashTable>
+  void emitLoadIteratorValues(Register result, Register temp, Register front);
+
+  void emitStringToInt64(LInstruction* lir, Register input, Register64 output);
+
+  OutOfLineCode* createBigIntOutOfLine(LInstruction* lir, Scalar::Type type,
+                                       Register64 input, Register output);
+
+  void emitCreateBigInt(LInstruction* lir, Scalar::Type type, Register64 input,
+                        Register output, Register maybeTemp);
+
+  template <size_t NumDefs>
+  void emitIonToWasmCallBase(LIonToWasmCallBase<NumDefs>* lir);
+
+  IonScriptCounts* maybeCreateScriptCounts();
+
+  void emitWasmCompareAndSelect(LWasmCompareAndSelect* ins);
+
+  void testValueTruthyForType(JSValueType type, ScratchTagScope& tag,
+                              const ValueOperand& value, Register tempToUnbox,
+                              Register temp, FloatRegister floatTemp,
+                              Label* ifTruthy, Label* ifFalsy,
+                              OutOfLineTestObject* ool, bool skipTypeTest);
+
+  // Test whether value is truthy or not and jump to the corresponding label.
+  // The control flow falls through when the object is truthy, as an
+  // optimization.
+  void testValueTruthy(const ValueOperand& value, Register tempToUnbox,
+                       Register temp, FloatRegister floatTemp,
+                       const TypeDataList& observedTypes, Label* ifTruthy,
+                       Label* ifFalsy, OutOfLineTestObject* ool);
+
+  // This function behaves like testObjectEmulatesUndefined with the exception
+  // that it can choose to let control flow fall through when the object
+  // doesn't emulate undefined, as an optimization. Use the regular
+  // testObjectEmulatesUndefined when it's required to branch to one of the
+  // two labels.
+  void testObjectEmulatesUndefinedKernel(Register objreg,
+                                         Label* ifEmulatesUndefined,
+                                         Label* ifDoesntEmulateUndefined,
+                                         Register scratch,
+                                         OutOfLineTestObject* ool);
+
+  // Test whether an object emulates |undefined|.  If it does, jump to
+  // |ifEmulatesUndefined|; the caller is responsible for binding this label.
+  // If it doesn't, fall through; the label |ifDoesntEmulateUndefined| (which
+  // must be initially unbound) will be bound at this point.
+  void branchTestObjectEmulatesUndefined(Register objreg,
+                                         Label* ifEmulatesUndefined,
+                                         Label* ifDoesntEmulateUndefined,
+                                         Register scratch,
+                                         OutOfLineTestObject* ool);
+
+  // Test whether an object emulates |undefined|, and jump to the
+  // corresponding label.
+  //
+  // This method should be used when subsequent code can't be laid out in a
+  // straight line; if it can, branchTest* should be used instead.
+  void testObjectEmulatesUndefined(Register objreg, Label* ifEmulatesUndefined,
+                                   Label* ifDoesntEmulateUndefined,
+                                   Register scratch, OutOfLineTestObject* ool);
+
+  void emitStoreElementTyped(const LAllocation* value, MIRType valueType,
+                             Register elements, const LAllocation* index);
+
+  // Bailout if an element about to be written to is a hole.
+  void emitStoreHoleCheck(Register elements, const LAllocation* index,
+                          LSnapshot* snapshot);
+
+  void emitAssertRangeI(MIRType type, const Range* r, Register input);
+  void emitAssertRangeD(const Range* r, FloatRegister input,
+                        FloatRegister temp);
+
+  void maybeEmitGlobalBarrierCheck(const LAllocation* maybeGlobal,
+                                   OutOfLineCode* ool);
+
+  void incrementWarmUpCounter(AbsoluteAddress warmUpCount, JSScript* script,
+                              Register tmp);
+
+  Vector<CodeOffset, 0, JitAllocPolicy> ionScriptLabels_;
+
+  // Used to bake in a pointer into the IonScript's list of nursery objects, for
+  // MNurseryObject codegen.
+  struct NurseryObjectLabel {
+    CodeOffset offset;
+    uint32_t nurseryIndex;
+    NurseryObjectLabel(CodeOffset offset, uint32_t nurseryIndex)
+        : offset(offset), nurseryIndex(nurseryIndex) {}
+  };
+  Vector<NurseryObjectLabel, 0, JitAllocPolicy> ionNurseryObjectLabels_;
+
+  void branchIfInvalidated(Register temp, Label* invalidated);
+
+#ifdef DEBUG
+  void emitDebugResultChecks(LInstruction* ins);
+  void emitGCThingResultChecks(LInstruction* lir, MDefinition* mir);
+  void emitValueResultChecks(LInstruction* lir, MDefinition* mir);
+#endif
+
+  // Script counts created during code generation.
+  IonScriptCounts* scriptCounts_;
+
+  IonPerfSpewer perfSpewer_;
+
+  // Bit mask of JitRealm stubs that are to be read-barriered.
+  uint32_t realmStubsToReadBarrier_;
+
+#ifdef FUZZING_JS_FUZZILLI
+  void emitFuzzilliHashDouble(FloatRegister floatDouble, Register scratch,
+                              Register output);
+  void emitFuzzilliHashObject(LInstruction* lir, Register obj, Register output);
+  void emitFuzzilliHashBigInt(Register bigInt, Register output);
+#endif
+
+#define LIR_OP(op) void visit##op(L##op* ins);
+  LIR_OPCODE_LIST(LIR_OP)
+#undef LIR_OP
+};
+
+class OutOfLineResumableWasmTrap : public OutOfLineCodeBase<CodeGenerator> {
+  LInstruction* lir_;
+  size_t framePushed_;
+  wasm::BytecodeOffset bytecodeOffset_;
+  wasm::Trap trap_;
+
+ public:
+  OutOfLineResumableWasmTrap(LInstruction* lir, size_t framePushed,
+                             wasm::BytecodeOffset bytecodeOffset,
+                             wasm::Trap trap)
+      : lir_(lir),
+        framePushed_(framePushed),
+        bytecodeOffset_(bytecodeOffset),
+        trap_(trap) {}
+
+  void accept(CodeGenerator* codegen) override {
+    codegen->visitOutOfLineResumableWasmTrap(this);
+  }
+  LInstruction* lir() const { return lir_; }
+  size_t framePushed() const { return framePushed_; }
+  wasm::BytecodeOffset bytecodeOffset() const { return bytecodeOffset_; }
+  wasm::Trap trap() const { return trap_; }
+};
+
+class OutOfLineAbortingWasmTrap : public OutOfLineCodeBase<CodeGenerator> {
+  wasm::BytecodeOffset bytecodeOffset_;
+  wasm::Trap trap_;
+
+ public:
+  OutOfLineAbortingWasmTrap(wasm::BytecodeOffset bytecodeOffset,
+                            wasm::Trap trap)
+      : bytecodeOffset_(bytecodeOffset), trap_(trap) {}
+
+  void accept(CodeGenerator* codegen) override {
+    codegen->visitOutOfLineAbortingWasmTrap(this);
+  }
+  wasm::BytecodeOffset bytecodeOffset() const { return bytecodeOffset_; }
+  wasm::Trap trap() const { return trap_; }
+};
+
+}  // namespace jit
+}  // namespace js
+
+#endif /* jit_CodeGenerator_h */
-- 
cgit v1.2.3