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