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