1 | /* |
2 | * Copyright (C) 2009 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 | #ifndef Executable_h |
27 | #define Executable_h |
28 | |
29 | #include "JSFunction.h" |
30 | #include "Interpreter.h" |
31 | #include "Nodes.h" |
32 | #include "SamplingTool.h" |
33 | |
34 | namespace JSC { |
35 | |
36 | class CodeBlock; |
37 | class Debugger; |
38 | class EvalCodeBlock; |
39 | class ProgramCodeBlock; |
40 | class ScopeChainNode; |
41 | |
42 | struct ExceptionInfo; |
43 | |
44 | class ExecutableBase : public RefCounted<ExecutableBase> { |
45 | friend class JIT; |
46 | |
47 | protected: |
48 | static const int NUM_PARAMETERS_IS_HOST = 0; |
49 | static const int NUM_PARAMETERS_NOT_COMPILED = -1; |
50 | |
51 | public: |
52 | ExecutableBase(int numParameters) |
53 | : m_numParameters(numParameters) |
54 | { |
55 | } |
56 | |
57 | virtual ~ExecutableBase() {} |
58 | |
59 | bool isHostFunction() const { return m_numParameters == NUM_PARAMETERS_IS_HOST; } |
60 | |
61 | protected: |
62 | int m_numParameters; |
63 | |
64 | #if ENABLE(JIT) |
65 | public: |
66 | JITCode& generatedJITCode() |
67 | { |
68 | ASSERT(m_jitCode); |
69 | return m_jitCode; |
70 | } |
71 | |
72 | ExecutablePool* getExecutablePool() |
73 | { |
74 | return m_jitCode.getExecutablePool(); |
75 | } |
76 | |
77 | protected: |
78 | JITCode m_jitCode; |
79 | #endif |
80 | }; |
81 | |
82 | #if ENABLE(JIT) |
83 | class NativeExecutable : public ExecutableBase { |
84 | public: |
85 | NativeExecutable(ExecState* exec) |
86 | : ExecutableBase(NUM_PARAMETERS_IS_HOST) |
87 | { |
88 | m_jitCode = JITCode(JITCode::HostFunction(code: exec->globalData().jitStubs.ctiNativeCallThunk())); |
89 | } |
90 | |
91 | ~NativeExecutable(); |
92 | }; |
93 | #endif |
94 | |
95 | class VPtrHackExecutable : public ExecutableBase { |
96 | public: |
97 | VPtrHackExecutable() |
98 | : ExecutableBase(NUM_PARAMETERS_IS_HOST) |
99 | { |
100 | } |
101 | |
102 | ~VPtrHackExecutable(); |
103 | }; |
104 | |
105 | class ScriptExecutable : public ExecutableBase { |
106 | public: |
107 | ScriptExecutable(JSGlobalData* globalData, const SourceCode& source) |
108 | : ExecutableBase(NUM_PARAMETERS_NOT_COMPILED) |
109 | , m_source(source) |
110 | , m_features(0) |
111 | { |
112 | #if ENABLE(CODEBLOCK_SAMPLING) |
113 | if (SamplingTool* sampler = globalData->interpreter->sampler()) |
114 | sampler->notifyOfScope(this); |
115 | #else |
116 | UNUSED_PARAM(globalData); |
117 | #endif |
118 | } |
119 | |
120 | ScriptExecutable(ExecState* exec, const SourceCode& source) |
121 | : ExecutableBase(NUM_PARAMETERS_NOT_COMPILED) |
122 | , m_source(source) |
123 | , m_features(0) |
124 | { |
125 | #if ENABLE(CODEBLOCK_SAMPLING) |
126 | if (SamplingTool* sampler = exec->globalData().interpreter->sampler()) |
127 | sampler->notifyOfScope(this); |
128 | #else |
129 | UNUSED_PARAM(exec); |
130 | #endif |
131 | } |
132 | |
133 | const SourceCode& source() { return m_source; } |
134 | intptr_t sourceID() const { return m_source.provider()->asID(); } |
135 | const UString& sourceURL() const { return m_source.provider()->url(); } |
136 | int lineNo() const { return m_firstLine; } |
137 | int lastLine() const { return m_lastLine; } |
138 | |
139 | bool usesEval() const { return m_features & EvalFeature; } |
140 | bool usesArguments() const { return m_features & ArgumentsFeature; } |
141 | bool needsActivation() const { return m_features & (EvalFeature | ClosureFeature | WithFeature | CatchFeature); } |
142 | |
143 | virtual ExceptionInfo* reparseExceptionInfo(JSGlobalData*, ScopeChainNode*, CodeBlock*) = 0; |
144 | |
145 | protected: |
146 | void recordParse(CodeFeatures features, int firstLine, int lastLine) |
147 | { |
148 | m_features = features; |
149 | m_firstLine = firstLine; |
150 | m_lastLine = lastLine; |
151 | } |
152 | |
153 | SourceCode m_source; |
154 | CodeFeatures m_features; |
155 | int m_firstLine; |
156 | int m_lastLine; |
157 | }; |
158 | |
159 | class EvalExecutable : public ScriptExecutable { |
160 | public: |
161 | |
162 | ~EvalExecutable(); |
163 | |
164 | EvalCodeBlock& bytecode(ExecState* exec, ScopeChainNode* scopeChainNode) |
165 | { |
166 | if (!m_evalCodeBlock) { |
167 | JSObject* error = compile(exec, scopeChainNode); |
168 | ASSERT_UNUSED(!error, error); |
169 | } |
170 | return *m_evalCodeBlock; |
171 | } |
172 | |
173 | JSObject* compile(ExecState*, ScopeChainNode*); |
174 | |
175 | bool isCompiled() const { return m_evalCodeBlock; } |
176 | |
177 | ExceptionInfo* reparseExceptionInfo(JSGlobalData*, ScopeChainNode*, CodeBlock*); |
178 | static PassRefPtr<EvalExecutable> create(ExecState* exec, const SourceCode& source) { return adoptRef(p: new EvalExecutable(exec, source)); } |
179 | |
180 | private: |
181 | EvalExecutable(ExecState* exec, const SourceCode& source) |
182 | : ScriptExecutable(exec, source) |
183 | , m_evalCodeBlock(0) |
184 | { |
185 | } |
186 | EvalCodeBlock* m_evalCodeBlock; |
187 | |
188 | #if ENABLE(JIT) |
189 | public: |
190 | JITCode& jitCode(ExecState* exec, ScopeChainNode* scopeChainNode) |
191 | { |
192 | if (!m_jitCode) |
193 | generateJITCode(exec, scopeChainNode); |
194 | return m_jitCode; |
195 | } |
196 | |
197 | private: |
198 | void generateJITCode(ExecState*, ScopeChainNode*); |
199 | #endif |
200 | }; |
201 | |
202 | class ProgramExecutable : public ScriptExecutable { |
203 | public: |
204 | static PassRefPtr<ProgramExecutable> create(ExecState* exec, const SourceCode& source) |
205 | { |
206 | return adoptRef(p: new ProgramExecutable(exec, source)); |
207 | } |
208 | |
209 | ~ProgramExecutable(); |
210 | |
211 | ProgramCodeBlock& bytecode(ExecState* exec, ScopeChainNode* scopeChainNode) |
212 | { |
213 | if (!m_programCodeBlock) { |
214 | JSObject* error = compile(exec, scopeChainNode); |
215 | ASSERT_UNUSED(!error, error); |
216 | } |
217 | return *m_programCodeBlock; |
218 | } |
219 | |
220 | JSObject* checkSyntax(ExecState*); |
221 | JSObject* compile(ExecState*, ScopeChainNode*); |
222 | |
223 | // CodeBlocks for program code are transient and therefore do not gain from from throwing out there exception information. |
224 | ExceptionInfo* reparseExceptionInfo(JSGlobalData*, ScopeChainNode*, CodeBlock*) { ASSERT_NOT_REACHED(); return 0; } |
225 | |
226 | private: |
227 | ProgramExecutable(ExecState* exec, const SourceCode& source) |
228 | : ScriptExecutable(exec, source) |
229 | , m_programCodeBlock(0) |
230 | { |
231 | } |
232 | ProgramCodeBlock* m_programCodeBlock; |
233 | |
234 | #if ENABLE(JIT) |
235 | public: |
236 | JITCode& jitCode(ExecState* exec, ScopeChainNode* scopeChainNode) |
237 | { |
238 | if (!m_jitCode) |
239 | generateJITCode(exec, scopeChainNode); |
240 | return m_jitCode; |
241 | } |
242 | |
243 | private: |
244 | void generateJITCode(ExecState*, ScopeChainNode*); |
245 | #endif |
246 | }; |
247 | |
248 | class FunctionExecutable : public ScriptExecutable { |
249 | friend class JIT; |
250 | public: |
251 | static PassRefPtr<FunctionExecutable> create(ExecState* exec, const Identifier& name, const SourceCode& source, bool forceUsesArguments, FunctionParameters* parameters, int firstLine, int lastLine) |
252 | { |
253 | return adoptRef(p: new FunctionExecutable(exec, name, source, forceUsesArguments, parameters, firstLine, lastLine)); |
254 | } |
255 | |
256 | static PassRefPtr<FunctionExecutable> create(JSGlobalData* globalData, const Identifier& name, const SourceCode& source, bool forceUsesArguments, FunctionParameters* parameters, int firstLine, int lastLine) |
257 | { |
258 | return adoptRef(p: new FunctionExecutable(globalData, name, source, forceUsesArguments, parameters, firstLine, lastLine)); |
259 | } |
260 | |
261 | ~FunctionExecutable(); |
262 | |
263 | JSFunction* make(ExecState* exec, ScopeChainNode* scopeChain) |
264 | { |
265 | return new (exec) JSFunction(exec, this, scopeChain); |
266 | } |
267 | |
268 | CodeBlock& bytecode(ExecState* exec, ScopeChainNode* scopeChainNode) |
269 | { |
270 | ASSERT(scopeChainNode); |
271 | if (!m_codeBlock) |
272 | compile(exec, scopeChainNode); |
273 | return *m_codeBlock; |
274 | } |
275 | |
276 | bool isGenerated() const |
277 | { |
278 | return m_codeBlock; |
279 | } |
280 | |
281 | CodeBlock& generatedBytecode() |
282 | { |
283 | ASSERT(m_codeBlock); |
284 | return *m_codeBlock; |
285 | } |
286 | |
287 | const Identifier& name() { return m_name; } |
288 | size_t parameterCount() const { return m_parameters->size(); } |
289 | size_t variableCount() const { return m_numVariables; } |
290 | UString paramString() const; |
291 | #ifdef QT_BUILD_SCRIPT_LIB |
292 | UString parameterName(int i) const { return (*m_parameters)[i].ustring(); } |
293 | #endif |
294 | |
295 | void recompile(ExecState*); |
296 | ExceptionInfo* reparseExceptionInfo(JSGlobalData*, ScopeChainNode*, CodeBlock*); |
297 | void markAggregate(MarkStack& markStack); |
298 | static PassRefPtr<FunctionExecutable> fromGlobalCode(const Identifier&, ExecState*, Debugger*, const SourceCode&, int* errLine = 0, UString* errMsg = 0); |
299 | |
300 | private: |
301 | FunctionExecutable(JSGlobalData* globalData, const Identifier& name, const SourceCode& source, bool forceUsesArguments, FunctionParameters* parameters, int firstLine, int lastLine) |
302 | : ScriptExecutable(globalData, source) |
303 | , m_forceUsesArguments(forceUsesArguments) |
304 | , m_parameters(parameters) |
305 | , m_codeBlock(0) |
306 | , m_name(name) |
307 | , m_numVariables(0) |
308 | { |
309 | m_firstLine = firstLine; |
310 | m_lastLine = lastLine; |
311 | } |
312 | |
313 | FunctionExecutable(ExecState* exec, const Identifier& name, const SourceCode& source, bool forceUsesArguments, FunctionParameters* parameters, int firstLine, int lastLine) |
314 | : ScriptExecutable(exec, source) |
315 | , m_forceUsesArguments(forceUsesArguments) |
316 | , m_parameters(parameters) |
317 | , m_codeBlock(0) |
318 | , m_name(name) |
319 | , m_numVariables(0) |
320 | { |
321 | m_firstLine = firstLine; |
322 | m_lastLine = lastLine; |
323 | } |
324 | |
325 | void compile(ExecState*, ScopeChainNode*); |
326 | |
327 | bool m_forceUsesArguments; |
328 | RefPtr<FunctionParameters> m_parameters; |
329 | CodeBlock* m_codeBlock; |
330 | Identifier m_name; |
331 | size_t m_numVariables; |
332 | |
333 | #if ENABLE(JIT) |
334 | public: |
335 | JITCode& jitCode(ExecState* exec, ScopeChainNode* scopeChainNode) |
336 | { |
337 | if (!m_jitCode) |
338 | generateJITCode(exec, scopeChainNode); |
339 | return m_jitCode; |
340 | } |
341 | |
342 | private: |
343 | void generateJITCode(ExecState*, ScopeChainNode*); |
344 | #endif |
345 | }; |
346 | |
347 | inline FunctionExecutable* JSFunction::jsExecutable() const |
348 | { |
349 | ASSERT(!isHostFunctionNonInline()); |
350 | return static_cast<FunctionExecutable*>(m_executable.get()); |
351 | } |
352 | |
353 | inline bool JSFunction::isHostFunction() const |
354 | { |
355 | ASSERT(m_executable); |
356 | return m_executable->isHostFunction(); |
357 | } |
358 | |
359 | } |
360 | |
361 | #endif |
362 | |