WebKit Bugzilla
Attachment 340417 Details for
Bug 185652
: JSC should have InstanceOf inline caching
Home
|
New
|
Browse
|
Search
|
[?]
|
Reports
|
Requests
|
Help
|
New Account
|
Log In
Remember
[x]
|
Forgot Password
Login:
[x]
[patch]
it begins
blah.patch (text/plain), 20.29 KB, created by
Filip Pizlo
on 2018-05-15 10:06:25 PDT
(
hide
)
Description:
it begins
Filename:
MIME Type:
Creator:
Filip Pizlo
Created:
2018-05-15 10:06:25 PDT
Size:
20.29 KB
patch
obsolete
>Index: Source/JavaScriptCore/bytecode/AccessCase.cpp >=================================================================== >--- Source/JavaScriptCore/bytecode/AccessCase.cpp (revision 231772) >+++ Source/JavaScriptCore/bytecode/AccessCase.cpp (working copy) >@@ -221,12 +221,13 @@ bool AccessCase::canReplace(const Access > { > // This puts in a good effort to try to figure out if 'other' is made superfluous by '*this'. > // It's fine for this to return false if it's in doubt. >- >+ > switch (type()) { > case ArrayLength: > case StringLength: > case DirectArgumentsLength: > case ScopedArgumentsLength: >+ case InstanceOfGeneric: > return other.type() == type(); > case ModuleNamespaceLoad: { > if (other.type() != type()) >@@ -235,6 +236,16 @@ bool AccessCase::canReplace(const Access > auto& otherCase = this->as<ModuleNamespaceAccessCase>(); > return thisCase.moduleNamespaceObject() == otherCase.moduleNamespaceObject(); > } >+ case InstanceOfHit: >+ case InstanceOfMiss: { >+ if (other.type() != type()) >+ return false; >+ >+ if (this->as<InstanceOfAccessCase>().prototype() != other.as<InstanceOfAccessCase>().prototype()) >+ return false; >+ >+ return structure() == other.structure(); >+ } > default: > if (other.type() != type()) > return false; >@@ -311,6 +322,9 @@ bool AccessCase::visitWeak(VM& vm) const > return false; > if (accessCase.moduleEnvironment() && !Heap::isMarked(accessCase.moduleEnvironment())) > return false; >+ } else if (type() == InstanceOfHit || type() == InstanceOfMiss) { >+ if (as<InstanceOfAccessCase>().prototype() && !Heap::isMarked(as<InstanceOfAccessCase>().prototype())) >+ return false; > } > > return true; >Index: Source/JavaScriptCore/bytecode/AccessCase.h >=================================================================== >--- Source/JavaScriptCore/bytecode/AccessCase.h (revision 231772) >+++ Source/JavaScriptCore/bytecode/AccessCase.h (working copy) >@@ -99,6 +99,9 @@ public: > DirectArgumentsLength, > ScopedArgumentsLength, > ModuleNamespaceLoad, >+ InstanceOfHit, >+ InstanceOfMiss, >+ InstanceOfGeneric > }; > > enum State : uint8_t { >@@ -126,7 +129,7 @@ public: > // This create method should be used for transitions. > static std::unique_ptr<AccessCase> create(VM&, JSCell* owner, PropertyOffset, Structure* oldStructure, > Structure* newStructure, const ObjectPropertyConditionSet&, std::unique_ptr<PolyProtoAccessChain>); >- >+ > static std::unique_ptr<AccessCase> fromStructureStubInfo(VM&, JSCell* owner, StructureStubInfo&); > > AccessType type() const { return m_type; } >Index: Source/JavaScriptCore/bytecode/InstanceOfAccessCase.h >=================================================================== >--- Source/JavaScriptCore/bytecode/InstanceOfAccessCase.h (nonexistent) >+++ Source/JavaScriptCore/bytecode/InstanceOfAccessCase.h (working copy) >@@ -0,0 +1,61 @@ >+/* >+ * Copyright (C) 2018 Apple Inc. All rights reserved. >+ * >+ * Redistribution and use in source and binary forms, with or without >+ * modification, are permitted provided that the following conditions >+ * are met: >+ * 1. Redistributions of source code must retain the above copyright >+ * notice, this list of conditions and the following disclaimer. >+ * 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. >+ * >+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY >+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE >+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR >+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR >+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, >+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, >+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR >+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY >+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT >+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE >+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. >+ */ >+ >+#pragma once >+ >+#if ENABLE(JIT) >+ >+#include "AccessCase.h" >+ >+namespace JSC { >+ >+class InstanceOfAccessCase : public AccessCase { >+public: >+ using Base = AccessCase; >+ >+ static std::unique_ptr<AccessCase> create( >+ VM&, JSCell*, AccessType, Structure*, const ObjectPropertyConditionSet&, >+ JSObject* prototype); >+ >+ JSObject* prototype() const { return m_prototype.get(); } >+ >+ void dumpImpl(PrintStream&, CommaPrinter&) const override; >+ std::unique_ptr<AccessCase> clone() const override; >+ >+ ~InstanceOFAccessCase(); >+ >+protected: >+ InstanceOfAccessCase( >+ VM&, JSCell*, AccessType, Structure*, const ObjectPropertyConditionSet&, >+ JSObject* prototype); >+ >+private: >+ WriteBarrier<JSObject> m_prototype; >+}; >+ >+} // namespace JSC >+ >+#endif // ENABLE(JIT) >+ >Index: Source/JavaScriptCore/bytecode/PolymorphicAccess.cpp >=================================================================== >--- Source/JavaScriptCore/bytecode/PolymorphicAccess.cpp (revision 231772) >+++ Source/JavaScriptCore/bytecode/PolymorphicAccess.cpp (working copy) >@@ -258,39 +258,41 @@ AccessGenerationResult PolymorphicAccess > if (casesToAdd.isEmpty()) > return AccessGenerationResult::MadeNoChanges; > >- bool shouldReset = false; >- AccessGenerationResult resetResult(AccessGenerationResult::ResetStubAndFireWatchpoints); >- auto considerPolyProtoReset = [&] (Structure* a, Structure* b) { >- if (Structure::shouldConvertToPolyProto(a, b)) { >- // For now, we only reset if this is our first time invalidating this watchpoint. >- // The reason we don't immediately fire this watchpoint is that we may be already >- // watching the poly proto watchpoint, which if fired, would destroy us. We let >- // the person handling the result to do a delayed fire. >- ASSERT(a->rareData()->sharedPolyProtoWatchpoint().get() == b->rareData()->sharedPolyProtoWatchpoint().get()); >- if (a->rareData()->sharedPolyProtoWatchpoint()->isStillValid()) { >- shouldReset = true; >- resetResult.addWatchpointToFire(*a->rareData()->sharedPolyProtoWatchpoint(), StringFireDetail("Detected poly proto optimization opportunity.")); >+ if (stubInfo.accessType != AccessType::InstanceOf) { >+ bool shouldReset = false; >+ AccessGenerationResult resetResult(AccessGenerationResult::ResetStubAndFireWatchpoints); >+ auto considerPolyProtoReset = [&] (Structure* a, Structure* b) { >+ if (Structure::shouldConvertToPolyProto(a, b)) { >+ // For now, we only reset if this is our first time invalidating this watchpoint. >+ // The reason we don't immediately fire this watchpoint is that we may be already >+ // watching the poly proto watchpoint, which if fired, would destroy us. We let >+ // the person handling the result to do a delayed fire. >+ ASSERT(a->rareData()->sharedPolyProtoWatchpoint().get() == b->rareData()->sharedPolyProtoWatchpoint().get()); >+ if (a->rareData()->sharedPolyProtoWatchpoint()->isStillValid()) { >+ shouldReset = true; >+ resetResult.addWatchpointToFire(*a->rareData()->sharedPolyProtoWatchpoint(), StringFireDetail("Detected poly proto optimization opportunity.")); >+ } > } >- } >- }; >+ }; > >- for (auto& caseToAdd : casesToAdd) { >- for (auto& existingCase : m_list) { >- Structure* a = caseToAdd->structure(); >- Structure* b = existingCase->structure(); >- considerPolyProtoReset(a, b); >+ for (auto& caseToAdd : casesToAdd) { >+ for (auto& existingCase : m_list) { >+ Structure* a = caseToAdd->structure(); >+ Structure* b = existingCase->structure(); >+ considerPolyProtoReset(a, b); >+ } > } >- } >- for (unsigned i = 0; i < casesToAdd.size(); ++i) { >- for (unsigned j = i + 1; j < casesToAdd.size(); ++j) { >- Structure* a = casesToAdd[i]->structure(); >- Structure* b = casesToAdd[j]->structure(); >- considerPolyProtoReset(a, b); >+ for (unsigned i = 0; i < casesToAdd.size(); ++i) { >+ for (unsigned j = i + 1; j < casesToAdd.size(); ++j) { >+ Structure* a = casesToAdd[i]->structure(); >+ Structure* b = casesToAdd[j]->structure(); >+ considerPolyProtoReset(a, b); >+ } > } >- } > >- if (shouldReset) >- return resetResult; >+ if (shouldReset) >+ return resetResult; >+ } > > // Now add things to the new list. Note that at this point, we will still have old cases that > // may be replaced by the new ones. That's fine. We will sort that out when we regenerate. >Index: Source/JavaScriptCore/bytecode/StructureStubInfo.h >=================================================================== >--- Source/JavaScriptCore/bytecode/StructureStubInfo.h (revision 231772) >+++ Source/JavaScriptCore/bytecode/StructureStubInfo.h (working copy) >@@ -50,7 +50,8 @@ enum class AccessType : int8_t { > GetDirect, > TryGet, > Put, >- In >+ In, >+ InstanceOf > }; > > enum class CacheType : int8_t { >@@ -138,6 +139,10 @@ public: > // we don't already have a case buffered for. Note that if this returns true but the > // bufferingCountdown is not zero then we will buffer the access case for later without > // immediately generating code for it. >+ // >+ // NOTE: This will behave oddly for InstanceOf if the user varies the prototype but not >+ // the base's structure. That seems unlikely for the canonical use of instanceof, where >+ // the prototype is fixed. > bool isNewlyAdded = bufferedStructures.add(structure); > if (isNewlyAdded) { > VM& vm = *codeBlock->vm(); >@@ -169,7 +174,7 @@ public: > StructureSet bufferedStructures; > > struct { >- CodeLocationLabel<JITStubRoutinePtrTag> start; // This is either the start of the inline IC for *byId caches, or the location of patchable jump for 'in' caches. >+ CodeLocationLabel<JITStubRoutinePtrTag> start; // This is either the start of the inline IC for *byId caches, or the location of patchable jump for 'in' and 'instanceof' caches. > RegisterSet usedRegisters; > uint32_t inlineSize; > int32_t deltaFromStartToSlowPathCallLocation; >Index: Source/JavaScriptCore/jit/JITInlineCacheGenerator.cpp >=================================================================== >--- Source/JavaScriptCore/jit/JITInlineCacheGenerator.cpp (revision 231772) >+++ Source/JavaScriptCore/jit/JITInlineCacheGenerator.cpp (working copy) >@@ -43,23 +43,44 @@ static StructureStubInfo* garbageStubInf > } > > JITInlineCacheGenerator::JITInlineCacheGenerator( >- CodeBlock* codeBlock, CodeOrigin codeOrigin, CallSiteIndex callSite, AccessType accessType) >+ CodeBlock* codeBlock, CodeOrigin codeOrigin, CallSiteIndex callSite, AccessType accessType, >+ const RegisterSet& usedRegisters) > : m_codeBlock(codeBlock) > { > m_stubInfo = m_codeBlock ? m_codeBlock->addStubInfo(accessType) : garbageStubInfo(); > m_stubInfo->codeOrigin = codeOrigin; > m_stubInfo->callSiteIndex = callSite; >+ >+ m_stubInfo->patch.usedRegisters = usedRegisters; >+} >+ >+JITInlineCacheGenerator::~JITInlineCacheGenerator() >+{ >+} >+ >+void JITInlineCacheGenerator::finalize( >+ LinkBuffer& fastPath, LinkBuffer& slowPath, CodeLocationLabel<JITStubRoutinePtrTag> start) >+{ >+ m_stubInfo->patch.start = start; >+ >+ int32_t inlineSize = MacroAssembler::differenceBetweenCodePtr( >+ start, fastPath.locationOf<NoPtrTag>(m_done)); >+ ASSERT(inlineSize > 0); >+ m_stubInfo->patch.inlineSize = inlineSize; >+ >+ m_stubInfo->patch.deltaFromStartToSlowPathCallLocation = MacroAssembler::differenceBetweenCodePtr( >+ start, slowPath.locationOf<NoPtrTag>(m_slowPathCall)); >+ m_stubInfo->patch.deltaFromStartToSlowPathStart = MacroAssembler::differenceBetweenCodePtr( >+ start, slowPath.locationOf<NoPtrTag>(m_slowPathBegin)); > } > > JITByIdGenerator::JITByIdGenerator( > CodeBlock* codeBlock, CodeOrigin codeOrigin, CallSiteIndex callSite, AccessType accessType, > const RegisterSet& usedRegisters, JSValueRegs base, JSValueRegs value) >- : JITInlineCacheGenerator(codeBlock, codeOrigin, callSite, accessType) >+ : JITInlineCacheGenerator(codeBlock, codeOrigin, callSite, accessType, usedRegisters) > , m_base(base) > , m_value(value) > { >- m_stubInfo->patch.usedRegisters = usedRegisters; >- > m_stubInfo->patch.baseGPR = static_cast<int8_t>(base.payloadGPR()); > m_stubInfo->patch.valueGPR = static_cast<int8_t>(value.payloadGPR()); > m_stubInfo->patch.thisGPR = static_cast<int8_t>(InvalidGPRReg); >@@ -73,23 +94,8 @@ JITByIdGenerator::JITByIdGenerator( > void JITByIdGenerator::finalize(LinkBuffer& fastPath, LinkBuffer& slowPath) > { > ASSERT(m_start.isSet()); >- CodeLocationLabel<JITStubRoutinePtrTag> start = fastPath.locationOf<JITStubRoutinePtrTag>(m_start); >- m_stubInfo->patch.start = start; >- >- int32_t inlineSize = MacroAssembler::differenceBetweenCodePtr( >- start, fastPath.locationOf<NoPtrTag>(m_done)); >- ASSERT(inlineSize > 0); >- m_stubInfo->patch.inlineSize = inlineSize; >- >- m_stubInfo->patch.deltaFromStartToSlowPathCallLocation = MacroAssembler::differenceBetweenCodePtr( >- start, slowPath.locationOf<NoPtrTag>(m_slowPathCall)); >- m_stubInfo->patch.deltaFromStartToSlowPathStart = MacroAssembler::differenceBetweenCodePtr( >- start, slowPath.locationOf<NoPtrTag>(m_slowPathBegin)); >-} >- >-void JITByIdGenerator::finalize(LinkBuffer& linkBuffer) >-{ >- finalize(linkBuffer, linkBuffer); >+ JITInlineCacheGenerator::finalize( >+ fastPath, slowPath, fastPath.locationOf<JITStubRoutinePtrTag>(m_start)); > } > > void JITByIdGenerator::generateFastCommon(MacroAssembler& jit, size_t inlineICSize) >@@ -165,6 +171,33 @@ V_JITOperation_ESsiJJI JITPutByIdGenerat > return operationPutByIdNonStrictOptimize; > } > >+void JITInstanceOfGenerator::JITInstanceOfGenerator( >+ CodeBlock* codeBlock, CodeOrigin codeOrigin, CallSiteIndex callSiteIndex, >+ const RegisterSet& usedRegisters, GPRReg result, GPRReg value, GPRReg prototype, >+ GPRReg scratch1, GPRReg scratch2) >+ : JITInlineCacheGenerator( >+ codeBlock, codeOrigin, callSiteIndex, AccessType::InstanceOf, usedRegisters) >+ , m_result(result) >+ , m_value(value) >+ , m_prototype(prototype) >+{ >+ m_stubInfo->patch.usedRegisters.clear(result); >+ m_stubInfo->patch.usedRegisters.clear(scratch1); >+ m_stubInfo->patch.usedRegisters.clear(scratch2); >+} >+ >+void JITInstanceOfGenerator::generateFastPath(MacroAssembler& jit) >+{ >+ m_jump = m_jit.patchableJump(); >+} >+ >+void JITInstanceOfGenerator::finalize(LinkBuffer& fastPath, LinkBuffer& slowPath) >+{ >+ JITInlineCacheGenerator::finalize( >+ fastPath, slowPath, >+ linkBuffer.locationOf<JITStubRoutinePtrTag>(m_jump)); >+} >+ > } // namespace JSC > > #endif // ENABLE(JIT) >Index: Source/JavaScriptCore/jit/JITInlineCacheGenerator.h >=================================================================== >--- Source/JavaScriptCore/jit/JITInlineCacheGenerator.h (revision 231772) >+++ Source/JavaScriptCore/jit/JITInlineCacheGenerator.h (working copy) >@@ -1,5 +1,5 @@ > /* >- * Copyright (C) 2013, 2015 Apple Inc. All rights reserved. >+ * Copyright (C) 2013-2018 Apple Inc. All rights reserved. > * > * Redistribution and use in source and binary forms, with or without > * modification, are permitted provided that the following conditions >@@ -45,14 +45,31 @@ enum class AccessType : int8_t; > class JITInlineCacheGenerator { > protected: > JITInlineCacheGenerator() { } >- JITInlineCacheGenerator(CodeBlock*, CodeOrigin, CallSiteIndex, AccessType); >+ JITInlineCacheGenerator( >+ CodeBlock*, CodeOrigin, CallSiteIndex, AccessType, const RegisterSet& usedRegisters); > > public: > StructureStubInfo* stubInfo() const { return m_stubInfo; } > >+ void reportSlowPathCall(MacroAssembler::Label slowPathBegin, MacroAssembler::Call call) >+ { >+ m_slowPathBegin = slowPathBegin; >+ m_slowPathCall = call; >+ } >+ >+ MacroAssembler::Label slowPathBegin() const { return m_slowPathBegin; } >+ >+ void finalize( >+ LinkBuffer& fastPathLinkBuffer, LinkBuffer& slowPathLinkBuffer, >+ CodeLocationLabel<JITStubRoutinePtrTag> start); >+ > protected: > CodeBlock* m_codeBlock; > StructureStubInfo* m_stubInfo; >+ >+ MacroAssembler::Label m_done; >+ MacroAssembler::Label m_slowPathBegin; >+ MacroAssembler::Call m_slowPathCall; > }; > > class JITByIdGenerator : public JITInlineCacheGenerator { >@@ -60,36 +77,27 @@ protected: > JITByIdGenerator() { } > > JITByIdGenerator( >- CodeBlock*, CodeOrigin, CallSiteIndex, AccessType, const RegisterSet&, JSValueRegs base, >- JSValueRegs value); >- >+ CodeBlock*, CodeOrigin, CallSiteIndex, AccessType, const RegisterSet& usedRegisters, >+ JSValueRegs base, JSValueRegs value); >+ > public: >- void reportSlowPathCall(MacroAssembler::Label slowPathBegin, MacroAssembler::Call call) >- { >- m_slowPathBegin = slowPathBegin; >- m_slowPathCall = call; >- } >- >- MacroAssembler::Label slowPathBegin() const { return m_slowPathBegin; } > MacroAssembler::Jump slowPathJump() const > { > ASSERT(m_slowPathJump.isSet()); > return m_slowPathJump; > } > >- void finalize(LinkBuffer& fastPathLinkBuffer, LinkBuffer& slowPathLinkBuffer); >- void finalize(LinkBuffer&); >+ void finalize( >+ LinkBuffer& fastPathLinkBuffer, LinkBuffer& slowPathLinkBuffer); > > protected: >+ > void generateFastCommon(MacroAssembler&, size_t size); > > JSValueRegs m_base; > JSValueRegs m_value; >- >+ > MacroAssembler::Label m_start; >- MacroAssembler::Label m_done; >- MacroAssembler::Label m_slowPathBegin; >- MacroAssembler::Call m_slowPathCall; > MacroAssembler::Jump m_slowPathJump; > }; > >@@ -124,7 +132,7 @@ public: > > JITPutByIdGenerator( > CodeBlock*, CodeOrigin, CallSiteIndex, const RegisterSet& usedRegisters, JSValueRegs base, >- JSValueRegs, GPRReg scratch, ECMAMode, PutKind); >+ JSValueRegs value, GPRReg scratch, ECMAMode, PutKind); > > void generateFastPath(MacroAssembler&); > >@@ -135,6 +143,26 @@ private: > PutKind m_putKind; > }; > >+class JITInstanceOfGenerator : public JITInlineCacheGenerator { >+public: >+ JITInstanceOfGenerator() { } >+ >+ JITInstanceOfGenerator( >+ CodeBlock*, CodeOrigin, CallSiteIndex, const RegisterSet& usedRegisters, GPRReg result, >+ GPRReg value, GPRReg prototype, GPRReg scratch1, GPRReg scratch2); >+ >+ void generateFastPath(MacroAssembler&); >+ >+ void finalize(LinkBuffer& fastPathLinkBuffer, LinkBuffer& slowPathLinkBuffer); >+ >+private: >+ GPRReg m_result; >+ GPRReg m_value; >+ GPRReg m_prototype; >+ >+ MacroAssembler::PatchableJump m_jump; >+}; >+ > } // namespace JSC > > #endif // ENABLE(JIT) >Index: Source/JavaScriptCore/runtime/Options.h >=================================================================== >--- Source/JavaScriptCore/runtime/Options.h (revision 231772) >+++ Source/JavaScriptCore/runtime/Options.h (working copy) >@@ -284,7 +284,7 @@ constexpr bool enableWebAssemblyStreamin > v(bool, logExecutableAllocation, false, Normal, nullptr) \ > \ > v(bool, useConcurrentJIT, true, Normal, "allows the DFG / FTL compilation in threads other than the executing JS thread") \ >- v(unsigned, numberOfDFGCompilerThreads, computeNumberOfWorkerThreads(3, 2) - 1, Normal, nullptr) \ >+ v(unsigned, numberOfDFGCompilerThreads, computeNumberOfWorkerThreads(MAXIMUM_NUMBER_OF_FTL_COMPILER_THREADS, 2) - 1, Normal, nullptr) \ > v(unsigned, numberOfFTLCompilerThreads, computeNumberOfWorkerThreads(MAXIMUM_NUMBER_OF_FTL_COMPILER_THREADS, 2) - 1, Normal, nullptr) \ > v(int32, priorityDeltaOfDFGCompilerThreads, computePriorityDeltaOfWorkerThreads(-1, 0), Normal, nullptr) \ > v(int32, priorityDeltaOfFTLCompilerThreads, computePriorityDeltaOfWorkerThreads(-2, 0), Normal, nullptr) \
You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
View the attachment on a separate page
.
View Attachment As Diff
View Attachment As Raw
Actions:
View
|
Formatted Diff
|
Diff
Attachments on
bug 185652
:
340417
|
340419
|
340440
|
340446
|
340499
|
340511
|
340512
|
340537
|
340548
|
340549
|
340551
|
340555
|
340556
|
340573
|
340574
|
340576
|
340580
|
340585
|
340593
|
340616
|
340636
|
340649
|
340665
|
340703
|
340704