Home | History | Annotate | Download | only in runtime
      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:
     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