Ignore:
Timestamp:
Aug 21, 2009, 2:54:20 PM (16 years ago)
Author:
[email protected]
Message:

Restructure Executable types so that host functions do not hold a FunctionExecutable.
https://bugs.webkit.org/show_bug.cgi?id=28621

Reviewed by Oliver Hunt.

All JSFunction objects have a pointer to an Executable*. This is currently always a
FunctionExecutable, however this has a couple of drawbacks. Host functions do not
store a range of information that the FunctionExecutable provides (source, name,
CodeBlock & information presently held on the FunctionBodyNode).

[ * nearly all... see below! ]

Instead, make JSFunctions hold a pointer to an ExecutableBase, move fields specific
to JS sourced executable types (source, node) into a new subclass (ScriptExecutable),
and create a new NativeExecutable type. We now provide a new method in JSFunction
to access & downcast to FunctionExecutable, but in doing so we can make an early
check (with an ASSERT) to ensure that the Executable read from a function will only
be treated as a FunctionExecutable (and thus the JS sepcific fields will only be
accessed) if the JSFunction is not a host function.

There is one JSFunction that currently does not have an Executable, which is the
object created to allow us to read out the vtable pointer. By making this change
we can also add a new Executable type fror this object (VPtrHackExecutable).
Since this means that really all JSFunctions have an Executable we no longer have
to null-check m_executable before us it - particularly in isHostFunction().

This patch removes CacheableEvalExecutable, since all subclasses of ExecutableBase
can now be ref-counted - since both JSFunction holds (and ref-counts) an ExecutableBase
that might be a FunctionExecutable or a NativeExecutable. This does now mean that all
ProgramExecutables and EvalExecutables (unnecessarily) provide an interface to be
ref-counted, however this seems less-bad than host functions unnecessarily providing
interface to access non-host specific information.

The class hierarcy has changed from this:

  • ExecutableBase
    • ProgramExecutable
    • EvalExecutable
      • CacheableEvalExecutable (also RefCounted by multiple-inheritance)
    • FunctionExecutable (also RefCounted by multiple-inheritance, 'special' FunctionExecutable also used for host functions)

To this:

  • RefCounted
    • ExecutableBase
      • NativeExecutable
      • VPtrHackExecutable
      • ScriptExecutable
        • ProgramExecutable
        • EvalExecutable
        • FunctionExecutable

This patch speeds up sunspidey by a couple of ms (presumably due to the changes to isHostFunction()).

  • bytecode/CodeBlock.cpp:

(JSC::CodeBlock::CodeBlock):

  • bytecode/CodeBlock.h:

(JSC::CodeBlock::ownerExecutable):
(JSC::GlobalCodeBlock::GlobalCodeBlock):

  • bytecode/EvalCodeCache.h:

(JSC::EvalCodeCache::get):

  • debugger/Debugger.cpp:

(JSC::Debugger::recompileAllJSFunctions):

  • interpreter/CachedCall.h:

(JSC::CachedCall::CachedCall):

  • interpreter/Interpreter.cpp:

(JSC::Interpreter::callEval):
(JSC::Interpreter::privateExecute):

  • jit/JITStubs.cpp:

(JSC::DEFINE_STUB_FUNCTION):

  • profiler/Profiler.cpp:

(JSC::createCallIdentifierFromFunctionImp):

  • runtime/Arguments.h:

(JSC::Arguments::getArgumentsData):
(JSC::Arguments::Arguments):

  • runtime/Executable.cpp:

(JSC::NativeExecutable::~NativeExecutable):
(JSC::VPtrHackExecutable::~VPtrHackExecutable):

  • runtime/Executable.h:

(JSC::ExecutableBase::ExecutableBase):
(JSC::ExecutableBase::~ExecutableBase):
(JSC::ExecutableBase::isHostFunction):
(JSC::NativeExecutable::NativeExecutable):
(JSC::VPtrHackExecutable::VPtrHackExecutable):
(JSC::ScriptExecutable::ScriptExecutable):
(JSC::ScriptExecutable::source):
(JSC::ScriptExecutable::sourceID):
(JSC::ScriptExecutable::sourceURL):
(JSC::ScriptExecutable::lineNo):
(JSC::ScriptExecutable::lastLine):
(JSC::ScriptExecutable::usesEval):
(JSC::ScriptExecutable::usesArguments):
(JSC::ScriptExecutable::needsActivation):
(JSC::EvalExecutable::EvalExecutable):
(JSC::EvalExecutable::create):
(JSC::ProgramExecutable::ProgramExecutable):
(JSC::FunctionExecutable::FunctionExecutable):

  • runtime/FunctionPrototype.cpp:

(JSC::functionProtoFuncToString):

  • runtime/JSFunction.cpp:

(JSC::JSFunction::JSFunction):
(JSC::JSFunction::~JSFunction):
(JSC::JSFunction::markChildren):
(JSC::JSFunction::getCallData):
(JSC::JSFunction::call):
(JSC::JSFunction::lengthGetter):
(JSC::JSFunction::getConstructData):
(JSC::JSFunction::construct):

  • runtime/JSFunction.h:

(JSC::JSFunction::executable):
(JSC::JSFunction::jsExecutable):
(JSC::JSFunction::isHostFunction):

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/JavaScriptCore/runtime/Executable.h

    r47620 r47641  
    2828
    2929#include "Nodes.h"
     30#include "JSFunction.h"
    3031
    3132namespace JSC {
     
    3839    struct ExceptionInfo;
    3940
    40     class ExecutableBase {
     41    class ExecutableBase : public RefCounted<ExecutableBase> {
    4142        friend class JIT;
    42     public:
    43         enum Mode {
    44             NoJITCode,
    45             HasJITCode,
    46             IsHost
    47         };
     43
     44    protected:
    4845        static const int NUM_PARAMETERS_IS_HOST = 0;
    4946        static const int NUM_PARAMETERS_NOT_COMPILED = -1;
    5047   
     48    public:
     49        ExecutableBase(int numParameters)
     50            : m_numParameters(numParameters)
     51        {
     52        }
     53
    5154        virtual ~ExecutableBase() {}
    5255
    53         ExecutableBase(const SourceCode& source)
    54             : m_source(source)
    55             , m_numParameters(NUM_PARAMETERS_NOT_COMPILED)
     56        bool isHostFunction() const { return m_numParameters == NUM_PARAMETERS_IS_HOST; }
     57
     58    protected:
     59        int m_numParameters;
     60
     61#if ENABLE(JIT)
     62    public:
     63        JITCode& generatedJITCode()
     64        {
     65            ASSERT(m_jitCode);
     66            return m_jitCode;
     67        }
     68
     69        ExecutablePool* getExecutablePool()
     70        {
     71            return m_jitCode.getExecutablePool();
     72        }
     73
     74    protected:
     75        JITCode m_jitCode;
     76#endif
     77    };
     78
     79    class NativeExecutable : public ExecutableBase {
     80    public:
     81        NativeExecutable(ExecState* exec)
     82            : ExecutableBase(NUM_PARAMETERS_IS_HOST)
     83        {
     84            m_jitCode = JITCode(JITCode::HostFunction(exec->globalData().jitStubs.ctiNativeCallThunk()));
     85        }
     86
     87        ~NativeExecutable();
     88    };
     89
     90    class VPtrHackExecutable : public ExecutableBase {
     91    public:
     92        VPtrHackExecutable()
     93            : ExecutableBase(NUM_PARAMETERS_IS_HOST)
     94        {
     95        }
     96
     97        ~VPtrHackExecutable();
     98    };
     99
     100    class ScriptExecutable : public ExecutableBase {
     101    public:
     102        ScriptExecutable(const SourceCode& source)
     103            : ExecutableBase(NUM_PARAMETERS_NOT_COMPILED)
     104            , m_source(source)
    56105        {
    57106        }
     
    70119
    71120    protected:
     121        SourceCode m_source;
    72122        RefPtr<ScopeNode> m_node;
    73         SourceCode m_source;
    74         int m_numParameters;
    75 
    76     private:
    77         // For use making native thunk.
    78         friend class FunctionExecutable;
    79         ExecutableBase()
    80         {
    81         }
    82 
    83 #if ENABLE(JIT)
    84     public:
    85         JITCode& generatedJITCode()
    86         {
    87             ASSERT(m_jitCode);
    88             return m_jitCode;
    89         }
    90 
    91         ExecutablePool* getExecutablePool()
    92         {
    93             return m_jitCode.getExecutablePool();
    94         }
    95 
    96     protected:
    97         JITCode m_jitCode;
    98 #endif
    99     };
    100 
    101     class EvalExecutable : public ExecutableBase {
     123    };
     124
     125    class EvalExecutable : public ScriptExecutable {
    102126    public:
    103127        EvalExecutable(const SourceCode& source)
    104             : ExecutableBase(source)
     128            : ScriptExecutable(source)
    105129            , m_evalCodeBlock(0)
    106130        {
     
    120144        ExceptionInfo* reparseExceptionInfo(JSGlobalData*, ScopeChainNode*, CodeBlock*);
    121145
     146        static PassRefPtr<EvalExecutable> create(const SourceCode& source) { return adoptRef(new EvalExecutable(source)); }
     147
    122148    private:
    123149        EvalNode* evalNode() { return static_cast<EvalNode*>(m_node.get()); }
     
    141167    };
    142168
    143     class CacheableEvalExecutable : public EvalExecutable, public RefCounted<CacheableEvalExecutable> {
    144     public:
    145         static PassRefPtr<CacheableEvalExecutable> create(const SourceCode& source) { return adoptRef(new CacheableEvalExecutable(source)); }
    146 
    147     private:
    148         CacheableEvalExecutable(const SourceCode& source)
    149             : EvalExecutable(source)
    150         {
    151         }
    152     };
    153 
    154     class ProgramExecutable : public ExecutableBase {
     169    class ProgramExecutable : public ScriptExecutable {
    155170    public:
    156171        ProgramExecutable(const SourceCode& source)
    157             : ExecutableBase(source)
     172            : ScriptExecutable(source)
    158173            , m_programCodeBlock(0)
    159174        {
     
    195210    };
    196211
    197     class FunctionExecutable : public ExecutableBase, public RefCounted<FunctionExecutable> {
     212    class FunctionExecutable : public ScriptExecutable {
    198213        friend class JIT;
    199214    public:
    200215        FunctionExecutable(const Identifier& name, FunctionBodyNode* body)
    201             : ExecutableBase(body->source())
     216            : ScriptExecutable(body->source())
    202217            , m_codeBlock(0)
    203218            , m_name(name)
     
    232247        UString paramString() const { return body()->paramString(); }
    233248
    234         bool isHostFunction() const { return m_numParameters == NUM_PARAMETERS_IS_HOST; }
    235249        bool isGenerated() const
    236250        {
     
    262276        }
    263277
    264         static PassRefPtr<FunctionExecutable> createNativeThunk(ExecState* exec)
    265         {
    266             return adoptRef(new FunctionExecutable(exec));
    267         }
    268 
    269     private:
    270         FunctionExecutable(ExecState* exec);
     278    private:
    271279        void generateJITCode(ScopeChainNode*);
    272280#endif
    273281    };
    274282
    275 };
    276 
    277 #endif
     283    inline FunctionExecutable* JSFunction::jsExecutable() const { ASSERT(!isHostFunctionNonInline()); return static_cast<FunctionExecutable*>(m_executable.get()); }
     284
     285    inline JSFunction* FunctionExecutable::make(ExecState* exec, ScopeChainNode* scopeChain)
     286    {
     287        return new (exec) JSFunction(exec, this, scopeChain);
     288    }
     289
     290    inline bool JSFunction::isHostFunction() const
     291    {
     292        ASSERT(m_executable);
     293        return m_executable->isHostFunction();
     294    }
     295
     296}
     297
     298#endif
Note: See TracChangeset for help on using the changeset viewer.