• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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:
ExecutableBase(int numParameters)52         ExecutableBase(int numParameters)
53             : m_numParameters(numParameters)
54         {
55         }
56 
~ExecutableBase()57         virtual ~ExecutableBase() {}
58 
isHostFunction()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:
generatedJITCode()66         JITCode& generatedJITCode()
67         {
68             ASSERT(m_jitCode);
69             return m_jitCode;
70         }
71 
getExecutablePool()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:
NativeExecutable(ExecState * exec)85         NativeExecutable(ExecState* exec)
86             : ExecutableBase(NUM_PARAMETERS_IS_HOST)
87         {
88             m_jitCode = JITCode(JITCode::HostFunction(exec->globalData().jitStubs.ctiNativeCallThunk()));
89         }
90 
91         ~NativeExecutable();
92     };
93 #endif
94 
95     class VPtrHackExecutable : public ExecutableBase {
96     public:
VPtrHackExecutable()97         VPtrHackExecutable()
98             : ExecutableBase(NUM_PARAMETERS_IS_HOST)
99         {
100         }
101 
102         ~VPtrHackExecutable();
103     };
104 
105     class ScriptExecutable : public ExecutableBase {
106     public:
ScriptExecutable(JSGlobalData * globalData,const SourceCode & source)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 
ScriptExecutable(ExecState * exec,const SourceCode & source)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 
source()133         const SourceCode& source() { return m_source; }
sourceID()134         intptr_t sourceID() const { return m_source.provider()->asID(); }
sourceURL()135         const UString& sourceURL() const { return m_source.provider()->url(); }
lineNo()136         int lineNo() const { return m_firstLine; }
lastLine()137         int lastLine() const { return m_lastLine; }
138 
usesEval()139         bool usesEval() const { return m_features & EvalFeature; }
usesArguments()140         bool usesArguments() const { return m_features & ArgumentsFeature; }
needsActivation()141         bool needsActivation() const { return m_features & (EvalFeature | ClosureFeature | WithFeature | CatchFeature); }
142 
143         virtual ExceptionInfo* reparseExceptionInfo(JSGlobalData*, ScopeChainNode*, CodeBlock*) = 0;
144 
145     protected:
recordParse(CodeFeatures features,int firstLine,int lastLine)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 
bytecode(ExecState * exec,ScopeChainNode * scopeChainNode)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         ExceptionInfo* reparseExceptionInfo(JSGlobalData*, ScopeChainNode*, CodeBlock*);
create(ExecState * exec,const SourceCode & source)176         static PassRefPtr<EvalExecutable> create(ExecState* exec, const SourceCode& source) { return adoptRef(new EvalExecutable(exec, source)); }
177 
178     private:
EvalExecutable(ExecState * exec,const SourceCode & source)179         EvalExecutable(ExecState* exec, const SourceCode& source)
180             : ScriptExecutable(exec, source)
181             , m_evalCodeBlock(0)
182         {
183         }
184         EvalCodeBlock* m_evalCodeBlock;
185 
186 #if ENABLE(JIT)
187     public:
jitCode(ExecState * exec,ScopeChainNode * scopeChainNode)188         JITCode& jitCode(ExecState* exec, ScopeChainNode* scopeChainNode)
189         {
190             if (!m_jitCode)
191                 generateJITCode(exec, scopeChainNode);
192             return m_jitCode;
193         }
194 
195     private:
196         void generateJITCode(ExecState*, ScopeChainNode*);
197 #endif
198     };
199 
200     class ProgramExecutable : public ScriptExecutable {
201     public:
create(ExecState * exec,const SourceCode & source)202         static PassRefPtr<ProgramExecutable> create(ExecState* exec, const SourceCode& source)
203         {
204             return adoptRef(new ProgramExecutable(exec, source));
205         }
206 
207         ~ProgramExecutable();
208 
bytecode(ExecState * exec,ScopeChainNode * scopeChainNode)209         ProgramCodeBlock& bytecode(ExecState* exec, ScopeChainNode* scopeChainNode)
210         {
211             if (!m_programCodeBlock) {
212                 JSObject* error = compile(exec, scopeChainNode);
213                 ASSERT_UNUSED(!error, error);
214             }
215             return *m_programCodeBlock;
216         }
217 
218         JSObject* checkSyntax(ExecState*);
219         JSObject* compile(ExecState*, ScopeChainNode*);
220 
221         // CodeBlocks for program code are transient and therefore do not gain from from throwing out there exception information.
reparseExceptionInfo(JSGlobalData *,ScopeChainNode *,CodeBlock *)222         ExceptionInfo* reparseExceptionInfo(JSGlobalData*, ScopeChainNode*, CodeBlock*) { ASSERT_NOT_REACHED(); return 0; }
223 
224     private:
ProgramExecutable(ExecState * exec,const SourceCode & source)225         ProgramExecutable(ExecState* exec, const SourceCode& source)
226             : ScriptExecutable(exec, source)
227             , m_programCodeBlock(0)
228         {
229         }
230         ProgramCodeBlock* m_programCodeBlock;
231 
232 #if ENABLE(JIT)
233     public:
jitCode(ExecState * exec,ScopeChainNode * scopeChainNode)234         JITCode& jitCode(ExecState* exec, ScopeChainNode* scopeChainNode)
235         {
236             if (!m_jitCode)
237                 generateJITCode(exec, scopeChainNode);
238             return m_jitCode;
239         }
240 
241     private:
242         void generateJITCode(ExecState*, ScopeChainNode*);
243 #endif
244     };
245 
246     class FunctionExecutable : public ScriptExecutable {
247         friend class JIT;
248     public:
create(ExecState * exec,const Identifier & name,const SourceCode & source,bool forceUsesArguments,FunctionParameters * parameters,int firstLine,int lastLine)249         static PassRefPtr<FunctionExecutable> create(ExecState* exec, const Identifier& name, const SourceCode& source, bool forceUsesArguments, FunctionParameters* parameters, int firstLine, int lastLine)
250         {
251             return adoptRef(new FunctionExecutable(exec, name, source, forceUsesArguments, parameters, firstLine, lastLine));
252         }
253 
create(JSGlobalData * globalData,const Identifier & name,const SourceCode & source,bool forceUsesArguments,FunctionParameters * parameters,int firstLine,int lastLine)254         static PassRefPtr<FunctionExecutable> create(JSGlobalData* globalData, const Identifier& name, const SourceCode& source, bool forceUsesArguments, FunctionParameters* parameters, int firstLine, int lastLine)
255         {
256             return adoptRef(new FunctionExecutable(globalData, name, source, forceUsesArguments, parameters, firstLine, lastLine));
257         }
258 
259         ~FunctionExecutable();
260 
make(ExecState * exec,ScopeChainNode * scopeChain)261         JSFunction* make(ExecState* exec, ScopeChainNode* scopeChain)
262         {
263             return new (exec) JSFunction(exec, this, scopeChain);
264         }
265 
bytecode(ExecState * exec,ScopeChainNode * scopeChainNode)266         CodeBlock& bytecode(ExecState* exec, ScopeChainNode* scopeChainNode)
267         {
268             ASSERT(scopeChainNode);
269             if (!m_codeBlock)
270                 compile(exec, scopeChainNode);
271             return *m_codeBlock;
272         }
273 
isGenerated()274         bool isGenerated() const
275         {
276             return m_codeBlock;
277         }
278 
generatedBytecode()279         CodeBlock& generatedBytecode()
280         {
281             ASSERT(m_codeBlock);
282             return *m_codeBlock;
283         }
284 
name()285         const Identifier& name() { return m_name; }
parameterCount()286         size_t parameterCount() const { return m_parameters->size(); }
variableCount()287         size_t variableCount() const { return m_numVariables; }
288         UString paramString() const;
289 
290         void recompile(ExecState*);
291         ExceptionInfo* reparseExceptionInfo(JSGlobalData*, ScopeChainNode*, CodeBlock*);
292         void markAggregate(MarkStack& markStack);
293         static PassRefPtr<FunctionExecutable> fromGlobalCode(const Identifier&, ExecState*, Debugger*, const SourceCode&, int* errLine = 0, UString* errMsg = 0);
294 
295     private:
FunctionExecutable(JSGlobalData * globalData,const Identifier & name,const SourceCode & source,bool forceUsesArguments,FunctionParameters * parameters,int firstLine,int lastLine)296         FunctionExecutable(JSGlobalData* globalData, const Identifier& name, const SourceCode& source, bool forceUsesArguments, FunctionParameters* parameters, int firstLine, int lastLine)
297             : ScriptExecutable(globalData, source)
298             , m_forceUsesArguments(forceUsesArguments)
299             , m_parameters(parameters)
300             , m_codeBlock(0)
301             , m_name(name)
302             , m_numVariables(0)
303         {
304             m_firstLine = firstLine;
305             m_lastLine = lastLine;
306         }
307 
FunctionExecutable(ExecState * exec,const Identifier & name,const SourceCode & source,bool forceUsesArguments,FunctionParameters * parameters,int firstLine,int lastLine)308         FunctionExecutable(ExecState* exec, const Identifier& name, const SourceCode& source, bool forceUsesArguments, FunctionParameters* parameters, int firstLine, int lastLine)
309             : ScriptExecutable(exec, source)
310             , m_forceUsesArguments(forceUsesArguments)
311             , m_parameters(parameters)
312             , m_codeBlock(0)
313             , m_name(name)
314             , m_numVariables(0)
315         {
316             m_firstLine = firstLine;
317             m_lastLine = lastLine;
318         }
319 
320         void compile(ExecState*, ScopeChainNode*);
321 
322         bool m_forceUsesArguments;
323         RefPtr<FunctionParameters> m_parameters;
324         CodeBlock* m_codeBlock;
325         Identifier m_name;
326         size_t m_numVariables;
327 
328 #if ENABLE(JIT)
329     public:
jitCode(ExecState * exec,ScopeChainNode * scopeChainNode)330         JITCode& jitCode(ExecState* exec, ScopeChainNode* scopeChainNode)
331         {
332             if (!m_jitCode)
333                 generateJITCode(exec, scopeChainNode);
334             return m_jitCode;
335         }
336 
337     private:
338         void generateJITCode(ExecState*, ScopeChainNode*);
339 #endif
340     };
341 
jsExecutable()342     inline FunctionExecutable* JSFunction::jsExecutable() const
343     {
344         ASSERT(!isHostFunctionNonInline());
345         return static_cast<FunctionExecutable*>(m_executable.get());
346     }
347 
isHostFunction()348     inline bool JSFunction::isHostFunction() const
349     {
350         ASSERT(m_executable);
351         return m_executable->isHostFunction();
352     }
353 
354 }
355 
356 #endif
357