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/JSFunction.cpp

    r47597 r47641  
    4646const ClassInfo JSFunction::info = { "Function", &InternalFunction::info, 0, 0 };
    4747
    48 inline bool JSFunction::isHostFunction() const
    49 {
    50     return m_executable && m_executable->isHostFunction();
    51 }
    52 
    5348bool JSFunction::isHostFunctionNonInline() const
    5449{
     
    5853JSFunction::JSFunction(PassRefPtr<Structure> structure)
    5954    : Base(structure)
    60 {
    61     clearScopeChain();
     55#if ENABLE(JIT)
     56    , m_executable(adoptRef(new VPtrHackExecutable()))
     57#endif
     58{
    6259}
    6360
     
    6562    : Base(&exec->globalData(), structure, name)
    6663#if ENABLE(JIT)
    67     , m_executable(FunctionExecutable::createNativeThunk(exec))
     64    , m_executable(adoptRef(new NativeExecutable(exec)))
    6865#endif
    6966{
     
    9289    if (!isHostFunction()) {
    9390#if ENABLE(JIT_OPTIMIZE_CALL)
    94         if (m_executable && m_executable->isGenerated())
    95             m_executable->generatedBytecode().unlinkCallers();
     91        ASSERT(m_executable);
     92        if (jsExecutable()->isGenerated())
     93            jsExecutable()->generatedBytecode().unlinkCallers();
    9694#endif
    9795        scopeChain().~ScopeChain(); // FIXME: Don't we need to do this in the interpreter too?
     
    102100{
    103101    Base::markChildren(markStack);
    104     m_executable->markAggregate(markStack);
    105     if (!isHostFunction())
     102    if (!isHostFunction()) {
     103        jsExecutable()->markAggregate(markStack);
    106104        scopeChain().markAggregate(markStack);
     105    }
    107106}
    108107
     
    113112        return CallTypeHost;
    114113    }
    115     callData.js.functionExecutable = m_executable.get();
     114    callData.js.functionExecutable = jsExecutable();
    116115    callData.js.scopeChain = scopeChain().node();
    117116    return CallTypeJS;
     
    121120{
    122121    ASSERT(!isHostFunction());
    123     return exec->interpreter()->execute(m_executable.get(), exec, this, thisValue.toThisObject(exec), args, scopeChain().node(), exec->exceptionSlot());
     122    return exec->interpreter()->execute(jsExecutable(), exec, this, thisValue.toThisObject(exec), args, scopeChain().node(), exec->exceptionSlot());
    124123}
    125124
     
    142141    JSFunction* thisObj = asFunction(slot.slotBase());
    143142    ASSERT(!thisObj->isHostFunction());
    144     return jsNumber(exec, thisObj->m_executable->parameterCount());
     143    return jsNumber(exec, thisObj->jsExecutable()->parameterCount());
    145144}
    146145
     
    206205    if (isHostFunction())
    207206        return ConstructTypeNone;
    208     constructData.js.functionExecutable = m_executable.get();
     207    constructData.js.functionExecutable = jsExecutable();
    209208    constructData.js.scopeChain = scopeChain().node();
    210209    return ConstructTypeJS;
     
    222221    JSObject* thisObj = new (exec) JSObject(structure);
    223222
    224     JSValue result = exec->interpreter()->execute(m_executable.get(), exec, this, thisObj, args, scopeChain().node(), exec->exceptionSlot());
     223    JSValue result = exec->interpreter()->execute(jsExecutable(), exec, this, thisObj, args, scopeChain().node(), exec->exceptionSlot());
    225224    if (exec->hadException() || !result.isObject())
    226225        return thisObj;
Note: See TracChangeset for help on using the changeset viewer.