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
|
---|