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
36namespace 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:
55        ExecutableBase(JSGlobalData& globalData, Structure* structure, int numParameters)
56            : JSCell(globalData, structure)
57            , m_numParametersForCall(numParameters)
58            , m_numParametersForConstruct(numParameters)
59        {
60        }
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        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:
78        JITCode& generatedJITCodeForCall()
79        {
80            ASSERT(m_jitCodeForCall);
81            return m_jitCodeForCall;
82        }
83
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)
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
117        NativeFunction function() { return m_function; }
118
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)
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:
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
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
179        const SourceCode& source() { return m_source; }
180        intptr_t sourceID() const { return m_source.provider()->asID(); }
181        const UString& sourceURL() const { return m_source.provider()->url(); }
182        int lineNo() const { return m_firstLine; }
183        int lastLine() const { return m_lastLine; }
184
185        bool usesEval() const { return m_features & EvalFeature; }
186        bool usesArguments() const { return m_features & ArgumentsFeature; }
187        bool needsActivation() const { return m_hasCapturedVariables || m_features & (EvalFeature | WithFeature | CatchFeature); }
188        bool isStrictMode() const { return m_features & StrictModeFeature; }
189
190    protected:
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
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
221        EvalCodeBlock& generatedBytecode()
222        {
223            ASSERT(m_evalCodeBlock);
224            return *m_evalCodeBlock;
225        }
226
227        static EvalExecutable* create(ExecState* exec, const SourceCode& source, bool isInStrictContext) { return new (exec) EvalExecutable(exec, source, isInStrictContext); }
228
229#if ENABLE(JIT)
230        JITCode& generatedJITCode()
231        {
232            return generatedJITCodeForCall();
233        }
234#endif
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:
250        static ProgramExecutable* create(ExecState* exec, const SourceCode& source)
251        {
252            return new (exec) ProgramExecutable(exec, source);
253        }
254
255        ~ProgramExecutable();
256
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
267        ProgramCodeBlock& generatedBytecode()
268        {
269            ASSERT(m_programCodeBlock);
270            return *m_programCodeBlock;
271        }
272
273        JSObject* checkSyntax(ExecState*);
274
275#if ENABLE(JIT)
276        JITCode& generatedJITCode()
277        {
278            return generatedJITCodeForCall();
279        }
280#endif
281
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:
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
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
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().
316        FunctionCodeBlock& generatedBytecode()
317        {
318            if (m_codeBlockForCall)
319                return *m_codeBlockForCall;
320            ASSERT(m_codeBlockForConstruct);
321            return *m_codeBlockForConstruct;
322        }
323
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
334        bool isGeneratedForCall() const
335        {
336            return m_codeBlockForCall;
337        }
338
339        FunctionCodeBlock& generatedBytecodeForCall()
340        {
341            ASSERT(m_codeBlockForCall);
342            return *m_codeBlockForCall;
343        }
344
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
355        bool isGeneratedForConstruct() const
356        {
357            return m_codeBlockForConstruct;
358        }
359
360        FunctionCodeBlock& generatedBytecodeForConstruct()
361        {
362            ASSERT(m_codeBlockForConstruct);
363            return *m_codeBlockForConstruct;
364        }
365
366        const Identifier& name() { return m_name; }
367        size_t parameterCount() const { return m_parameters->size(); }
368        unsigned capturedVariableCount() const { return m_numCapturedVariables; }
369        UString paramString() const;
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);
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:
397        MacroAssemblerCodePtr generatedJITCodeForCallWithArityCheck()
398        {
399            ASSERT(m_jitCodeForCall);
400            ASSERT(m_jitCodeForCallWithArityCheck);
401            return m_jitCodeForCallWithArityCheck;
402        }
403
404        MacroAssemblerCodePtr generatedJITCodeForConstructWithArityCheck()
405        {
406            ASSERT(m_jitCodeForConstruct);
407            ASSERT(m_jitCodeForConstructWithArityCheck);
408            return m_jitCodeForConstructWithArityCheck;
409        }
410#endif
411    };
412
413    inline FunctionExecutable* JSFunction::jsExecutable() const
414    {
415        ASSERT(!isHostFunctionNonInline());
416        return static_cast<FunctionExecutable*>(m_executable.get());
417    }
418
419    inline bool JSFunction::isHostFunction() const
420    {
421        ASSERT(m_executable);
422        return m_executable->isHostFunction();
423    }
424
425    inline NativeFunction JSFunction::nativeFunction()
426    {
427        ASSERT(isHostFunction());
428        return static_cast<NativeExecutable*>(m_executable.get())->function();
429    }
430}
431
432#endif
433