Ignore:
Timestamp:
Nov 10, 2011, 1:59:39 PM (14 years ago)
Author:
[email protected]
Message:

DFG should not reparse code that was just parsed
https://bugs.webkit.org/show_bug.cgi?id=71977

Reviewed by Geoff Garen.

The instruction stream of a code block is now kept around until
the next GC. When doing either an optimizing compilation of an
executable, or inlining of an executable, we now try to find the
already preexisting bytecode. If we find it, we don't have to parse.
If we don't find it, we parse as before. Inlining takes the extra
step of caching code blocks, so if the same executable gets inlined
multiple times into the same caller, then we parse it at most once
even if prior to inlining that executable did not have any code
blocks with an instruction stream.

Also fixed a silly bug where the strict mode for various operations
was being determined by looking at the machine code block rather
than the inlinee.

To enable the delete-on-next-GC policy, I introduced the notion
of an ultra weak finalizer, which anyone can register during
tracing. This is thread-safe (for parallel GC) and
stop-the-world-safe (so calls to free() are postponed until the
world is resumed). This required reusing some facilities previously
created for WeakReferenceHarvester, so I created a common utility
class. I also retweaked the handling of WeakReferenceHarvesters,
since they should be executed during stop-the-world since in the
future we may want to allow them to call drain().

2% win on SunSpider. 2% win on V8, when run in my harness. Neutral
elsewhere.

(JSC::CodeBlock::CodeBlock):
(JSC::CodeBlock::visitAggregate):
(JSC::CodeBlock::copyPostParseDataFrom):
(JSC::CodeBlock::copyPostParseDataFromAlternative):
(JSC::CodeBlock::finalizeUnconditionally):

  • bytecode/CodeBlock.h:

(JSC::CodeBlock::canProduceCopyWithBytecode):
(JSC::CodeBlock::discardBytecodeLater):
(JSC::CodeBlock::handleBytecodeDiscardingOpportunity):
(JSC::GlobalCodeBlock::GlobalCodeBlock):
(JSC::ProgramCodeBlock::ProgramCodeBlock):
(JSC::EvalCodeBlock::EvalCodeBlock):
(JSC::FunctionCodeBlock::FunctionCodeBlock):
(JSC::BytecodeDestructionBlocker::BytecodeDestructionBlocker):
(JSC::BytecodeDestructionBlocker::~BytecodeDestructionBlocker):

  • dfg/DFGAssemblyHelpers.h:

(JSC::DFG::AssemblyHelpers::strictModeFor):

  • dfg/DFGByteCodeCache.h: Added.

(JSC::DFG::CodeBlockKey::CodeBlockKey):
(JSC::DFG::CodeBlockKey::operator==):
(JSC::DFG::CodeBlockKey::hash):
(JSC::DFG::CodeBlockKey::executable):
(JSC::DFG::CodeBlockKey::kind):
(JSC::DFG::CodeBlockKey::isHashTableDeletedValue):
(JSC::DFG::CodeBlockKeyHash::hash):
(JSC::DFG::CodeBlockKeyHash::equal):
(JSC::DFG::ByteCodeCache::ByteCodeCache):
(JSC::DFG::ByteCodeCache::~ByteCodeCache):
(JSC::DFG::ByteCodeCache::get):

  • dfg/DFGByteCodeParser.cpp:

(JSC::DFG::ByteCodeParser::handleInlining):

  • dfg/DFGJITCodeGenerator32_64.cpp:

(JSC::DFG::JITCodeGenerator::cachedPutById):

  • dfg/DFGJITCodeGenerator64.cpp:

(JSC::DFG::JITCodeGenerator::cachedPutById):

  • dfg/DFGSpeculativeJIT64.cpp:

(JSC::DFG::SpeculativeJIT::compile):

  • heap/Heap.cpp:

(JSC::Heap::finalizeUnconditionally):
(JSC::Heap::markRoots):
(JSC::Heap::collect):

  • heap/Heap.h:
  • heap/ListableHandler.h: Added.

(JSC::ListableHandler::ListableHandler):
(JSC::ListableHandler::~ListableHandler):
(JSC::ListableHandler::List::List):
(JSC::ListableHandler::List::addNotThreadSafe):
(JSC::ListableHandler::List::addThreadSafe):
(JSC::ListableHandler::List::hasNext):
(JSC::ListableHandler::List::removeNext):

  • heap/MarkStack.cpp:

(JSC::MarkStackThreadSharedData::MarkStackThreadSharedData):
(JSC::SlotVisitor::harvestWeakReferences):
(JSC::SlotVisitor::finalizeUnconditionally):

  • heap/MarkStack.h:

(JSC::MarkStack::addWeakReferenceHarvester):
(JSC::MarkStack::addUnconditionalFinalizer):

  • heap/SlotVisitor.h:
  • heap/UnconditionalFinalizer.h: Added.

(JSC::UnconditionalFinalizer::~UnconditionalFinalizer):

  • heap/WeakReferenceHarvester.h:

(JSC::WeakReferenceHarvester::WeakReferenceHarvester):
(JSC::WeakReferenceHarvester::~WeakReferenceHarvester):

  • runtime/Executable.cpp:

(JSC::EvalExecutable::compileInternal):
(JSC::ProgramExecutable::compileInternal):
(JSC::FunctionExecutable::baselineCodeBlockFor):
(JSC::FunctionExecutable::codeBlockWithBytecodeFor):
(JSC::FunctionExecutable::produceCodeBlockFor):
(JSC::FunctionExecutable::compileForCallInternal):
(JSC::FunctionExecutable::compileForConstructInternal):

  • runtime/Executable.h:

(JSC::FunctionExecutable::profiledCodeBlockFor):

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/Source/JavaScriptCore/runtime/Executable.cpp

    r99374 r99898  
    157157    JSGlobalData* globalData = &exec->globalData();
    158158    JSGlobalObject* lexicalGlobalObject = exec->lexicalGlobalObject();
    159     if (!lexicalGlobalObject->evalEnabled())
    160         return throwError(exec, createEvalError(exec, "Eval is disabled"));
    161     RefPtr<EvalNode> evalNode = parse<EvalNode>(globalData, lexicalGlobalObject, m_source, 0, isStrictMode() ? JSParseStrict : JSParseNormal, EvalNode::isFunctionNode ? JSParseFunctionCode : JSParseProgramCode, lexicalGlobalObject->debugger(), exec, &exception);
    162     if (!evalNode) {
    163         ASSERT(exception);
    164         return exception;
    165     }
    166     recordParse(evalNode->features(), evalNode->hasCapturedVariables(), evalNode->lineNo(), evalNode->lastLine());
    167 
    168     JSGlobalObject* globalObject = scopeChainNode->globalObject.get();
    169 
    170     OwnPtr<CodeBlock> previousCodeBlock = m_evalCodeBlock.release();
    171     ASSERT((jitType == JITCode::bottomTierJIT()) == !previousCodeBlock);
    172     m_evalCodeBlock = adoptPtr(new EvalCodeBlock(this, globalObject, source().provider(), scopeChainNode->localDepth(), previousCodeBlock.release()));
    173     OwnPtr<BytecodeGenerator> generator(adoptPtr(new BytecodeGenerator(evalNode.get(), scopeChainNode, m_evalCodeBlock->symbolTable(), m_evalCodeBlock.get(), !!m_evalCodeBlock->alternative() ? OptimizingCompilation : FirstCompilation)));
    174     if ((exception = generator->generate())) {
    175         m_evalCodeBlock = static_pointer_cast<EvalCodeBlock>(m_evalCodeBlock->releaseAlternative());
     159   
     160    if (!!m_evalCodeBlock && m_evalCodeBlock->canProduceCopyWithBytecode()) {
     161        BytecodeDestructionBlocker blocker(m_evalCodeBlock.get());
     162        OwnPtr<EvalCodeBlock> newCodeBlock = adoptPtr(new EvalCodeBlock(CodeBlock::CopyParsedBlock, *m_evalCodeBlock));
     163        newCodeBlock->setAlternative(static_pointer_cast<CodeBlock>(m_evalCodeBlock.release()));
     164        m_evalCodeBlock = newCodeBlock.release();
     165    } else {
     166        if (!lexicalGlobalObject->evalEnabled())
     167            return throwError(exec, createEvalError(exec, "Eval is disabled"));
     168        RefPtr<EvalNode> evalNode = parse<EvalNode>(globalData, lexicalGlobalObject, m_source, 0, isStrictMode() ? JSParseStrict : JSParseNormal, EvalNode::isFunctionNode ? JSParseFunctionCode : JSParseProgramCode, lexicalGlobalObject->debugger(), exec, &exception);
     169        if (!evalNode) {
     170            ASSERT(exception);
     171            return exception;
     172        }
     173        recordParse(evalNode->features(), evalNode->hasCapturedVariables(), evalNode->lineNo(), evalNode->lastLine());
     174       
     175        JSGlobalObject* globalObject = scopeChainNode->globalObject.get();
     176       
     177        OwnPtr<CodeBlock> previousCodeBlock = m_evalCodeBlock.release();
     178        ASSERT((jitType == JITCode::bottomTierJIT()) == !previousCodeBlock);
     179        m_evalCodeBlock = adoptPtr(new EvalCodeBlock(this, globalObject, source().provider(), scopeChainNode->localDepth(), previousCodeBlock.release()));
     180        OwnPtr<BytecodeGenerator> generator(adoptPtr(new BytecodeGenerator(evalNode.get(), scopeChainNode, m_evalCodeBlock->symbolTable(), m_evalCodeBlock.get(), !!m_evalCodeBlock->alternative() ? OptimizingCompilation : FirstCompilation)));
     181        if ((exception = generator->generate())) {
     182            m_evalCodeBlock = static_pointer_cast<EvalCodeBlock>(m_evalCodeBlock->releaseAlternative());
     183            evalNode->destroyData();
     184            return exception;
     185        }
     186       
    176187        evalNode->destroyData();
    177         return exception;
    178     }
    179 
    180     evalNode->destroyData();
    181     m_evalCodeBlock->copyDataFromAlternative();
     188        m_evalCodeBlock->copyPostParseDataFromAlternative();
     189    }
    182190
    183191#if ENABLE(JIT)
     
    199207#if !ENABLE(OPCODE_SAMPLING)
    200208        if (!BytecodeGenerator::dumpsGeneratedCode())
    201             m_evalCodeBlock->discardBytecode();
     209            m_evalCodeBlock->handleBytecodeDiscardingOpportunity();
    202210#endif
    203211        m_evalCodeBlock->setJITCode(m_jitCodeForCall, MacroAssemblerCodePtr());
     
    291299    JSGlobalData* globalData = &exec->globalData();
    292300    JSGlobalObject* lexicalGlobalObject = exec->lexicalGlobalObject();
    293     RefPtr<ProgramNode> programNode = parse<ProgramNode>(globalData, lexicalGlobalObject, m_source, 0, isStrictMode() ? JSParseStrict : JSParseNormal, ProgramNode::isFunctionNode ? JSParseFunctionCode : JSParseProgramCode, lexicalGlobalObject->debugger(), exec, &exception);
    294     if (!programNode) {
    295         ASSERT(exception);
    296         return exception;
    297     }
    298     recordParse(programNode->features(), programNode->hasCapturedVariables(), programNode->lineNo(), programNode->lastLine());
    299 
    300     JSGlobalObject* globalObject = scopeChainNode->globalObject.get();
    301    
    302     OwnPtr<CodeBlock> previousCodeBlock = m_programCodeBlock.release();
    303     ASSERT((jitType == JITCode::bottomTierJIT()) == !previousCodeBlock);
    304     m_programCodeBlock = adoptPtr(new ProgramCodeBlock(this, GlobalCode, globalObject, source().provider(), previousCodeBlock.release()));
    305     OwnPtr<BytecodeGenerator> generator(adoptPtr(new BytecodeGenerator(programNode.get(), scopeChainNode, &globalObject->symbolTable(), m_programCodeBlock.get(), !!m_programCodeBlock->alternative() ? OptimizingCompilation : FirstCompilation)));
    306     if ((exception = generator->generate())) {
    307         m_programCodeBlock = static_pointer_cast<ProgramCodeBlock>(m_programCodeBlock->releaseAlternative());
     301   
     302    if (!!m_programCodeBlock && m_programCodeBlock->canProduceCopyWithBytecode()) {
     303        BytecodeDestructionBlocker blocker(m_programCodeBlock.get());
     304        OwnPtr<ProgramCodeBlock> newCodeBlock = adoptPtr(new ProgramCodeBlock(CodeBlock::CopyParsedBlock, *m_programCodeBlock));
     305        newCodeBlock->setAlternative(static_pointer_cast<CodeBlock>(m_programCodeBlock.release()));
     306        m_programCodeBlock = newCodeBlock.release();
     307    } else {
     308        RefPtr<ProgramNode> programNode = parse<ProgramNode>(globalData, lexicalGlobalObject, m_source, 0, isStrictMode() ? JSParseStrict : JSParseNormal, ProgramNode::isFunctionNode ? JSParseFunctionCode : JSParseProgramCode, lexicalGlobalObject->debugger(), exec, &exception);
     309        if (!programNode) {
     310            ASSERT(exception);
     311            return exception;
     312        }
     313        recordParse(programNode->features(), programNode->hasCapturedVariables(), programNode->lineNo(), programNode->lastLine());
     314
     315        JSGlobalObject* globalObject = scopeChainNode->globalObject.get();
     316   
     317        OwnPtr<CodeBlock> previousCodeBlock = m_programCodeBlock.release();
     318        ASSERT((jitType == JITCode::bottomTierJIT()) == !previousCodeBlock);
     319        m_programCodeBlock = adoptPtr(new ProgramCodeBlock(this, GlobalCode, globalObject, source().provider(), previousCodeBlock.release()));
     320        OwnPtr<BytecodeGenerator> generator(adoptPtr(new BytecodeGenerator(programNode.get(), scopeChainNode, &globalObject->symbolTable(), m_programCodeBlock.get(), !!m_programCodeBlock->alternative() ? OptimizingCompilation : FirstCompilation)));
     321        if ((exception = generator->generate())) {
     322            m_programCodeBlock = static_pointer_cast<ProgramCodeBlock>(m_programCodeBlock->releaseAlternative());
     323            programNode->destroyData();
     324            return exception;
     325        }
     326
    308327        programNode->destroyData();
    309         return exception;
    310     }
    311 
    312     programNode->destroyData();
    313     m_programCodeBlock->copyDataFromAlternative();
     328        m_programCodeBlock->copyPostParseDataFromAlternative();
     329    }
    314330
    315331#if ENABLE(JIT)
     
    330346#if !ENABLE(OPCODE_SAMPLING)
    331347        if (!BytecodeGenerator::dumpsGeneratedCode())
    332             m_programCodeBlock->discardBytecode();
     348            m_programCodeBlock->handleBytecodeDiscardingOpportunity();
    333349#endif
    334350        m_programCodeBlock->setJITCode(m_jitCodeForCall, MacroAssemblerCodePtr());
     
    389405}
    390406
    391 CodeBlock* FunctionExecutable::baselineCodeBlockFor(CodeSpecializationKind kind)
    392 {
    393     CodeBlock* result;
     407FunctionCodeBlock* FunctionExecutable::baselineCodeBlockFor(CodeSpecializationKind kind)
     408{
     409    FunctionCodeBlock* result;
    394410    if (kind == CodeForCall)
    395411        result = m_codeBlockForCall.get();
     
    401417        return 0;
    402418    while (result->alternative())
    403         result = result->alternative();
     419        result = static_cast<FunctionCodeBlock*>(result->alternative());
    404420    ASSERT(result);
    405421    ASSERT(result->getJITType() == JITCode::BaselineJIT);
     
    429445}
    430446
     447FunctionCodeBlock* FunctionExecutable::codeBlockWithBytecodeFor(CodeSpecializationKind kind)
     448{
     449    FunctionCodeBlock* codeBlock = baselineCodeBlockFor(kind);
     450    if (codeBlock->canProduceCopyWithBytecode())
     451        return codeBlock;
     452    return 0;
     453}
     454
    431455PassOwnPtr<FunctionCodeBlock> FunctionExecutable::produceCodeBlockFor(ScopeChainNode* scopeChainNode, CompilationKind compilationKind, CodeSpecializationKind specializationKind, JSObject*& exception)
    432456{
     457    if (!!codeBlockFor(specializationKind) && codeBlockFor(specializationKind)->canProduceCopyWithBytecode()) {
     458        BytecodeDestructionBlocker blocker(codeBlockFor(specializationKind).get());
     459        return adoptPtr(new FunctionCodeBlock(CodeBlock::CopyParsedBlock, *codeBlockFor(specializationKind)));
     460    }
     461   
    433462    exception = 0;
    434463    JSGlobalData* globalData = scopeChainNode->globalData;
     
    454483        return nullptr;
    455484
    456     result->copyDataFrom(codeBlockFor(specializationKind).get());
     485    result->copyPostParseDataFrom(codeBlockFor(specializationKind).get());
    457486    return result.release();
    458487}
     
    499528#if !ENABLE(OPCODE_SAMPLING)
    500529        if (!BytecodeGenerator::dumpsGeneratedCode())
    501             m_codeBlockForCall->discardBytecode();
     530            m_codeBlockForCall->handleBytecodeDiscardingOpportunity();
    502531#endif
    503532       
     
    562591#if !ENABLE(OPCODE_SAMPLING)
    563592        if (!BytecodeGenerator::dumpsGeneratedCode())
    564             m_codeBlockForConstruct->discardBytecode();
     593            m_codeBlockForConstruct->handleBytecodeDiscardingOpportunity();
    565594#endif
    566595       
Note: See TracChangeset for help on using the changeset viewer.