Ignore:
Timestamp:
Oct 16, 2012, 3:28:32 PM (13 years ago)
Author:
[email protected]
Message:

Bytecode should not have responsibility for determining how to perform non-local resolves
https://bugs.webkit.org/show_bug.cgi?id=99349

Reviewed by Gavin Barraclough.

This patch removes lexical analysis from the bytecode generation. This allows
us to delay lookup of a non-local variables until the lookup is actually necessary,
and simplifies a lot of the resolve logic in BytecodeGenerator.

Once a lookup is performed we cache the lookup information in a set of out-of-line
buffers in CodeBlock. This allows subsequent lookups to avoid unnecessary hashing,
etc, and allows the respective JITs to recreated optimal lookup code.

This is currently still a performance regression in LLInt, but most of the remaining
regression is caused by a lot of indirection that I'll remove in future work, as well
as some work necessary to allow LLInt to perform in line instruction repatching.
We will also want to improve the behaviour of the baseline JIT for some of the lookup
operations, however this patch was getting quite large already so I'm landing it now
that we've reached the bar of "performance-neutral".

  • GNUmakefile.list.am:
  • JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.vcproj:
  • JavaScriptCore.xcodeproj/project.pbxproj:
  • bytecode/CodeBlock.cpp:

(JSC::CodeBlock::printStructures):
(JSC::CodeBlock::dump):
(JSC::CodeBlock::CodeBlock):
(JSC::CodeBlock::visitStructures):
(JSC):
(JSC::CodeBlock::finalizeUnconditionally):
(JSC::CodeBlock::shrinkToFit):

  • bytecode/CodeBlock.h:

(JSC::CodeBlock::addResolve):
(JSC::CodeBlock::addPutToBase):
(CodeBlock):
(JSC::CodeBlock::resolveOperations):
(JSC::CodeBlock::putToBaseOperation):
(JSC::CodeBlock::numberOfResolveOperations):
(JSC::CodeBlock::numberOfPutToBaseOperations):
(JSC::CodeBlock::addPropertyAccessInstruction):
(JSC::CodeBlock::globalObjectConstant):
(JSC::CodeBlock::setGlobalObjectConstant):

  • bytecode/GlobalResolveInfo.h: Removed.
  • bytecode/Opcode.h:

(JSC):
(JSC::padOpcodeName):

  • bytecode/ResolveGlobalStatus.cpp:

(JSC::computeForStructure):
(JSC::ResolveGlobalStatus::computeFor):

  • bytecode/ResolveGlobalStatus.h:

(JSC):
(ResolveGlobalStatus):

  • bytecode/ResolveOperation.h: Added. The new types and logic we use to perform the cached lookups.

(JSC):
(ResolveOperation):
(JSC::ResolveOperation::getAndReturnScopedVar):
(JSC::ResolveOperation::checkForDynamicEntriesBeforeGlobalScope):
(JSC::ResolveOperation::getAndReturnGlobalVar):
(JSC::ResolveOperation::getAndReturnGlobalProperty):
(JSC::ResolveOperation::resolveFail):
(JSC::ResolveOperation::skipTopScopeNode):
(JSC::ResolveOperation::skipScopes):
(JSC::ResolveOperation::returnGlobalObjectAsBase):
(JSC::ResolveOperation::setBaseToGlobal):
(JSC::ResolveOperation::setBaseToUndefined):
(JSC::ResolveOperation::setBaseToScope):
(JSC::ResolveOperation::returnScopeAsBase):
(JSC::PutToBaseOperation::PutToBaseOperation):

  • bytecompiler/BytecodeGenerator.cpp:

(JSC::ResolveResult::checkValidity):
(JSC):
(JSC::BytecodeGenerator::BytecodeGenerator):
(JSC::BytecodeGenerator::resolve):
(JSC::BytecodeGenerator::resolveConstDecl):
(JSC::BytecodeGenerator::shouldAvoidResolveGlobal):
(JSC::BytecodeGenerator::emitResolve):
(JSC::BytecodeGenerator::emitResolveBase):
(JSC::BytecodeGenerator::emitResolveBaseForPut):
(JSC::BytecodeGenerator::emitResolveWithBaseForPut):
(JSC::BytecodeGenerator::emitResolveWithThis):
(JSC::BytecodeGenerator::emitGetLocalVar):
(JSC::BytecodeGenerator::emitInitGlobalConst):
(JSC::BytecodeGenerator::emitPutToBase):

  • bytecompiler/BytecodeGenerator.h:

(JSC::ResolveResult::registerResolve):
(JSC::ResolveResult::dynamicResolve):
(ResolveResult):
(JSC::ResolveResult::ResolveResult):
(JSC):
(NonlocalResolveInfo):
(JSC::NonlocalResolveInfo::NonlocalResolveInfo):
(JSC::NonlocalResolveInfo::~NonlocalResolveInfo):
(JSC::NonlocalResolveInfo::resolved):
(JSC::NonlocalResolveInfo::put):
(BytecodeGenerator):
(JSC::BytecodeGenerator::getResolveOperations):
(JSC::BytecodeGenerator::getResolveWithThisOperations):
(JSC::BytecodeGenerator::getResolveBaseOperations):
(JSC::BytecodeGenerator::getResolveBaseForPutOperations):
(JSC::BytecodeGenerator::getResolveWithBaseForPutOperations):
(JSC::BytecodeGenerator::getPutToBaseOperation):

  • bytecompiler/NodesCodegen.cpp:

(JSC::ResolveNode::isPure):
(JSC::FunctionCallResolveNode::emitBytecode):
(JSC::PostfixNode::emitResolve):
(JSC::PrefixNode::emitResolve):
(JSC::ReadModifyResolveNode::emitBytecode):
(JSC::AssignResolveNode::emitBytecode):
(JSC::ConstDeclNode::emitCodeSingle):
(JSC::ForInNode::emitBytecode):

  • dfg/DFGAbstractState.cpp:

(JSC::DFG::AbstractState::execute):

  • dfg/DFGByteCodeParser.cpp:

(ByteCodeParser):
(InlineStackEntry):
(JSC::DFG::ByteCodeParser::handleGetByOffset):
(DFG):
(JSC::DFG::ByteCodeParser::parseResolveOperations):
(JSC::DFG::ByteCodeParser::parseBlock):
(JSC::DFG::ByteCodeParser::InlineStackEntry::InlineStackEntry):

  • dfg/DFGCapabilities.h:

(JSC::DFG::canCompileResolveOperations):
(DFG):
(JSC::DFG::canCompilePutToBaseOperation):
(JSC::DFG::canCompileOpcode):
(JSC::DFG::canInlineOpcode):

  • dfg/DFGGraph.h:

(ResolveGlobalData):
(ResolveOperationData):
(DFG):
(PutToBaseOperationData):
(Graph):

  • dfg/DFGNode.h:

(JSC::DFG::Node::hasIdentifier):
(JSC::DFG::Node::resolveOperationsDataIndex):
(Node):

  • dfg/DFGNodeType.h:

(DFG):

  • dfg/DFGOSRExit.cpp:

(JSC::DFG::OSRExit::OSRExit):

  • dfg/DFGOSRExit.h:

(OSRExit):

  • dfg/DFGOSRExitCompiler.cpp:
  • dfg/DFGOSRExitCompiler32_64.cpp:

(JSC::DFG::OSRExitCompiler::compileExit):

  • dfg/DFGOSRExitCompiler64.cpp:

(JSC::DFG::OSRExitCompiler::compileExit):

  • dfg/DFGOperations.cpp:
  • dfg/DFGOperations.h:
  • dfg/DFGPredictionPropagationPhase.cpp:

(JSC::DFG::PredictionPropagationPhase::propagate):

  • dfg/DFGRepatch.cpp:

(JSC::DFG::tryCacheGetByID):

  • dfg/DFGSpeculativeJIT.cpp:

(JSC::DFG::SpeculativeJIT::convertLastOSRExitToForward):

  • dfg/DFGSpeculativeJIT.h:

(JSC::DFG::SpeculativeJIT::resolveOperations):
(SpeculativeJIT):
(JSC::DFG::SpeculativeJIT::putToBaseOperation):
(JSC::DFG::SpeculativeJIT::callOperation):

  • dfg/DFGSpeculativeJIT32_64.cpp:

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

  • dfg/DFGSpeculativeJIT64.cpp:

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

  • dfg/DFGStructureCheckHoistingPhase.cpp:

(JSC::DFG::StructureCheckHoistingPhase::run):

  • jit/JIT.cpp:

(JSC::JIT::privateCompileMainPass):
(JSC::JIT::privateCompileSlowCases):

  • jit/JIT.h:

(JIT):

  • jit/JITOpcodes.cpp:

(JSC::JIT::emit_op_put_to_base):
(JSC):
(JSC::JIT::emit_resolve_operations):
(JSC::JIT::emitSlow_link_resolve_operations):
(JSC::JIT::emit_op_resolve):
(JSC::JIT::emitSlow_op_resolve):
(JSC::JIT::emit_op_resolve_base):
(JSC::JIT::emitSlow_op_resolve_base):
(JSC::JIT::emit_op_resolve_with_base):
(JSC::JIT::emitSlow_op_resolve_with_base):
(JSC::JIT::emit_op_resolve_with_this):
(JSC::JIT::emitSlow_op_resolve_with_this):
(JSC::JIT::emitSlow_op_put_to_base):

  • jit/JITOpcodes32_64.cpp:

(JSC::JIT::emit_op_put_to_base):
(JSC):

  • jit/JITPropertyAccess.cpp:

(JSC::JIT::emit_op_init_global_const):
(JSC::JIT::emit_op_init_global_const_check):
(JSC::JIT::emitSlow_op_init_global_const_check):

  • jit/JITPropertyAccess32_64.cpp:

(JSC::JIT::emit_op_init_global_const):
(JSC::JIT::emit_op_init_global_const_check):
(JSC::JIT::emitSlow_op_init_global_const_check):

  • jit/JITStubs.cpp:

(JSC::DEFINE_STUB_FUNCTION):
(JSC):

  • jit/JITStubs.h:
  • llint/LLIntSlowPaths.cpp:

(LLInt):
(JSC::LLInt::LLINT_SLOW_PATH_DECL):

  • llint/LLIntSlowPaths.h:

(LLInt):

  • llint/LowLevelInterpreter.asm:
  • llint/LowLevelInterpreter32_64.asm:
  • llint/LowLevelInterpreter64.asm:
  • runtime/JSScope.cpp:

(JSC::LookupResult::base):
(JSC::LookupResult::value):
(JSC::LookupResult::setBase):
(JSC::LookupResult::setValue):
(LookupResult):
(JSC):
(JSC::setPutPropertyAccessOffset):
(JSC::executeResolveOperations):
(JSC::JSScope::resolveContainingScopeInternal):
(JSC::JSScope::resolveContainingScope):
(JSC::JSScope::resolve):
(JSC::JSScope::resolveBase):
(JSC::JSScope::resolveWithBase):
(JSC::JSScope::resolveWithThis):
(JSC::JSScope::resolvePut):
(JSC::JSScope::resolveGlobal):

  • runtime/JSScope.h:

(JSScope):

  • runtime/JSVariableObject.cpp:

(JSC):

  • runtime/JSVariableObject.h:

(JSVariableObject):

  • runtime/Structure.h:

(JSC::Structure::propertyAccessesAreCacheable):
(Structure):

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/Source/JavaScriptCore/bytecompiler/NodesCodegen.cpp

    r130612 r131516  
    142142bool ResolveNode::isPure(BytecodeGenerator& generator) const
    143143{
    144     return generator.resolve(m_ident).isStatic();
     144    return generator.resolve(m_ident).isRegister();
    145145}
    146146
     
    430430        generator.emitLoad(callArguments.thisRegister(), jsUndefined());
    431431        return generator.emitCall(generator.finalDestinationOrIgnored(dst, callArguments.thisRegister()), func.get(), callArguments, divot(), startOffset(), endOffset());
    432     }
    433 
    434     if (resolveResult.isStatic()) {
    435         RefPtr<RegisterID> func = generator.newTemporary();
    436         CallArguments callArguments(generator, m_args);
    437         generator.emitGetStaticVar(func.get(), resolveResult, m_ident);
    438         generator.emitLoad(callArguments.thisRegister(), jsUndefined());
    439         return generator.emitCall(generator.finalDestinationOrIgnored(dst, func.get()), func.get(), callArguments, divot(), startOffset(), endOffset());
    440432    }
    441433
     
    624616        return emitPostIncOrDec(generator, generator.finalDestination(dst), local, m_operator);
    625617    }
    626 
    627     if (resolveResult.isStatic() && !resolveResult.isReadOnly()) {
    628         RefPtr<RegisterID> value = generator.emitGetStaticVar(generator.newTemporary(), resolveResult, ident);
    629         RegisterID* oldValue;
    630         if (dst == generator.ignoredResult()) {
    631             oldValue = 0;
    632             emitPreIncOrDec(generator, value.get(), m_operator);
    633         } else
    634             oldValue = emitPostIncOrDec(generator, generator.finalDestination(dst), value.get(), m_operator);
    635         generator.emitPutStaticVar(resolveResult, ident, value.get());
    636         return oldValue;
    637     }
    638618   
    639619    generator.emitExpressionInfo(divot(), startOffset(), endOffset());
    640620    RefPtr<RegisterID> value = generator.newTemporary();
    641     RefPtr<RegisterID> base = generator.emitResolveWithBase(generator.newTemporary(), value.get(), resolveResult, ident);
     621    NonlocalResolveInfo resolveInfo;
     622    RefPtr<RegisterID> base = generator.emitResolveWithBaseForPut(generator.newTemporary(), value.get(), resolveResult, ident, resolveInfo);
    642623    RegisterID* oldValue;
    643624    if (dst == generator.ignoredResult()) {
     
    646627    } else
    647628        oldValue = emitPostIncOrDec(generator, generator.finalDestination(dst), value.get(), m_operator);
    648     generator.emitPutById(base.get(), ident, value.get());
     629    generator.emitPutToBase(base.get(), ident, value.get(), resolveInfo);
    649630    return oldValue;
    650631}
     
    821802    }
    822803
    823     if (resolveResult.isStatic() && !resolveResult.isReadOnly()) {
    824         RefPtr<RegisterID> propDst = generator.emitGetStaticVar(generator.tempDestination(dst), resolveResult, ident);
    825         emitPreIncOrDec(generator, propDst.get(), m_operator);
    826         generator.emitPutStaticVar(resolveResult, ident, propDst.get());
    827         return generator.moveToDestinationIfNeeded(dst, propDst.get());
    828     }
    829 
    830804    generator.emitExpressionInfo(divot(), startOffset(), endOffset());
    831805    RefPtr<RegisterID> propDst = generator.tempDestination(dst);
    832     RefPtr<RegisterID> base = generator.emitResolveWithBase(generator.newTemporary(), propDst.get(), resolveResult, ident);
     806    NonlocalResolveInfo resolveVerifier;
     807    RefPtr<RegisterID> base = generator.emitResolveWithBaseForPut(generator.newTemporary(), propDst.get(), resolveResult, ident, resolveVerifier);
    833808    emitPreIncOrDec(generator, propDst.get(), m_operator);
    834     generator.emitPutById(base.get(), ident, propDst.get());
     809    generator.emitPutToBase(base.get(), ident, propDst.get(), resolveVerifier);
    835810    return generator.moveToDestinationIfNeeded(dst, propDst.get());
    836811}
     
    12581233    }
    12591234
    1260     if (resolveResult.isStatic() && !resolveResult.isReadOnly()) {
    1261         RefPtr<RegisterID> src1 = generator.emitGetStaticVar(generator.tempDestination(dst), resolveResult, m_ident);
    1262         RegisterID* result = emitReadModifyAssignment(generator, generator.finalDestination(dst, src1.get()), src1.get(), m_right, m_operator, OperandTypes(ResultType::unknownType(), m_right->resultDescriptor()));
    1263         generator.emitPutStaticVar(resolveResult, m_ident, result);
    1264         return result;
    1265     }
    1266 
    12671235    RefPtr<RegisterID> src1 = generator.tempDestination(dst);
    12681236    generator.emitExpressionInfo(divot() - startOffset() + m_ident.length(), m_ident.length(), 0);
    1269     RefPtr<RegisterID> base = generator.emitResolveWithBase(generator.newTemporary(), src1.get(), resolveResult, m_ident);
     1237    NonlocalResolveInfo resolveVerifier;
     1238    RefPtr<RegisterID> base = generator.emitResolveWithBaseForPut(generator.newTemporary(), src1.get(), resolveResult, m_ident, resolveVerifier);
    12701239    RegisterID* result = emitReadModifyAssignment(generator, generator.finalDestination(dst, src1.get()), src1.get(), m_right, m_operator, OperandTypes(ResultType::unknownType(), m_right->resultDescriptor()), this);
    1271     return generator.emitPutById(base.get(), m_ident, result);
     1240    return generator.emitPutToBase(base.get(), m_ident, result, resolveVerifier);
    12721241}
    12731242
     
    12781247    ResolveResult resolveResult = generator.resolve(m_ident);
    12791248
    1280     if (RegisterID *local = resolveResult.local()) {
     1249    if (RegisterID* local = resolveResult.local()) {
    12811250        if (resolveResult.isReadOnly()) {
    12821251            generator.emitReadOnlyExceptionIfNeeded();
     
    12871256    }
    12881257
    1289     if (resolveResult.isStatic() && !resolveResult.isReadOnly()) {
    1290         if (dst == generator.ignoredResult())
    1291             dst = 0;
    1292         RegisterID* value = generator.emitNode(dst, m_right);
    1293         generator.emitPutStaticVar(resolveResult, m_ident, value);
    1294         return value;
    1295     }
    1296 
    1297     RefPtr<RegisterID> base = generator.emitResolveBaseForPut(generator.newTemporary(), resolveResult, m_ident);
     1258    NonlocalResolveInfo resolveVerifier;
     1259    RefPtr<RegisterID> base = generator.emitResolveBaseForPut(generator.newTemporary(), resolveResult, m_ident, resolveVerifier);
    12981260    if (dst == generator.ignoredResult())
    12991261        dst = 0;
    13001262    RegisterID* value = generator.emitNode(dst, m_right);
    13011263    generator.emitExpressionInfo(divot(), startOffset(), endOffset());
    1302     return generator.emitPutById(base.get(), m_ident, value);
     1264    return generator.emitPutToBase(base.get(), m_ident, value, resolveVerifier);
    13031265}
    13041266
     
    13951357    RefPtr<RegisterID> value = m_init ? generator.emitNode(m_init) : generator.emitLoad(0, jsUndefined());
    13961358
    1397     if (resolveResult.isStatic()) {
    1398         if (generator.codeType() == GlobalCode)
    1399             return generator.emitInitGlobalConst(resolveResult, m_ident, value.get());
    1400         return generator.emitPutStaticVar(resolveResult, m_ident, value.get());
     1359    if (generator.codeType() == GlobalCode) {
     1360        if (RegisterID* result = generator.emitInitGlobalConst(m_ident, value.get()))
     1361            return result;
    14011362    }
    14021363    if (generator.codeType() != EvalCode)
    14031364        return value.get();
    14041365
    1405     // FIXME: While this code should only be hit in an eval block, it will assign
    1406     // to the wrong base if m_ident exists in an intervening with scope.
     1366    // FIXME: This will result in incorrect assignment if m_ident exists in an intervening with scope.
    14071367    RefPtr<RegisterID> base = generator.emitResolveBase(generator.newTemporary(), resolveResult, m_ident);
    14081368    return generator.emitPutById(base.get(), m_ident, value.get());
     
    16921652            propertyName = generator.newTemporary();
    16931653            RefPtr<RegisterID> protect = propertyName;
    1694             RegisterID* base = generator.emitResolveBaseForPut(generator.newTemporary(), resolveResult, ident);
     1654            NonlocalResolveInfo resolveVerifier;
     1655            RegisterID* base = generator.emitResolveBaseForPut(generator.newTemporary(), resolveResult, ident, resolveVerifier);
    16951656
    16961657            generator.emitExpressionInfo(divot(), startOffset(), endOffset());
    1697             generator.emitPutById(base, ident, propertyName);
     1658            generator.emitPutToBase(base, ident, propertyName, resolveVerifier);
    16981659        } else {
    16991660            expectedSubscript = generator.emitMove(generator.newTemporary(), propertyName);
Note: See TracChangeset for help on using the changeset viewer.