From a4e969f4965059196ca948db781e52f7cfebf19e Mon Sep 17 00:00:00 2001 From: Lorry Tar Creator Date: Tue, 24 May 2016 08:28:08 +0000 Subject: webkitgtk-2.12.3 --- Source/JavaScriptCore/bytecode/CodeBlock.h | 1061 ++++++++++++++++------------ 1 file changed, 600 insertions(+), 461 deletions(-) (limited to 'Source/JavaScriptCore/bytecode/CodeBlock.h') diff --git a/Source/JavaScriptCore/bytecode/CodeBlock.h b/Source/JavaScriptCore/bytecode/CodeBlock.h index 0d9868079..96cee40c7 100644 --- a/Source/JavaScriptCore/bytecode/CodeBlock.h +++ b/Source/JavaScriptCore/bytecode/CodeBlock.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2008, 2009, 2010, 2011, 2012, 2013, 2014 Apple Inc. All rights reserved. + * Copyright (C) 2008-2015 Apple Inc. All rights reserved. * Copyright (C) 2008 Cameron Zwarich * * 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 Computer, Inc. ("Apple") nor the names of + * 3. Neither the name of Apple 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,34 +38,30 @@ #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" @@ -73,8 +69,8 @@ #include "VirtualRegister.h" #include "Watchpoint.h" #include +#include #include -#include #include #include #include @@ -85,31 +81,51 @@ namespace JSC { class ExecState; class LLIntOffsetsExtractor; -class RepatchBuffer; - -inline VirtualRegister unmodifiedArgumentsRegister(VirtualRegister argumentsRegister) { return VirtualRegister(argumentsRegister.offset() + 1); } - -static ALWAYS_INLINE int missingThisObjectMarker() { return std::numeric_limits::max(); } +class RegisterAtOffsetList; +class TypeLocation; +class JSModuleEnvironment; +class PCToCodeOriginMap; enum ReoptimizationMode { DontCountReoptimization, CountReoptimization }; -class CodeBlock : public ThreadSafeRefCounted, public UnconditionalFinalizer, public WeakReferenceHarvester { - WTF_MAKE_FAST_ALLOCATED; +class CodeBlock : public JSCell { + typedef JSCell Base; 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(CopyParsedBlockTag, CodeBlock& other); - - CodeBlock(ScriptExecutable* ownerExecutable, UnlinkedCodeBlock*, JSScope*, PassRefPtr, unsigned sourceOffset, unsigned firstLineColumnOffset); + CodeBlock(VM*, Structure*, CopyParsedBlockTag, CodeBlock& other); + CodeBlock(VM*, Structure*, ScriptExecutable* ownerExecutable, UnlinkedCodeBlock*, JSScope*, PassRefPtr, 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 WriteBarrier m_globalObject; - Heap* m_heap; public: - JS_EXPORT_PRIVATE virtual ~CodeBlock(); + JS_EXPORT_PRIVATE ~CodeBlock(); UnlinkedCodeBlock* unlinkedCodeBlock() const { return m_unlinkedCode.get(); } @@ -117,6 +133,7 @@ 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; @@ -125,28 +142,58 @@ 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() { return m_alternative.get(); } - PassRefPtr releaseAlternative() { return m_alternative.release(); } - void setAlternative(PassRefPtr alternative) { m_alternative = alternative; } + CodeBlock* alternative() const { return static_cast(m_alternative.get()); } + void setAlternative(VM&, CodeBlock*); + + template void forEachRelatedCodeBlock(Functor&& functor) + { + Functor f(std::forward(functor)); + Vector 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); + } + } CodeSpecializationKind specializationKind() const { return specializationFromIsConstruct(m_isConstructor); } - - CodeBlock* baselineAlternative(); + + CodeBlock* alternativeForJettison(); + JS_EXPORT_PRIVATE CodeBlock* baselineAlternative(); // FIXME: Get rid of this. // https://bugs.webkit.org/show_bug.cgi?id=123677 CodeBlock* baselineVersion(); - void visitAggregate(SlotVisitor&); - - void dumpBytecode(PrintStream& = WTF::dataFile()); - void dumpBytecode(PrintStream&, unsigned bytecodeOffset); + 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 printStructures(PrintStream&, const Instruction*); void printStructure(PrintStream&, const char* name, const Instruction*, int operand); @@ -169,72 +216,72 @@ public: return index >= m_numVars; } - HandlerInfo* handlerForBytecodeOffset(unsigned bytecodeOffset); + enum class RequiredHandler { + CatchHandler, + AnyHandler + }; + HandlerInfo* handlerForBytecodeOffset(unsigned bytecodeOffset, RequiredHandler = RequiredHandler::AnyHandler); + HandlerInfo* handlerForIndex(unsigned, RequiredHandler = RequiredHandler::AnyHandler); + void removeExceptionHandlerForCallSite(CallSiteIndex); unsigned lineNumberForBytecodeOffset(unsigned bytecodeOffset); unsigned columnNumberForBytecodeOffset(unsigned bytecodeOffset); void expressionRangeForBytecodeOffset(unsigned bytecodeOffset, int& divot, int& startOffset, int& endOffset, unsigned& line, unsigned& column); -#if ENABLE(JIT) - StructureStubInfo* addStubInfo(); - Bag::iterator begin() { return m_stubInfos.begin(); } - Bag::iterator end() { return m_stubInfos.end(); } + void getStubInfoMap(const ConcurrentJITLocker&, StubInfoMap& result); + void getStubInfoMap(StubInfoMap& result); + + void getCallLinkInfoMap(const ConcurrentJITLocker&, CallLinkInfoMap& result); + void getCallLinkInfoMap(CallLinkInfoMap& result); - void resetStub(StructureStubInfo&); + void getByValInfoMap(const ConcurrentJITLocker&, ByValInfoMap& result); + void getByValInfoMap(ByValInfoMap& result); - void getStubInfoMap(const ConcurrentJITLocker&, StubInfoMap& result); +#if ENABLE(JIT) + StructureStubInfo* addStubInfo(AccessType); + Bag::iterator stubInfoBegin() { return m_stubInfos.begin(); } + Bag::iterator stubInfoEnd() { return m_stubInfos.end(); } + + // O(n) operation. Use getStubInfoMap() unless you really only intend to get one + // stub info. + StructureStubInfo* findStubInfo(CodeOrigin); - ByValInfo& getByValInfo(unsigned bytecodeIndex) - { - return *(binarySearch(m_byValInfos, m_byValInfos.size(), bytecodeIndex, getByValInfoBytecodeIndex)); - } + ByValInfo* addByValInfo(); - CallLinkInfo& getCallLinkInfo(ReturnAddressPtr returnAddress) - { - return *(binarySearch(m_callLinkInfos, m_callLinkInfos.size(), returnAddress.value(), getCallLinkInfoReturnLocation)); - } + CallLinkInfo* addCallLinkInfo(); + Bag::iterator callLinkInfosBegin() { return m_callLinkInfos.begin(); } + Bag::iterator callLinkInfosEnd() { return m_callLinkInfos.end(); } - CallLinkInfo& getCallLinkInfo(unsigned bytecodeIndex) - { - ASSERT(!JITCode::isOptimizingJIT(jitType())); - return *(binarySearch(m_callLinkInfos, m_callLinkInfos.size(), bytecodeIndex, getCallLinkInfoBytecodeIndex)); - } + // 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); #endif // ENABLE(JIT) void unlinkIncomingCalls(); #if ENABLE(JIT) - void unlinkCalls(); - void linkIncomingCall(ExecState* callerFrame, CallLinkInfo*); - - bool isIncomingCallAlreadyLinked(CallLinkInfo* incoming) - { - return m_incomingCalls.isOnList(incoming); - } + void linkIncomingPolymorphicCall(ExecState* callerFrame, PolymorphicCallNode*); #endif // ENABLE(JIT) -#if ENABLE(LLINT) void linkIncomingCall(ExecState* callerFrame, LLIntCallLinkInfo*); -#endif // ENABLE(LLINT) - void setJITCodeMap(PassOwnPtr jitCodeMap) + void setJITCodeMap(std::unique_ptr jitCodeMap) { - m_jitCodeMap = jitCodeMap; + m_jitCodeMap = WTFMove(jitCodeMap); } CompactJITCodeMap* jitCodeMap() { return m_jitCodeMap.get(); } - + unsigned bytecodeOffset(Instruction* returnAddress) { RELEASE_ASSERT(returnAddress >= instructions().begin() && returnAddress < instructions().end()); return static_cast(returnAddress) - instructions().begin(); } - bool isNumericCompareFunction() { return m_unlinkedCode->isNumericCompareFunction(); } - unsigned numberOfInstructions() const { return m_instructions.size(); } RefCountedArray& instructions() { return m_instructions; } const RefCountedArray& instructions() const { return m_instructions; } @@ -245,28 +292,19 @@ 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()) - PassRefPtr newReplacement(); + CodeBlock* newReplacement(); - void setJITCode(PassRefPtr code, MacroAssemblerCodePtr codeWithArityCheck) + void setJITCode(PassRefPtr code) { - ASSERT(m_heap->isDeferred()); - m_heap->reportExtraMemoryCost(code->size()); + ASSERT(heap()->isDeferred()); + heap()->reportExtraMemoryAllocated(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() { return m_jitCode; } - MacroAssemblerCodePtr jitCodeWithArityCheck() { return m_jitCodeWithArityCheck; } + static ptrdiff_t jitCodeOffset() { return OBJECT_OFFSETOF(CodeBlock, m_jitCode); } JITCode::JITType jitType() const { JITCode* jitCode = m_jitCode.get(); @@ -282,24 +320,20 @@ public: } #if ENABLE(JIT) - virtual CodeBlock* replacement() = 0; + CodeBlock* replacement(); - virtual DFG::CapabilityLevel capabilityLevelInternal() = 0; - DFG::CapabilityLevel capabilityLevel() - { - DFG::CapabilityLevel result = capabilityLevelInternal(); - m_capabilityLevelState = result; - return result; - } - DFG::CapabilityLevel capabilityLevelState() { return m_capabilityLevelState; } + DFG::CapabilityLevel computeCapabilityLevel(); + DFG::CapabilityLevel capabilityLevel(); + DFG::CapabilityLevel capabilityLevelState() { return static_cast(m_capabilityLevelState); } bool hasOptimizedReplacement(JITCode::JITType typeToReplace); bool hasOptimizedReplacement(); // the typeToReplace is my JITType #endif - void jettison(ReoptimizationMode = DontCountReoptimization); + void jettison(Profiler::JettisonReason, ReoptimizationMode = DontCountReoptimization, const FireDetail* = nullptr); - ScriptExecutable* ownerExecutable() const { return m_ownerExecutable.get(); } + ExecutableBase* ownerExecutable() const { return m_ownerExecutable.get(); } + ScriptExecutable* ownerScriptExecutable() const { return jsCast(m_ownerExecutable.get()); } void setVM(VM* vm) { m_vm = vm; } VM* vm() { return m_vm; } @@ -307,78 +341,24 @@ 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 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() + void setScopeRegister(VirtualRegister scopeRegister) { - if (!needsFullScopeChain()) - return VirtualRegister(); - return activationRegister(); + ASSERT(scopeRegister.isLocal() || !scopeRegister.isValid()); + m_scopeRegister = scopeRegister; } - bool usesArguments() const { return m_argumentsRegister.isValid(); } - - bool needsActivation() const - { - return m_needsActivation; - } - - unsigned captureCount() const + VirtualRegister scopeRegister() const { - if (!symbolTable()) - return 0; - return symbolTable()->captureCount(); - } - - int captureStart() const - { - if (!symbolTable()) - return 0; - return symbolTable()->captureStart(); + return m_scopeRegister; } - int captureEnd() const + CodeType codeType() const { - if (!symbolTable()) - return 0; - return symbolTable()->captureEnd(); + return static_cast(m_codeType); } - 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) @@ -393,20 +373,8 @@ 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); @@ -422,17 +390,7 @@ public: unsigned numberOfValueProfiles() { return m_valueProfiles.size(); } ValueProfile* valueProfile(int index) { return &m_valueProfiles[index]; } - ValueProfile* valueProfileForBytecodeOffset(int bytecodeOffset) - { - ValueProfile* result = binarySearch( - m_valueProfiles, m_valueProfiles.size(), bytecodeOffset, - getValueProfileBytecodeOffset); - ASSERT(result->m_bytecodeOffset != -1); - ASSERT(instructions()[bytecodeOffset + opcodeLength( - m_vm->interpreter->getOpcodeID( - instructions()[bytecodeOffset].u.opcode)) - 1].u.profile == result); - return result; - } + ValueProfile* valueProfileForBytecodeOffset(int bytecodeOffset); SpeculatedType valueProfilePredictionForBytecodeOffset(const ConcurrentJITLocker& locker, int bytecodeOffset) { return valueProfileForBytecodeOffset(bytecodeOffset)->computeUpdatedPrediction(locker); @@ -455,19 +413,14 @@ public: return &m_rareCaseProfiles.last(); } unsigned numberOfRareCaseProfiles() { return m_rareCaseProfiles.size(); } - RareCaseProfile* rareCaseProfile(int index) { return &m_rareCaseProfiles[index]; } - RareCaseProfile* rareCaseProfileForBytecodeOffset(int bytecodeOffset) - { - return tryBinarySearch( - m_rareCaseProfiles, m_rareCaseProfiles.size(), bytecodeOffset, - getRareCaseProfileBytecodeOffset); - } + RareCaseProfile* rareCaseProfileForBytecodeOffset(int bytecodeOffset); + unsigned rareCaseProfileCountForBytecodeOffset(int bytecodeOffset); bool likelyToTakeSlowCase(int bytecodeOffset) { if (!hasBaselineJITProfiling()) return false; - unsigned value = rareCaseProfileForBytecodeOffset(bytecodeOffset)->m_counter; + unsigned value = rareCaseProfileCountForBytecodeOffset(bytecodeOffset); return value >= Options::likelyToTakeSlowCaseMinimumCount(); } @@ -475,60 +428,42 @@ public: { if (!hasBaselineJITProfiling()) return false; - unsigned value = rareCaseProfileForBytecodeOffset(bytecodeOffset)->m_counter; + unsigned value = rareCaseProfileCountForBytecodeOffset(bytecodeOffset); return value >= Options::couldTakeSlowCaseMinimumCount(); } - 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* ensureResultProfile(int bytecodeOffset) { - return tryBinarySearch( - m_specialFastCaseProfiles, m_specialFastCaseProfiles.size(), bytecodeOffset, - getRareCaseProfileBytecodeOffset); + 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(); + m_bytecodeOffsetToResultProfileIndexMap->add(bytecodeOffset, m_resultProfiles.size() - 1); + } + return profile; } + unsigned numberOfResultProfiles() { return m_resultProfiles.size(); } + ResultProfile* resultProfileForBytecodeOffset(int bytecodeOffset); - bool likelyToTakeSpecialFastCase(int bytecodeOffset) + unsigned specialFastCaseProfileCountForBytecodeOffset(int bytecodeOffset) { - if (!hasBaselineJITProfiling()) - return false; - unsigned specialFastCaseCount = specialFastCaseProfileForBytecodeOffset(bytecodeOffset)->m_counter; - return specialFastCaseCount >= Options::likelyToTakeSlowCaseMinimumCount(); + ResultProfile* profile = resultProfileForBytecodeOffset(bytecodeOffset); + if (!profile) + return 0; + return profile->specialFastPathCount(); } bool couldTakeSpecialFastCase(int bytecodeOffset) { if (!hasBaselineJITProfiling()) return false; - unsigned specialFastCaseCount = specialFastCaseProfileForBytecodeOffset(bytecodeOffset)->m_counter; + unsigned specialFastCaseCount = specialFastCaseProfileCountForBytecodeOffset(bytecodeOffset); 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) @@ -547,10 +482,7 @@ public: bool hasExpressionInfo() { return m_unlinkedCode->hasExpressionInfo(); } #if ENABLE(DFG_JIT) - Vector& codeOrigins() - { - return m_jitCode->dfgCommon()->codeOrigins; - } + Vector& codeOrigins(); // Having code origins implies that there has been some inlining. bool hasCodeOrigins() @@ -558,16 +490,16 @@ public: return JITCode::isOptimizingJIT(jitType()); } - bool canGetCodeOrigin(unsigned index) + bool canGetCodeOrigin(CallSiteIndex index) { if (!hasCodeOrigins()) return false; - return index < codeOrigins().size(); + return index.bits() < codeOrigins().size(); } - CodeOrigin codeOrigin(unsigned index) + CodeOrigin codeOrigin(CallSiteIndex index) { - return codeOrigins()[index]; + return codeOrigins()[index.bits()]; } bool addFrequentExitSite(const DFG::FrequentExitSite& site) @@ -576,11 +508,15 @@ 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 m_exitProfile.hasExitSite(locker, site); + return hasExitSite(locker, site); } DFG::ExitProfile& exitProfile() { return m_exitProfile; } @@ -589,44 +525,26 @@ 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 - { - 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(index) < unlinkedIdentifiers) - return m_unlinkedCode->identifier(index); - ASSERT(JITCode::isOptimizingJIT(jitType())); - return m_jitCode->dfgCommon()->dfgIdentifiers[index - unlinkedIdentifiers]; - } + size_t numberOfDFGIdentifiers() const; + const Identifier& identifier(int index) const; #else size_t numberOfIdentifiers() const { return m_unlinkedCode->numberOfIdentifiers(); } const Identifier& identifier(int index) const { return m_unlinkedCode->identifier(index); } #endif Vector>& constants() { return m_constantRegisters; } - size_t numberOfConstantRegisters() const { return m_constantRegisters.size(); } + Vector& constantsSourceCodeRepresentation() { return m_constantsSourceCodeRepresentation; } unsigned addConstant(JSValue v) { unsigned result = m_constantRegisters.size(); m_constantRegisters.append(WriteBarrier()); - m_constantRegisters.last().set(m_globalObject->vm(), m_ownerExecutable.get(), v); + m_constantRegisters.last().set(m_globalObject->vm(), this, v); + m_constantsSourceCodeRepresentation.append(SourceCodeRepresentation::Other); return result; } @@ -634,19 +552,19 @@ public: { unsigned result = m_constantRegisters.size(); m_constantRegisters.append(WriteBarrier()); + m_constantsSourceCodeRepresentation.append(SourceCodeRepresentation::Other); return result; } - bool findConstant(JSValue, unsigned& result); - unsigned addOrFindConstant(JSValue); WriteBarrier& 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 @@ -673,15 +591,26 @@ public: return constantBufferAsVector(index).data(); } + Heap* heap() const { return &m_vm->heap; } JSGlobalObject* globalObject() { return m_globalObject.get(); } JSGlobalObject* globalObjectFor(CodeOrigin); BytecodeLivenessAnalysis& livenessAnalysis() { - if (!m_livenessAnalysis) - m_livenessAnalysis = std::make_unique(this); - return *m_livenessAnalysis; + { + ConcurrentJITLocker locker(m_lock); + if (!!m_livenessAnalysis) + return *m_livenessAnalysis; + } + std::unique_ptr analysis = + std::make_unique(this); + { + ConcurrentJITLocker locker(m_lock); + if (!m_livenessAnalysis) + m_livenessAnalysis = WTFMove(analysis); + return *m_livenessAnalysis; + } } void validate(); @@ -702,8 +631,17 @@ 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]; } - - SymbolTable* symbolTable() const { return m_symbolTable.get(); } + // 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]; + } EvalCodeCache& evalCodeCache() { createRareDataIfNecessary(); return m_rareData->m_evalCodeCache; } @@ -741,7 +679,7 @@ public: m_llintExecuteCounter.setNewThreshold(Options::thresholdForJITSoon(), this); } - const ExecutionCounter& llintExecuteCounter() const + const BaselineExecutionCounter& llintExecuteCounter() const { return m_llintExecuteCounter; } @@ -767,9 +705,13 @@ public: // When we observe a lot of speculation failures, we trigger a // reoptimization. But each time, we increase the optimization trigger // to avoid thrashing. - unsigned reoptimizationRetryCounter() const; + JS_EXPORT_PRIVATE 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; @@ -781,11 +723,11 @@ public: return &m_jitExecuteCounter.m_counter; } - 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); } + 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); } - const ExecutionCounter& jitExecuteCounter() const { return m_jitExecuteCounter; } + const BaselineExecutionCounter& jitExecuteCounter() const { return m_jitExecuteCounter; } unsigned optimizationDelayCounter() const { return m_optimizationDelayCounter; } @@ -855,7 +797,14 @@ public: uint32_t exitCountThresholdForReoptimizationFromLoop(); bool shouldReoptimizeNow(); bool shouldReoptimizeFromLoopNow(); + + void setCalleeSaveRegisters(RegisterSet); + void setCalleeSaveRegisters(std::unique_ptr); + + 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 @@ -866,10 +815,11 @@ public: void updateAllPredictions(); unsigned frameRegisterCount(); + int stackPointerOffset(); bool hasOpDebugForLineAndColumn(unsigned line, unsigned column); - int hasDebuggerRequests() const { return !!m_debuggerRequests; } + bool hasDebuggerRequests() const { return m_debuggerRequests; } void* debuggerRequestsAddress() { return &m_debuggerRequests; } void addBreakpoint(unsigned numBreakpoints); @@ -885,13 +835,16 @@ public: }; void setSteppingMode(SteppingMode); - void clearDebuggerRequests() { m_debuggerRequests = 0; } - + void clearDebuggerRequests() + { + m_steppingMode = SteppingModeDisabled; + m_numBreakpoints = 0; + } + // FIXME: Make these remaining members private. - int m_numCalleeRegisters; + int m_numCalleeLocals; 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: @@ -910,20 +863,67 @@ 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; - - bool m_shouldAlwaysBeInlined; - bool m_allTransitionsHaveBeenMarked; // Initialized and used on every GC. - - bool m_didFailFTLCompilation; + + Atomic 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 // 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 m_exceptionHandlers; + + // Buffers used for large array literals + Vector> m_constantBuffers; + + // Jump Tables + Vector m_switchJumpTables; + Vector m_stringSwitchJumpTables; + + Vector 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&&); + Optional findPC(void* pc); +#endif + protected: - virtual void visitWeakReferences(SlotVisitor&) override; - virtual void finalizeUnconditionally() override; + void finalizeLLIntInlineCaches(); + void finalizeBaselineJITInlineCaches(); #if ENABLE(DFG_JIT) void tallyFrequentExitSites(); @@ -940,298 +940,386 @@ private: double optimizationThresholdScalingFactor(); -#if ENABLE(JIT) - ClosureCallStubRoutine* findClosureCallForReturnPC(ReturnAddressPtr); -#endif - void updateAllPredictionsAndCountLiveness(unsigned& numberOfLiveNonArgumentValueProfiles, unsigned& numberOfSamplesInProfiles); - void setConstantRegisters(const Vector>& constants) + void setConstantRegisters(const Vector>& constants, const Vector& constantsSourceCodeRepresentation) { + ASSERT(constants.size() == constantsSourceCodeRepresentation.size()); size_t count = constants.size(); - m_constantRegisters.resize(count); + m_constantRegisters.resizeToFit(count); for (size_t i = 0; i < count; i++) - m_constantRegisters[i].set(*m_vm, ownerExecutable(), constants[i].get()); + m_constantRegisters[i].set(*m_vm, this, constants[i].get()); + m_constantsSourceCodeRepresentation = constantsSourceCodeRepresentation; } - void dumpBytecode(PrintStream&, ExecState*, const Instruction* begin, const Instruction*&, const StubInfoMap& = StubInfoMap()); + void replaceConstant(int index, JSValue value) + { + ASSERT(isConstantRegisterIndex(index) && static_cast(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()); 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); + void printCallOp(PrintStream&, ExecState*, int location, const Instruction*&, const char* op, CacheDumpMode, bool& hasPrintedProfiling, const CallLinkInfoMap&); void printPutByIdOp(PrintStream&, ExecState*, int location, const Instruction*&, const char* op); - 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 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 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); - -#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; + void dumpResultProfile(PrintStream&, ResultProfile*, bool& hasPrintedProfiling); - // 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 + bool shouldVisitStrongly(); + bool shouldJettisonDueToWeakReference(); + bool shouldJettisonDueToOldAge(); 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::steady_clock::now() - m_creationTime); + } void createRareDataIfNecessary() { if (!m_rareData) - m_rareData = adoptPtr(new RareData); + m_rareData = std::make_unique(); } - -#if ENABLE(JIT) - void resetStubInternal(RepatchBuffer&, StructureStubInfo&); - void resetStubDuringGCInternal(RepatchBuffer&, StructureStubInfo&); -#endif + + void insertBasicBlockBoundariesForControlFlowProfiler(RefCountedArray&); + WriteBarrier m_unlinkedCode; int m_numParameters; union { unsigned m_debuggerRequests; struct { + unsigned m_hasDebuggerStatement : 1; unsigned m_steppingMode : 1; - unsigned m_numBreakpoints : 31; + unsigned m_numBreakpoints : 30; }; }; - WriteBarrier m_ownerExecutable; + WriteBarrier m_ownerExecutable; VM* m_vm; RefCountedArray m_instructions; - WriteBarrier m_symbolTable; VirtualRegister m_thisRegister; - VirtualRegister m_argumentsRegister; - VirtualRegister m_activationRegister; - - bool m_isStrictMode; - bool m_needsActivation; - bool m_mayBeExecuting; - uint8_t m_visitAggregateHasBeenCalled; + VirtualRegister m_scopeRegister; + mutable CodeBlockHash m_hash; RefPtr m_source; unsigned m_sourceOffset; unsigned m_firstLineColumnOffset; - unsigned m_codeType; -#if ENABLE(LLINT) - Vector m_llintCallLinkInfos; + RefCountedArray m_llintCallLinkInfos; SentinelLinkedList> m_incomingLLIntCalls; -#endif RefPtr m_jitCode; - MacroAssemblerCodePtr m_jitCodeWithArityCheck; #if ENABLE(JIT) + std::unique_ptr m_calleeSaveRegisters; Bag m_stubInfos; - Vector m_byValInfos; - Vector m_callLinkInfos; + Bag m_byValInfos; + Bag m_callLinkInfos; SentinelLinkedList> m_incomingCalls; + SentinelLinkedList> m_incomingPolymorphicCalls; + std::unique_ptr m_pcToCodeOriginMap; #endif - OwnPtr m_jitCodeMap; + std::unique_ptr 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 - Vector m_argumentValueProfiles; - Vector m_valueProfiles; + RefCountedArray m_argumentValueProfiles; + RefCountedArray m_valueProfiles; SegmentedVector m_rareCaseProfiles; - SegmentedVector m_specialFastCaseProfiles; - Vector m_arrayAllocationProfiles; + SegmentedVector m_resultProfiles; + typedef HashMap, WTF::UnsignedWithZeroKeyHashTraits> BytecodeOffsetToResultProfileIndexMap; + std::unique_ptr m_bytecodeOffsetToResultProfileIndexMap; + RefCountedArray m_arrayAllocationProfiles; ArrayProfileVector m_arrayProfiles; - Vector m_objectAllocationProfiles; + RefCountedArray m_objectAllocationProfiles; // Constant Pool COMPILE_ASSERT(sizeof(Register) == sizeof(WriteBarrier), 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> m_constantRegisters; - Vector> m_functionDecls; - Vector> m_functionExprs; + Vector m_constantsSourceCodeRepresentation; + RefCountedArray> m_functionDecls; + RefCountedArray> m_functionExprs; - RefPtr m_alternative; + WriteBarrier m_alternative; - ExecutionCounter m_llintExecuteCounter; + BaselineExecutionCounter m_llintExecuteCounter; - ExecutionCounter m_jitExecuteCounter; - int32_t m_totalJITExecutions; + BaselineExecutionCounter m_jitExecuteCounter; uint32_t m_osrExitCounter; uint16_t m_optimizationDelayCounter; uint16_t m_reoptimizationRetryCounter; - - mutable CodeBlockHash m_hash; - - std::unique_ptr m_livenessAnalysis; - struct RareData { - WTF_MAKE_FAST_ALLOCATED; - public: - Vector m_exceptionHandlers; + std::chrono::steady_clock::time_point m_creationTime; - // Buffers used for large array literals - Vector> m_constantBuffers; + std::unique_ptr m_livenessAnalysis; - // Jump Tables - Vector m_switchJumpTables; - Vector m_stringSwitchJumpTables; + std::unique_ptr m_rareData; - EvalCodeCache m_evalCodeCache; - }; -#if COMPILER(MSVC) - friend void WTF::deleteOwnedPtr(RareData*); -#endif - OwnPtr m_rareData; -#if ENABLE(JIT) - DFG::CapabilityLevel m_capabilityLevelState; -#endif + UnconditionalFinalizer m_unconditionalFinalizer; + WeakReferenceHarvester m_weakReferenceHarvester; }; // 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(CopyParsedBlockTag, GlobalCodeBlock& other) - : CodeBlock(CopyParsedBlock, other) + GlobalCodeBlock(VM* vm, Structure* structure, CopyParsedBlockTag, GlobalCodeBlock& other) + : CodeBlock(vm, structure, CopyParsedBlock, other) { } - - GlobalCodeBlock(ScriptExecutable* ownerExecutable, UnlinkedCodeBlock* unlinkedCodeBlock, JSScope* scope, PassRefPtr sourceProvider, unsigned sourceOffset, unsigned firstLineColumnOffset) - : CodeBlock(ownerExecutable, unlinkedCodeBlock, scope, sourceProvider, sourceOffset, firstLineColumnOffset) + + GlobalCodeBlock(VM* vm, Structure* structure, ScriptExecutable* ownerExecutable, UnlinkedCodeBlock* unlinkedCodeBlock, JSScope* scope, PassRefPtr sourceProvider, unsigned sourceOffset, unsigned firstLineColumnOffset) + : CodeBlock(vm, structure, ownerExecutable, unlinkedCodeBlock, scope, sourceProvider, sourceOffset, firstLineColumnOffset) { } }; class ProgramCodeBlock : public GlobalCodeBlock { public: - ProgramCodeBlock(CopyParsedBlockTag, ProgramCodeBlock& other) - : GlobalCodeBlock(CopyParsedBlock, other) + typedef GlobalCodeBlock Base; + DECLARE_INFO; + + static ProgramCodeBlock* create(VM* vm, CopyParsedBlockTag, ProgramCodeBlock& other) { + ProgramCodeBlock* instance = new (NotNull, allocateCell(vm->heap)) + ProgramCodeBlock(vm, vm->programCodeBlockStructure.get(), CopyParsedBlock, other); + instance->finishCreation(*vm, CopyParsedBlock, other); + return instance; } - ProgramCodeBlock(ProgramExecutable* ownerExecutable, UnlinkedProgramCodeBlock* unlinkedCodeBlock, JSScope* scope, PassRefPtr sourceProvider, unsigned firstLineColumnOffset) - : GlobalCodeBlock(ownerExecutable, unlinkedCodeBlock, scope, sourceProvider, 0, firstLineColumnOffset) + static ProgramCodeBlock* create(VM* vm, ProgramExecutable* ownerExecutable, UnlinkedProgramCodeBlock* unlinkedCodeBlock, + JSScope* scope, PassRefPtr sourceProvider, unsigned firstLineColumnOffset) { + ProgramCodeBlock* instance = new (NotNull, allocateCell(vm->heap)) + ProgramCodeBlock(vm, vm->programCodeBlockStructure.get(), ownerExecutable, unlinkedCodeBlock, scope, sourceProvider, firstLineColumnOffset); + instance->finishCreation(*vm, ownerExecutable, unlinkedCodeBlock, scope); + return instance; } -#if ENABLE(JIT) -protected: - virtual CodeBlock* replacement() override; - virtual DFG::CapabilityLevel capabilityLevelInternal() override; -#endif + 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, 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(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, unsigned firstLineColumnOffset) + { + ModuleProgramCodeBlock* instance = new (NotNull, allocateCell(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) + { + } + + ModuleProgramCodeBlock(VM* vm, Structure* structure, ModuleProgramExecutable* ownerExecutable, UnlinkedModuleProgramCodeBlock* unlinkedCodeBlock, + JSScope* scope, PassRefPtr sourceProvider, unsigned firstLineColumnOffset) + : GlobalCodeBlock(vm, structure, ownerExecutable, unlinkedCodeBlock, scope, sourceProvider, 0, firstLineColumnOffset) + { + } + + static void destroy(JSCell*); }; class EvalCodeBlock : public GlobalCodeBlock { public: - EvalCodeBlock(CopyParsedBlockTag, EvalCodeBlock& other) - : GlobalCodeBlock(CopyParsedBlock, other) + typedef GlobalCodeBlock Base; + DECLARE_INFO; + + static EvalCodeBlock* create(VM* vm, CopyParsedBlockTag, EvalCodeBlock& other) { + EvalCodeBlock* instance = new (NotNull, allocateCell(vm->heap)) + EvalCodeBlock(vm, vm->evalCodeBlockStructure.get(), CopyParsedBlock, other); + instance->finishCreation(*vm, CopyParsedBlock, other); + return instance; } - - EvalCodeBlock(EvalExecutable* ownerExecutable, UnlinkedEvalCodeBlock* unlinkedCodeBlock, JSScope* scope, PassRefPtr sourceProvider) - : GlobalCodeBlock(ownerExecutable, unlinkedCodeBlock, scope, sourceProvider, 0, 1) + + static EvalCodeBlock* create(VM* vm, EvalExecutable* ownerExecutable, UnlinkedEvalCodeBlock* unlinkedCodeBlock, + JSScope* scope, PassRefPtr sourceProvider) { + EvalCodeBlock* instance = new (NotNull, allocateCell(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) + { + return Structure::create(vm, globalObject, prototype, TypeInfo(CellType, StructureFlags), info()); + } + const Identifier& variable(unsigned index) { return unlinkedEvalCodeBlock()->variable(index); } unsigned numVariables() { return unlinkedEvalCodeBlock()->numVariables(); } -#if ENABLE(JIT) -protected: - virtual CodeBlock* replacement() override; - virtual DFG::CapabilityLevel capabilityLevelInternal() override; -#endif +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) + : GlobalCodeBlock(vm, structure, ownerExecutable, unlinkedCodeBlock, scope, sourceProvider, 0, 1) + { + } + static void destroy(JSCell*); + private: UnlinkedEvalCodeBlock* unlinkedEvalCodeBlock() const { return jsCast(unlinkedCodeBlock()); } }; class FunctionCodeBlock : public CodeBlock { public: - FunctionCodeBlock(CopyParsedBlockTag, FunctionCodeBlock& other) - : CodeBlock(CopyParsedBlock, other) + typedef CodeBlock Base; + DECLARE_INFO; + + static FunctionCodeBlock* create(VM* vm, CopyParsedBlockTag, FunctionCodeBlock& other) + { + FunctionCodeBlock* instance = new (NotNull, allocateCell(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, unsigned sourceOffset, unsigned firstLineColumnOffset) + { + FunctionCodeBlock* instance = new (NotNull, allocateCell(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(FunctionExecutable* ownerExecutable, UnlinkedFunctionCodeBlock* unlinkedCodeBlock, JSScope* scope, PassRefPtr sourceProvider, unsigned sourceOffset, unsigned firstLineColumnOffset) - : CodeBlock(ownerExecutable, unlinkedCodeBlock, scope, sourceProvider, sourceOffset, firstLineColumnOffset) + FunctionCodeBlock(VM* vm, Structure* structure, FunctionExecutable* ownerExecutable, UnlinkedFunctionCodeBlock* unlinkedCodeBlock, JSScope* scope, + PassRefPtr sourceProvider, unsigned sourceOffset, unsigned firstLineColumnOffset) + : CodeBlock(vm, structure, ownerExecutable, unlinkedCodeBlock, scope, sourceProvider, sourceOffset, firstLineColumnOffset) { } -#if ENABLE(JIT) -protected: - virtual CodeBlock* replacement() override; - virtual DFG::CapabilityLevel capabilityLevelInternal() override; -#endif + static void destroy(JSCell*); }; -inline CodeBlock* baselineCodeBlockForInlineCallFrame(InlineCallFrame* inlineCallFrame) -{ - RELEASE_ASSERT(inlineCallFrame); - ExecutableBase* executable = inlineCallFrame->executable.get(); - RELEASE_ASSERT(executable->structure()->classInfo() == FunctionExecutable::info()); - return static_cast(executable)->baselineCodeBlockFor(inlineCallFrame->isCall ? CodeForCall : CodeForConstruct); -} +#if ENABLE(WEBASSEMBLY) +class WebAssemblyCodeBlock : public CodeBlock { +public: + typedef CodeBlock Base; + DECLARE_INFO; -inline CodeBlock* baselineCodeBlockForOriginAndBaselineCodeBlock(const CodeOrigin& codeOrigin, CodeBlock* baselineCodeBlock) -{ - if (codeOrigin.inlineCallFrame) - return baselineCodeBlockForInlineCallFrame(codeOrigin.inlineCallFrame); - return baselineCodeBlock; -} + static WebAssemblyCodeBlock* create(VM* vm, CopyParsedBlockTag, WebAssemblyCodeBlock& other) + { + WebAssemblyCodeBlock* instance = new (NotNull, allocateCell(vm->heap)) + WebAssemblyCodeBlock(vm, vm->webAssemblyCodeBlockStructure.get(), CopyParsedBlock, other); + instance->finishCreation(*vm, CopyParsedBlock, other); + return instance; + } -inline int CodeBlock::argumentIndexAfterCapture(size_t argument) -{ - if (argument >= static_cast(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 WebAssemblyCodeBlock* create(VM* vm, WebAssemblyExecutable* ownerExecutable, JSGlobalObject* globalObject) + { + WebAssemblyCodeBlock* instance = new (NotNull, allocateCell(vm->heap)) + WebAssemblyCodeBlock(vm, vm->webAssemblyCodeBlockStructure.get(), ownerExecutable, globalObject); + instance->finishCreation(*vm, ownerExecutable, globalObject); + return instance; + } -inline bool CodeBlock::hasSlowArguments() -{ - return !!symbolTable()->slowArguments(); -} + static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue prototype) + { + return Structure::create(vm, globalObject, prototype, TypeInfo(CellType, StructureFlags), info()); + } + +private: + WebAssemblyCodeBlock(VM* vm, Structure* structure, CopyParsedBlockTag, WebAssemblyCodeBlock& other) + : CodeBlock(vm, structure, CopyParsedBlock, other) + { + } + + WebAssemblyCodeBlock(VM* vm, Structure* structure, WebAssemblyExecutable* ownerExecutable, JSGlobalObject* globalObject) + : CodeBlock(vm, structure, ownerExecutable, globalObject) + { + } + + static void destroy(JSCell*); +}; +#endif inline Register& ExecState::r(int index) { @@ -1241,25 +1329,30 @@ 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 JSValue ExecState::argumentAfterCapture(size_t argument) +inline Register& ExecState::uncheckedR(VirtualRegister reg) { - if (argument >= argumentCount()) - return jsUndefined(); - - if (!codeBlock()) - return this[argumentOffset(argument)].jsValue(); - - return this[codeBlock()->argumentIndexAfterCapture(argument)].jsValue(); + return uncheckedR(reg.offset()); } -inline void CodeBlockSet::mark(void* candidateCodeBlock) +inline void CodeBlock::clearVisitWeaklyHasBeenCalled() { + m_visitWeaklyHasBeenCalled.store(false, std::memory_order_relaxed); +} + +inline void CodeBlockSet::mark(const LockHolder& locker, 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(candidateCodeBlock); @@ -1268,15 +1361,61 @@ inline void CodeBlockSet::mark(void* candidateCodeBlock) // -1 + 1 = 0 if (value + 1 <= 1) return; - - HashSet::iterator iter = m_set.find(static_cast(candidateCodeBlock)); - if (iter == m_set.end()) + + CodeBlock* codeBlock = static_cast(candidateCodeBlock); + if (!m_oldCodeBlocks.contains(codeBlock) && !m_newCodeBlocks.contains(codeBlock)) return; - - (*iter)->m_mayBeExecuting = true; -#if ENABLE(GGC) - m_currentlyExecuting.append(static_cast(candidateCodeBlock)); -#endif + + mark(locker, codeBlock); +} + +inline void CodeBlockSet::mark(const LockHolder&, CodeBlock* codeBlock) +{ + if (!codeBlock) + 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 inline void ScriptExecutable::forEachCodeBlock(Functor&& functor) +{ + switch (type()) { + case ProgramExecutableType: { + if (CodeBlock* codeBlock = static_cast(jsCast(this)->m_programCodeBlock.get())) + codeBlock->forEachRelatedCodeBlock(std::forward(functor)); + break; + } + + case EvalExecutableType: { + if (CodeBlock* codeBlock = static_cast(jsCast(this)->m_evalCodeBlock.get())) + codeBlock->forEachRelatedCodeBlock(std::forward(functor)); + break; + } + + case FunctionExecutableType: { + Functor f(std::forward(functor)); + FunctionExecutable* executable = jsCast(this); + if (CodeBlock* codeBlock = static_cast(executable->m_codeBlockForCall.get())) + codeBlock->forEachRelatedCodeBlock(f); + if (CodeBlock* codeBlock = static_cast(executable->m_codeBlockForConstruct.get())) + codeBlock->forEachRelatedCodeBlock(f); + break; + } + + case ModuleProgramExecutableType: { + if (CodeBlock* codeBlock = static_cast(jsCast(this)->m_moduleProgramCodeBlock.get())) + codeBlock->forEachRelatedCodeBlock(std::forward(functor)); + break; + } + + default: + RELEASE_ASSERT_NOT_REACHED(); + } } } // namespace JSC -- cgit v1.2.1