Ignore:
Timestamp:
May 18, 2009, 12:46:37 PM (16 years ago)
Author:
[email protected]
Message:

2009-05-15 Gavin Barraclough <[email protected]>

Reviewed by Darin Adler.

Refactor JIT code-handle objects. The representation of generated code is currently
a bit of a mess. We have a class JITCode which wraps the pointer to a block of
generated code, but this object does not reference the executable pool meaning that
external events (the pool being derefed) could make the pointer become invalid.
To overcome this both the JIT and Yarr implement further (and similar) objects to
wrap the code pointer with a RefPtr to the pool. To add to the mire, as well as the
CodeBlock containing a handle onto the code the FunctionBodyNode also contains a
copy of the code pointer which is used almost (but not entirely) uniquely to access
the JIT code for a function.

Rationalization of all this:

  • Add a new type 'MacroAssembler::CodeRef' as a handle for a block of JIT generated code.
  • Change the JIT & Yarr to internally handle code using CodeRefs.
  • Move the CodeRef (formerly anow defunct JITCodeRef) from CodeBlock to its owner node.
  • Remove the (now) redundant code pointer from FunctionBodyNode.

While tidying this up I've made the PatchBuffer return code in new allocations using a CodeRef,
and have enforced an interface that the PatchBuffer will always be used, and 'finalizeCode()' or
'finalizeCodeAddendum()' will always be called exactly once on the PatchBuffer to complete code generation.

This gives us a potentially useful hook ('PatchBuffer::performFinalization()') at the end of generation,
which may have a number of uses. It may be helpful should we wish to switch our generation
model to allow RW/RX exclusive memory, and it may be useful on non-cache-coherent platforms to
give us an oportunity to cache flush as necessary.

No performance impact.

  • assembler/AbstractMacroAssembler.h: (JSC::AbstractMacroAssembler::ProcessorReturnAddress::relinkCallerToTrampoline): (JSC::AbstractMacroAssembler::CodeRef::CodeRef): (JSC::AbstractMacroAssembler::CodeRef::trampolineAt): (JSC::AbstractMacroAssembler::PatchBuffer::PatchBuffer): (JSC::AbstractMacroAssembler::PatchBuffer::~PatchBuffer): (JSC::AbstractMacroAssembler::PatchBuffer::link): (JSC::AbstractMacroAssembler::PatchBuffer::linkTailRecursive): (JSC::AbstractMacroAssembler::PatchBuffer::patch): (JSC::AbstractMacroAssembler::PatchBuffer::complete): (JSC::AbstractMacroAssembler::PatchBuffer::finalize): (JSC::AbstractMacroAssembler::PatchBuffer::entry):
  • bytecode/CodeBlock.cpp: (JSC::CodeBlock::CodeBlock): (JSC::CodeBlock::reparseForExceptionInfoIfNecessary): (JSC::CodeBlock::setJITCode):
  • bytecode/CodeBlock.h: (JSC::CodeBlock::getBytecodeIndex): (JSC::CodeBlock::executablePool):
  • interpreter/CallFrameClosure.h:
  • interpreter/Interpreter.cpp: (JSC::Interpreter::execute): (JSC::Interpreter::prepareForRepeatCall):
  • jit/JIT.cpp: (JSC::JIT::privateCompile): (JSC::JIT::privateCompileCTIMachineTrampolines): (JSC::JIT::linkCall):
  • jit/JIT.h:
  • jit/JITCode.h: (JSC::JITCode::JITCode): (JSC::JITCode::operator bool): (JSC::JITCode::addressForCall): (JSC::JITCode::offsetOf): (JSC::JITCode::execute): (JSC::JITCode::size): (JSC::JITCode::executablePool): (JSC::JITCode::HostFunction):
  • jit/JITPropertyAccess.cpp: (JSC::JIT::privateCompilePutByIdTransition): (JSC::JIT::privateCompilePatchGetArrayLength): (JSC::JIT::privateCompileGetByIdProto): (JSC::JIT::privateCompileGetByIdSelfList): (JSC::JIT::privateCompileGetByIdProtoList): (JSC::JIT::privateCompileGetByIdChainList): (JSC::JIT::privateCompileGetByIdChain):
  • jit/JITStubs.cpp: (JSC::JITStubs::cti_vm_dontLazyLinkCall): (JSC::JITStubs::cti_vm_lazyLinkCall):
  • parser/Nodes.cpp: (JSC::ProgramNode::generateJITCode): (JSC::EvalNode::generateJITCode): (JSC::FunctionBodyNode::FunctionBodyNode): (JSC::FunctionBodyNode::createNativeThunk): (JSC::FunctionBodyNode::generateJITCode):
  • parser/Nodes.h: (JSC::ScopeNode::generatedJITCode): (JSC::ScopeNode::getExecutablePool): (JSC::ScopeNode::setJITCode): (JSC::ProgramNode::jitCode): (JSC::EvalNode::jitCode): (JSC::FunctionBodyNode::jitCode):
  • runtime/RegExp.cpp: (JSC::RegExp::match):
  • yarr/RegexJIT.cpp: (JSC::Yarr::RegexGenerator::compile): (JSC::Yarr::jitCompileRegex): (JSC::Yarr::executeRegex):
  • yarr/RegexJIT.h: (JSC::Yarr::RegexCodeBlock::RegexCodeBlock): (JSC::Yarr::RegexCodeBlock::pcreFallback): (JSC::Yarr::RegexCodeBlock::setFallback): (JSC::Yarr::RegexCodeBlock::operator bool): (JSC::Yarr::RegexCodeBlock::set): (JSC::Yarr::RegexCodeBlock::execute):
File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/JavaScriptCore/assembler/AbstractMacroAssembler.h

    r43781 r43837  
    2727#define AbstractMacroAssembler_h
    2828
     29#include <wtf/Noncopyable.h>
    2930#include <wtf/Platform.h>
     31#include <wtf/UnusedParam.h>
    3032
    3133#if ENABLE(ASSEMBLER)
     
    4446    class CodeLocationDataLabel32;
    4547    class CodeLocationDataLabelPtr;
     48    class ProcessorReturnAddress;
     49
     50    struct CodeRef;
    4651
    4752    typedef typename AssemblerType::RegisterID RegisterID;
     
    195200    // it may be used as a destination for a jump.
    196201    class Label {
     202        template<class TemplateAssemblerType>
     203        friend class AbstractMacroAssembler;
    197204        friend class Jump;
    198         template<class AssemblerType_T>
    199         friend class AbstractMacroAssembler;
    200         friend class PatchBuffer;
     205        friend class PatchBuffer;
     206
     207        friend struct CodeRef;
     208
    201209    public:
    202210        Label()
     
    220228    // patched after the code has been generated.
    221229    class DataLabelPtr {
    222         template<class AssemblerType_T>
     230        template<class TemplateAssemblerType>
    223231        friend class AbstractMacroAssembler;
    224232        friend class PatchBuffer;
     
    242250    // patched after the code has been generated.
    243251    class DataLabel32 {
    244         template<class AssemblerType_T>
     252        template<class TemplateAssemblerType>
    245253        friend class AbstractMacroAssembler;
    246254        friend class PatchBuffer;
     
    266274    // destination.
    267275    class Call {
    268         friend class PatchBuffer;
    269         template<class AssemblerType_T>
     276        template<class TemplateAssemblerType>
    270277        friend class AbstractMacroAssembler;
     278        friend class PatchBuffer;
    271279    public:
    272280        enum Flags {
     
    310318    // destination.
    311319    class Jump {
    312         friend class PatchBuffer;
    313         template<class AssemblerType_T>
     320        template<class TemplateAssemblerType>
    314321        friend class AbstractMacroAssembler;
    315322        friend class Call;
     323        friend class PatchBuffer;
    316324    public:
    317325        Jump()
     
    456464        friend class CodeLocationJump;
    457465        friend class PatchBuffer;
     466        friend class ProcessorReturnAddress;
     467
    458468    public:
    459469        CodeLocationLabel()
     
    615625        }
    616626
     627        void relinkCallerToTrampoline(CodeLocationLabel label)
     628        {
     629            AssemblerType::patchMacroAssemblerCall(reinterpret_cast<intptr_t>(this->m_location), label.getJumpDestination());
     630        }
     631       
    617632        template<typename FunctionSig>
    618633        void relinkCallerToFunction(FunctionSig* newCalleeFunction)
     
    637652
    638653
    639     // Section 4: The patch buffer - utility to finalize code generation.
    640 
     654    // Section 4: CodeRef & PatchBuffer - utility to finalize code generation.
     655
     656    // CodeRef:
     657    //
     658    // A reference to a section of JIT generated code.  A CodeRef consists of a
     659    // pointer to the code, and a ref pointer to the pool from within which it
     660    // was allocated.
     661    class CodeRef {
     662    public:
     663        CodeRef()
     664            : m_code(0)
     665#ifndef NDEBUG
     666            , m_size(0)
     667#endif
     668        {
     669        }
     670
     671        CodeRef(AbstractMacroAssembler<AssemblerType>* masm, PassRefPtr<ExecutablePool> executablePool)
     672            : m_executablePool(executablePool)
     673#ifndef NDEBUG
     674            , m_size(masm->m_assembler.size())
     675#endif
     676        {
     677            m_code = masm->m_assembler.executableCopy(m_executablePool.get());
     678        }
     679
     680        CodeRef(void* code, PassRefPtr<ExecutablePool> executablePool, size_t size)
     681            : m_code(code)
     682            , m_executablePool(executablePool)
     683        {
     684#ifndef NDEBUG
     685            m_size = size;
     686#else
     687            UNUSED_PARAM(size);
     688#endif
     689        }
     690
     691        void* trampolineAt(Label label)
     692        {
     693            return AssemblerType::getRelocatedAddress(m_code, label.m_label);
     694        }
     695       
     696        void* m_code;
     697        RefPtr<ExecutablePool> m_executablePool;
     698#ifndef NDEBUG
     699        size_t m_size;
     700#endif
     701    };
    641702
    642703    // PatchBuffer:
     
    657718    // address of calls, as opposed to a point that can be used to later relink a Jump -
    658719    // possibly wrap the later up in an object that can do just that).
    659     class PatchBuffer {
    660     public:
    661         PatchBuffer(void* code)
    662             : m_code(code)
    663         {
    664         }
    665 
    666         CodeLocationLabel entry()
    667         {
    668             return CodeLocationLabel(m_code);
    669         }
    670 
    671         void* trampolineAt(Label label)
    672         {
    673             return AssemblerType::getRelocatedAddress(m_code, label.m_label);
    674         }
    675        
     720    class PatchBuffer : public Noncopyable {
     721    public:
     722        PatchBuffer(AbstractMacroAssembler<AssemblerType>* masm, PassRefPtr<ExecutablePool> executablePool)
     723            : m_ref(masm, executablePool)
     724#ifndef NDEBUG
     725            , m_completed(false)
     726#endif
     727        {
     728        }
     729
     730#ifndef NDEBUG
     731        ~PatchBuffer()
     732        {
     733            ASSERT(m_completed);
     734        }
     735#endif
     736
    676737        // These methods are used to link or set values at code generation time.
    677738
     
    681742            ASSERT(call.isFlagSet(Call::Linkable));
    682743#if PLATFORM(X86_64)
    683             if (call.isFlagSet(Call::Near)) {
    684                 AssemblerType::linkCall(m_code, call.m_jmp, reinterpret_cast<void*>(function));
    685             } else {
    686                 intptr_t callLocation = reinterpret_cast<intptr_t>(AssemblerType::getRelocatedAddress(m_code, call.m_jmp));
     744            if (call.isFlagSet(Call::Near))
     745                AssemblerType::linkCall(code(), call.m_jmp, reinterpret_cast<void*>(function));
     746            else {
     747                intptr_t callLocation = reinterpret_cast<intptr_t>(AssemblerType::getRelocatedAddress(code(), call.m_jmp));
    687748                AssemblerType::patchMacroAssemblerCall(callLocation, reinterpret_cast<void*>(function));
    688749            }
    689750#else
    690             AssemblerType::linkCall(m_code, call.m_jmp, reinterpret_cast<void*>(function));
     751            AssemblerType::linkCall(code(), call.m_jmp, reinterpret_cast<void*>(function));
    691752#endif
    692753        }
     
    695756        void linkTailRecursive(Jump jump, FunctionSig* function)
    696757        {
    697             AssemblerType::linkJump(m_code, jump.m_jmp, reinterpret_cast<void*>(function));
     758            AssemblerType::linkJump(code(), jump.m_jmp, reinterpret_cast<void*>(function));
    698759        }
    699760
     
    701762        void linkTailRecursive(JumpList list, FunctionSig* function)
    702763        {
    703             for (unsigned i = 0; i < list.m_jumps.size(); ++i) {
    704                 AssemblerType::linkJump(m_code, list.m_jumps[i].m_jmp, reinterpret_cast<void*>(function));
    705             }
     764            for (unsigned i = 0; i < list.m_jumps.size(); ++i)
     765                AssemblerType::linkJump(code(), list.m_jumps[i].m_jmp, reinterpret_cast<void*>(function));
    706766        }
    707767
    708768        void link(Jump jump, CodeLocationLabel label)
    709769        {
    710             AssemblerType::linkJump(m_code, jump.m_jmp, label.m_location);
     770            AssemblerType::linkJump(code(), jump.m_jmp, label.m_location);
    711771        }
    712772
     
    714774        {
    715775            for (unsigned i = 0; i < list.m_jumps.size(); ++i)
    716                 AssemblerType::linkJump(m_code, list.m_jumps[i].m_jmp, label.m_location);
     776                AssemblerType::linkJump(code(), list.m_jumps[i].m_jmp, label.m_location);
    717777        }
    718778
    719779        void patch(DataLabelPtr label, void* value)
    720780        {
    721             AssemblerType::patchAddress(m_code, label.m_label, value);
     781            AssemblerType::patchAddress(code(), label.m_label, value);
     782        }
     783
     784        void patch(DataLabelPtr label, CodeLocationLabel value)
     785        {
     786            AssemblerType::patchAddress(code(), label.m_label, value.getJumpDestination());
    722787        }
    723788
     
    728793            ASSERT(call.isFlagSet(Call::Linkable));
    729794            ASSERT(!call.isFlagSet(Call::Near));
    730             return CodeLocationCall(AssemblerType::getRelocatedAddress(m_code, call.m_jmp));
     795            return CodeLocationCall(AssemblerType::getRelocatedAddress(code(), call.m_jmp));
    731796        }
    732797
     
    735800            ASSERT(call.isFlagSet(Call::Linkable));
    736801            ASSERT(call.isFlagSet(Call::Near));
    737             return CodeLocationNearCall(AssemblerType::getRelocatedAddress(m_code, call.m_jmp));
     802            return CodeLocationNearCall(AssemblerType::getRelocatedAddress(code(), call.m_jmp));
    738803        }
    739804
    740805        CodeLocationLabel locationOf(Label label)
    741806        {
    742             return CodeLocationLabel(AssemblerType::getRelocatedAddress(m_code, label.m_label));
     807            return CodeLocationLabel(AssemblerType::getRelocatedAddress(code(), label.m_label));
    743808        }
    744809
    745810        CodeLocationDataLabelPtr locationOf(DataLabelPtr label)
    746811        {
    747             return CodeLocationDataLabelPtr(AssemblerType::getRelocatedAddress(m_code, label.m_label));
     812            return CodeLocationDataLabelPtr(AssemblerType::getRelocatedAddress(code(), label.m_label));
    748813        }
    749814
    750815        CodeLocationDataLabel32 locationOf(DataLabel32 label)
    751816        {
    752             return CodeLocationDataLabel32(AssemblerType::getRelocatedAddress(m_code, label.m_label));
     817            return CodeLocationDataLabel32(AssemblerType::getRelocatedAddress(code(), label.m_label));
    753818        }
    754819
     
    760825        }
    761826
    762     private:
    763         void* m_code;
     827        // Upon completion of all patching either 'finalizeCode()' or 'finalizeCodeAddendum()' should be called
     828        // once to complete generation of the code.  'finalizeCode()' is suited to situations
     829        // where the executable pool must also be retained, the lighter-weight 'finalizeCodeAddendum()' is
     830        // suited to adding to an existing allocation.
     831        CodeRef finalizeCode()
     832        {
     833            performFinalization();
     834
     835            return m_ref;
     836        }
     837        CodeLocationLabel finalizeCodeAddendum()
     838        {
     839            performFinalization();
     840
     841            return CodeLocationLabel(code());
     842        }
     843
     844    private:
     845        // Keep this private! - the underlying code should only be obtained externally via
     846        // finalizeCode() or finalizeCodeAddendum().
     847        void* code()
     848        {
     849            return m_ref.m_code;
     850        }
     851
     852        void performFinalization()
     853        {
     854#ifndef NDEBUG
     855            ASSERT(!m_completed);
     856            m_completed = true;
     857#endif
     858        }
     859
     860        CodeRef m_ref;
     861#ifndef NDEBUG
     862        bool m_completed;
     863#endif
    764864    };
    765865
     
    770870    {
    771871        return m_assembler.size();
    772     }
    773 
    774     void* copyCode(ExecutablePool* allocator)
    775     {
    776         return m_assembler.executableCopy(allocator);
    777872    }
    778873
Note: See TracChangeset for help on using the changeset viewer.