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)
236         {
237             return Structure::create(globalData, proto, TypeInfo(CompoundType, StructureFlags), AnonymousSlotCount, &s_info);
238         }
239 
240     private:
241         static const unsigned StructureFlags = OverridesVisitChildren | ScriptExecutable::StructureFlags;
242         static const ClassInfo s_info;
243         EvalExecutable(ExecState*, const SourceCode&, bool);
244 
245         JSObject* compileInternal(ExecState*, ScopeChainNode*);
246         virtual void visitChildren(SlotVisitor&);
247 
248         OwnPtr<EvalCodeBlock> m_evalCodeBlock;
249     };
250 
251     class ProgramExecutable : public ScriptExecutable {
252     public:
create(ExecState * exec,const SourceCode & source)253         static ProgramExecutable* create(ExecState* exec, const SourceCode& source)
254         {
255             return new (exec) ProgramExecutable(exec, source);
256         }
257 
258         ~ProgramExecutable();
259 
compile(ExecState * exec,ScopeChainNode * scopeChainNode)260         JSObject* compile(ExecState* exec, ScopeChainNode* scopeChainNode)
261         {
262             ASSERT(exec->globalData().dynamicGlobalObject);
263             JSObject* error = 0;
264             if (!m_programCodeBlock)
265                 error = compileInternal(exec, scopeChainNode);
266             ASSERT(!error == !!m_programCodeBlock);
267             return error;
268         }
269 
generatedBytecode()270         ProgramCodeBlock& generatedBytecode()
271         {
272             ASSERT(m_programCodeBlock);
273             return *m_programCodeBlock;
274         }
275 
276         JSObject* checkSyntax(ExecState*);
277 
278 #if ENABLE(JIT)
generatedJITCode()279         JITCode& generatedJITCode()
280         {
281             return generatedJITCodeForCall();
282         }
283 #endif
284 
createStructure(JSGlobalData & globalData,JSValue proto)285         static Structure* createStructure(JSGlobalData& globalData, JSValue proto)
286         {
287             return Structure::create(globalData, proto, TypeInfo(CompoundType, StructureFlags), AnonymousSlotCount, &s_info);
288         }
289 
290     private:
291         static const unsigned StructureFlags = OverridesVisitChildren | ScriptExecutable::StructureFlags;
292         static const ClassInfo s_info;
293         ProgramExecutable(ExecState*, const SourceCode&);
294 
295         JSObject* compileInternal(ExecState*, ScopeChainNode*);
296         virtual void visitChildren(SlotVisitor&);
297 
298         OwnPtr<ProgramCodeBlock> m_programCodeBlock;
299     };
300 
301     class FunctionExecutable : public ScriptExecutable {
302         friend class JIT;
303     public:
create(ExecState * exec,const Identifier & name,const SourceCode & source,bool forceUsesArguments,FunctionParameters * parameters,bool isInStrictContext,int firstLine,int lastLine)304         static FunctionExecutable* create(ExecState* exec, const Identifier& name, const SourceCode& source, bool forceUsesArguments, FunctionParameters* parameters, bool isInStrictContext, int firstLine, int lastLine)
305         {
306             return new (exec) FunctionExecutable(exec, name, source, forceUsesArguments, parameters, isInStrictContext, firstLine, lastLine);
307         }
308 
create(JSGlobalData * globalData,const Identifier & name,const SourceCode & source,bool forceUsesArguments,FunctionParameters * parameters,bool isInStrictContext,int firstLine,int lastLine)309         static FunctionExecutable* create(JSGlobalData* globalData, const Identifier& name, const SourceCode& source, bool forceUsesArguments, FunctionParameters* parameters, bool isInStrictContext, int firstLine, int lastLine)
310         {
311             return new (globalData) FunctionExecutable(globalData, name, source, forceUsesArguments, parameters, isInStrictContext, firstLine, lastLine);
312         }
313 
make(ExecState * exec,ScopeChainNode * scopeChain)314         JSFunction* make(ExecState* exec, ScopeChainNode* scopeChain)
315         {
316             return new (exec) JSFunction(exec, this, scopeChain);
317         }
318 
319         // Returns either call or construct bytecode. This can be appropriate
320         // for answering questions that that don't vary between call and construct --
321         // for example, argumentsRegister().
generatedBytecode()322         FunctionCodeBlock& generatedBytecode()
323         {
324             if (m_codeBlockForCall)
325                 return *m_codeBlockForCall;
326             ASSERT(m_codeBlockForConstruct);
327             return *m_codeBlockForConstruct;
328         }
329 
compileForCall(ExecState * exec,ScopeChainNode * scopeChainNode)330         JSObject* compileForCall(ExecState* exec, ScopeChainNode* scopeChainNode)
331         {
332             ASSERT(exec->globalData().dynamicGlobalObject);
333             JSObject* error = 0;
334             if (!m_codeBlockForCall)
335                 error = compileForCallInternal(exec, scopeChainNode);
336             ASSERT(!error == !!m_codeBlockForCall);
337             return error;
338         }
339 
isGeneratedForCall()340         bool isGeneratedForCall() const
341         {
342             return m_codeBlockForCall;
343         }
344 
generatedBytecodeForCall()345         FunctionCodeBlock& generatedBytecodeForCall()
346         {
347             ASSERT(m_codeBlockForCall);
348             return *m_codeBlockForCall;
349         }
350 
compileForConstruct(ExecState * exec,ScopeChainNode * scopeChainNode)351         JSObject* compileForConstruct(ExecState* exec, ScopeChainNode* scopeChainNode)
352         {
353             ASSERT(exec->globalData().dynamicGlobalObject);
354             JSObject* error = 0;
355             if (!m_codeBlockForConstruct)
356                 error = compileForConstructInternal(exec, scopeChainNode);
357             ASSERT(!error == !!m_codeBlockForConstruct);
358             return error;
359         }
360 
isGeneratedForConstruct()361         bool isGeneratedForConstruct() const
362         {
363             return m_codeBlockForConstruct;
364         }
365 
generatedBytecodeForConstruct()366         FunctionCodeBlock& generatedBytecodeForConstruct()
367         {
368             ASSERT(m_codeBlockForConstruct);
369             return *m_codeBlockForConstruct;
370         }
371 
name()372         const Identifier& name() { return m_name; }
parameterCount()373         size_t parameterCount() const { return m_parameters->size(); }
capturedVariableCount()374         unsigned capturedVariableCount() const { return m_numCapturedVariables; }
375         UString paramString() const;
symbolTable()376         SharedSymbolTable* symbolTable() const { return m_symbolTable; }
377 
378         void discardCode();
379         void visitChildren(SlotVisitor&);
380         static FunctionExecutable* fromGlobalCode(const Identifier&, ExecState*, Debugger*, const SourceCode&, JSObject** exception);
createStructure(JSGlobalData & globalData,JSValue proto)381         static Structure* createStructure(JSGlobalData& globalData, JSValue proto)
382         {
383             return Structure::create(globalData, proto, TypeInfo(CompoundType, StructureFlags), AnonymousSlotCount, &s_info);
384         }
385 
386     private:
387         FunctionExecutable(JSGlobalData*, const Identifier& name, const SourceCode&, bool forceUsesArguments, FunctionParameters*, bool, int firstLine, int lastLine);
388         FunctionExecutable(ExecState*, const Identifier& name, const SourceCode&, bool forceUsesArguments, FunctionParameters*, bool, int firstLine, int lastLine);
389 
390         JSObject* compileForCallInternal(ExecState*, ScopeChainNode*);
391         JSObject* compileForConstructInternal(ExecState*, ScopeChainNode*);
392 
393         static const unsigned StructureFlags = OverridesVisitChildren | ScriptExecutable::StructureFlags;
394         static const ClassInfo s_info;
395         unsigned m_numCapturedVariables : 31;
396         bool m_forceUsesArguments : 1;
397 
398         RefPtr<FunctionParameters> m_parameters;
399         OwnPtr<FunctionCodeBlock> m_codeBlockForCall;
400         OwnPtr<FunctionCodeBlock> m_codeBlockForConstruct;
401         Identifier m_name;
402         SharedSymbolTable* m_symbolTable;
403 
404 #if ENABLE(JIT)
405     public:
generatedJITCodeForCallWithArityCheck()406         MacroAssemblerCodePtr generatedJITCodeForCallWithArityCheck()
407         {
408             ASSERT(m_jitCodeForCall);
409             ASSERT(m_jitCodeForCallWithArityCheck);
410             return m_jitCodeForCallWithArityCheck;
411         }
412 
generatedJITCodeForConstructWithArityCheck()413         MacroAssemblerCodePtr generatedJITCodeForConstructWithArityCheck()
414         {
415             ASSERT(m_jitCodeForConstruct);
416             ASSERT(m_jitCodeForConstructWithArityCheck);
417             return m_jitCodeForConstructWithArityCheck;
418         }
419 #endif
420     };
421 
jsExecutable()422     inline FunctionExecutable* JSFunction::jsExecutable() const
423     {
424         ASSERT(!isHostFunctionNonInline());
425         return static_cast<FunctionExecutable*>(m_executable.get());
426     }
427 
isHostFunction()428     inline bool JSFunction::isHostFunction() const
429     {
430         ASSERT(m_executable);
431         return m_executable->isHostFunction();
432     }
433 
nativeFunction()434     inline NativeFunction JSFunction::nativeFunction()
435     {
436         ASSERT(isHostFunction());
437         return static_cast<NativeExecutable*>(m_executable.get())->function();
438     }
439 }
440 
441 #endif
442