Ignore:
Timestamp:
Aug 14, 2014, 4:59:44 PM (11 years ago)
Author:
[email protected]
Message:

Allow high fidelity type profiling to be enabled and disabled.
https://bugs.webkit.org/show_bug.cgi?id=135423

Patch by Saam Barati <[email protected]> on 2014-08-14
Reviewed by Geoffrey Garen.

Source/JavaScriptCore:

  • Merged op_put_to_scope_with_profile and op_get_from_scope_with_profile into op_profile_types_with_high_fidelity by adding extra arguments to the opcode.
  • Altered SymbolTable to use less memory by adding a rare data structure for type profiling.
  • Created an interface to turn on and off type profiling from the Web Inspector.
  • Refactored how entries are written to HighFidelityLog to make it easier to inline when generating machine code.
  • Implemented op_profile_types_with_high_fidelity in the baseline JIT by inlining the process of writing to the log and doing a small amount of type inference optimizations.
  • bytecode/BytecodeList.json:
  • bytecode/BytecodeUseDef.h:

(JSC::computeUsesForBytecodeOffset):
(JSC::computeDefsForBytecodeOffset):

  • bytecode/CodeBlock.cpp:

(JSC::CodeBlock::dumpBytecode):
(JSC::CodeBlock::CodeBlock):
(JSC::CodeBlock::finalizeUnconditionally):
(JSC::CodeBlock::scopeDependentProfile): Deleted.

  • bytecode/CodeBlock.h:
  • bytecode/TypeLocation.h:

(JSC::TypeLocation::TypeLocation):

  • bytecompiler/BytecodeGenerator.cpp:

(JSC::BytecodeGenerator::generate):
(JSC::BytecodeGenerator::emitMove):
(JSC::BytecodeGenerator::emitProfileTypesWithHighFidelity):
(JSC::BytecodeGenerator::emitGetFromScopeWithProfile): Deleted.
(JSC::BytecodeGenerator::emitPutToScopeWithProfile): Deleted.

  • bytecompiler/BytecodeGenerator.h:
  • bytecompiler/NodesCodegen.cpp:

(JSC::ThisNode::emitBytecode):
(JSC::ResolveNode::emitBytecode):
(JSC::BracketAccessorNode::emitBytecode):
(JSC::DotAccessorNode::emitBytecode):
(JSC::FunctionCallValueNode::emitBytecode):
(JSC::FunctionCallResolveNode::emitBytecode):
(JSC::FunctionCallBracketNode::emitBytecode):
(JSC::FunctionCallDotNode::emitBytecode):
(JSC::CallFunctionCallDotNode::emitBytecode):
(JSC::ApplyFunctionCallDotNode::emitBytecode):
(JSC::PostfixNode::emitResolve):
(JSC::PostfixNode::emitBracket):
(JSC::PostfixNode::emitDot):
(JSC::PrefixNode::emitResolve):
(JSC::PrefixNode::emitBracket):
(JSC::PrefixNode::emitDot):
(JSC::ReadModifyResolveNode::emitBytecode):
(JSC::AssignResolveNode::emitBytecode):
(JSC::AssignDotNode::emitBytecode):
(JSC::ReadModifyDotNode::emitBytecode):
(JSC::AssignBracketNode::emitBytecode):
(JSC::ReadModifyBracketNode::emitBytecode):
(JSC::ReturnNode::emitBytecode):
(JSC::FunctionBodyNode::emitBytecode):

  • inspector/agents/InspectorRuntimeAgent.cpp:

(Inspector::InspectorRuntimeAgent::InspectorRuntimeAgent):
(Inspector::InspectorRuntimeAgent::getRuntimeTypesForVariablesAtOffsets):
(Inspector::TypeRecompiler::operator()):
(Inspector::recompileAllJSFunctionsForTypeProfiling):
(Inspector::InspectorRuntimeAgent::willDestroyFrontendAndBackend):
(Inspector::InspectorRuntimeAgent::enableHighFidelityTypeProfiling):
(Inspector::InspectorRuntimeAgent::disableHighFidelityTypeProfiling):
(Inspector::InspectorRuntimeAgent::setHighFidelityTypeProfilingEnabledState):

  • inspector/agents/InspectorRuntimeAgent.h:
  • inspector/agents/JSGlobalObjectRuntimeAgent.cpp:

(Inspector::JSGlobalObjectRuntimeAgent::willDestroyFrontendAndBackend):

  • inspector/protocol/Runtime.json:
  • jit/JIT.cpp:

(JSC::JIT::privateCompileMainPass):
(JSC::JIT::privateCompile):

  • jit/JIT.h:
  • jit/JITOpcodes.cpp:

(JSC::JIT::emit_op_profile_types_with_high_fidelity):

  • jit/JITOpcodes32_64.cpp:

(JSC::JIT::emit_op_profile_types_with_high_fidelity):

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

(JSC::LLInt::LLINT_SLOW_PATH_DECL):
(JSC::LLInt::getFromScopeCommon): Deleted.
(JSC::LLInt::putToScopeCommon): Deleted.

  • llint/LLIntSlowPaths.h:
  • llint/LowLevelInterpreter.asm:
  • runtime/CodeCache.cpp:

(JSC::CodeCache::getGlobalCodeBlock):

  • runtime/CommonSlowPaths.cpp:

(JSC::SLOW_PATH_DECL):

  • runtime/CommonSlowPaths.h:
  • runtime/HighFidelityLog.cpp:

(JSC::HighFidelityLog::initializeHighFidelityLog):
(JSC::HighFidelityLog::~HighFidelityLog):
(JSC::HighFidelityLog::processHighFidelityLog):

  • runtime/HighFidelityLog.h:

(JSC::HighFidelityLog::LogEntry::structureIDOffset):
(JSC::HighFidelityLog::LogEntry::valueOffset):
(JSC::HighFidelityLog::LogEntry::locationOffset):
(JSC::HighFidelityLog::recordTypeInformationForLocation):
(JSC::HighFidelityLog::logEndPtr):
(JSC::HighFidelityLog::logStartOffset):
(JSC::HighFidelityLog::currentLogEntryOffset):

  • runtime/HighFidelityTypeProfiler.cpp:

(JSC::HighFidelityTypeProfiler::logTypesForTypeLocation):
(JSC::descriptorMatchesTypeLocation):

  • runtime/HighFidelityTypeProfiler.h:
  • runtime/SymbolTable.cpp:

(JSC::SymbolTable::SymbolTable):
(JSC::SymbolTable::cloneCapturedNames):
(JSC::SymbolTable::prepareForHighFidelityTypeProfiling):
(JSC::SymbolTable::uniqueIDForVariable):
(JSC::SymbolTable::uniqueIDForRegister):
(JSC::SymbolTable::globalTypeSetForRegister):
(JSC::SymbolTable::globalTypeSetForVariable):

  • runtime/SymbolTable.h:

(JSC::SymbolTable::add):
(JSC::SymbolTable::set):

  • runtime/TypeLocationCache.cpp:

(JSC::TypeLocationCache::getTypeLocation):

  • runtime/TypeSet.cpp:

(JSC::TypeSet::getRuntimeTypeForValue):
(JSC::TypeSet::addTypeInformation):
(JSC::TypeSet::allPrimitiveTypeNames):
(JSC::TypeSet::addTypeForValue): Deleted.

  • runtime/TypeSet.h:
  • runtime/VM.cpp:

(JSC::VM::VM):
(JSC::VM::nextTypeLocation):
(JSC::VM::enableHighFidelityTypeProfiling):
(JSC::VM::disableHighFidelityTypeProfiling):
(JSC::VM::dumpHighFidelityProfilingTypes):

  • runtime/VM.h:

(JSC::VM::nextLocation): Deleted.

Source/WebCore:

PageRuntimeAgent and WorkerRuntimeAgent now call their super
class's (InspectorRuntimeAgent) implementation of willDestroyFrontendAndBackend
to give InspectorRuntimeAgent a chance to recompile all JavaScript
functions, if necessary, for type profiling.

  • inspector/PageRuntimeAgent.cpp:

(WebCore::PageRuntimeAgent::willDestroyFrontendAndBackend):

  • inspector/WorkerRuntimeAgent.cpp:

(WebCore::WorkerRuntimeAgent::willDestroyFrontendAndBackend):

Location:
trunk/Source/JavaScriptCore/bytecode
Files:
5 edited

Legend:

Unmodified
Added
Removed
  • trunk/Source/JavaScriptCore/bytecode/BytecodeList.json

    r172176 r172614  
    110110            { "name" : "op_resolve_scope", "length" : 6 },
    111111            { "name" : "op_get_from_scope", "length" : 8 },
    112             { "name" : "op_get_from_scope_with_profile", "length" : 9 },
    113112            { "name" : "op_put_to_scope", "length" : 7 },
    114             { "name" : "op_put_to_scope_with_profile", "length" : 8 },
    115113            { "name" : "op_push_with_scope", "length" : 2 },
    116114            { "name" : "op_pop_scope", "length" : 1 },
     
    123121            { "name" : "op_profile_did_call", "length" : 2 },
    124122            { "name" : "op_end", "length" : 2 },
    125             { "name" : "op_profile_types_with_high_fidelity", "length" : 4 },
     123            { "name" : "op_profile_types_with_high_fidelity", "length" : 6 },
    126124            { "name" : "op_get_enumerable_length", "length" : 3 },
    127125            { "name" : "op_has_indexed_property", "length" : 5 },
  • trunk/Source/JavaScriptCore/bytecode/BytecodeUseDef.h

    r172176 r172614  
    107107    case op_put_by_id_out_of_line:
    108108    case op_put_by_id:
    109     case op_put_to_scope_with_profile:
    110109    case op_put_to_scope: {
    111110        functor(codeBlock, instruction, opcodeID, instruction[1].u.operand);
     
    124123    case op_init_global_const:
    125124    case op_push_name_scope:
    126     case op_get_from_scope_with_profile:
    127125    case op_get_from_scope:
    128126    case op_to_primitive:
     
    252250    case op_push_with_scope:
    253251    case op_put_to_scope:
    254     case op_put_to_scope_with_profile:
    255252    case op_pop_scope:
    256253    case op_end:
     
    322319    case op_call_varargs:
    323320    case op_construct_varargs:
    324     case op_get_from_scope_with_profile:
    325321    case op_get_from_scope:
    326322    case op_call:
  • trunk/Source/JavaScriptCore/bytecode/CodeBlock.cpp

    r172176 r172614  
    15241524            break;
    15251525        }
    1526         case op_put_to_scope_with_profile:
    15271526        case op_put_to_scope: {
    15281527            int r0 = (++it)->u.operand;
     
    15331532            int operand = (++it)->u.operand; // Operand
    15341533            printLocationAndOp(out, exec, location, it, "put_to_scope");
    1535             if (opcode == op_put_to_scope_with_profile)
    1536                 ++it;
    15371534            out.printf("%s, %s, %s, %u<%s|%s>, <structure>, %d",
    15381535                registerName(r0).data(), idName(id0, identifier(id0)).data(), registerName(r1).data(),
     
    17171714   
    17181715    if (SymbolTable* symbolTable = unlinkedCodeBlock->symbolTable()) {
     1716        if (m_vm->isProfilingTypesWithHighFidelity()) {
     1717            ConcurrentJITLocker locker(symbolTable->m_lock);
     1718            symbolTable->prepareForHighFidelityTypeProfiling(locker);
     1719        }
     1720
    17191721        if (codeType() == FunctionCode && symbolTable->captureCount()) {
    17201722            m_symbolTable.set(*m_vm, m_ownerExecutable.get(), symbolTable->cloneCapturedNames(*m_vm));
     
    19501952        }
    19511953
    1952         case op_get_from_scope_with_profile:
    19531954        case op_get_from_scope: {
    1954             int offset = (pc[0].u.opcode == op_get_from_scope_with_profile ? 2 : 1);
    1955             ValueProfile* profile = &m_valueProfiles[pc[opLength - offset].u.operand];
     1955            ValueProfile* profile = &m_valueProfiles[pc[opLength - 1].u.operand];
    19561956            ASSERT(profile->m_bytecodeOffset == -1);
    19571957            profile->m_bytecodeOffset = i;
    1958             instructions[i + opLength - offset] = profile;
     1958            instructions[i + opLength - 1] = profile;
    19591959
    19601960            // get_from_scope dst, scope, id, ResolveModeAndType, Structure, Operand
     
    19701970            instructions[i + 6].u.pointer = reinterpret_cast<void*>(op.operand);
    19711971
    1972             if (pc[0].u.opcode == op_get_from_scope_with_profile) {
    1973                 // The format of this instruction is: get_from_scope_with_profile dst, scope, id, ResolveModeAndType, Structure, Operand, ..., TypeLocation
    1974                 size_t instructionOffset = i + opLength - 1;
    1975                 TypeLocation* location = scopeDependentProfile(op, ident, instructionOffset);
    1976                 instructions[i + 8].u.location = location;
    1977             }
    1978             break;
    1979         }
    1980 
    1981         case op_put_to_scope_with_profile:
     1972            break;
     1973        }
     1974
    19821975        case op_put_to_scope: {
    19831976            // put_to_scope scope, id, value, ResolveModeAndType, Structure, Operand
     
    19961989            instructions[i + 6].u.pointer = reinterpret_cast<void*>(op.operand);
    19971990
    1998             if (pc[0].u.opcode == op_put_to_scope_with_profile) {
    1999                 // The format of this instruction is: put_to_scope_with_profile scope, id, value, ResolveModeAndType, Structure, Operand, TypeLocation*
    2000                 size_t instructionOffset = i + opLength - 1;
    2001                 TypeLocation* location = scopeDependentProfile(op, ident, instructionOffset);
    2002                 instructions[i + 7].u.location = location;
    2003             }
    20041991            break;
    20051992        }
    20061993
    20071994        case op_profile_types_with_high_fidelity: {
     1995            // The format of this instruction is: op_profile_types_with_high_fidelity regToProfile, TypeLocation*, flag, identifier?, resolveType?
    20081996            size_t instructionOffset = i + opLength - 1;
    20091997            unsigned divotStart, divotEnd;
     
    20111999            RefPtr<TypeSet> globalTypeSet;
    20122000            bool shouldAnalyze = m_unlinkedCode->highFidelityTypeProfileExpressionInfoForBytecodeOffset(instructionOffset, divotStart, divotEnd);
    2013             VirtualRegister virtualRegister(pc[1].u.operand);
    2014             SymbolTable* symbolTable = m_symbolTable.get();
    2015 
     2001            VirtualRegister profileRegister(pc[1].u.operand);
    20162002            ProfileTypesWithHighFidelityBytecodeFlag flag = static_cast<ProfileTypesWithHighFidelityBytecodeFlag>(pc[3].u.operand);
     2003            SymbolTable* symbolTable = nullptr;
     2004
    20172005            switch (flag) {
     2006            case ProfileTypesBytecodePutToScope:
     2007            case ProfileTypesBytecodeGetFromScope: {
     2008                const Identifier& ident = identifier(pc[4].u.operand);
     2009                ResolveType type = static_cast<ResolveType>(pc[5].u.operand);
     2010                ResolveOp op = JSScope::abstractResolve(m_globalObject->globalExec(), scope, ident, (flag == ProfileTypesBytecodeGetFromScope ? Get : Put), type);
     2011
     2012                // FIXME: handle other values for op.type here, and also consider what to do when we can't statically determine the globalID
     2013                // https://bugs.webkit.org/show_bug.cgi?id=135184
     2014                if (op.type == ClosureVar)
     2015                    symbolTable = op.activation->symbolTable();
     2016                else if (op.type == GlobalVar)
     2017                    symbolTable = m_globalObject.get()->symbolTable();
     2018               
     2019                if (symbolTable) {
     2020                    ConcurrentJITLocker locker(symbolTable->m_lock);
     2021                    // If our parent scope was created while profiling was disabled, it will not have prepared for profiling yet.
     2022                    symbolTable->prepareForHighFidelityTypeProfiling(locker);
     2023                    globalVariableID = symbolTable->uniqueIDForVariable(locker, ident.impl(), *vm());
     2024                    globalTypeSet = symbolTable->globalTypeSetForVariable(locker, ident.impl(), *vm());
     2025                } else
     2026                    globalVariableID = HighFidelityNoGlobalIDExists;
     2027
     2028                break;
     2029            }
    20182030            case ProfileTypesBytecodeHasGlobalID: {
     2031                symbolTable = m_symbolTable.get();
    20192032                ConcurrentJITLocker locker(symbolTable->m_lock);
    2020                 globalVariableID = symbolTable->uniqueIDForRegister(locker, virtualRegister.offset(), *vm());
    2021                 globalTypeSet = symbolTable->globalTypeSetForRegister(locker, virtualRegister.offset(), *vm());
     2033                globalVariableID = symbolTable->uniqueIDForRegister(locker, profileRegister.offset(), *vm());
     2034                globalTypeSet = symbolTable->globalTypeSetForRegister(locker, profileRegister.offset(), *vm());
    20222035                break;
    20232036            }
     
    20252038            case ProfileTypesBytecodeFunctionArgument: {
    20262039                globalVariableID = HighFidelityNoGlobalIDExists;
    2027                 break;
    2028             }
    2029             case ProfileTypesBytecodeFunctionThisObject: {
    2030                 globalVariableID = HighFidelityThisStatement;
    20312040                break;
    20322041            }
     
    20442053            }
    20452054
    2046             std::pair<TypeLocation*, bool> locationPair = vm()->highFidelityTypeProfiler()->typeLocationCache()->getTypeLocation(globalVariableID, m_ownerExecutable->sourceID(), divotStart, divotEnd, globalTypeSet, vm());
     2055            std::pair<TypeLocation*, bool> locationPair = vm()->highFidelityTypeProfiler()->typeLocationCache()->getTypeLocation(globalVariableID,
     2056                m_ownerExecutable->sourceID(), divotStart, divotEnd, globalTypeSet, vm());
    20472057            TypeLocation* location = locationPair.first;
    20482058            bool isNewLocation = locationPair.second;
     
    25252535                break;
    25262536            }
    2527             case op_get_from_scope_with_profile:
    25282537            case op_get_from_scope:
    2529             case op_put_to_scope_with_profile:
    25302538            case op_put_to_scope: {
    25312539                ResolveModeAndType modeAndType =
     
    39363944#endif
    39373945
    3938 TypeLocation* CodeBlock::scopeDependentProfile(ResolveOp op, const Identifier& ident, size_t instructionOffset)
    3939 {
    3940     unsigned divotStart, divotEnd;
    3941     bool shouldAnalyze = m_unlinkedCode->highFidelityTypeProfileExpressionInfoForBytecodeOffset(instructionOffset, divotStart, divotEnd);
    3942     GlobalVariableID globalVariableID;
    3943     RefPtr<TypeSet> globalTypeSet;
    3944 
    3945     // FIXME: handle other values for op.type here, and also consider what to do when we can't statically determine the globalID
    3946     SymbolTable* symbolTable = nullptr;
    3947     if (op.type == ClosureVar)
    3948         symbolTable = op.activation->symbolTable();
    3949     else if (op.type == GlobalVar)
    3950         symbolTable = m_globalObject.get()->symbolTable();
    3951    
    3952     if (symbolTable) {
    3953         ConcurrentJITLocker locker(symbolTable->m_lock);
    3954         globalVariableID = symbolTable->uniqueIDForVariable(locker, ident.impl(), *vm());
    3955         globalTypeSet = symbolTable->globalTypeSetForVariable(locker, ident.impl(), *vm());
    3956     } else
    3957         globalVariableID = HighFidelityNoGlobalIDExists;
    3958 
    3959     std::pair<TypeLocation*, bool> locationPair = vm()->highFidelityTypeProfiler()->typeLocationCache()->getTypeLocation(globalVariableID, m_ownerExecutable->sourceID(), divotStart, divotEnd, globalTypeSet, vm());
    3960     TypeLocation* location = locationPair.first;
    3961     bool isNewLocation = locationPair.second;
    3962 
    3963     if (shouldAnalyze & isNewLocation)
    3964         vm()->highFidelityTypeProfiler()->insertNewLocation(location);
    3965 
    3966     return location;
    3967 }
    3968 
    39693946} // namespace JSC
  • trunk/Source/JavaScriptCore/bytecode/CodeBlock.h

    r172176 r172614  
    10211021    }
    10221022
    1023     TypeLocation* scopeDependentProfile(ResolveOp, const Identifier&, size_t);
    1024    
    10251023#if ENABLE(JIT)
    10261024    void resetStubInternal(RepatchBuffer&, StructureStubInfo&);
  • trunk/Source/JavaScriptCore/bytecode/TypeLocation.h

    r172176 r172614  
    3434    HighFidelityNeedsUniqueIDGeneration = -1,
    3535    HighFidelityNoGlobalIDExists = -2,
    36     HighFidelityReturnStatement = -3,
    37     HighFidelityThisStatement = -4
     36    HighFidelityReturnStatement = -3
    3837};
    3938
     
    4241class TypeLocation {
    4342public:
    44     TypeLocation()
    45         : m_divotForFunctionOffsetIfReturnStatement(UINT_MAX)
     43    TypeLocation()
     44        : m_lastSeenType(TypeNothing)
     45        , m_divotForFunctionOffsetIfReturnStatement(UINT_MAX)
    4646        , m_instructionTypeSet(TypeSet::create())
    4747        , m_globalTypeSet(nullptr)
     
    5050
    5151    GlobalVariableID m_globalVariableID;
     52    RuntimeType m_lastSeenType;
    5253    intptr_t m_sourceID;
    5354    unsigned m_divotStart;
Note: See TracChangeset for help on using the changeset viewer.