TrialInlining.h (6068B)
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 #ifndef jit_TrialInlining_h 8 #define jit_TrialInlining_h 9 10 #include "mozilla/Attributes.h" 11 #include "mozilla/Maybe.h" 12 13 #include <stddef.h> 14 #include <stdint.h> 15 16 #include "jstypes.h" 17 #include "NamespaceImports.h" 18 19 #include "gc/Barrier.h" 20 #include "jit/CacheIR.h" 21 #include "js/RootingAPI.h" 22 #include "js/TypeDecls.h" 23 #include "js/UniquePtr.h" 24 #include "js/Vector.h" 25 #include "vm/JSScript.h" 26 27 /* 28 * [SMDOC] Trial Inlining 29 * 30 * WarpBuilder relies on transpiling CacheIR. When inlining scripted 31 * functions in WarpBuilder, we want our ICs to be as monomorphic as 32 * possible. Functions with multiple callers complicate this. An IC in 33 * such a function might be monomorphic for any given caller, but 34 * polymorphic overall. This make the input to WarpBuilder less precise. 35 * 36 * To solve this problem, we do trial inlining. During baseline 37 * execution, we identify call sites for which it would be useful to 38 * have more precise inlining data. For each such call site, we 39 * allocate a fresh ICScript and replace the existing call IC with a 40 * new specialized IC that invokes the callee using the new 41 * ICScript. Other callers of the callee will continue using the 42 * default ICScript. When we eventually Warp-compile the script, we 43 * can generate code for the callee using the IC information in our 44 * private ICScript, which is specialized for its caller. 45 * 46 * The same approach can be used to inline recursively. 47 */ 48 49 class JS_PUBLIC_API JSTracer; 50 struct JS_PUBLIC_API JSContext; 51 52 namespace JS { 53 class Zone; 54 } 55 56 namespace js { 57 58 class BytecodeLocation; 59 60 namespace jit { 61 62 class BaselineFrame; 63 class CacheIRWriter; 64 class ICCacheIRStub; 65 class ICEntry; 66 class ICFallbackStub; 67 class ICScript; 68 class ICStubSpace; 69 70 /* 71 * An InliningRoot is owned by a JitScript. In turn, it owns the set 72 * of ICScripts that are candidates for being inlined in that JitScript. 73 */ 74 class InliningRoot { 75 public: 76 explicit InliningRoot(JSContext* cx, JSScript* owningScript) 77 : owningScript_(owningScript), 78 inlinedScripts_(cx), 79 totalBytecodeSize_(owningScript->length()) {} 80 81 void trace(JSTracer* trc); 82 bool traceWeak(JSTracer* trc); 83 84 bool addInlinedScript(js::UniquePtr<ICScript> icScript); 85 86 uint32_t numInlinedScripts() const { return inlinedScripts_.length(); } 87 88 void purgeInactiveICScripts(); 89 90 JSScript* owningScript() const { return owningScript_; } 91 92 size_t totalBytecodeSize() const { return totalBytecodeSize_; } 93 94 void addToTotalBytecodeSize(size_t size) { totalBytecodeSize_ += size; } 95 96 template <typename F> 97 void forEachInlinedScript(const F& f) const { 98 for (auto& script : inlinedScripts_) { 99 f(script.get()); 100 } 101 } 102 103 private: 104 HeapPtr<JSScript*> owningScript_; 105 js::Vector<js::UniquePtr<ICScript>> inlinedScripts_; 106 107 // Bytecode size of outer script and all inlined scripts. 108 size_t totalBytecodeSize_; 109 }; 110 111 class InlinableOpData { 112 public: 113 JSScript* target = nullptr; 114 ICScript* icScript = nullptr; 115 const uint8_t* endOfSharedPrefix = nullptr; 116 }; 117 118 class InlinableCallData : public InlinableOpData { 119 public: 120 ObjOperandId calleeOperand; 121 CallFlags callFlags; 122 }; 123 124 class InlinableGetterData : public InlinableOpData { 125 public: 126 ValOperandId receiverOperand; 127 ObjOperandId calleeOperand; 128 bool sameRealm = false; 129 }; 130 131 class InlinableSetterData : public InlinableOpData { 132 public: 133 ObjOperandId receiverOperand; 134 ObjOperandId calleeOperand; 135 ValOperandId rhsOperand; 136 bool sameRealm = false; 137 }; 138 139 mozilla::Maybe<InlinableOpData> FindInlinableOpData(ICCacheIRStub* stub, 140 BytecodeLocation loc); 141 142 mozilla::Maybe<InlinableCallData> FindInlinableCallData(ICCacheIRStub* stub); 143 mozilla::Maybe<InlinableGetterData> FindInlinableGetterData( 144 ICCacheIRStub* stub); 145 mozilla::Maybe<InlinableSetterData> FindInlinableSetterData( 146 ICCacheIRStub* stub); 147 148 enum class TrialInliningDecision { 149 NoInline, 150 Inline, 151 MonomorphicInline, 152 }; 153 154 class MOZ_RAII TrialInliner { 155 public: 156 TrialInliner(JSContext* cx, HandleScript script, ICScript* icScript) 157 : cx_(cx), script_(script), icScript_(icScript) {} 158 159 JSContext* cx() { return cx_; } 160 161 [[nodiscard]] bool tryInlining(); 162 [[nodiscard]] bool maybeInlineCall(ICEntry& entry, ICFallbackStub* fallback, 163 BytecodeLocation loc); 164 [[nodiscard]] bool maybeInlineGetter(ICEntry& entry, ICFallbackStub* fallback, 165 BytecodeLocation loc, CacheKind kind); 166 [[nodiscard]] bool maybeInlineSetter(ICEntry& entry, ICFallbackStub* fallback, 167 BytecodeLocation loc, CacheKind kind); 168 169 static bool canInline(JSContext* cx, JSScript* target, HandleScript caller, 170 BytecodeLocation loc); 171 172 static bool IsValidInliningOp(JSOp op); 173 174 private: 175 ICCacheIRStub* maybeSingleStub(const ICEntry& entry); 176 void cloneSharedPrefix(ICCacheIRStub* stub, const uint8_t* endOfPrefix, 177 CacheIRWriter& writer); 178 ICScript* createInlinedICScript(JSScript* target, BytecodeLocation loc); 179 [[nodiscard]] bool replaceICStub(ICEntry& entry, ICFallbackStub* fallback, 180 CacheIRWriter& writer, CacheKind kind); 181 182 TrialInliningDecision getInliningDecision(JSScript* target, 183 ICCacheIRStub* stub, 184 BytecodeLocation loc); 185 186 InliningRoot* getOrCreateInliningRoot(); 187 InliningRoot* maybeGetInliningRoot() const; 188 size_t inliningRootTotalBytecodeSize() const; 189 190 JSContext* cx_; 191 HandleScript script_; 192 ICScript* icScript_; 193 }; 194 195 bool DoTrialInlining(JSContext* cx, BaselineFrame* frame); 196 197 } // namespace jit 198 } // namespace js 199 200 #endif /* jit_TrialInlining_h */