Home | History | Annotate | Download | only in runtime
      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:
     52         ExecutableBase(int numParameters)
     53             : m_numParameters(numParameters)
     54         {
     55         }
     56 
     57         virtual ~ExecutableBase() {}
     58 
     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:
     66         JITCode& generatedJITCode()
     67         {
     68             ASSERT(m_jitCode);
     69             return m_jitCode;
     70         }
     71 
     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:
     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:
     97         VPtrHackExecutable()
     98             : ExecutableBase(NUM_PARAMETERS_IS_HOST)
     99         {
    100         }
    101 
    102         ~VPtrHackExecutable();
    103     };
    104 
    105     class ScriptExecutable : public ExecutableBase {
    106     public:
    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 
    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 
    133         const SourceCode& source() { return m_source; }
    134         intptr_t sourceID() const { return m_source.provider()->asID(); }
    135         const UString& sourceURL() const { return m_source.provider()->url(); }
    136         int lineNo() const { return m_firstLine; }
    137         int lastLine() const { return m_lastLine; }
    138 
    139         bool usesEval() const { return m_features & EvalFeature; }
    140         bool usesArguments() const { return m_features & ArgumentsFeature; }
    141         bool needsActivation() const { return m_features & (EvalFeature | ClosureFeature | WithFeature | CatchFeature); }
    142 
    143         virtual ExceptionInfo* reparseExceptionInfo(JSGlobalData*, ScopeChainNode*, CodeBlock*) = 0;
    144 
    145     protected:
    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 
    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*);
    176         static PassRefPtr<EvalExecutable> create(ExecState* exec, const SourceCode& source) { return adoptRef(new EvalExecutable(exec, source)); }
    177 
    178     private:
    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:
    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:
    202         static PassRefPtr<ProgramExecutable> create(ExecState* exec, const SourceCode& source)
    203         {
    204             return adoptRef(new ProgramExecutable(exec, source));
    205         }
    206 
    207         ~ProgramExecutable();
    208 
    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.
    222         ExceptionInfo* reparseExceptionInfo(JSGlobalData*, ScopeChainNode*, CodeBlock*) { ASSERT_NOT_REACHED(); return 0; }
    223 
    224     private:
    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:
    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:
    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 
    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 
    261         JSFunction* make(ExecState* exec, ScopeChainNode* scopeChain)
    262         {
    263             return new (exec) JSFunction(exec, this, scopeChain);
    264         }
    265 
    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 
    274         bool isGenerated() const
    275         {
    276             return m_codeBlock;
    277         }
    278 
    279         CodeBlock& generatedBytecode()
    280         {
    281             ASSERT(m_codeBlock);
    282             return *m_codeBlock;
    283         }
    284 
    285         const Identifier& name() { return m_name; }
    286         size_t parameterCount() const { return m_parameters->size(); }
    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:
    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 
    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:
    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 
    342     inline FunctionExecutable* JSFunction::jsExecutable() const
    343     {
    344         ASSERT(!isHostFunctionNonInline());
    345         return static_cast<FunctionExecutable*>(m_executable.get());
    346     }
    347 
    348     inline bool JSFunction::isHostFunction() const
    349     {
    350         ASSERT(m_executable);
    351         return m_executable->isHostFunction();
    352     }
    353 
    354 }
    355 
    356 #endif
    357