diff options
Diffstat (limited to 'Source/JavaScriptCore/bytecode/CodeBlock.h')
-rw-r--r-- | Source/JavaScriptCore/bytecode/CodeBlock.h | 1061 |
1 files changed, 461 insertions, 600 deletions
diff --git a/Source/JavaScriptCore/bytecode/CodeBlock.h b/Source/JavaScriptCore/bytecode/CodeBlock.h index 96cee40c7..0d9868079 100644 --- a/Source/JavaScriptCore/bytecode/CodeBlock.h +++ b/Source/JavaScriptCore/bytecode/CodeBlock.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2008-2015 Apple Inc. All rights reserved. + * Copyright (C) 2008, 2009, 2010, 2011, 2012, 2013, 2014 Apple Inc. All rights reserved. * Copyright (C) 2008 Cameron Zwarich <cwzwarich@uwaterloo.ca> * * Redistribution and use in source and binary forms, with or without @@ -11,7 +11,7 @@ * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. - * 3. Neither the name of Apple Inc. ("Apple") nor the names of + * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of * its contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * @@ -38,30 +38,34 @@ #include "CallReturnOffsetToBytecodeOffset.h" #include "CodeBlockHash.h" #include "CodeBlockSet.h" +#include "ConcurrentJITLock.h" #include "CodeOrigin.h" #include "CodeType.h" #include "CompactJITCodeMap.h" -#include "ConcurrentJITLock.h" #include "DFGCommon.h" +#include "DFGCommonData.h" #include "DFGExitProfile.h" +#include "DFGMinifiedGraph.h" +#include "DFGOSREntry.h" +#include "DFGOSRExit.h" +#include "DFGVariableEventStream.h" #include "DeferredCompilationCallback.h" #include "EvalCodeCache.h" #include "ExecutionCounter.h" #include "ExpressionRangeInfo.h" #include "HandlerInfo.h" +#include "ObjectAllocationProfile.h" +#include "Options.h" +#include "Operations.h" +#include "PutPropertySlot.h" #include "Instruction.h" #include "JITCode.h" #include "JITWriteBarrier.h" -#include "JSCell.h" #include "JSGlobalObject.h" #include "JumpTable.h" #include "LLIntCallLinkInfo.h" #include "LazyOperandValueProfile.h" -#include "ObjectAllocationProfile.h" -#include "Options.h" #include "ProfilerCompilation.h" -#include "ProfilerJettisonReason.h" -#include "PutPropertySlot.h" #include "RegExpObject.h" #include "StructureStubInfo.h" #include "UnconditionalFinalizer.h" @@ -69,8 +73,8 @@ #include "VirtualRegister.h" #include "Watchpoint.h" #include <wtf/Bag.h> -#include <wtf/FastBitVector.h> #include <wtf/FastMalloc.h> +#include <wtf/PassOwnPtr.h> #include <wtf/RefCountedArray.h> #include <wtf/RefPtr.h> #include <wtf/SegmentedVector.h> @@ -81,51 +85,31 @@ namespace JSC { class ExecState; class LLIntOffsetsExtractor; -class RegisterAtOffsetList; -class TypeLocation; -class JSModuleEnvironment; -class PCToCodeOriginMap; +class RepatchBuffer; + +inline VirtualRegister unmodifiedArgumentsRegister(VirtualRegister argumentsRegister) { return VirtualRegister(argumentsRegister.offset() + 1); } + +static ALWAYS_INLINE int missingThisObjectMarker() { return std::numeric_limits<int>::max(); } enum ReoptimizationMode { DontCountReoptimization, CountReoptimization }; -class CodeBlock : public JSCell { - typedef JSCell Base; +class CodeBlock : public ThreadSafeRefCounted<CodeBlock>, public UnconditionalFinalizer, public WeakReferenceHarvester { + WTF_MAKE_FAST_ALLOCATED; friend class BytecodeLivenessAnalysis; friend class JIT; friend class LLIntOffsetsExtractor; - - class UnconditionalFinalizer : public JSC::UnconditionalFinalizer { - virtual void finalizeUnconditionally() override; - }; - - class WeakReferenceHarvester : public JSC::WeakReferenceHarvester { - virtual void visitWeakReferences(SlotVisitor&) override; - }; - public: enum CopyParsedBlockTag { CopyParsedBlock }; - - static const unsigned StructureFlags = Base::StructureFlags | StructureIsImmortal; - - DECLARE_INFO; - protected: - CodeBlock(VM*, Structure*, CopyParsedBlockTag, CodeBlock& other); - CodeBlock(VM*, Structure*, ScriptExecutable* ownerExecutable, UnlinkedCodeBlock*, JSScope*, PassRefPtr<SourceProvider>, unsigned sourceOffset, unsigned firstLineColumnOffset); -#if ENABLE(WEBASSEMBLY) - CodeBlock(VM*, Structure*, WebAssemblyExecutable* ownerExecutable, JSGlobalObject*); -#endif - - void finishCreation(VM&, CopyParsedBlockTag, CodeBlock& other); - void finishCreation(VM&, ScriptExecutable* ownerExecutable, UnlinkedCodeBlock*, JSScope*); -#if ENABLE(WEBASSEMBLY) - void finishCreation(VM&, WebAssemblyExecutable* ownerExecutable, JSGlobalObject*); -#endif + CodeBlock(CopyParsedBlockTag, CodeBlock& other); + + CodeBlock(ScriptExecutable* ownerExecutable, UnlinkedCodeBlock*, JSScope*, PassRefPtr<SourceProvider>, unsigned sourceOffset, unsigned firstLineColumnOffset); WriteBarrier<JSGlobalObject> m_globalObject; + Heap* m_heap; public: - JS_EXPORT_PRIVATE ~CodeBlock(); + JS_EXPORT_PRIVATE virtual ~CodeBlock(); UnlinkedCodeBlock* unlinkedCodeBlock() const { return m_unlinkedCode.get(); } @@ -133,7 +117,6 @@ public: CodeBlockHash hash() const; bool hasHash() const; bool isSafeToComputeHash() const; - CString hashAsStringIfPossible() const; CString sourceCodeForTools() const; // Not quite the actual source we parsed; this will do things like prefix the source for a function with a reified signature. CString sourceCodeOnOneLine() const; // As sourceCodeForTools(), but replaces all whitespace runs with a single space. void dumpAssumingJITType(PrintStream&, JITCode::JITType) const; @@ -142,58 +125,28 @@ public: int numParameters() const { return m_numParameters; } void setNumParameters(int newValue); - int numCalleeLocals() const { return m_numCalleeLocals; } - int* addressOfNumParameters() { return &m_numParameters; } static ptrdiff_t offsetOfNumParameters() { return OBJECT_OFFSETOF(CodeBlock, m_numParameters); } - CodeBlock* alternative() const { return static_cast<CodeBlock*>(m_alternative.get()); } - void setAlternative(VM&, CodeBlock*); - - template <typename Functor> void forEachRelatedCodeBlock(Functor&& functor) - { - Functor f(std::forward<Functor>(functor)); - Vector<CodeBlock*, 4> codeBlocks; - codeBlocks.append(this); - - while (!codeBlocks.isEmpty()) { - CodeBlock* currentCodeBlock = codeBlocks.takeLast(); - f(currentCodeBlock); - - if (CodeBlock* alternative = currentCodeBlock->alternative()) - codeBlocks.append(alternative); - if (CodeBlock* osrEntryBlock = currentCodeBlock->specialOSREntryBlockOrNull()) - codeBlocks.append(osrEntryBlock); - } - } + CodeBlock* alternative() { return m_alternative.get(); } + PassRefPtr<CodeBlock> releaseAlternative() { return m_alternative.release(); } + void setAlternative(PassRefPtr<CodeBlock> alternative) { m_alternative = alternative; } CodeSpecializationKind specializationKind() const { return specializationFromIsConstruct(m_isConstructor); } - - CodeBlock* alternativeForJettison(); - JS_EXPORT_PRIVATE CodeBlock* baselineAlternative(); + + CodeBlock* baselineAlternative(); // FIXME: Get rid of this. // https://bugs.webkit.org/show_bug.cgi?id=123677 CodeBlock* baselineVersion(); - static size_t estimatedSize(JSCell*); - static void visitChildren(JSCell*, SlotVisitor&); - void visitChildren(SlotVisitor&); - void visitWeakly(SlotVisitor&); - void clearVisitWeaklyHasBeenCalled(); - - void dumpSource(); - void dumpSource(PrintStream&); - - void dumpBytecode(); - void dumpBytecode(PrintStream&); - void dumpBytecode( - PrintStream&, unsigned bytecodeOffset, - const StubInfoMap& = StubInfoMap(), const CallLinkInfoMap& = CallLinkInfoMap()); - void dumpExceptionHandlers(PrintStream&); + void visitAggregate(SlotVisitor&); + + void dumpBytecode(PrintStream& = WTF::dataFile()); + void dumpBytecode(PrintStream&, unsigned bytecodeOffset); void printStructures(PrintStream&, const Instruction*); void printStructure(PrintStream&, const char* name, const Instruction*, int operand); @@ -216,72 +169,72 @@ public: return index >= m_numVars; } - enum class RequiredHandler { - CatchHandler, - AnyHandler - }; - HandlerInfo* handlerForBytecodeOffset(unsigned bytecodeOffset, RequiredHandler = RequiredHandler::AnyHandler); - HandlerInfo* handlerForIndex(unsigned, RequiredHandler = RequiredHandler::AnyHandler); - void removeExceptionHandlerForCallSite(CallSiteIndex); + HandlerInfo* handlerForBytecodeOffset(unsigned bytecodeOffset); unsigned lineNumberForBytecodeOffset(unsigned bytecodeOffset); unsigned columnNumberForBytecodeOffset(unsigned bytecodeOffset); void expressionRangeForBytecodeOffset(unsigned bytecodeOffset, int& divot, int& startOffset, int& endOffset, unsigned& line, unsigned& column); - void getStubInfoMap(const ConcurrentJITLocker&, StubInfoMap& result); - void getStubInfoMap(StubInfoMap& result); - - void getCallLinkInfoMap(const ConcurrentJITLocker&, CallLinkInfoMap& result); - void getCallLinkInfoMap(CallLinkInfoMap& result); - - void getByValInfoMap(const ConcurrentJITLocker&, ByValInfoMap& result); - void getByValInfoMap(ByValInfoMap& result); - #if ENABLE(JIT) - StructureStubInfo* addStubInfo(AccessType); - Bag<StructureStubInfo>::iterator stubInfoBegin() { return m_stubInfos.begin(); } - Bag<StructureStubInfo>::iterator stubInfoEnd() { return m_stubInfos.end(); } + StructureStubInfo* addStubInfo(); + Bag<StructureStubInfo>::iterator begin() { return m_stubInfos.begin(); } + Bag<StructureStubInfo>::iterator end() { return m_stubInfos.end(); } + + void resetStub(StructureStubInfo&); - // O(n) operation. Use getStubInfoMap() unless you really only intend to get one - // stub info. - StructureStubInfo* findStubInfo(CodeOrigin); + void getStubInfoMap(const ConcurrentJITLocker&, StubInfoMap& result); - ByValInfo* addByValInfo(); + ByValInfo& getByValInfo(unsigned bytecodeIndex) + { + return *(binarySearch<ByValInfo, unsigned>(m_byValInfos, m_byValInfos.size(), bytecodeIndex, getByValInfoBytecodeIndex)); + } - CallLinkInfo* addCallLinkInfo(); - Bag<CallLinkInfo>::iterator callLinkInfosBegin() { return m_callLinkInfos.begin(); } - Bag<CallLinkInfo>::iterator callLinkInfosEnd() { return m_callLinkInfos.end(); } + CallLinkInfo& getCallLinkInfo(ReturnAddressPtr returnAddress) + { + return *(binarySearch<CallLinkInfo, void*>(m_callLinkInfos, m_callLinkInfos.size(), returnAddress.value(), getCallLinkInfoReturnLocation)); + } - // This is a slow function call used primarily for compiling OSR exits in the case - // that there had been inlining. Chances are if you want to use this, you're really - // looking for a CallLinkInfoMap to amortize the cost of calling this. - CallLinkInfo* getCallLinkInfoForBytecodeIndex(unsigned bytecodeIndex); + CallLinkInfo& getCallLinkInfo(unsigned bytecodeIndex) + { + ASSERT(!JITCode::isOptimizingJIT(jitType())); + return *(binarySearch<CallLinkInfo, unsigned>(m_callLinkInfos, m_callLinkInfos.size(), bytecodeIndex, getCallLinkInfoBytecodeIndex)); + } #endif // ENABLE(JIT) void unlinkIncomingCalls(); #if ENABLE(JIT) + void unlinkCalls(); + void linkIncomingCall(ExecState* callerFrame, CallLinkInfo*); - void linkIncomingPolymorphicCall(ExecState* callerFrame, PolymorphicCallNode*); + + bool isIncomingCallAlreadyLinked(CallLinkInfo* incoming) + { + return m_incomingCalls.isOnList(incoming); + } #endif // ENABLE(JIT) +#if ENABLE(LLINT) void linkIncomingCall(ExecState* callerFrame, LLIntCallLinkInfo*); +#endif // ENABLE(LLINT) - void setJITCodeMap(std::unique_ptr<CompactJITCodeMap> jitCodeMap) + void setJITCodeMap(PassOwnPtr<CompactJITCodeMap> jitCodeMap) { - m_jitCodeMap = WTFMove(jitCodeMap); + m_jitCodeMap = jitCodeMap; } CompactJITCodeMap* jitCodeMap() { return m_jitCodeMap.get(); } - + unsigned bytecodeOffset(Instruction* returnAddress) { RELEASE_ASSERT(returnAddress >= instructions().begin() && returnAddress < instructions().end()); return static_cast<Instruction*>(returnAddress) - instructions().begin(); } + bool isNumericCompareFunction() { return m_unlinkedCode->isNumericCompareFunction(); } + unsigned numberOfInstructions() const { return m_instructions.size(); } RefCountedArray<Instruction>& instructions() { return m_instructions; } const RefCountedArray<Instruction>& instructions() const { return m_instructions; } @@ -292,19 +245,28 @@ public: unsigned instructionCount() const { return m_instructions.size(); } + int argumentIndexAfterCapture(size_t argument); + + bool hasSlowArguments(); + const SlowArgument* machineSlowArguments(); + + // Exactly equivalent to codeBlock->ownerExecutable()->installCode(codeBlock); + void install(); + // Exactly equivalent to codeBlock->ownerExecutable()->newReplacementCodeBlockFor(codeBlock->specializationKind()) - CodeBlock* newReplacement(); + PassRefPtr<CodeBlock> newReplacement(); - void setJITCode(PassRefPtr<JITCode> code) + void setJITCode(PassRefPtr<JITCode> code, MacroAssemblerCodePtr codeWithArityCheck) { - ASSERT(heap()->isDeferred()); - heap()->reportExtraMemoryAllocated(code->size()); + ASSERT(m_heap->isDeferred()); + m_heap->reportExtraMemoryCost(code->size()); ConcurrentJITLocker locker(m_lock); WTF::storeStoreFence(); // This is probably not needed because the lock will also do something similar, but it's good to be paranoid. m_jitCode = code; + m_jitCodeWithArityCheck = codeWithArityCheck; } PassRefPtr<JITCode> jitCode() { return m_jitCode; } - static ptrdiff_t jitCodeOffset() { return OBJECT_OFFSETOF(CodeBlock, m_jitCode); } + MacroAssemblerCodePtr jitCodeWithArityCheck() { return m_jitCodeWithArityCheck; } JITCode::JITType jitType() const { JITCode* jitCode = m_jitCode.get(); @@ -320,20 +282,24 @@ public: } #if ENABLE(JIT) - CodeBlock* replacement(); + virtual CodeBlock* replacement() = 0; - DFG::CapabilityLevel computeCapabilityLevel(); - DFG::CapabilityLevel capabilityLevel(); - DFG::CapabilityLevel capabilityLevelState() { return static_cast<DFG::CapabilityLevel>(m_capabilityLevelState); } + virtual DFG::CapabilityLevel capabilityLevelInternal() = 0; + DFG::CapabilityLevel capabilityLevel() + { + DFG::CapabilityLevel result = capabilityLevelInternal(); + m_capabilityLevelState = result; + return result; + } + DFG::CapabilityLevel capabilityLevelState() { return m_capabilityLevelState; } bool hasOptimizedReplacement(JITCode::JITType typeToReplace); bool hasOptimizedReplacement(); // the typeToReplace is my JITType #endif - void jettison(Profiler::JettisonReason, ReoptimizationMode = DontCountReoptimization, const FireDetail* = nullptr); + void jettison(ReoptimizationMode = DontCountReoptimization); - ExecutableBase* ownerExecutable() const { return m_ownerExecutable.get(); } - ScriptExecutable* ownerScriptExecutable() const { return jsCast<ScriptExecutable*>(m_ownerExecutable.get()); } + ScriptExecutable* ownerExecutable() const { return m_ownerExecutable.get(); } void setVM(VM* vm) { m_vm = vm; } VM* vm() { return m_vm; } @@ -341,24 +307,78 @@ public: void setThisRegister(VirtualRegister thisRegister) { m_thisRegister = thisRegister; } VirtualRegister thisRegister() const { return m_thisRegister; } + bool needsFullScopeChain() const { return m_unlinkedCode->needsFullScopeChain(); } bool usesEval() const { return m_unlinkedCode->usesEval(); } - void setScopeRegister(VirtualRegister scopeRegister) + void setArgumentsRegister(VirtualRegister argumentsRegister) + { + ASSERT(argumentsRegister.isValid()); + m_argumentsRegister = argumentsRegister; + ASSERT(usesArguments()); + } + VirtualRegister argumentsRegister() const + { + ASSERT(usesArguments()); + return m_argumentsRegister; + } + VirtualRegister uncheckedArgumentsRegister() + { + if (!usesArguments()) + return VirtualRegister(); + return argumentsRegister(); + } + void setActivationRegister(VirtualRegister activationRegister) + { + m_activationRegister = activationRegister; + } + + VirtualRegister activationRegister() const + { + ASSERT(needsFullScopeChain()); + return m_activationRegister; + } + + VirtualRegister uncheckedActivationRegister() { - ASSERT(scopeRegister.isLocal() || !scopeRegister.isValid()); - m_scopeRegister = scopeRegister; + if (!needsFullScopeChain()) + return VirtualRegister(); + return activationRegister(); } - VirtualRegister scopeRegister() const + bool usesArguments() const { return m_argumentsRegister.isValid(); } + + bool needsActivation() const + { + return m_needsActivation; + } + + unsigned captureCount() const { - return m_scopeRegister; + if (!symbolTable()) + return 0; + return symbolTable()->captureCount(); + } + + int captureStart() const + { + if (!symbolTable()) + return 0; + return symbolTable()->captureStart(); } - CodeType codeType() const + int captureEnd() const { - return static_cast<CodeType>(m_codeType); + if (!symbolTable()) + return 0; + return symbolTable()->captureEnd(); } + bool isCaptured(VirtualRegister operand, InlineCallFrame* = 0) const; + + int framePointerOffsetToGetActivationRegisters(int machineCaptureStart); + int framePointerOffsetToGetActivationRegisters(); + + CodeType codeType() const { return m_unlinkedCode->codeType(); } PutPropertySlot::Context putByIdContext() const { if (codeType() == EvalCode) @@ -373,8 +393,20 @@ public: size_t numberOfJumpTargets() const { return m_unlinkedCode->numberOfJumpTargets(); } unsigned jumpTarget(int index) const { return m_unlinkedCode->jumpTarget(index); } + void clearEvalCache(); + String nameForRegister(VirtualRegister); +#if ENABLE(JIT) + void setNumberOfByValInfos(size_t size) { m_byValInfos.resizeToFit(size); } + size_t numberOfByValInfos() const { return m_byValInfos.size(); } + ByValInfo& byValInfo(size_t index) { return m_byValInfos[index]; } + + void setNumberOfCallLinkInfos(size_t size) { m_callLinkInfos.resizeToFit(size); } + size_t numberOfCallLinkInfos() const { return m_callLinkInfos.size(); } + CallLinkInfo& callLinkInfo(int index) { return m_callLinkInfos[index]; } +#endif + unsigned numberOfArgumentValueProfiles() { ASSERT(m_numParameters >= 0); @@ -390,7 +422,17 @@ public: unsigned numberOfValueProfiles() { return m_valueProfiles.size(); } ValueProfile* valueProfile(int index) { return &m_valueProfiles[index]; } - ValueProfile* valueProfileForBytecodeOffset(int bytecodeOffset); + ValueProfile* valueProfileForBytecodeOffset(int bytecodeOffset) + { + ValueProfile* result = binarySearch<ValueProfile, int>( + m_valueProfiles, m_valueProfiles.size(), bytecodeOffset, + getValueProfileBytecodeOffset<ValueProfile>); + ASSERT(result->m_bytecodeOffset != -1); + ASSERT(instructions()[bytecodeOffset + opcodeLength( + m_vm->interpreter->getOpcodeID( + instructions()[bytecodeOffset].u.opcode)) - 1].u.profile == result); + return result; + } SpeculatedType valueProfilePredictionForBytecodeOffset(const ConcurrentJITLocker& locker, int bytecodeOffset) { return valueProfileForBytecodeOffset(bytecodeOffset)->computeUpdatedPrediction(locker); @@ -413,14 +455,19 @@ public: return &m_rareCaseProfiles.last(); } unsigned numberOfRareCaseProfiles() { return m_rareCaseProfiles.size(); } - RareCaseProfile* rareCaseProfileForBytecodeOffset(int bytecodeOffset); - unsigned rareCaseProfileCountForBytecodeOffset(int bytecodeOffset); + RareCaseProfile* rareCaseProfile(int index) { return &m_rareCaseProfiles[index]; } + RareCaseProfile* rareCaseProfileForBytecodeOffset(int bytecodeOffset) + { + return tryBinarySearch<RareCaseProfile, int>( + m_rareCaseProfiles, m_rareCaseProfiles.size(), bytecodeOffset, + getRareCaseProfileBytecodeOffset); + } bool likelyToTakeSlowCase(int bytecodeOffset) { if (!hasBaselineJITProfiling()) return false; - unsigned value = rareCaseProfileCountForBytecodeOffset(bytecodeOffset); + unsigned value = rareCaseProfileForBytecodeOffset(bytecodeOffset)->m_counter; return value >= Options::likelyToTakeSlowCaseMinimumCount(); } @@ -428,42 +475,60 @@ public: { if (!hasBaselineJITProfiling()) return false; - unsigned value = rareCaseProfileCountForBytecodeOffset(bytecodeOffset); + unsigned value = rareCaseProfileForBytecodeOffset(bytecodeOffset)->m_counter; return value >= Options::couldTakeSlowCaseMinimumCount(); } - ResultProfile* ensureResultProfile(int bytecodeOffset) + RareCaseProfile* addSpecialFastCaseProfile(int bytecodeOffset) + { + m_specialFastCaseProfiles.append(RareCaseProfile(bytecodeOffset)); + return &m_specialFastCaseProfiles.last(); + } + unsigned numberOfSpecialFastCaseProfiles() { return m_specialFastCaseProfiles.size(); } + RareCaseProfile* specialFastCaseProfile(int index) { return &m_specialFastCaseProfiles[index]; } + RareCaseProfile* specialFastCaseProfileForBytecodeOffset(int bytecodeOffset) { - ResultProfile* profile = resultProfileForBytecodeOffset(bytecodeOffset); - if (!profile) { - m_resultProfiles.append(ResultProfile(bytecodeOffset)); - profile = &m_resultProfiles.last(); - ASSERT(&m_resultProfiles.last() == &m_resultProfiles[m_resultProfiles.size() - 1]); - if (!m_bytecodeOffsetToResultProfileIndexMap) - m_bytecodeOffsetToResultProfileIndexMap = std::make_unique<BytecodeOffsetToResultProfileIndexMap>(); - m_bytecodeOffsetToResultProfileIndexMap->add(bytecodeOffset, m_resultProfiles.size() - 1); - } - return profile; + return tryBinarySearch<RareCaseProfile, int>( + m_specialFastCaseProfiles, m_specialFastCaseProfiles.size(), bytecodeOffset, + getRareCaseProfileBytecodeOffset); } - unsigned numberOfResultProfiles() { return m_resultProfiles.size(); } - ResultProfile* resultProfileForBytecodeOffset(int bytecodeOffset); - unsigned specialFastCaseProfileCountForBytecodeOffset(int bytecodeOffset) + bool likelyToTakeSpecialFastCase(int bytecodeOffset) { - ResultProfile* profile = resultProfileForBytecodeOffset(bytecodeOffset); - if (!profile) - return 0; - return profile->specialFastPathCount(); + if (!hasBaselineJITProfiling()) + return false; + unsigned specialFastCaseCount = specialFastCaseProfileForBytecodeOffset(bytecodeOffset)->m_counter; + return specialFastCaseCount >= Options::likelyToTakeSlowCaseMinimumCount(); } bool couldTakeSpecialFastCase(int bytecodeOffset) { if (!hasBaselineJITProfiling()) return false; - unsigned specialFastCaseCount = specialFastCaseProfileCountForBytecodeOffset(bytecodeOffset); + unsigned specialFastCaseCount = specialFastCaseProfileForBytecodeOffset(bytecodeOffset)->m_counter; return specialFastCaseCount >= Options::couldTakeSlowCaseMinimumCount(); } + bool likelyToTakeDeepestSlowCase(int bytecodeOffset) + { + if (!hasBaselineJITProfiling()) + return false; + unsigned slowCaseCount = rareCaseProfileForBytecodeOffset(bytecodeOffset)->m_counter; + unsigned specialFastCaseCount = specialFastCaseProfileForBytecodeOffset(bytecodeOffset)->m_counter; + unsigned value = slowCaseCount - specialFastCaseCount; + return value >= Options::likelyToTakeSlowCaseMinimumCount(); + } + + bool likelyToTakeAnySlowCase(int bytecodeOffset) + { + if (!hasBaselineJITProfiling()) + return false; + unsigned slowCaseCount = rareCaseProfileForBytecodeOffset(bytecodeOffset)->m_counter; + unsigned specialFastCaseCount = specialFastCaseProfileForBytecodeOffset(bytecodeOffset)->m_counter; + unsigned value = slowCaseCount + specialFastCaseCount; + return value >= Options::likelyToTakeSlowCaseMinimumCount(); + } + unsigned numberOfArrayProfiles() const { return m_arrayProfiles.size(); } const ArrayProfileVector& arrayProfiles() { return m_arrayProfiles; } ArrayProfile* addArrayProfile(unsigned bytecodeOffset) @@ -482,7 +547,10 @@ public: bool hasExpressionInfo() { return m_unlinkedCode->hasExpressionInfo(); } #if ENABLE(DFG_JIT) - Vector<CodeOrigin, 0, UnsafeVectorOverflow>& codeOrigins(); + Vector<CodeOrigin, 0, UnsafeVectorOverflow>& codeOrigins() + { + return m_jitCode->dfgCommon()->codeOrigins; + } // Having code origins implies that there has been some inlining. bool hasCodeOrigins() @@ -490,16 +558,16 @@ public: return JITCode::isOptimizingJIT(jitType()); } - bool canGetCodeOrigin(CallSiteIndex index) + bool canGetCodeOrigin(unsigned index) { if (!hasCodeOrigins()) return false; - return index.bits() < codeOrigins().size(); + return index < codeOrigins().size(); } - CodeOrigin codeOrigin(CallSiteIndex index) + CodeOrigin codeOrigin(unsigned index) { - return codeOrigins()[index.bits()]; + return codeOrigins()[index]; } bool addFrequentExitSite(const DFG::FrequentExitSite& site) @@ -508,15 +576,11 @@ public: ConcurrentJITLocker locker(m_lock); return m_exitProfile.add(locker, site); } - - bool hasExitSite(const ConcurrentJITLocker& locker, const DFG::FrequentExitSite& site) const - { - return m_exitProfile.hasExitSite(locker, site); - } + bool hasExitSite(const DFG::FrequentExitSite& site) const { ConcurrentJITLocker locker(m_lock); - return hasExitSite(locker, site); + return m_exitProfile.hasExitSite(locker, site); } DFG::ExitProfile& exitProfile() { return m_exitProfile; } @@ -525,26 +589,44 @@ public: { return m_lazyOperandValueProfiles; } +#else // ENABLE(DFG_JIT) + bool addFrequentExitSite(const DFG::FrequentExitSite&) + { + return false; + } #endif // ENABLE(DFG_JIT) // Constant Pool #if ENABLE(DFG_JIT) size_t numberOfIdentifiers() const { return m_unlinkedCode->numberOfIdentifiers() + numberOfDFGIdentifiers(); } - size_t numberOfDFGIdentifiers() const; - const Identifier& identifier(int index) const; + size_t numberOfDFGIdentifiers() const + { + if (!JITCode::isOptimizingJIT(jitType())) + return 0; + + return m_jitCode->dfgCommon()->dfgIdentifiers.size(); + } + + const Identifier& identifier(int index) const + { + size_t unlinkedIdentifiers = m_unlinkedCode->numberOfIdentifiers(); + if (static_cast<unsigned>(index) < unlinkedIdentifiers) + return m_unlinkedCode->identifier(index); + ASSERT(JITCode::isOptimizingJIT(jitType())); + return m_jitCode->dfgCommon()->dfgIdentifiers[index - unlinkedIdentifiers]; + } #else size_t numberOfIdentifiers() const { return m_unlinkedCode->numberOfIdentifiers(); } const Identifier& identifier(int index) const { return m_unlinkedCode->identifier(index); } #endif Vector<WriteBarrier<Unknown>>& constants() { return m_constantRegisters; } - Vector<SourceCodeRepresentation>& constantsSourceCodeRepresentation() { return m_constantsSourceCodeRepresentation; } + size_t numberOfConstantRegisters() const { return m_constantRegisters.size(); } unsigned addConstant(JSValue v) { unsigned result = m_constantRegisters.size(); m_constantRegisters.append(WriteBarrier<Unknown>()); - m_constantRegisters.last().set(m_globalObject->vm(), this, v); - m_constantsSourceCodeRepresentation.append(SourceCodeRepresentation::Other); + m_constantRegisters.last().set(m_globalObject->vm(), m_ownerExecutable.get(), v); return result; } @@ -552,19 +634,19 @@ public: { unsigned result = m_constantRegisters.size(); m_constantRegisters.append(WriteBarrier<Unknown>()); - m_constantsSourceCodeRepresentation.append(SourceCodeRepresentation::Other); return result; } + bool findConstant(JSValue, unsigned& result); + unsigned addOrFindConstant(JSValue); WriteBarrier<Unknown>& constantRegister(int index) { return m_constantRegisters[index - FirstConstantRegisterIndex]; } ALWAYS_INLINE bool isConstantRegisterIndex(int index) const { return index >= FirstConstantRegisterIndex; } ALWAYS_INLINE JSValue getConstant(int index) const { return m_constantRegisters[index - FirstConstantRegisterIndex].get(); } - ALWAYS_INLINE SourceCodeRepresentation constantSourceCodeRepresentation(int index) const { return m_constantsSourceCodeRepresentation[index - FirstConstantRegisterIndex]; } FunctionExecutable* functionDecl(int index) { return m_functionDecls[index].get(); } int numberOfFunctionDecls() { return m_functionDecls.size(); } FunctionExecutable* functionExpr(int index) { return m_functionExprs[index].get(); } - + RegExp* regexp(int index) const { return m_unlinkedCode->regexp(index); } unsigned numberOfConstantBuffers() const @@ -591,26 +673,15 @@ public: return constantBufferAsVector(index).data(); } - Heap* heap() const { return &m_vm->heap; } JSGlobalObject* globalObject() { return m_globalObject.get(); } JSGlobalObject* globalObjectFor(CodeOrigin); BytecodeLivenessAnalysis& livenessAnalysis() { - { - ConcurrentJITLocker locker(m_lock); - if (!!m_livenessAnalysis) - return *m_livenessAnalysis; - } - std::unique_ptr<BytecodeLivenessAnalysis> analysis = - std::make_unique<BytecodeLivenessAnalysis>(this); - { - ConcurrentJITLocker locker(m_lock); - if (!m_livenessAnalysis) - m_livenessAnalysis = WTFMove(analysis); - return *m_livenessAnalysis; - } + if (!m_livenessAnalysis) + m_livenessAnalysis = std::make_unique<BytecodeLivenessAnalysis>(this); + return *m_livenessAnalysis; } void validate(); @@ -631,17 +702,8 @@ public: StringJumpTable& addStringSwitchJumpTable() { createRareDataIfNecessary(); m_rareData->m_stringSwitchJumpTables.append(StringJumpTable()); return m_rareData->m_stringSwitchJumpTables.last(); } StringJumpTable& stringSwitchJumpTable(int tableIndex) { RELEASE_ASSERT(m_rareData); return m_rareData->m_stringSwitchJumpTables[tableIndex]; } - // Live callee registers at yield points. - const FastBitVector& liveCalleeLocalsAtYield(unsigned index) const - { - RELEASE_ASSERT(m_rareData); - return m_rareData->m_liveCalleeLocalsAtYield[index]; - } - FastBitVector& liveCalleeLocalsAtYield(unsigned index) - { - RELEASE_ASSERT(m_rareData); - return m_rareData->m_liveCalleeLocalsAtYield[index]; - } + + SymbolTable* symbolTable() const { return m_symbolTable.get(); } EvalCodeCache& evalCodeCache() { createRareDataIfNecessary(); return m_rareData->m_evalCodeCache; } @@ -679,7 +741,7 @@ public: m_llintExecuteCounter.setNewThreshold(Options::thresholdForJITSoon(), this); } - const BaselineExecutionCounter& llintExecuteCounter() const + const ExecutionCounter& llintExecuteCounter() const { return m_llintExecuteCounter; } @@ -705,13 +767,9 @@ public: // When we observe a lot of speculation failures, we trigger a // reoptimization. But each time, we increase the optimization trigger // to avoid thrashing. - JS_EXPORT_PRIVATE unsigned reoptimizationRetryCounter() const; + unsigned reoptimizationRetryCounter() const; void countReoptimization(); #if ENABLE(JIT) - static unsigned numberOfLLIntBaselineCalleeSaveRegisters() { return RegisterSet::llintBaselineCalleeSaveRegisters().numberOfSetRegisters(); } - static size_t llintBaselineCalleeSaveSpaceAsVirtualRegisters(); - size_t calleeSaveSpaceAsVirtualRegisters(); - unsigned numberOfDFGCompiles(); int32_t codeTypeThresholdMultiplier() const; @@ -723,11 +781,11 @@ public: return &m_jitExecuteCounter.m_counter; } - static ptrdiff_t offsetOfJITExecuteCounter() { return OBJECT_OFFSETOF(CodeBlock, m_jitExecuteCounter) + OBJECT_OFFSETOF(BaselineExecutionCounter, m_counter); } - static ptrdiff_t offsetOfJITExecutionActiveThreshold() { return OBJECT_OFFSETOF(CodeBlock, m_jitExecuteCounter) + OBJECT_OFFSETOF(BaselineExecutionCounter, m_activeThreshold); } - static ptrdiff_t offsetOfJITExecutionTotalCount() { return OBJECT_OFFSETOF(CodeBlock, m_jitExecuteCounter) + OBJECT_OFFSETOF(BaselineExecutionCounter, m_totalCount); } + static ptrdiff_t offsetOfJITExecuteCounter() { return OBJECT_OFFSETOF(CodeBlock, m_jitExecuteCounter) + OBJECT_OFFSETOF(ExecutionCounter, m_counter); } + static ptrdiff_t offsetOfJITExecutionActiveThreshold() { return OBJECT_OFFSETOF(CodeBlock, m_jitExecuteCounter) + OBJECT_OFFSETOF(ExecutionCounter, m_activeThreshold); } + static ptrdiff_t offsetOfJITExecutionTotalCount() { return OBJECT_OFFSETOF(CodeBlock, m_jitExecuteCounter) + OBJECT_OFFSETOF(ExecutionCounter, m_totalCount); } - const BaselineExecutionCounter& jitExecuteCounter() const { return m_jitExecuteCounter; } + const ExecutionCounter& jitExecuteCounter() const { return m_jitExecuteCounter; } unsigned optimizationDelayCounter() const { return m_optimizationDelayCounter; } @@ -797,14 +855,7 @@ public: uint32_t exitCountThresholdForReoptimizationFromLoop(); bool shouldReoptimizeNow(); bool shouldReoptimizeFromLoopNow(); - - void setCalleeSaveRegisters(RegisterSet); - void setCalleeSaveRegisters(std::unique_ptr<RegisterAtOffsetList>); - - RegisterAtOffsetList* calleeSaveRegisters() const { return m_calleeSaveRegisters.get(); } #else // No JIT - static unsigned numberOfLLIntBaselineCalleeSaveRegisters() { return 0; } - static size_t llintBaselineCalleeSaveSpaceAsVirtualRegisters() { return 0; }; void optimizeAfterWarmUp() { } unsigned numberOfDFGCompiles() { return 0; } #endif @@ -815,11 +866,10 @@ public: void updateAllPredictions(); unsigned frameRegisterCount(); - int stackPointerOffset(); bool hasOpDebugForLineAndColumn(unsigned line, unsigned column); - bool hasDebuggerRequests() const { return m_debuggerRequests; } + int hasDebuggerRequests() const { return !!m_debuggerRequests; } void* debuggerRequestsAddress() { return &m_debuggerRequests; } void addBreakpoint(unsigned numBreakpoints); @@ -835,16 +885,13 @@ public: }; void setSteppingMode(SteppingMode); - void clearDebuggerRequests() - { - m_steppingMode = SteppingModeDisabled; - m_numBreakpoints = 0; - } - + void clearDebuggerRequests() { m_debuggerRequests = 0; } + // FIXME: Make these remaining members private. - int m_numCalleeLocals; + int m_numCalleeRegisters; int m_numVars; + bool m_isConstructor; // This is intentionally public; it's the responsibility of anyone doing any // of the following to hold the lock: @@ -863,67 +910,20 @@ public: // without holding any locks, because the GC is guaranteed to wait until any // concurrent compilation threads finish what they're doing. mutable ConcurrentJITLock m_lock; - - Atomic<bool> m_visitWeaklyHasBeenCalled; - - bool m_shouldAlwaysBeInlined; // Not a bitfield because the JIT wants to store to it. - -#if ENABLE(JIT) - unsigned m_capabilityLevelState : 2; // DFG::CapabilityLevel -#endif - - bool m_allTransitionsHaveBeenMarked : 1; // Initialized and used on every GC. - - bool m_didFailFTLCompilation : 1; - bool m_hasBeenCompiledWithFTL : 1; - bool m_isConstructor : 1; - bool m_isStrictMode : 1; - unsigned m_codeType : 2; // CodeType + + bool m_shouldAlwaysBeInlined; + bool m_allTransitionsHaveBeenMarked; // Initialized and used on every GC. + + bool m_didFailFTLCompilation; // Internal methods for use by validation code. It would be private if it wasn't // for the fact that we use it from anonymous namespaces. void beginValidationDidFail(); NO_RETURN_DUE_TO_CRASH void endValidationDidFail(); - struct RareData { - WTF_MAKE_FAST_ALLOCATED; - public: - Vector<HandlerInfo> m_exceptionHandlers; - - // Buffers used for large array literals - Vector<Vector<JSValue>> m_constantBuffers; - - // Jump Tables - Vector<SimpleJumpTable> m_switchJumpTables; - Vector<StringJumpTable> m_stringSwitchJumpTables; - - Vector<FastBitVector> m_liveCalleeLocalsAtYield; - - EvalCodeCache m_evalCodeCache; - }; - - void clearExceptionHandlers() - { - if (m_rareData) - m_rareData->m_exceptionHandlers.clear(); - } - - void appendExceptionHandler(const HandlerInfo& handler) - { - createRareDataIfNecessary(); // We may be handling the exception of an inlined call frame. - m_rareData->m_exceptionHandlers.append(handler); - } - - CallSiteIndex newExceptionHandlingCallSiteIndex(CallSiteIndex originalCallSite); - -#if ENABLE(JIT) - void setPCToCodeOriginMap(std::unique_ptr<PCToCodeOriginMap>&&); - Optional<CodeOrigin> findPC(void* pc); -#endif - protected: - void finalizeLLIntInlineCaches(); - void finalizeBaselineJITInlineCaches(); + virtual void visitWeakReferences(SlotVisitor&) override; + virtual void finalizeUnconditionally() override; #if ENABLE(DFG_JIT) void tallyFrequentExitSites(); @@ -940,386 +940,298 @@ private: double optimizationThresholdScalingFactor(); +#if ENABLE(JIT) + ClosureCallStubRoutine* findClosureCallForReturnPC(ReturnAddressPtr); +#endif + void updateAllPredictionsAndCountLiveness(unsigned& numberOfLiveNonArgumentValueProfiles, unsigned& numberOfSamplesInProfiles); - void setConstantRegisters(const Vector<WriteBarrier<Unknown>>& constants, const Vector<SourceCodeRepresentation>& constantsSourceCodeRepresentation) + void setConstantRegisters(const Vector<WriteBarrier<Unknown>>& constants) { - ASSERT(constants.size() == constantsSourceCodeRepresentation.size()); size_t count = constants.size(); - m_constantRegisters.resizeToFit(count); + m_constantRegisters.resize(count); for (size_t i = 0; i < count; i++) - m_constantRegisters[i].set(*m_vm, this, constants[i].get()); - m_constantsSourceCodeRepresentation = constantsSourceCodeRepresentation; + m_constantRegisters[i].set(*m_vm, ownerExecutable(), constants[i].get()); } - void replaceConstant(int index, JSValue value) - { - ASSERT(isConstantRegisterIndex(index) && static_cast<size_t>(index - FirstConstantRegisterIndex) < m_constantRegisters.size()); - m_constantRegisters[index - FirstConstantRegisterIndex].set(m_globalObject->vm(), this, value); - } - - void dumpBytecode( - PrintStream&, ExecState*, const Instruction* begin, const Instruction*&, - const StubInfoMap& = StubInfoMap(), const CallLinkInfoMap& = CallLinkInfoMap()); + void dumpBytecode(PrintStream&, ExecState*, const Instruction* begin, const Instruction*&, const StubInfoMap& = StubInfoMap()); CString registerName(int r) const; - CString constantName(int index) const; void printUnaryOp(PrintStream&, ExecState*, int location, const Instruction*&, const char* op); void printBinaryOp(PrintStream&, ExecState*, int location, const Instruction*&, const char* op); void printConditionalJump(PrintStream&, ExecState*, const Instruction*, const Instruction*&, int location, const char* op); void printGetByIdOp(PrintStream&, ExecState*, int location, const Instruction*&); void printGetByIdCacheStatus(PrintStream&, ExecState*, int location, const StubInfoMap&); enum CacheDumpMode { DumpCaches, DontDumpCaches }; - void printCallOp(PrintStream&, ExecState*, int location, const Instruction*&, const char* op, CacheDumpMode, bool& hasPrintedProfiling, const CallLinkInfoMap&); + void printCallOp(PrintStream&, ExecState*, int location, const Instruction*&, const char* op, CacheDumpMode, bool& hasPrintedProfiling); void printPutByIdOp(PrintStream&, ExecState*, int location, const Instruction*&, const char* op); - void printPutByIdCacheStatus(PrintStream&, int location, const StubInfoMap&); - void printLocationAndOp(PrintStream&, ExecState*, int location, const Instruction*&, const char* op); - void printLocationOpAndRegisterOperand(PrintStream&, ExecState*, int location, const Instruction*& it, const char* op, int operand); + void printLocationAndOp(PrintStream& out, ExecState*, int location, const Instruction*&, const char* op) + { + out.printf("[%4d] %-17s ", location, op); + } + + void printLocationOpAndRegisterOperand(PrintStream& out, ExecState* exec, int location, const Instruction*& it, const char* op, int operand) + { + printLocationAndOp(out, exec, location, it, op); + out.printf("%s", registerName(operand).data()); + } void beginDumpProfiling(PrintStream&, bool& hasPrintedProfiling); void dumpValueProfiling(PrintStream&, const Instruction*&, bool& hasPrintedProfiling); void dumpArrayProfiling(PrintStream&, const Instruction*&, bool& hasPrintedProfiling); void dumpRareCaseProfile(PrintStream&, const char* name, RareCaseProfile*, bool& hasPrintedProfiling); - void dumpResultProfile(PrintStream&, ResultProfile*, bool& hasPrintedProfiling); + +#if ENABLE(DFG_JIT) + bool shouldImmediatelyAssumeLivenessDuringScan() + { + // Interpreter and Baseline JIT CodeBlocks don't need to be jettisoned when + // their weak references go stale. So if a basline JIT CodeBlock gets + // scanned, we can assume that this means that it's live. + if (!JITCode::isOptimizingJIT(jitType())) + return true; - bool shouldVisitStrongly(); - bool shouldJettisonDueToWeakReference(); - bool shouldJettisonDueToOldAge(); + // For simplicity, we don't attempt to jettison code blocks during GC if + // they are executing. Instead we strongly mark their weak references to + // allow them to continue to execute soundly. + if (m_mayBeExecuting) + return true; + + if (Options::forceDFGCodeBlockLiveness()) + return true; + + return false; + } +#else + bool shouldImmediatelyAssumeLivenessDuringScan() { return true; } +#endif void propagateTransitions(SlotVisitor&); void determineLiveness(SlotVisitor&); void stronglyVisitStrongReferences(SlotVisitor&); void stronglyVisitWeakReferences(SlotVisitor&); - void visitOSRExitTargets(SlotVisitor&); - - std::chrono::milliseconds timeSinceCreation() - { - return std::chrono::duration_cast<std::chrono::milliseconds>( - std::chrono::steady_clock::now() - m_creationTime); - } void createRareDataIfNecessary() { if (!m_rareData) - m_rareData = std::make_unique<RareData>(); + m_rareData = adoptPtr(new RareData); } - - void insertBasicBlockBoundariesForControlFlowProfiler(RefCountedArray<Instruction>&); - + +#if ENABLE(JIT) + void resetStubInternal(RepatchBuffer&, StructureStubInfo&); + void resetStubDuringGCInternal(RepatchBuffer&, StructureStubInfo&); +#endif WriteBarrier<UnlinkedCodeBlock> m_unlinkedCode; int m_numParameters; union { unsigned m_debuggerRequests; struct { - unsigned m_hasDebuggerStatement : 1; unsigned m_steppingMode : 1; - unsigned m_numBreakpoints : 30; + unsigned m_numBreakpoints : 31; }; }; - WriteBarrier<ExecutableBase> m_ownerExecutable; + WriteBarrier<ScriptExecutable> m_ownerExecutable; VM* m_vm; RefCountedArray<Instruction> m_instructions; + WriteBarrier<SymbolTable> m_symbolTable; VirtualRegister m_thisRegister; - VirtualRegister m_scopeRegister; - mutable CodeBlockHash m_hash; + VirtualRegister m_argumentsRegister; + VirtualRegister m_activationRegister; + + bool m_isStrictMode; + bool m_needsActivation; + bool m_mayBeExecuting; + uint8_t m_visitAggregateHasBeenCalled; RefPtr<SourceProvider> m_source; unsigned m_sourceOffset; unsigned m_firstLineColumnOffset; + unsigned m_codeType; - RefCountedArray<LLIntCallLinkInfo> m_llintCallLinkInfos; +#if ENABLE(LLINT) + Vector<LLIntCallLinkInfo> m_llintCallLinkInfos; SentinelLinkedList<LLIntCallLinkInfo, BasicRawSentinelNode<LLIntCallLinkInfo>> m_incomingLLIntCalls; +#endif RefPtr<JITCode> m_jitCode; + MacroAssemblerCodePtr m_jitCodeWithArityCheck; #if ENABLE(JIT) - std::unique_ptr<RegisterAtOffsetList> m_calleeSaveRegisters; Bag<StructureStubInfo> m_stubInfos; - Bag<ByValInfo> m_byValInfos; - Bag<CallLinkInfo> m_callLinkInfos; + Vector<ByValInfo> m_byValInfos; + Vector<CallLinkInfo> m_callLinkInfos; SentinelLinkedList<CallLinkInfo, BasicRawSentinelNode<CallLinkInfo>> m_incomingCalls; - SentinelLinkedList<PolymorphicCallNode, BasicRawSentinelNode<PolymorphicCallNode>> m_incomingPolymorphicCalls; - std::unique_ptr<PCToCodeOriginMap> m_pcToCodeOriginMap; #endif - std::unique_ptr<CompactJITCodeMap> m_jitCodeMap; + OwnPtr<CompactJITCodeMap> m_jitCodeMap; #if ENABLE(DFG_JIT) // This is relevant to non-DFG code blocks that serve as the profiled code block // for DFG code blocks. DFG::ExitProfile m_exitProfile; CompressedLazyOperandValueProfileHolder m_lazyOperandValueProfiles; #endif - RefCountedArray<ValueProfile> m_argumentValueProfiles; - RefCountedArray<ValueProfile> m_valueProfiles; + Vector<ValueProfile> m_argumentValueProfiles; + Vector<ValueProfile> m_valueProfiles; SegmentedVector<RareCaseProfile, 8> m_rareCaseProfiles; - SegmentedVector<ResultProfile, 8> m_resultProfiles; - typedef HashMap<unsigned, unsigned, IntHash<unsigned>, WTF::UnsignedWithZeroKeyHashTraits<unsigned>> BytecodeOffsetToResultProfileIndexMap; - std::unique_ptr<BytecodeOffsetToResultProfileIndexMap> m_bytecodeOffsetToResultProfileIndexMap; - RefCountedArray<ArrayAllocationProfile> m_arrayAllocationProfiles; + SegmentedVector<RareCaseProfile, 8> m_specialFastCaseProfiles; + Vector<ArrayAllocationProfile> m_arrayAllocationProfiles; ArrayProfileVector m_arrayProfiles; - RefCountedArray<ObjectAllocationProfile> m_objectAllocationProfiles; + Vector<ObjectAllocationProfile> m_objectAllocationProfiles; // Constant Pool COMPILE_ASSERT(sizeof(Register) == sizeof(WriteBarrier<Unknown>), Register_must_be_same_size_as_WriteBarrier_Unknown); // TODO: This could just be a pointer to m_unlinkedCodeBlock's data, but the DFG mutates // it, so we're stuck with it for now. Vector<WriteBarrier<Unknown>> m_constantRegisters; - Vector<SourceCodeRepresentation> m_constantsSourceCodeRepresentation; - RefCountedArray<WriteBarrier<FunctionExecutable>> m_functionDecls; - RefCountedArray<WriteBarrier<FunctionExecutable>> m_functionExprs; + Vector<WriteBarrier<FunctionExecutable>> m_functionDecls; + Vector<WriteBarrier<FunctionExecutable>> m_functionExprs; - WriteBarrier<CodeBlock> m_alternative; + RefPtr<CodeBlock> m_alternative; - BaselineExecutionCounter m_llintExecuteCounter; + ExecutionCounter m_llintExecuteCounter; - BaselineExecutionCounter m_jitExecuteCounter; + ExecutionCounter m_jitExecuteCounter; + int32_t m_totalJITExecutions; uint32_t m_osrExitCounter; uint16_t m_optimizationDelayCounter; uint16_t m_reoptimizationRetryCounter; - - std::chrono::steady_clock::time_point m_creationTime; + + mutable CodeBlockHash m_hash; std::unique_ptr<BytecodeLivenessAnalysis> m_livenessAnalysis; - std::unique_ptr<RareData> m_rareData; + struct RareData { + WTF_MAKE_FAST_ALLOCATED; + public: + Vector<HandlerInfo> m_exceptionHandlers; + + // Buffers used for large array literals + Vector<Vector<JSValue>> m_constantBuffers; + + // Jump Tables + Vector<SimpleJumpTable> m_switchJumpTables; + Vector<StringJumpTable> m_stringSwitchJumpTables; - UnconditionalFinalizer m_unconditionalFinalizer; - WeakReferenceHarvester m_weakReferenceHarvester; + EvalCodeCache m_evalCodeCache; + }; +#if COMPILER(MSVC) + friend void WTF::deleteOwnedPtr<RareData>(RareData*); +#endif + OwnPtr<RareData> m_rareData; +#if ENABLE(JIT) + DFG::CapabilityLevel m_capabilityLevelState; +#endif }; // Program code is not marked by any function, so we make the global object // responsible for marking it. class GlobalCodeBlock : public CodeBlock { - typedef CodeBlock Base; - DECLARE_INFO; - protected: - GlobalCodeBlock(VM* vm, Structure* structure, CopyParsedBlockTag, GlobalCodeBlock& other) - : CodeBlock(vm, structure, CopyParsedBlock, other) + GlobalCodeBlock(CopyParsedBlockTag, GlobalCodeBlock& other) + : CodeBlock(CopyParsedBlock, other) { } - - GlobalCodeBlock(VM* vm, Structure* structure, ScriptExecutable* ownerExecutable, UnlinkedCodeBlock* unlinkedCodeBlock, JSScope* scope, PassRefPtr<SourceProvider> sourceProvider, unsigned sourceOffset, unsigned firstLineColumnOffset) - : CodeBlock(vm, structure, ownerExecutable, unlinkedCodeBlock, scope, sourceProvider, sourceOffset, firstLineColumnOffset) + + GlobalCodeBlock(ScriptExecutable* ownerExecutable, UnlinkedCodeBlock* unlinkedCodeBlock, JSScope* scope, PassRefPtr<SourceProvider> sourceProvider, unsigned sourceOffset, unsigned firstLineColumnOffset) + : CodeBlock(ownerExecutable, unlinkedCodeBlock, scope, sourceProvider, sourceOffset, firstLineColumnOffset) { } }; class ProgramCodeBlock : public GlobalCodeBlock { public: - typedef GlobalCodeBlock Base; - DECLARE_INFO; - - static ProgramCodeBlock* create(VM* vm, CopyParsedBlockTag, ProgramCodeBlock& other) - { - ProgramCodeBlock* instance = new (NotNull, allocateCell<ProgramCodeBlock>(vm->heap)) - ProgramCodeBlock(vm, vm->programCodeBlockStructure.get(), CopyParsedBlock, other); - instance->finishCreation(*vm, CopyParsedBlock, other); - return instance; - } - - static ProgramCodeBlock* create(VM* vm, ProgramExecutable* ownerExecutable, UnlinkedProgramCodeBlock* unlinkedCodeBlock, - JSScope* scope, PassRefPtr<SourceProvider> sourceProvider, unsigned firstLineColumnOffset) - { - ProgramCodeBlock* instance = new (NotNull, allocateCell<ProgramCodeBlock>(vm->heap)) - ProgramCodeBlock(vm, vm->programCodeBlockStructure.get(), ownerExecutable, unlinkedCodeBlock, scope, sourceProvider, firstLineColumnOffset); - instance->finishCreation(*vm, ownerExecutable, unlinkedCodeBlock, scope); - return instance; - } - - static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype) - { - return Structure::create(vm, globalObject, prototype, TypeInfo(CellType, StructureFlags), info()); - } - -private: - ProgramCodeBlock(VM* vm, Structure* structure, CopyParsedBlockTag, ProgramCodeBlock& other) - : GlobalCodeBlock(vm, structure, CopyParsedBlock, other) - { - } - - ProgramCodeBlock(VM* vm, Structure* structure, ProgramExecutable* ownerExecutable, UnlinkedProgramCodeBlock* unlinkedCodeBlock, - JSScope* scope, PassRefPtr<SourceProvider> sourceProvider, unsigned firstLineColumnOffset) - : GlobalCodeBlock(vm, structure, ownerExecutable, unlinkedCodeBlock, scope, sourceProvider, 0, firstLineColumnOffset) - { - } - - static void destroy(JSCell*); -}; - -class ModuleProgramCodeBlock : public GlobalCodeBlock { -public: - typedef GlobalCodeBlock Base; - DECLARE_INFO; - - static ModuleProgramCodeBlock* create(VM* vm, CopyParsedBlockTag, ModuleProgramCodeBlock& other) - { - ModuleProgramCodeBlock* instance = new (NotNull, allocateCell<ModuleProgramCodeBlock>(vm->heap)) - ModuleProgramCodeBlock(vm, vm->moduleProgramCodeBlockStructure.get(), CopyParsedBlock, other); - instance->finishCreation(*vm, CopyParsedBlock, other); - return instance; - } - - static ModuleProgramCodeBlock* create(VM* vm, ModuleProgramExecutable* ownerExecutable, UnlinkedModuleProgramCodeBlock* unlinkedCodeBlock, - JSScope* scope, PassRefPtr<SourceProvider> sourceProvider, unsigned firstLineColumnOffset) - { - ModuleProgramCodeBlock* instance = new (NotNull, allocateCell<ModuleProgramCodeBlock>(vm->heap)) - ModuleProgramCodeBlock(vm, vm->moduleProgramCodeBlockStructure.get(), ownerExecutable, unlinkedCodeBlock, scope, sourceProvider, firstLineColumnOffset); - instance->finishCreation(*vm, ownerExecutable, unlinkedCodeBlock, scope); - return instance; - } - - static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype) - { - return Structure::create(vm, globalObject, prototype, TypeInfo(CellType, StructureFlags), info()); - } - -private: - ModuleProgramCodeBlock(VM* vm, Structure* structure, CopyParsedBlockTag, ModuleProgramCodeBlock& other) - : GlobalCodeBlock(vm, structure, CopyParsedBlock, other) + ProgramCodeBlock(CopyParsedBlockTag, ProgramCodeBlock& other) + : GlobalCodeBlock(CopyParsedBlock, other) { } - ModuleProgramCodeBlock(VM* vm, Structure* structure, ModuleProgramExecutable* ownerExecutable, UnlinkedModuleProgramCodeBlock* unlinkedCodeBlock, - JSScope* scope, PassRefPtr<SourceProvider> sourceProvider, unsigned firstLineColumnOffset) - : GlobalCodeBlock(vm, structure, ownerExecutable, unlinkedCodeBlock, scope, sourceProvider, 0, firstLineColumnOffset) + ProgramCodeBlock(ProgramExecutable* ownerExecutable, UnlinkedProgramCodeBlock* unlinkedCodeBlock, JSScope* scope, PassRefPtr<SourceProvider> sourceProvider, unsigned firstLineColumnOffset) + : GlobalCodeBlock(ownerExecutable, unlinkedCodeBlock, scope, sourceProvider, 0, firstLineColumnOffset) { } - static void destroy(JSCell*); +#if ENABLE(JIT) +protected: + virtual CodeBlock* replacement() override; + virtual DFG::CapabilityLevel capabilityLevelInternal() override; +#endif }; class EvalCodeBlock : public GlobalCodeBlock { public: - typedef GlobalCodeBlock Base; - DECLARE_INFO; - - static EvalCodeBlock* create(VM* vm, CopyParsedBlockTag, EvalCodeBlock& other) + EvalCodeBlock(CopyParsedBlockTag, EvalCodeBlock& other) + : GlobalCodeBlock(CopyParsedBlock, other) { - EvalCodeBlock* instance = new (NotNull, allocateCell<EvalCodeBlock>(vm->heap)) - EvalCodeBlock(vm, vm->evalCodeBlockStructure.get(), CopyParsedBlock, other); - instance->finishCreation(*vm, CopyParsedBlock, other); - return instance; } - - static EvalCodeBlock* create(VM* vm, EvalExecutable* ownerExecutable, UnlinkedEvalCodeBlock* unlinkedCodeBlock, - JSScope* scope, PassRefPtr<SourceProvider> sourceProvider) - { - EvalCodeBlock* instance = new (NotNull, allocateCell<EvalCodeBlock>(vm->heap)) - EvalCodeBlock(vm, vm->evalCodeBlockStructure.get(), ownerExecutable, unlinkedCodeBlock, scope, sourceProvider); - instance->finishCreation(*vm, ownerExecutable, unlinkedCodeBlock, scope); - return instance; - } - - static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype) + + EvalCodeBlock(EvalExecutable* ownerExecutable, UnlinkedEvalCodeBlock* unlinkedCodeBlock, JSScope* scope, PassRefPtr<SourceProvider> sourceProvider) + : GlobalCodeBlock(ownerExecutable, unlinkedCodeBlock, scope, sourceProvider, 0, 1) { - return Structure::create(vm, globalObject, prototype, TypeInfo(CellType, StructureFlags), info()); } - + const Identifier& variable(unsigned index) { return unlinkedEvalCodeBlock()->variable(index); } unsigned numVariables() { return unlinkedEvalCodeBlock()->numVariables(); } -private: - EvalCodeBlock(VM* vm, Structure* structure, CopyParsedBlockTag, EvalCodeBlock& other) - : GlobalCodeBlock(vm, structure, CopyParsedBlock, other) - { - } - - EvalCodeBlock(VM* vm, Structure* structure, EvalExecutable* ownerExecutable, UnlinkedEvalCodeBlock* unlinkedCodeBlock, - JSScope* scope, PassRefPtr<SourceProvider> sourceProvider) - : GlobalCodeBlock(vm, structure, ownerExecutable, unlinkedCodeBlock, scope, sourceProvider, 0, 1) - { - } +#if ENABLE(JIT) +protected: + virtual CodeBlock* replacement() override; + virtual DFG::CapabilityLevel capabilityLevelInternal() override; +#endif - static void destroy(JSCell*); - private: UnlinkedEvalCodeBlock* unlinkedEvalCodeBlock() const { return jsCast<UnlinkedEvalCodeBlock*>(unlinkedCodeBlock()); } }; class FunctionCodeBlock : public CodeBlock { public: - typedef CodeBlock Base; - DECLARE_INFO; - - static FunctionCodeBlock* create(VM* vm, CopyParsedBlockTag, FunctionCodeBlock& other) - { - FunctionCodeBlock* instance = new (NotNull, allocateCell<FunctionCodeBlock>(vm->heap)) - FunctionCodeBlock(vm, vm->functionCodeBlockStructure.get(), CopyParsedBlock, other); - instance->finishCreation(*vm, CopyParsedBlock, other); - return instance; - } - - static FunctionCodeBlock* create(VM* vm, FunctionExecutable* ownerExecutable, UnlinkedFunctionCodeBlock* unlinkedCodeBlock, JSScope* scope, - PassRefPtr<SourceProvider> sourceProvider, unsigned sourceOffset, unsigned firstLineColumnOffset) - { - FunctionCodeBlock* instance = new (NotNull, allocateCell<FunctionCodeBlock>(vm->heap)) - FunctionCodeBlock(vm, vm->functionCodeBlockStructure.get(), ownerExecutable, unlinkedCodeBlock, scope, sourceProvider, sourceOffset, firstLineColumnOffset); - instance->finishCreation(*vm, ownerExecutable, unlinkedCodeBlock, scope); - return instance; - } - - static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype) - { - return Structure::create(vm, globalObject, prototype, TypeInfo(CellType, StructureFlags), info()); - } - -private: - FunctionCodeBlock(VM* vm, Structure* structure, CopyParsedBlockTag, FunctionCodeBlock& other) - : CodeBlock(vm, structure, CopyParsedBlock, other) + FunctionCodeBlock(CopyParsedBlockTag, FunctionCodeBlock& other) + : CodeBlock(CopyParsedBlock, other) { } - FunctionCodeBlock(VM* vm, Structure* structure, FunctionExecutable* ownerExecutable, UnlinkedFunctionCodeBlock* unlinkedCodeBlock, JSScope* scope, - PassRefPtr<SourceProvider> sourceProvider, unsigned sourceOffset, unsigned firstLineColumnOffset) - : CodeBlock(vm, structure, ownerExecutable, unlinkedCodeBlock, scope, sourceProvider, sourceOffset, firstLineColumnOffset) + FunctionCodeBlock(FunctionExecutable* ownerExecutable, UnlinkedFunctionCodeBlock* unlinkedCodeBlock, JSScope* scope, PassRefPtr<SourceProvider> sourceProvider, unsigned sourceOffset, unsigned firstLineColumnOffset) + : CodeBlock(ownerExecutable, unlinkedCodeBlock, scope, sourceProvider, sourceOffset, firstLineColumnOffset) { } - static void destroy(JSCell*); +#if ENABLE(JIT) +protected: + virtual CodeBlock* replacement() override; + virtual DFG::CapabilityLevel capabilityLevelInternal() override; +#endif }; -#if ENABLE(WEBASSEMBLY) -class WebAssemblyCodeBlock : public CodeBlock { -public: - typedef CodeBlock Base; - DECLARE_INFO; - - static WebAssemblyCodeBlock* create(VM* vm, CopyParsedBlockTag, WebAssemblyCodeBlock& other) - { - WebAssemblyCodeBlock* instance = new (NotNull, allocateCell<WebAssemblyCodeBlock>(vm->heap)) - WebAssemblyCodeBlock(vm, vm->webAssemblyCodeBlockStructure.get(), CopyParsedBlock, other); - instance->finishCreation(*vm, CopyParsedBlock, other); - return instance; - } - - static WebAssemblyCodeBlock* create(VM* vm, WebAssemblyExecutable* ownerExecutable, JSGlobalObject* globalObject) - { - WebAssemblyCodeBlock* instance = new (NotNull, allocateCell<WebAssemblyCodeBlock>(vm->heap)) - WebAssemblyCodeBlock(vm, vm->webAssemblyCodeBlockStructure.get(), ownerExecutable, globalObject); - instance->finishCreation(*vm, ownerExecutable, globalObject); - return instance; - } - - static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype) - { - return Structure::create(vm, globalObject, prototype, TypeInfo(CellType, StructureFlags), info()); - } +inline CodeBlock* baselineCodeBlockForInlineCallFrame(InlineCallFrame* inlineCallFrame) +{ + RELEASE_ASSERT(inlineCallFrame); + ExecutableBase* executable = inlineCallFrame->executable.get(); + RELEASE_ASSERT(executable->structure()->classInfo() == FunctionExecutable::info()); + return static_cast<FunctionExecutable*>(executable)->baselineCodeBlockFor(inlineCallFrame->isCall ? CodeForCall : CodeForConstruct); +} -private: - WebAssemblyCodeBlock(VM* vm, Structure* structure, CopyParsedBlockTag, WebAssemblyCodeBlock& other) - : CodeBlock(vm, structure, CopyParsedBlock, other) - { - } +inline CodeBlock* baselineCodeBlockForOriginAndBaselineCodeBlock(const CodeOrigin& codeOrigin, CodeBlock* baselineCodeBlock) +{ + if (codeOrigin.inlineCallFrame) + return baselineCodeBlockForInlineCallFrame(codeOrigin.inlineCallFrame); + return baselineCodeBlock; +} - WebAssemblyCodeBlock(VM* vm, Structure* structure, WebAssemblyExecutable* ownerExecutable, JSGlobalObject* globalObject) - : CodeBlock(vm, structure, ownerExecutable, globalObject) - { - } +inline int CodeBlock::argumentIndexAfterCapture(size_t argument) +{ + if (argument >= static_cast<size_t>(symbolTable()->parameterCount())) + return CallFrame::argumentOffset(argument); + + const SlowArgument* slowArguments = symbolTable()->slowArguments(); + if (!slowArguments || slowArguments[argument].status == SlowArgument::Normal) + return CallFrame::argumentOffset(argument); + + ASSERT(slowArguments[argument].status == SlowArgument::Captured); + return slowArguments[argument].index; +} - static void destroy(JSCell*); -}; -#endif +inline bool CodeBlock::hasSlowArguments() +{ + return !!symbolTable()->slowArguments(); +} inline Register& ExecState::r(int index) { @@ -1329,30 +1241,25 @@ inline Register& ExecState::r(int index) return this[index]; } -inline Register& ExecState::r(VirtualRegister reg) -{ - return r(reg.offset()); -} - inline Register& ExecState::uncheckedR(int index) { RELEASE_ASSERT(index < FirstConstantRegisterIndex); return this[index]; } -inline Register& ExecState::uncheckedR(VirtualRegister reg) +inline JSValue ExecState::argumentAfterCapture(size_t argument) { - return uncheckedR(reg.offset()); -} - -inline void CodeBlock::clearVisitWeaklyHasBeenCalled() -{ - m_visitWeaklyHasBeenCalled.store(false, std::memory_order_relaxed); + if (argument >= argumentCount()) + return jsUndefined(); + + if (!codeBlock()) + return this[argumentOffset(argument)].jsValue(); + + return this[codeBlock()->argumentIndexAfterCapture(argument)].jsValue(); } -inline void CodeBlockSet::mark(const LockHolder& locker, void* candidateCodeBlock) +inline void CodeBlockSet::mark(void* candidateCodeBlock) { - ASSERT(m_lock.isLocked()); // We have to check for 0 and -1 because those are used by the HashMap as markers. uintptr_t value = reinterpret_cast<uintptr_t>(candidateCodeBlock); @@ -1361,61 +1268,15 @@ inline void CodeBlockSet::mark(const LockHolder& locker, void* candidateCodeBloc // -1 + 1 = 0 if (value + 1 <= 1) return; - - CodeBlock* codeBlock = static_cast<CodeBlock*>(candidateCodeBlock); - if (!m_oldCodeBlocks.contains(codeBlock) && !m_newCodeBlocks.contains(codeBlock)) - return; - - mark(locker, codeBlock); -} - -inline void CodeBlockSet::mark(const LockHolder&, CodeBlock* codeBlock) -{ - if (!codeBlock) + + HashSet<CodeBlock*>::iterator iter = m_set.find(static_cast<CodeBlock*>(candidateCodeBlock)); + if (iter == m_set.end()) return; - - // Try to recover gracefully if we forget to execute a barrier for a - // CodeBlock that does value profiling. This is probably overkill, but we - // have always done it. - Heap::heap(codeBlock)->writeBarrier(codeBlock); - - m_currentlyExecuting.add(codeBlock); -} - -template <typename Functor> inline void ScriptExecutable::forEachCodeBlock(Functor&& functor) -{ - switch (type()) { - case ProgramExecutableType: { - if (CodeBlock* codeBlock = static_cast<CodeBlock*>(jsCast<ProgramExecutable*>(this)->m_programCodeBlock.get())) - codeBlock->forEachRelatedCodeBlock(std::forward<Functor>(functor)); - break; - } - - case EvalExecutableType: { - if (CodeBlock* codeBlock = static_cast<CodeBlock*>(jsCast<EvalExecutable*>(this)->m_evalCodeBlock.get())) - codeBlock->forEachRelatedCodeBlock(std::forward<Functor>(functor)); - break; - } - - case FunctionExecutableType: { - Functor f(std::forward<Functor>(functor)); - FunctionExecutable* executable = jsCast<FunctionExecutable*>(this); - if (CodeBlock* codeBlock = static_cast<CodeBlock*>(executable->m_codeBlockForCall.get())) - codeBlock->forEachRelatedCodeBlock(f); - if (CodeBlock* codeBlock = static_cast<CodeBlock*>(executable->m_codeBlockForConstruct.get())) - codeBlock->forEachRelatedCodeBlock(f); - break; - } - - case ModuleProgramExecutableType: { - if (CodeBlock* codeBlock = static_cast<CodeBlock*>(jsCast<ModuleProgramExecutable*>(this)->m_moduleProgramCodeBlock.get())) - codeBlock->forEachRelatedCodeBlock(std::forward<Functor>(functor)); - break; - } - - default: - RELEASE_ASSERT_NOT_REACHED(); - } + + (*iter)->m_mayBeExecuting = true; +#if ENABLE(GGC) + m_currentlyExecuting.append(static_cast<CodeBlock*>(candidateCodeBlock)); +#endif } } // namespace JSC |