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_Ion_h
8 #define jit_Ion_h
9 
10 #include "mozilla/Assertions.h"
11 #include "mozilla/Attributes.h"
12 #include "mozilla/Likely.h"
13 #include "mozilla/MemoryReporting.h"
14 
15 #include <stddef.h>
16 #include <stdint.h>
17 
18 #include "jsfriendapi.h"
19 #include "jspubtd.h"
20 
21 #include "jit/BaselineJIT.h"
22 #include "jit/IonTypes.h"
23 #include "jit/JitContext.h"
24 #include "jit/JitOptions.h"
25 #include "js/Principals.h"
26 #include "js/TypeDecls.h"
27 #include "vm/BytecodeUtil.h"
28 #include "vm/JSContext.h"
29 #include "vm/JSFunction.h"
30 #include "vm/JSScript.h"
31 
32 namespace js {
33 
34 class RunState;
35 
36 namespace jit {
37 
38 class BaselineFrame;
39 
40 bool CanIonCompileScript(JSContext* cx, JSScript* script);
41 bool CanIonInlineScript(JSScript* script);
42 
43 [[nodiscard]] bool IonCompileScriptForBaselineAtEntry(JSContext* cx,
44                                                       BaselineFrame* frame);
45 
46 struct IonOsrTempData {
47   void* jitcode;
48   uint8_t* baselineFrame;
49 
offsetOfJitCodeIonOsrTempData50   static constexpr size_t offsetOfJitCode() {
51     return offsetof(IonOsrTempData, jitcode);
52   }
offsetOfBaselineFrameIonOsrTempData53   static constexpr size_t offsetOfBaselineFrame() {
54     return offsetof(IonOsrTempData, baselineFrame);
55   }
56 };
57 
58 [[nodiscard]] bool IonCompileScriptForBaselineOSR(JSContext* cx,
59                                                   BaselineFrame* frame,
60                                                   uint32_t frameSize,
61                                                   jsbytecode* pc,
62                                                   IonOsrTempData** infoPtr);
63 
64 MethodStatus CanEnterIon(JSContext* cx, RunState& state);
65 
66 class MIRGenerator;
67 class LIRGraph;
68 class CodeGenerator;
69 class LazyLinkExitFrameLayout;
70 class WarpSnapshot;
71 
72 [[nodiscard]] bool OptimizeMIR(MIRGenerator* mir);
73 LIRGraph* GenerateLIR(MIRGenerator* mir);
74 CodeGenerator* GenerateCode(MIRGenerator* mir, LIRGraph* lir);
75 CodeGenerator* CompileBackEnd(MIRGenerator* mir, WarpSnapshot* snapshot);
76 
77 void LinkIonScript(JSContext* cx, HandleScript calleescript);
78 uint8_t* LazyLinkTopActivation(JSContext* cx, LazyLinkExitFrameLayout* frame);
79 
IsIonInlinableGetterOrSetterOp(JSOp op)80 inline bool IsIonInlinableGetterOrSetterOp(JSOp op) {
81   // JSOp::GetProp, JSOp::CallProp, JSOp::Length, JSOp::GetElem,
82   // and JSOp::CallElem. (Inlined Getters)
83   // JSOp::SetProp, JSOp::SetName, JSOp::SetGName (Inlined Setters)
84   return IsGetPropOp(op) || IsGetElemOp(op) || IsSetPropOp(op);
85 }
86 
IsIonInlinableOp(JSOp op)87 inline bool IsIonInlinableOp(JSOp op) {
88   // JSOp::Call, JSOp::FunCall, JSOp::FunApply, JSOp::Eval,
89   // JSOp::New (Normal Callsites) or an inlinable getter or setter.
90   return (IsInvokeOp(op) && !IsSpreadOp(op)) ||
91          IsIonInlinableGetterOrSetterOp(op);
92 }
93 
TooManyActualArguments(unsigned nargs)94 inline bool TooManyActualArguments(unsigned nargs) {
95   return nargs > JitOptions.maxStackArgs;
96 }
97 
TooManyFormalArguments(unsigned nargs)98 inline bool TooManyFormalArguments(unsigned nargs) {
99   return nargs >= SNAPSHOT_MAX_NARGS || TooManyActualArguments(nargs);
100 }
101 
NumLocalsAndArgs(JSScript * script)102 inline size_t NumLocalsAndArgs(JSScript* script) {
103   size_t num = 1 /* this */ + script->nfixed();
104   if (JSFunction* fun = script->function()) {
105     num += fun->nargs();
106   }
107   return num;
108 }
109 
110 // Debugging RAII class which marks the current thread as performing an Ion
111 // backend compilation.
112 class MOZ_RAII AutoEnterIonBackend {
113  public:
AutoEnterIonBackend()114   AutoEnterIonBackend() {
115 #ifdef DEBUG
116     JitContext* jcx = GetJitContext();
117     jcx->enterIonBackend();
118 #endif
119   }
120 
121 #ifdef DEBUG
~AutoEnterIonBackend()122   ~AutoEnterIonBackend() {
123     JitContext* jcx = GetJitContext();
124     jcx->leaveIonBackend();
125   }
126 #endif
127 };
128 
129 bool OffThreadCompilationAvailable(JSContext* cx);
130 
131 void ForbidCompilation(JSContext* cx, JSScript* script);
132 
133 size_t SizeOfIonData(JSScript* script, mozilla::MallocSizeOf mallocSizeOf);
134 
IsIonEnabled(JSContext * cx)135 inline bool IsIonEnabled(JSContext* cx) {
136   if (MOZ_UNLIKELY(!IsBaselineJitEnabled(cx) || cx->options().disableIon())) {
137     return false;
138   }
139 
140   if (MOZ_LIKELY(JitOptions.ion)) {
141     return true;
142   }
143   if (JitOptions.jitForTrustedPrincipals) {
144     JS::Realm* realm = js::GetContextRealm(cx);
145     return realm && JS::GetRealmPrincipals(realm) &&
146            JS::GetRealmPrincipals(realm)->isSystemOrAddonPrincipal();
147   }
148   return false;
149 }
150 
151 // Implemented per-platform.  Returns true if the flags will not require
152 // further (lazy) computation.
153 bool CPUFlagsHaveBeenComputed();
154 
155 }  // namespace jit
156 }  // namespace js
157 
158 #endif /* jit_Ion_h */
159