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