|
1 /* |
|
2 * Copyright (C) 2009, 2010 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 "CallData.h" |
|
30 #include "JSFunction.h" |
|
31 #include "Interpreter.h" |
|
32 #include "Nodes.h" |
|
33 #include "SamplingTool.h" |
|
34 #include <wtf/PassOwnPtr.h> |
|
35 |
|
36 namespace JSC { |
|
37 |
|
38 class CodeBlock; |
|
39 class Debugger; |
|
40 class EvalCodeBlock; |
|
41 class FunctionCodeBlock; |
|
42 class ProgramCodeBlock; |
|
43 class ScopeChainNode; |
|
44 |
|
45 struct ExceptionInfo; |
|
46 |
|
47 class ExecutableBase : public RefCounted<ExecutableBase> { |
|
48 friend class JIT; |
|
49 |
|
50 protected: |
|
51 static const int NUM_PARAMETERS_IS_HOST = 0; |
|
52 static const int NUM_PARAMETERS_NOT_COMPILED = -1; |
|
53 |
|
54 public: |
|
55 ExecutableBase(int numParameters) |
|
56 : m_numParametersForCall(numParameters) |
|
57 , m_numParametersForConstruct(numParameters) |
|
58 { |
|
59 } |
|
60 |
|
61 virtual ~ExecutableBase() {} |
|
62 |
|
63 bool isHostFunction() const |
|
64 { |
|
65 ASSERT((m_numParametersForCall == NUM_PARAMETERS_IS_HOST) == (m_numParametersForConstruct == NUM_PARAMETERS_IS_HOST)); |
|
66 return m_numParametersForCall == NUM_PARAMETERS_IS_HOST; |
|
67 } |
|
68 |
|
69 protected: |
|
70 int m_numParametersForCall; |
|
71 int m_numParametersForConstruct; |
|
72 |
|
73 #if ENABLE(JIT) |
|
74 public: |
|
75 JITCode& generatedJITCodeForCall() |
|
76 { |
|
77 ASSERT(m_jitCodeForCall); |
|
78 return m_jitCodeForCall; |
|
79 } |
|
80 |
|
81 JITCode& generatedJITCodeForConstruct() |
|
82 { |
|
83 ASSERT(m_jitCodeForConstruct); |
|
84 return m_jitCodeForConstruct; |
|
85 } |
|
86 |
|
87 protected: |
|
88 JITCode m_jitCodeForCall; |
|
89 JITCode m_jitCodeForConstruct; |
|
90 MacroAssemblerCodePtr m_jitCodeForCallWithArityCheck; |
|
91 MacroAssemblerCodePtr m_jitCodeForConstructWithArityCheck; |
|
92 #endif |
|
93 }; |
|
94 |
|
95 #if ENABLE(JIT) |
|
96 class NativeExecutable : public ExecutableBase { |
|
97 friend class JIT; |
|
98 public: |
|
99 static PassRefPtr<NativeExecutable> create(MacroAssemblerCodePtr callThunk, NativeFunction function, MacroAssemblerCodePtr constructThunk, NativeFunction constructor) |
|
100 { |
|
101 if (!callThunk) |
|
102 return adoptRef(new NativeExecutable(JITCode(), function, JITCode(), constructor)); |
|
103 return adoptRef(new NativeExecutable(JITCode::HostFunction(callThunk), function, JITCode::HostFunction(constructThunk), constructor)); |
|
104 } |
|
105 |
|
106 ~NativeExecutable(); |
|
107 |
|
108 NativeFunction function() { return m_function; } |
|
109 |
|
110 private: |
|
111 NativeExecutable(JITCode callThunk, NativeFunction function, JITCode constructThunk, NativeFunction constructor) |
|
112 : ExecutableBase(NUM_PARAMETERS_IS_HOST) |
|
113 , m_function(function) |
|
114 , m_constructor(constructor) |
|
115 { |
|
116 m_jitCodeForCall = callThunk; |
|
117 m_jitCodeForConstruct = constructThunk; |
|
118 m_jitCodeForCallWithArityCheck = callThunk.addressForCall(); |
|
119 m_jitCodeForConstructWithArityCheck = constructThunk.addressForCall(); |
|
120 } |
|
121 |
|
122 NativeFunction m_function; |
|
123 // Probably should be a NativeConstructor, but this will currently require rewriting the JIT |
|
124 // trampoline. It may be easier to make NativeFunction be passed 'this' as a part of the ArgList. |
|
125 NativeFunction m_constructor; |
|
126 }; |
|
127 #endif |
|
128 |
|
129 class VPtrHackExecutable : public ExecutableBase { |
|
130 public: |
|
131 VPtrHackExecutable() |
|
132 : ExecutableBase(NUM_PARAMETERS_IS_HOST) |
|
133 { |
|
134 } |
|
135 |
|
136 ~VPtrHackExecutable(); |
|
137 }; |
|
138 |
|
139 class ScriptExecutable : public ExecutableBase { |
|
140 public: |
|
141 ScriptExecutable(JSGlobalData* globalData, const SourceCode& source) |
|
142 : ExecutableBase(NUM_PARAMETERS_NOT_COMPILED) |
|
143 , m_source(source) |
|
144 , m_features(0) |
|
145 { |
|
146 #if ENABLE(CODEBLOCK_SAMPLING) |
|
147 if (SamplingTool* sampler = globalData->interpreter->sampler()) |
|
148 sampler->notifyOfScope(this); |
|
149 #else |
|
150 UNUSED_PARAM(globalData); |
|
151 #endif |
|
152 } |
|
153 |
|
154 ScriptExecutable(ExecState* exec, const SourceCode& source) |
|
155 : ExecutableBase(NUM_PARAMETERS_NOT_COMPILED) |
|
156 , m_source(source) |
|
157 , m_features(0) |
|
158 { |
|
159 #if ENABLE(CODEBLOCK_SAMPLING) |
|
160 if (SamplingTool* sampler = exec->globalData().interpreter->sampler()) |
|
161 sampler->notifyOfScope(this); |
|
162 #else |
|
163 UNUSED_PARAM(exec); |
|
164 #endif |
|
165 } |
|
166 |
|
167 const SourceCode& source() { return m_source; } |
|
168 intptr_t sourceID() const { return m_source.provider()->asID(); } |
|
169 const UString& sourceURL() const { return m_source.provider()->url(); } |
|
170 int lineNo() const { return m_firstLine; } |
|
171 int lastLine() const { return m_lastLine; } |
|
172 |
|
173 bool usesEval() const { return m_features & EvalFeature; } |
|
174 bool usesArguments() const { return m_features & ArgumentsFeature; } |
|
175 bool needsActivation() const { return m_features & (EvalFeature | ClosureFeature | WithFeature | CatchFeature); } |
|
176 |
|
177 virtual PassOwnPtr<ExceptionInfo> reparseExceptionInfo(JSGlobalData*, ScopeChainNode*, CodeBlock*) = 0; |
|
178 |
|
179 protected: |
|
180 void recordParse(CodeFeatures features, int firstLine, int lastLine) |
|
181 { |
|
182 m_features = features; |
|
183 m_firstLine = firstLine; |
|
184 m_lastLine = lastLine; |
|
185 } |
|
186 |
|
187 SourceCode m_source; |
|
188 CodeFeatures m_features; |
|
189 int m_firstLine; |
|
190 int m_lastLine; |
|
191 }; |
|
192 |
|
193 class EvalExecutable : public ScriptExecutable { |
|
194 public: |
|
195 |
|
196 ~EvalExecutable(); |
|
197 |
|
198 JSObject* compile(ExecState* exec, ScopeChainNode* scopeChainNode) |
|
199 { |
|
200 JSObject* error = 0; |
|
201 if (!m_evalCodeBlock) |
|
202 error = compileInternal(exec, scopeChainNode); |
|
203 ASSERT(!error == !!m_evalCodeBlock); |
|
204 return error; |
|
205 } |
|
206 |
|
207 EvalCodeBlock& generatedBytecode() |
|
208 { |
|
209 ASSERT(m_evalCodeBlock); |
|
210 return *m_evalCodeBlock; |
|
211 } |
|
212 |
|
213 static PassRefPtr<EvalExecutable> create(ExecState* exec, const SourceCode& source) { return adoptRef(new EvalExecutable(exec, source)); } |
|
214 |
|
215 #if ENABLE(JIT) |
|
216 JITCode& generatedJITCode() |
|
217 { |
|
218 return generatedJITCodeForCall(); |
|
219 } |
|
220 #endif |
|
221 |
|
222 private: |
|
223 EvalExecutable(ExecState*, const SourceCode&); |
|
224 |
|
225 JSObject* compileInternal(ExecState*, ScopeChainNode*); |
|
226 |
|
227 virtual PassOwnPtr<ExceptionInfo> reparseExceptionInfo(JSGlobalData*, ScopeChainNode*, CodeBlock*); |
|
228 |
|
229 OwnPtr<EvalCodeBlock> m_evalCodeBlock; |
|
230 }; |
|
231 |
|
232 class ProgramExecutable : public ScriptExecutable { |
|
233 public: |
|
234 static PassRefPtr<ProgramExecutable> create(ExecState* exec, const SourceCode& source) |
|
235 { |
|
236 return adoptRef(new ProgramExecutable(exec, source)); |
|
237 } |
|
238 |
|
239 ~ProgramExecutable(); |
|
240 |
|
241 JSObject* compile(ExecState* exec, ScopeChainNode* scopeChainNode) |
|
242 { |
|
243 JSObject* error = 0; |
|
244 if (!m_programCodeBlock) |
|
245 error = compileInternal(exec, scopeChainNode); |
|
246 ASSERT(!error == !!m_programCodeBlock); |
|
247 return error; |
|
248 } |
|
249 |
|
250 ProgramCodeBlock& generatedBytecode() |
|
251 { |
|
252 ASSERT(m_programCodeBlock); |
|
253 return *m_programCodeBlock; |
|
254 } |
|
255 |
|
256 JSObject* checkSyntax(ExecState*); |
|
257 |
|
258 #if ENABLE(JIT) |
|
259 JITCode& generatedJITCode() |
|
260 { |
|
261 return generatedJITCodeForCall(); |
|
262 } |
|
263 #endif |
|
264 |
|
265 private: |
|
266 ProgramExecutable(ExecState*, const SourceCode&); |
|
267 |
|
268 JSObject* compileInternal(ExecState*, ScopeChainNode*); |
|
269 |
|
270 virtual PassOwnPtr<ExceptionInfo> reparseExceptionInfo(JSGlobalData*, ScopeChainNode*, CodeBlock*); |
|
271 |
|
272 OwnPtr<ProgramCodeBlock> m_programCodeBlock; |
|
273 }; |
|
274 |
|
275 class FunctionExecutable : public ScriptExecutable { |
|
276 friend class JIT; |
|
277 public: |
|
278 static PassRefPtr<FunctionExecutable> create(ExecState* exec, const Identifier& name, const SourceCode& source, bool forceUsesArguments, FunctionParameters* parameters, int firstLine, int lastLine) |
|
279 { |
|
280 return adoptRef(new FunctionExecutable(exec, name, source, forceUsesArguments, parameters, firstLine, lastLine)); |
|
281 } |
|
282 |
|
283 static PassRefPtr<FunctionExecutable> create(JSGlobalData* globalData, const Identifier& name, const SourceCode& source, bool forceUsesArguments, FunctionParameters* parameters, int firstLine, int lastLine) |
|
284 { |
|
285 return adoptRef(new FunctionExecutable(globalData, name, source, forceUsesArguments, parameters, firstLine, lastLine)); |
|
286 } |
|
287 |
|
288 ~FunctionExecutable(); |
|
289 |
|
290 JSFunction* make(ExecState* exec, ScopeChainNode* scopeChain) |
|
291 { |
|
292 return new (exec) JSFunction(exec, this, scopeChain); |
|
293 } |
|
294 |
|
295 // Returns either call or construct bytecode. This can be appropriate |
|
296 // for answering questions that that don't vary between call and construct -- |
|
297 // for example, argumentsRegister(). |
|
298 FunctionCodeBlock& generatedBytecode() |
|
299 { |
|
300 if (m_codeBlockForCall) |
|
301 return *m_codeBlockForCall; |
|
302 ASSERT(m_codeBlockForConstruct); |
|
303 return *m_codeBlockForConstruct; |
|
304 } |
|
305 |
|
306 JSObject* compileForCall(ExecState* exec, ScopeChainNode* scopeChainNode) |
|
307 { |
|
308 JSObject* error = 0; |
|
309 if (!m_codeBlockForCall) |
|
310 error = compileForCallInternal(exec, scopeChainNode); |
|
311 ASSERT(!error == !!m_codeBlockForCall); |
|
312 return error; |
|
313 } |
|
314 |
|
315 bool isGeneratedForCall() const |
|
316 { |
|
317 return m_codeBlockForCall; |
|
318 } |
|
319 |
|
320 FunctionCodeBlock& generatedBytecodeForCall() |
|
321 { |
|
322 ASSERT(m_codeBlockForCall); |
|
323 return *m_codeBlockForCall; |
|
324 } |
|
325 |
|
326 JSObject* compileForConstruct(ExecState* exec, ScopeChainNode* scopeChainNode) |
|
327 { |
|
328 JSObject* error = 0; |
|
329 if (!m_codeBlockForConstruct) |
|
330 error = compileForConstructInternal(exec, scopeChainNode); |
|
331 ASSERT(!error == !!m_codeBlockForConstruct); |
|
332 return error; |
|
333 } |
|
334 |
|
335 bool isGeneratedForConstruct() const |
|
336 { |
|
337 return m_codeBlockForConstruct; |
|
338 } |
|
339 |
|
340 FunctionCodeBlock& generatedBytecodeForConstruct() |
|
341 { |
|
342 ASSERT(m_codeBlockForConstruct); |
|
343 return *m_codeBlockForConstruct; |
|
344 } |
|
345 |
|
346 const Identifier& name() { return m_name; } |
|
347 size_t parameterCount() const { return m_parameters->size(); } |
|
348 unsigned variableCount() const { return m_numVariables; } |
|
349 UString paramString() const; |
|
350 SharedSymbolTable* symbolTable() const { return m_symbolTable; } |
|
351 |
|
352 void recompile(ExecState*); |
|
353 void markAggregate(MarkStack&); |
|
354 static PassRefPtr<FunctionExecutable> fromGlobalCode(const Identifier&, ExecState*, Debugger*, const SourceCode&, JSObject** exception); |
|
355 |
|
356 private: |
|
357 FunctionExecutable(JSGlobalData*, const Identifier& name, const SourceCode&, bool forceUsesArguments, FunctionParameters*, int firstLine, int lastLine); |
|
358 FunctionExecutable(ExecState*, const Identifier& name, const SourceCode&, bool forceUsesArguments, FunctionParameters*, int firstLine, int lastLine); |
|
359 |
|
360 JSObject* compileForCallInternal(ExecState*, ScopeChainNode*); |
|
361 JSObject* compileForConstructInternal(ExecState*, ScopeChainNode*); |
|
362 |
|
363 virtual PassOwnPtr<ExceptionInfo> reparseExceptionInfo(JSGlobalData*, ScopeChainNode*, CodeBlock*); |
|
364 |
|
365 unsigned m_numVariables : 31; |
|
366 bool m_forceUsesArguments : 1; |
|
367 |
|
368 RefPtr<FunctionParameters> m_parameters; |
|
369 OwnPtr<FunctionCodeBlock> m_codeBlockForCall; |
|
370 OwnPtr<FunctionCodeBlock> m_codeBlockForConstruct; |
|
371 Identifier m_name; |
|
372 SharedSymbolTable* m_symbolTable; |
|
373 |
|
374 #if ENABLE(JIT) |
|
375 public: |
|
376 MacroAssemblerCodePtr generatedJITCodeForCallWithArityCheck() |
|
377 { |
|
378 ASSERT(m_jitCodeForCall); |
|
379 ASSERT(m_jitCodeForCallWithArityCheck); |
|
380 return m_jitCodeForCallWithArityCheck; |
|
381 } |
|
382 |
|
383 MacroAssemblerCodePtr generatedJITCodeForConstructWithArityCheck() |
|
384 { |
|
385 ASSERT(m_jitCodeForConstruct); |
|
386 ASSERT(m_jitCodeForConstructWithArityCheck); |
|
387 return m_jitCodeForConstructWithArityCheck; |
|
388 } |
|
389 #endif |
|
390 }; |
|
391 |
|
392 inline FunctionExecutable* JSFunction::jsExecutable() const |
|
393 { |
|
394 ASSERT(!isHostFunctionNonInline()); |
|
395 return static_cast<FunctionExecutable*>(m_executable.get()); |
|
396 } |
|
397 |
|
398 inline bool JSFunction::isHostFunction() const |
|
399 { |
|
400 ASSERT(m_executable); |
|
401 return m_executable->isHostFunction(); |
|
402 } |
|
403 |
|
404 #if ENABLE(JIT) |
|
405 inline NativeFunction JSFunction::nativeFunction() |
|
406 { |
|
407 ASSERT(isHostFunction()); |
|
408 return static_cast<NativeExecutable*>(m_executable.get())->function(); |
|
409 } |
|
410 #endif |
|
411 } |
|
412 |
|
413 #endif |