1 | /* |
2 | * Copyright (C) 2009-2018 Apple Inc. All rights reserved. |
3 | * |
4 | * Redistribution and use in source and binary forms, with or without |
5 | * modification, are permitted provided that the following conditions |
6 | * are met: |
7 | * 1. Redistributions of source code must retain the above copyright |
8 | * notice, this list of conditions and the following disclaimer. |
9 | * 2. Redistributions in binary form must reproduce the above copyright |
10 | * notice, this list of conditions and the following disclaimer in the |
11 | * documentation and/or other materials provided with the distribution. |
12 | * |
13 | * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY |
14 | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
15 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
16 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR |
17 | * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, |
18 | * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, |
19 | * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR |
20 | * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY |
21 | * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
22 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
23 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
24 | */ |
25 | |
26 | #pragma once |
27 | |
28 | #include "ArityCheckMode.h" |
29 | #include "CallData.h" |
30 | #include "CodeBlockHash.h" |
31 | #include "CodeSpecializationKind.h" |
32 | #include "JITCode.h" |
33 | #include "JSGlobalObject.h" |
34 | #include "UnlinkedCodeBlock.h" |
35 | #include "UnlinkedFunctionExecutable.h" |
36 | |
37 | namespace JSC { |
38 | |
39 | class CodeBlock; |
40 | class EvalCodeBlock; |
41 | class FunctionCodeBlock; |
42 | class JSScope; |
43 | class JSWebAssemblyModule; |
44 | class ; |
45 | class ModuleProgramCodeBlock; |
46 | class ProgramCodeBlock; |
47 | |
48 | enum CompilationKind { FirstCompilation, OptimizingCompilation }; |
49 | |
50 | inline bool isCall(CodeSpecializationKind kind) |
51 | { |
52 | if (kind == CodeForCall) |
53 | return true; |
54 | ASSERT(kind == CodeForConstruct); |
55 | return false; |
56 | } |
57 | |
58 | class ExecutableBase : public JSCell { |
59 | friend class JIT; |
60 | friend MacroAssemblerCodeRef<JITThunkPtrTag> boundThisNoArgsFunctionCallGenerator(VM*); |
61 | |
62 | protected: |
63 | ExecutableBase(VM& vm, Structure* structure) |
64 | : JSCell(vm, structure) |
65 | { |
66 | } |
67 | |
68 | void finishCreation(VM& vm) |
69 | { |
70 | Base::finishCreation(vm); |
71 | } |
72 | |
73 | public: |
74 | typedef JSCell Base; |
75 | static const unsigned StructureFlags = Base::StructureFlags; |
76 | |
77 | static const bool needsDestruction = true; |
78 | static void destroy(JSCell*); |
79 | |
80 | // Force subclasses to override this. |
81 | template<typename, SubspaceAccess> |
82 | static void subspaceFor(VM&) { } |
83 | |
84 | CodeBlockHash hashFor(CodeSpecializationKind) const; |
85 | |
86 | bool isEvalExecutable() const |
87 | { |
88 | return type() == EvalExecutableType; |
89 | } |
90 | bool isFunctionExecutable() const |
91 | { |
92 | return type() == FunctionExecutableType; |
93 | } |
94 | bool isProgramExecutable() const |
95 | { |
96 | return type() == ProgramExecutableType; |
97 | } |
98 | bool isModuleProgramExecutable() |
99 | { |
100 | return type() == ModuleProgramExecutableType; |
101 | } |
102 | bool isHostFunction() const |
103 | { |
104 | return type() == NativeExecutableType; |
105 | } |
106 | |
107 | static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue proto) { return Structure::create(vm, globalObject, proto, TypeInfo(CellType, StructureFlags), info()); } |
108 | |
109 | DECLARE_EXPORT_INFO; |
110 | |
111 | public: |
112 | Ref<JITCode> generatedJITCodeForCall() const |
113 | { |
114 | ASSERT(m_jitCodeForCall); |
115 | return *m_jitCodeForCall; |
116 | } |
117 | |
118 | Ref<JITCode> generatedJITCodeForConstruct() const |
119 | { |
120 | ASSERT(m_jitCodeForConstruct); |
121 | return *m_jitCodeForConstruct; |
122 | } |
123 | |
124 | Ref<JITCode> generatedJITCodeFor(CodeSpecializationKind kind) const |
125 | { |
126 | if (kind == CodeForCall) |
127 | return generatedJITCodeForCall(); |
128 | ASSERT(kind == CodeForConstruct); |
129 | return generatedJITCodeForConstruct(); |
130 | } |
131 | |
132 | MacroAssemblerCodePtr<JSEntryPtrTag> entrypointFor(CodeSpecializationKind kind, ArityCheckMode arity) |
133 | { |
134 | // Check if we have a cached result. We only have it for arity check because we use the |
135 | // no-arity entrypoint in non-virtual calls, which will "cache" this value directly in |
136 | // machine code. |
137 | if (arity == MustCheckArity) { |
138 | switch (kind) { |
139 | case CodeForCall: |
140 | if (MacroAssemblerCodePtr<JSEntryPtrTag> result = m_jitCodeForCallWithArityCheck) |
141 | return result; |
142 | break; |
143 | case CodeForConstruct: |
144 | if (MacroAssemblerCodePtr<JSEntryPtrTag> result = m_jitCodeForConstructWithArityCheck) |
145 | return result; |
146 | break; |
147 | } |
148 | } |
149 | MacroAssemblerCodePtr<JSEntryPtrTag> result = generatedJITCodeFor(kind)->addressForCall(arity); |
150 | if (arity == MustCheckArity) { |
151 | // Cache the result; this is necessary for the JIT's virtual call optimizations. |
152 | switch (kind) { |
153 | case CodeForCall: |
154 | m_jitCodeForCallWithArityCheck = result; |
155 | break; |
156 | case CodeForConstruct: |
157 | m_jitCodeForConstructWithArityCheck = result; |
158 | break; |
159 | } |
160 | } |
161 | return result; |
162 | } |
163 | |
164 | static ptrdiff_t offsetOfJITCodeWithArityCheckFor( |
165 | CodeSpecializationKind kind) |
166 | { |
167 | switch (kind) { |
168 | case CodeForCall: |
169 | return OBJECT_OFFSETOF(ExecutableBase, m_jitCodeForCallWithArityCheck); |
170 | case CodeForConstruct: |
171 | return OBJECT_OFFSETOF(ExecutableBase, m_jitCodeForConstructWithArityCheck); |
172 | } |
173 | RELEASE_ASSERT_NOT_REACHED(); |
174 | return 0; |
175 | } |
176 | |
177 | bool hasJITCodeForCall() const; |
178 | bool hasJITCodeForConstruct() const; |
179 | |
180 | bool hasJITCodeFor(CodeSpecializationKind kind) const |
181 | { |
182 | if (kind == CodeForCall) |
183 | return hasJITCodeForCall(); |
184 | ASSERT(kind == CodeForConstruct); |
185 | return hasJITCodeForConstruct(); |
186 | } |
187 | |
188 | // Intrinsics are only for calls, currently. |
189 | Intrinsic intrinsic() const; |
190 | |
191 | Intrinsic intrinsicFor(CodeSpecializationKind kind) const |
192 | { |
193 | if (isCall(kind)) |
194 | return intrinsic(); |
195 | return NoIntrinsic; |
196 | } |
197 | |
198 | void dump(PrintStream&) const; |
199 | |
200 | protected: |
201 | RefPtr<JITCode> m_jitCodeForCall; |
202 | RefPtr<JITCode> m_jitCodeForConstruct; |
203 | MacroAssemblerCodePtr<JSEntryPtrTag> m_jitCodeForCallWithArityCheck; |
204 | MacroAssemblerCodePtr<JSEntryPtrTag> m_jitCodeForConstructWithArityCheck; |
205 | }; |
206 | |
207 | } // namespace JSC |
208 | |