diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-28 14:29:10 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-28 14:29:10 +0000 |
commit | 2aa4a82499d4becd2284cdb482213d541b8804dd (patch) | |
tree | b80bf8bf13c3766139fbacc530efd0dd9d54394c /js/src/jit/CodeGenerator.h | |
parent | Initial commit. (diff) | |
download | firefox-2aa4a82499d4becd2284cdb482213d541b8804dd.tar.xz firefox-2aa4a82499d4becd2284cdb482213d541b8804dd.zip |
Adding upstream version 86.0.1.upstream/86.0.1upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'js/src/jit/CodeGenerator.h')
-rw-r--r-- | js/src/jit/CodeGenerator.h | 357 |
1 files changed, 357 insertions, 0 deletions
diff --git a/js/src/jit/CodeGenerator.h b/js/src/jit/CodeGenerator.h new file mode 100644 index 0000000000..b79b42c584 --- /dev/null +++ b/js/src/jit/CodeGenerator.h @@ -0,0 +1,357 @@ +/* -*- 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/CacheIR.h" +#if defined(JS_ION_PERF) +# include "jit/PerfSpewer.h" +#endif +#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_NONE) +# include "jit/none/CodeGenerator-none.h" +#else +# error "Unknown architecture!" +#endif + +#include "wasm/WasmGC.h" + +namespace js { +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 OutOfLineUpdateCache; +class OutOfLineICFallback; +class OutOfLineCallPostWriteBarrier; +class OutOfLineCallPostWriteElementBarrier; +class OutOfLineIsCallable; +class OutOfLineIsConstructor; +class OutOfLineRegExpMatcher; +class OutOfLineRegExpSearcher; +class OutOfLineRegExpTester; +class OutOfLineRegExpPrototypeOptimizable; +class OutOfLineRegExpInstanceOptimizable; +class OutOfLineNaNToZero; +class OutOfLineZeroIfNaN; +class OutOfLineTypedArrayIndexToInt32; +class OutOfLineBoxNonStrictThis; + +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, + const Register* dynStack); + + template <typename Fn, Fn fn> + void callVM(LInstruction* ins, const Register* dynStack = nullptr); + + template <typename Fn, Fn fn, class ArgSeq, class StoreOutputTo> + inline OutOfLineCode* oolCallVM(LInstruction* ins, const ArgSeq& args, + const StoreOutputTo& out); + + public: + CodeGenerator(MIRGenerator* gen, LIRGraph* graph, + MacroAssembler* masm = nullptr); + ~CodeGenerator(); + + [[nodiscard]] bool generate(); + [[nodiscard]] bool generateWasm(wasm::TypeIdDesc funcTypeId, + wasm::BytecodeOffset trapOffset, + const wasm::ArgTypeVector& argTys, + const MachineState& trapExitLayout, + size_t trapExitLayoutNumWords, + wasm::FuncOffsets* offsets, + wasm::StackMaps* stackMaps); + + [[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 emitTypeOfObject(Register obj, Register output, Label* done); + + 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 visitOutOfLineRegExpTester(OutOfLineRegExpTester* ool); + void visitOutOfLineRegExpPrototypeOptimizable( + OutOfLineRegExpPrototypeOptimizable* ool); + void visitOutOfLineRegExpInstanceOptimizable( + OutOfLineRegExpInstanceOptimizable* ool); + + void visitOutOfLineTypeOfV(OutOfLineTypeOfV* ool); + + template <SwitchTableType tableType> + void visitOutOfLineSwitch(OutOfLineSwitch<tableType>* ool); + + void visitOutOfLineIsCallable(OutOfLineIsCallable* ool); + void visitOutOfLineIsConstructor(OutOfLineIsConstructor* ool); + + void visitOutOfLineNaNToZero(OutOfLineNaNToZero* ool); + void visitOutOfLineZeroIfNaN(OutOfLineZeroIfNaN* 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 visitOutOfLineNewArray(OutOfLineNewArray* ool); + void visitOutOfLineNewObject(OutOfLineNewObject* ool); + + void visitOutOfLineTypedArrayIndexToInt32( + OutOfLineTypedArrayIndexToInt32* ool); + + private: + void emitPostWriteBarrier(const LAllocation* obj); + void emitPostWriteBarrier(Register objreg); + void emitPostWriteBarrierS(Address address, Register prev, Register next); + + 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, Register extraStackSize); + void emitAllocateSpaceForApply(Register argcreg, Register extraStackSpace); + void emitAllocateSpaceForConstructAndPushNewTarget( + Register argcreg, Register newTargetAndExtraStackSpace); + void emitCopyValuesForApply(Register argvSrcBase, Register argvIndex, + Register copyreg, size_t argvSrcOffset, + size_t argvDstOffset); + void emitPopArguments(Register extraStackSize); + void emitPushElementsAsArguments(Register tmpArgc, Register elementsAndArgc, + Register extraStackSpace); + void emitPushArguments(LApplyArgsGeneric* apply, Register extraStackSpace); + void emitPushArguments(LApplyArrayGeneric* apply, Register extraStackSpace); + void emitPushArguments(LConstructArrayGeneric* construct, + Register extraStackSpace); + + void visitNewArrayCallVM(LNewArray* lir); + void visitNewObjectVMCall(LNewObject* lir); + + void emitConcat(LInstruction* lir, Register lhs, Register rhs, + Register output); + + void emitRest(LInstruction* lir, Register array, Register numActuals, + Register temp0, Register temp1, unsigned numFormals, + JSObject* templateObject, bool saveAndRestore, + Register resultreg); + void emitInstanceOf(LInstruction* ins, const LAllocation* prototypeObject); + + 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); + + [[nodiscard]] bool generateBranchV(const ValueOperand& value, Label* ifTrue, + Label* ifFalse, FloatRegister fr); + + void emitLambdaInit(Register resultReg, Register envChainReg, + const LambdaFunctionInfo& info); + + void emitFilterArgumentsOrEval(LInstruction* lir, Register string, + Register temp1, Register temp2); + + 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); + + void emitCreateBigInt(LInstruction* lir, Scalar::Type type, Register64 input, + Register output, Register maybeTemp); + + template <size_t NumDefs> + void emitIonToWasmCallBase(LIonToWasmCallBase<NumDefs>* lir); + + IonScriptCounts* maybeCreateScriptCounts(); + + // This function behaves like testValueTruthy with the exception that it can + // choose to let control flow fall through when the object is truthy, as + // an optimization. Use testValueTruthy when it's required to branch to one + // of the two labels. + void testValueTruthyKernel(const ValueOperand& value, + const LDefinition* scratch1, + const LDefinition* scratch2, FloatRegister fr, + Label* ifTruthy, Label* ifFalsy, + OutOfLineTestObject* ool, MDefinition* valueMIR); + + // Test whether value is truthy or not and jump to the corresponding label. + // If the value can be an object that emulates |undefined|, |ool| must be + // non-null; otherwise it may be null (and the scratch definitions should + // be bogus), in which case an object encountered here will always be + // truthy. + void testValueTruthy(const ValueOperand& value, const LDefinition* scratch1, + const LDefinition* scratch2, FloatRegister fr, + Label* ifTruthy, Label* ifFalsy, + OutOfLineTestObject* ool, MDefinition* valueMIR); + + // 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, + MIRType elementType, 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(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_; + +#if defined(JS_ION_PERF) + PerfSpewer perfSpewer_; +#endif + + // Bit mask of JitRealm stubs that are to be read-barriered. + uint32_t realmStubsToReadBarrier_; + +#define LIR_OP(op) void visit##op(L##op* ins); + LIR_OPCODE_LIST(LIR_OP) +#undef LIR_OP +}; + +} // namespace jit +} // namespace js + +#endif /* jit_CodeGenerator_h */ |