DFG should be able to cache closure calls (part 2/2)
https://bugs.webkit.org/show_bug.cgi?id=102662
Reviewed by Gavin Barraclough.
Added caching of calls where the JSFunction* varies, but the Structure* and ExecutableBase*
stay the same. This is accomplished by replacing the branch that compares against a constant
JSFunction* with a jump to a closure call stub. The closure call stub contains a fast path,
and jumps slow directly to the virtual call thunk.
Looks like a 1% win on V8v7.
* CMakeLists.txt:
* GNUmakefile.list.am:
* JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.vcproj:
* JavaScriptCore.xcodeproj/project.pbxproj:
* Target.pri:
* bytecode/CallLinkInfo.cpp:
(JSC::CallLinkInfo::unlink):
* bytecode/CallLinkInfo.h:
(CallLinkInfo):
(JSC::CallLinkInfo::isLinked):
(JSC::getCallLinkInfoBytecodeIndex):
* bytecode/CodeBlock.cpp:
(JSC::CodeBlock::finalizeUnconditionally):
(JSC):
(JSC::CodeBlock::findClosureCallForReturnPC):
(JSC::CodeBlock::bytecodeOffset):
(JSC::CodeBlock::codeOriginForReturn):
* bytecode/CodeBlock.h:
(JSC::CodeBlock::getCallLinkInfo):
(CodeBlock):
(JSC::CodeBlock::isIncomingCallAlreadyLinked):
* dfg/DFGJITCompiler.cpp:
(JSC::DFG::JITCompiler::link):
* dfg/DFGJITCompiler.h:
(JSC::DFG::JITCompiler::addJSCall):
(JSC::DFG::JITCompiler::JSCallRecord::JSCallRecord):
(JSCallRecord):
* dfg/DFGOperations.cpp:
* dfg/DFGOperations.h:
* dfg/DFGRepatch.cpp:
(JSC::DFG::linkSlowFor):
(DFG):
(JSC::DFG::dfgLinkFor):
(JSC::DFG::dfgLinkSlowFor):
(JSC::DFG::dfgLinkClosureCall):
* dfg/DFGRepatch.h:
(DFG):
* dfg/DFGSpeculativeJIT32_64.cpp:
(JSC::DFG::SpeculativeJIT::emitCall):
* dfg/DFGSpeculativeJIT64.cpp:
(JSC::DFG::SpeculativeJIT::emitCall):
* dfg/DFGThunks.cpp:
(DFG):
(JSC::DFG::linkClosureCallThunkGenerator):
* dfg/DFGThunks.h:
(DFG):
* heap/Heap.h:
(Heap):
(JSC::Heap::jitStubRoutines):
* heap/JITStubRoutineSet.h:
(JSC::JITStubRoutineSet::size):
(JSC::JITStubRoutineSet::at):
(JITStubRoutineSet):
* jit/ClosureCallStubRoutine.cpp: Added.
(JSC):
(JSC::ClosureCallStubRoutine::ClosureCallStubRoutine):
(JSC::ClosureCallStubRoutine::~ClosureCallStubRoutine):
(JSC::ClosureCallStubRoutine::markRequiredObjectsInternal):
* jit/ClosureCallStubRoutine.h: Added.
(JSC):
(ClosureCallStubRoutine):
(JSC::ClosureCallStubRoutine::structure):
(JSC::ClosureCallStubRoutine::executable):
(JSC::ClosureCallStubRoutine::codeOrigin):
* jit/GCAwareJITStubRoutine.cpp:
(JSC::GCAwareJITStubRoutine::GCAwareJITStubRoutine):
* jit/GCAwareJITStubRoutine.h:
(GCAwareJITStubRoutine):
(JSC::GCAwareJITStubRoutine::isClosureCall):
* jit/JIT.cpp:
(JSC::JIT::privateCompile):
git-svn-id: http://svn.webkit.org/repository/webkit/trunk@135336 268f45cc-cd09-0410-ab3c-d52691b4dbfc
diff --git a/Source/JavaScriptCore/CMakeLists.txt b/Source/JavaScriptCore/CMakeLists.txt
index 10040f1..70a7702 100644
--- a/Source/JavaScriptCore/CMakeLists.txt
+++ b/Source/JavaScriptCore/CMakeLists.txt
@@ -139,6 +139,7 @@
interpreter/JSStack.cpp
interpreter/VMInspector.cpp
+ jit/ClosureCallStubRoutine.cpp
jit/ExecutableAllocator.cpp
jit/HostCallReturnValue.cpp
jit/GCAwareJITStubRoutine.cpp
diff --git a/Source/JavaScriptCore/ChangeLog b/Source/JavaScriptCore/ChangeLog
index 2632dfa..3f4857d 100644
--- a/Source/JavaScriptCore/ChangeLog
+++ b/Source/JavaScriptCore/ChangeLog
@@ -1,5 +1,91 @@
2012-11-20 Filip Pizlo <fpizlo@apple.com>
+ DFG should be able to cache closure calls (part 2/2)
+ https://bugs.webkit.org/show_bug.cgi?id=102662
+
+ Reviewed by Gavin Barraclough.
+
+ Added caching of calls where the JSFunction* varies, but the Structure* and ExecutableBase*
+ stay the same. This is accomplished by replacing the branch that compares against a constant
+ JSFunction* with a jump to a closure call stub. The closure call stub contains a fast path,
+ and jumps slow directly to the virtual call thunk.
+
+ Looks like a 1% win on V8v7.
+
+ * CMakeLists.txt:
+ * GNUmakefile.list.am:
+ * JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.vcproj:
+ * JavaScriptCore.xcodeproj/project.pbxproj:
+ * Target.pri:
+ * bytecode/CallLinkInfo.cpp:
+ (JSC::CallLinkInfo::unlink):
+ * bytecode/CallLinkInfo.h:
+ (CallLinkInfo):
+ (JSC::CallLinkInfo::isLinked):
+ (JSC::getCallLinkInfoBytecodeIndex):
+ * bytecode/CodeBlock.cpp:
+ (JSC::CodeBlock::finalizeUnconditionally):
+ (JSC):
+ (JSC::CodeBlock::findClosureCallForReturnPC):
+ (JSC::CodeBlock::bytecodeOffset):
+ (JSC::CodeBlock::codeOriginForReturn):
+ * bytecode/CodeBlock.h:
+ (JSC::CodeBlock::getCallLinkInfo):
+ (CodeBlock):
+ (JSC::CodeBlock::isIncomingCallAlreadyLinked):
+ * dfg/DFGJITCompiler.cpp:
+ (JSC::DFG::JITCompiler::link):
+ * dfg/DFGJITCompiler.h:
+ (JSC::DFG::JITCompiler::addJSCall):
+ (JSC::DFG::JITCompiler::JSCallRecord::JSCallRecord):
+ (JSCallRecord):
+ * dfg/DFGOperations.cpp:
+ * dfg/DFGOperations.h:
+ * dfg/DFGRepatch.cpp:
+ (JSC::DFG::linkSlowFor):
+ (DFG):
+ (JSC::DFG::dfgLinkFor):
+ (JSC::DFG::dfgLinkSlowFor):
+ (JSC::DFG::dfgLinkClosureCall):
+ * dfg/DFGRepatch.h:
+ (DFG):
+ * dfg/DFGSpeculativeJIT32_64.cpp:
+ (JSC::DFG::SpeculativeJIT::emitCall):
+ * dfg/DFGSpeculativeJIT64.cpp:
+ (JSC::DFG::SpeculativeJIT::emitCall):
+ * dfg/DFGThunks.cpp:
+ (DFG):
+ (JSC::DFG::linkClosureCallThunkGenerator):
+ * dfg/DFGThunks.h:
+ (DFG):
+ * heap/Heap.h:
+ (Heap):
+ (JSC::Heap::jitStubRoutines):
+ * heap/JITStubRoutineSet.h:
+ (JSC::JITStubRoutineSet::size):
+ (JSC::JITStubRoutineSet::at):
+ (JITStubRoutineSet):
+ * jit/ClosureCallStubRoutine.cpp: Added.
+ (JSC):
+ (JSC::ClosureCallStubRoutine::ClosureCallStubRoutine):
+ (JSC::ClosureCallStubRoutine::~ClosureCallStubRoutine):
+ (JSC::ClosureCallStubRoutine::markRequiredObjectsInternal):
+ * jit/ClosureCallStubRoutine.h: Added.
+ (JSC):
+ (ClosureCallStubRoutine):
+ (JSC::ClosureCallStubRoutine::structure):
+ (JSC::ClosureCallStubRoutine::executable):
+ (JSC::ClosureCallStubRoutine::codeOrigin):
+ * jit/GCAwareJITStubRoutine.cpp:
+ (JSC::GCAwareJITStubRoutine::GCAwareJITStubRoutine):
+ * jit/GCAwareJITStubRoutine.h:
+ (GCAwareJITStubRoutine):
+ (JSC::GCAwareJITStubRoutine::isClosureCall):
+ * jit/JIT.cpp:
+ (JSC::JIT::privateCompile):
+
+2012-11-20 Filip Pizlo <fpizlo@apple.com>
+
DFG should be able to cache closure calls (part 1/2)
https://bugs.webkit.org/show_bug.cgi?id=102662
diff --git a/Source/JavaScriptCore/GNUmakefile.list.am b/Source/JavaScriptCore/GNUmakefile.list.am
index 656b555..fece9e6 100644
--- a/Source/JavaScriptCore/GNUmakefile.list.am
+++ b/Source/JavaScriptCore/GNUmakefile.list.am
@@ -384,6 +384,8 @@
Source/JavaScriptCore/interpreter/VMInspector.h \
Source/JavaScriptCore/JavaScriptCorePrefix.h \
Source/JavaScriptCore/jit/CompactJITCodeMap.h \
+ Source/JavaScriptCore/jit/ClosureCallStubRoutine.cpp \
+ Source/JavaScriptCore/jit/ClosureCallStubRoutine.h \
Source/JavaScriptCore/jit/ExecutableAllocator.cpp \
Source/JavaScriptCore/jit/ExecutableAllocator.h \
Source/JavaScriptCore/jit/GCAwareJITStubRoutine.cpp \
diff --git a/Source/JavaScriptCore/JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.vcproj b/Source/JavaScriptCore/JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.vcproj
index 9e85e55..f3fe110 100644
--- a/Source/JavaScriptCore/JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.vcproj
+++ b/Source/JavaScriptCore/JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.vcproj
@@ -1930,6 +1930,14 @@
Name="jit"
>
<File
+ RelativePath="..\..\jit\ClosureCallStubRoutine.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\..\jit\ClosureCallStubRoutine.h"
+ >
+ </File>
+ <File
RelativePath="..\..\jit\ExecutableAllocator.cpp"
>
</File>
diff --git a/Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj b/Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj
index 87747ca..2a8b726 100644
--- a/Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj
+++ b/Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj
@@ -147,6 +147,8 @@
0F63948515E4811B006A597C /* DFGArrayMode.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F63948215E48114006A597C /* DFGArrayMode.h */; settings = {ATTRIBUTES = (Private, ); }; };
0F66E16B14DF3F1600B7B2E4 /* DFGAdjacencyList.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F66E16814DF3F1300B7B2E4 /* DFGAdjacencyList.h */; settings = {ATTRIBUTES = (Private, ); }; };
0F66E16C14DF3F1600B7B2E4 /* DFGEdge.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F66E16914DF3F1300B7B2E4 /* DFGEdge.h */; settings = {ATTRIBUTES = (Private, ); }; };
+ 0F73D7AE165A142D00ACAB71 /* ClosureCallStubRoutine.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F73D7AB165A142A00ACAB71 /* ClosureCallStubRoutine.cpp */; };
+ 0F73D7AF165A143000ACAB71 /* ClosureCallStubRoutine.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F73D7AC165A142A00ACAB71 /* ClosureCallStubRoutine.h */; settings = {ATTRIBUTES = (Private, ); }; };
0F766D2815A8CC1E008F363E /* JITStubRoutine.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F766D2615A8CC1B008F363E /* JITStubRoutine.cpp */; };
0F766D2B15A8CC38008F363E /* JITStubRoutineSet.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F766D2915A8CC34008F363E /* JITStubRoutineSet.cpp */; };
0F766D2C15A8CC3A008F363E /* JITStubRoutineSet.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F766D2A15A8CC34008F363E /* JITStubRoutineSet.h */; settings = {ATTRIBUTES = (Private, ); }; };
@@ -165,9 +167,9 @@
0F7B294C14C3CD43007C3DB1 /* DFGByteCodeCache.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F5F08CC146BE602000472A9 /* DFGByteCodeCache.h */; settings = {ATTRIBUTES = (Private, ); }; };
0F7B294D14C3CD4C007C3DB1 /* DFGCommon.h in Headers */ = {isa = PBXBuildFile; fileRef = 0FC0977E1469EBC400CF2442 /* DFGCommon.h */; settings = {ATTRIBUTES = (Private, ); }; };
0F8023EA1613832B00A0BA45 /* ByValInfo.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F8023E91613832300A0BA45 /* ByValInfo.h */; settings = {ATTRIBUTES = (Private, ); }; };
- 0F8364B7164B0C110053329A /* DFGBranchDirection.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F8364B5164B0C0E0053329A /* DFGBranchDirection.h */; settings = {ATTRIBUTES = (Private, ); }; };
0F8335B71639C1E6001443B5 /* ArrayAllocationProfile.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F8335B41639C1E3001443B5 /* ArrayAllocationProfile.cpp */; };
0F8335B81639C1EA001443B5 /* ArrayAllocationProfile.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F8335B51639C1E3001443B5 /* ArrayAllocationProfile.h */; settings = {ATTRIBUTES = (Private, ); }; };
+ 0F8364B7164B0C110053329A /* DFGBranchDirection.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F8364B5164B0C0E0053329A /* DFGBranchDirection.h */; settings = {ATTRIBUTES = (Private, ); }; };
0F919D0C157EE09F004A4E7D /* JSSymbolTableObject.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F919D09157EE09D004A4E7D /* JSSymbolTableObject.cpp */; };
0F919D0D157EE0A2004A4E7D /* JSSymbolTableObject.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F919D0A157EE09D004A4E7D /* JSSymbolTableObject.h */; settings = {ATTRIBUTES = (Private, ); }; };
0F919D10157F3329004A4E7D /* JSSegmentedVariableObject.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0F919D0E157F3327004A4E7D /* JSSegmentedVariableObject.cpp */; };
@@ -938,6 +940,8 @@
0F63948215E48114006A597C /* DFGArrayMode.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DFGArrayMode.h; path = dfg/DFGArrayMode.h; sourceTree = "<group>"; };
0F66E16814DF3F1300B7B2E4 /* DFGAdjacencyList.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DFGAdjacencyList.h; path = dfg/DFGAdjacencyList.h; sourceTree = "<group>"; };
0F66E16914DF3F1300B7B2E4 /* DFGEdge.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DFGEdge.h; path = dfg/DFGEdge.h; sourceTree = "<group>"; };
+ 0F73D7AB165A142A00ACAB71 /* ClosureCallStubRoutine.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ClosureCallStubRoutine.cpp; sourceTree = "<group>"; };
+ 0F73D7AC165A142A00ACAB71 /* ClosureCallStubRoutine.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ClosureCallStubRoutine.h; sourceTree = "<group>"; };
0F766D1C15A5028D008F363E /* JITStubRoutine.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JITStubRoutine.h; sourceTree = "<group>"; };
0F766D2615A8CC1B008F363E /* JITStubRoutine.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JITStubRoutine.cpp; sourceTree = "<group>"; };
0F766D2915A8CC34008F363E /* JITStubRoutineSet.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JITStubRoutineSet.cpp; sourceTree = "<group>"; };
@@ -954,9 +958,9 @@
0F7700911402FF280078EB39 /* SamplingCounter.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = SamplingCounter.cpp; sourceTree = "<group>"; };
0F7B294814C3CD23007C3DB1 /* DFGCCallHelpers.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DFGCCallHelpers.h; path = dfg/DFGCCallHelpers.h; sourceTree = "<group>"; };
0F8023E91613832300A0BA45 /* ByValInfo.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ByValInfo.h; sourceTree = "<group>"; };
- 0F8364B5164B0C0E0053329A /* DFGBranchDirection.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DFGBranchDirection.h; path = dfg/DFGBranchDirection.h; sourceTree = "<group>"; };
0F8335B41639C1E3001443B5 /* ArrayAllocationProfile.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ArrayAllocationProfile.cpp; sourceTree = "<group>"; };
0F8335B51639C1E3001443B5 /* ArrayAllocationProfile.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ArrayAllocationProfile.h; sourceTree = "<group>"; };
+ 0F8364B5164B0C0E0053329A /* DFGBranchDirection.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DFGBranchDirection.h; path = dfg/DFGBranchDirection.h; sourceTree = "<group>"; };
0F919D09157EE09D004A4E7D /* JSSymbolTableObject.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JSSymbolTableObject.cpp; sourceTree = "<group>"; };
0F919D0A157EE09D004A4E7D /* JSSymbolTableObject.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSSymbolTableObject.h; sourceTree = "<group>"; };
0F919D0E157F3327004A4E7D /* JSSegmentedVariableObject.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JSSegmentedVariableObject.cpp; sourceTree = "<group>"; };
@@ -1803,6 +1807,8 @@
1429D92C0ED22D7000B89619 /* jit */ = {
isa = PBXGroup;
children = (
+ 0F73D7AB165A142A00ACAB71 /* ClosureCallStubRoutine.cpp */,
+ 0F73D7AC165A142A00ACAB71 /* ClosureCallStubRoutine.h */,
0FD82E37141AB14200179C94 /* CompactJITCodeMap.h */,
A7B48DB60EE74CFC00DCBDB6 /* ExecutableAllocator.cpp */,
A7B48DB50EE74CFC00DCBDB6 /* ExecutableAllocator.h */,
@@ -3022,6 +3028,7 @@
A7B601821639FD2A00372BA3 /* UnlinkedCodeBlock.h in Headers */,
A77F1822164088B200640A47 /* CodeCache.h in Headers */,
A77F1825164192C700640A47 /* ParserModes.h in Headers */,
+ 0F73D7AF165A143000ACAB71 /* ClosureCallStubRoutine.h in Headers */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -3601,6 +3608,7 @@
0F8335B71639C1E6001443B5 /* ArrayAllocationProfile.cpp in Sources */,
A76F279415F13C9600517D67 /* UnlinkedCodeBlock.cpp in Sources */,
A77F1821164088B200640A47 /* CodeCache.cpp in Sources */,
+ 0F73D7AE165A142D00ACAB71 /* ClosureCallStubRoutine.cpp in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
diff --git a/Source/JavaScriptCore/Target.pri b/Source/JavaScriptCore/Target.pri
index f978fb4..fb34a5e 100644
--- a/Source/JavaScriptCore/Target.pri
+++ b/Source/JavaScriptCore/Target.pri
@@ -144,6 +144,7 @@
interpreter/CallFrame.cpp \
interpreter/Interpreter.cpp \
interpreter/JSStack.cpp \
+ jit/ClosureCallStubRoutine.cpp \
jit/ExecutableAllocatorFixedVMPool.cpp \
jit/ExecutableAllocator.cpp \
jit/HostCallReturnValue.cpp \
diff --git a/Source/JavaScriptCore/bytecode/CallLinkInfo.cpp b/Source/JavaScriptCore/bytecode/CallLinkInfo.cpp
index 4933a49..762dca1 100644
--- a/Source/JavaScriptCore/bytecode/CallLinkInfo.cpp
+++ b/Source/JavaScriptCore/bytecode/CallLinkInfo.cpp
@@ -37,6 +37,7 @@
{
ASSERT(isLinked());
+ repatchBuffer.revertJumpReplacementToBranchPtrWithPatch(RepatchBuffer::startOfBranchPtrWithPatchOnRegister(hotPathBegin), static_cast<MacroAssembler::RegisterID>(calleeGPR), 0);
if (isDFG) {
#if ENABLE(DFG_JIT)
repatchBuffer.relink(callReturnLocation, (callType == Construct ? globalData.getCTIStub(DFG::linkConstructThunkGenerator) : globalData.getCTIStub(DFG::linkCallThunkGenerator)).code());
@@ -47,6 +48,7 @@
repatchBuffer.relink(callReturnLocation, callType == Construct ? globalData.jitStubs->ctiVirtualConstructLink() : globalData.jitStubs->ctiVirtualCallLink());
hasSeenShouldRepatch = false;
callee.clear();
+ stub.clear();
// It will be on a list if the callee has a code block.
if (isOnList())
diff --git a/Source/JavaScriptCore/bytecode/CallLinkInfo.h b/Source/JavaScriptCore/bytecode/CallLinkInfo.h
index 4a78e5d..89403b0 100644
--- a/Source/JavaScriptCore/bytecode/CallLinkInfo.h
+++ b/Source/JavaScriptCore/bytecode/CallLinkInfo.h
@@ -26,6 +26,7 @@
#ifndef CallLinkInfo_h
#define CallLinkInfo_h
+#include "ClosureCallStubRoutine.h"
#include "CodeLocation.h"
#include "JITWriteBarrier.h"
#include "JSFunction.h"
@@ -70,12 +71,14 @@
CodeLocationNearCall hotPathOther;
JITWriteBarrier<JSFunction> callee;
WriteBarrier<JSFunction> lastSeenCallee;
+ RefPtr<ClosureCallStubRoutine> stub;
bool hasSeenShouldRepatch : 1;
bool isDFG : 1;
CallType callType : 6;
- unsigned bytecodeIndex;
+ unsigned calleeGPR : 8;
+ CodeOrigin codeOrigin;
- bool isLinked() { return callee; }
+ bool isLinked() { return stub || callee; }
void unlink(JSGlobalData&, RepatchBuffer&);
bool seenOnce()
@@ -96,7 +99,7 @@
inline unsigned getCallLinkInfoBytecodeIndex(CallLinkInfo* callLinkInfo)
{
- return callLinkInfo->bytecodeIndex;
+ return callLinkInfo->codeOrigin.bytecodeIndex;
}
#endif // ENABLE(JIT)
diff --git a/Source/JavaScriptCore/bytecode/CodeBlock.cpp b/Source/JavaScriptCore/bytecode/CodeBlock.cpp
index 49cd5e9..9ce6139 100644
--- a/Source/JavaScriptCore/bytecode/CodeBlock.cpp
+++ b/Source/JavaScriptCore/bytecode/CodeBlock.cpp
@@ -2188,7 +2188,7 @@
// Check if we're not live. If we are, then jettison.
if (!(shouldImmediatelyAssumeLivenessDuringScan() || m_dfgData->livenessHasBeenProved)) {
if (verboseUnlinking)
- dataLog("Code block %p has dead weak references, jettisoning during GC.\n", this);
+ dataLog("Code block %p (executable %p) has dead weak references, jettisoning during GC.\n", this, ownerExecutable());
// Make sure that the baseline JIT knows that it should re-warm-up before
// optimizing.
@@ -2247,10 +2247,19 @@
if (!!getJITCode()) {
RepatchBuffer repatchBuffer(this);
for (unsigned i = 0; i < numberOfCallLinkInfos(); ++i) {
- if (callLinkInfo(i).isLinked() && !Heap::isMarked(callLinkInfo(i).callee.get())) {
- if (verboseUnlinking)
- dataLog("Clearing call from %p to %p.\n", this, callLinkInfo(i).callee.get());
- callLinkInfo(i).unlink(*m_globalData, repatchBuffer);
+ if (callLinkInfo(i).isLinked()) {
+ if (ClosureCallStubRoutine* stub = callLinkInfo(i).stub.get()) {
+ if (!Heap::isMarked(stub->structure())
+ || !Heap::isMarked(stub->executable())) {
+ if (verboseUnlinking)
+ dataLog("Clearing closure call from %p to %p, stub routine %p.\n", this, stub->executable(), stub);
+ callLinkInfo(i).unlink(*m_globalData, repatchBuffer);
+ }
+ } else if (!Heap::isMarked(callLinkInfo(i).callee.get())) {
+ if (verboseUnlinking)
+ dataLog("Clearing call from %p to %p.\n", this, callLinkInfo(i).callee.get());
+ callLinkInfo(i).unlink(*m_globalData, repatchBuffer);
+ }
}
if (!!callLinkInfo(i).lastSeenCallee
&& !Heap::isMarked(callLinkInfo(i).lastSeenCallee.get()))
@@ -2605,6 +2614,35 @@
}
#endif // ENABLE(LLINT)
+#if ENABLE(JIT)
+ClosureCallStubRoutine* CodeBlock::findClosureCallForReturnPC(ReturnAddressPtr returnAddress)
+{
+ for (unsigned i = m_callLinkInfos.size(); i--;) {
+ CallLinkInfo& info = m_callLinkInfos[i];
+ if (!info.stub)
+ continue;
+ if (!info.stub->code().executableMemory()->contains(returnAddress.value()))
+ continue;
+
+ return info.stub.get();
+ }
+
+ // The stub routine may have been jettisoned. This is rare, but we have to handle it.
+ const JITStubRoutineSet& set = m_globalData->heap.jitStubRoutines();
+ for (unsigned i = set.size(); i--;) {
+ GCAwareJITStubRoutine* genericStub = set.at(i);
+ if (!genericStub->isClosureCall())
+ continue;
+ ClosureCallStubRoutine* stub = static_cast<ClosureCallStubRoutine*>(genericStub);
+ if (!stub->code().executableMemory()->contains(returnAddress.value()))
+ continue;
+ return stub;
+ }
+
+ return 0;
+}
+#endif
+
unsigned CodeBlock::bytecodeOffset(ExecState* exec, ReturnAddressPtr returnAddress)
{
UNUSED_PARAM(exec);
@@ -2642,7 +2680,16 @@
Vector<CallReturnOffsetToBytecodeOffset>& callIndices = m_rareData->m_callReturnIndexVector;
if (!callIndices.size())
return 1;
- return binarySearch<CallReturnOffsetToBytecodeOffset, unsigned, getCallReturnOffset>(callIndices.begin(), callIndices.size(), getJITCode().offsetOf(returnAddress.value()))->bytecodeOffset;
+
+ if (getJITCode().getExecutableMemory()->contains(returnAddress.value())) {
+ unsigned callReturnOffset = getJITCode().offsetOf(returnAddress.value());
+ CallReturnOffsetToBytecodeOffset* result =
+ binarySearch<CallReturnOffsetToBytecodeOffset, unsigned, getCallReturnOffset>(callIndices.begin(), callIndices.size(), callReturnOffset);
+ ASSERT(result->callReturnOffset == callReturnOffset);
+ return result->bytecodeOffset;
+ }
+
+ return findClosureCallForReturnPC(returnAddress)->codeOrigin().bytecodeIndex;
#endif // ENABLE(JIT)
#if !ENABLE(LLINT) && !ENABLE(JIT)
@@ -2650,6 +2697,26 @@
#endif
}
+#if ENABLE(DFG_JIT)
+bool CodeBlock::codeOriginForReturn(ReturnAddressPtr returnAddress, CodeOrigin& codeOrigin)
+{
+ if (!hasCodeOrigins())
+ return false;
+
+ if (!getJITCode().getExecutableMemory()->contains(returnAddress.value())) {
+ codeOrigin = findClosureCallForReturnPC(returnAddress)->codeOrigin();
+ return true;
+ }
+
+ unsigned offset = getJITCode().offsetOf(returnAddress.value());
+ CodeOriginAtCallReturnOffset* entry = binarySearch<CodeOriginAtCallReturnOffset, unsigned, getCallReturnOffsetForCodeOrigin>(codeOrigins().begin(), codeOrigins().size(), offset, WTF::KeyMustNotBePresentInArray);
+ if (entry->callReturnOffset != offset)
+ return false;
+ codeOrigin = entry->codeOrigin;
+ return true;
+}
+#endif // ENABLE(DFG_JIT)
+
void CodeBlock::clearEvalCache()
{
if (!!m_alternative)
diff --git a/Source/JavaScriptCore/bytecode/CodeBlock.h b/Source/JavaScriptCore/bytecode/CodeBlock.h
index c841ec3..183ea1e 100644
--- a/Source/JavaScriptCore/bytecode/CodeBlock.h
+++ b/Source/JavaScriptCore/bytecode/CodeBlock.h
@@ -245,6 +245,7 @@
CallLinkInfo& getCallLinkInfo(unsigned bytecodeIndex)
{
+ ASSERT(JITCode::isBaselineCode(getJITType()));
return *(binarySearch<CallLinkInfo, unsigned, getCallLinkInfoBytecodeIndex>(m_callLinkInfos.begin(), m_callLinkInfos.size(), bytecodeIndex));
}
#endif // ENABLE(JIT)
@@ -274,6 +275,11 @@
{
m_incomingCalls.push(incoming);
}
+
+ bool isIncomingCallAlreadyLinked(CallLinkInfo* incoming)
+ {
+ return m_incomingCalls.isOnList(incoming);
+ }
#endif // ENABLE(JIT)
#if ENABLE(LLINT)
@@ -813,17 +819,7 @@
return m_rareData && !!m_rareData->m_codeOrigins.size();
}
- bool codeOriginForReturn(ReturnAddressPtr returnAddress, CodeOrigin& codeOrigin)
- {
- if (!hasCodeOrigins())
- return false;
- unsigned offset = getJITCode().offsetOf(returnAddress.value());
- CodeOriginAtCallReturnOffset* entry = binarySearch<CodeOriginAtCallReturnOffset, unsigned, getCallReturnOffsetForCodeOrigin>(codeOrigins().begin(), codeOrigins().size(), offset, WTF::KeyMustNotBePresentInArray);
- if (entry->callReturnOffset != offset)
- return false;
- codeOrigin = entry->codeOrigin;
- return true;
- }
+ bool codeOriginForReturn(ReturnAddressPtr, CodeOrigin&);
CodeOrigin codeOrigin(unsigned index)
{
@@ -1187,6 +1183,10 @@
private:
friend class DFGCodeBlocks;
+
+#if ENABLE(JIT)
+ ClosureCallStubRoutine* findClosureCallForReturnPC(ReturnAddressPtr);
+#endif
#if ENABLE(DFG_JIT)
void tallyFrequentExitSites();
diff --git a/Source/JavaScriptCore/dfg/DFGJITCompiler.cpp b/Source/JavaScriptCore/dfg/DFGJITCompiler.cpp
index c7f941a..537aafa 100644
--- a/Source/JavaScriptCore/dfg/DFGJITCompiler.cpp
+++ b/Source/JavaScriptCore/dfg/DFGJITCompiler.cpp
@@ -188,11 +188,12 @@
CallLinkInfo& info = m_codeBlock->callLinkInfo(i);
info.callType = m_jsCalls[i].m_callType;
info.isDFG = true;
- info.bytecodeIndex = m_jsCalls[i].m_codeOrigin.bytecodeIndex;
+ info.codeOrigin = m_jsCalls[i].m_codeOrigin;
linkBuffer.link(m_jsCalls[i].m_slowCall, FunctionPtr((m_globalData->getCTIStub(info.callType == CallLinkInfo::Construct ? linkConstructThunkGenerator : linkCallThunkGenerator)).code().executableAddress()));
info.callReturnLocation = linkBuffer.locationOfNearCall(m_jsCalls[i].m_slowCall);
info.hotPathBegin = linkBuffer.locationOf(m_jsCalls[i].m_targetToCheck);
info.hotPathOther = linkBuffer.locationOfNearCall(m_jsCalls[i].m_fastCall);
+ info.calleeGPR = static_cast<unsigned>(m_jsCalls[i].m_callee);
}
MacroAssemblerCodeRef osrExitThunk = globalData()->getCTIStub(osrExitGenerationThunkGenerator);
diff --git a/Source/JavaScriptCore/dfg/DFGJITCompiler.h b/Source/JavaScriptCore/dfg/DFGJITCompiler.h
index c739348..0bd88b7 100644
--- a/Source/JavaScriptCore/dfg/DFGJITCompiler.h
+++ b/Source/JavaScriptCore/dfg/DFGJITCompiler.h
@@ -357,9 +357,9 @@
m_propertyAccesses.append(record);
}
- void addJSCall(Call fastCall, Call slowCall, DataLabelPtr targetToCheck, CallLinkInfo::CallType callType, CodeOrigin codeOrigin)
+ void addJSCall(Call fastCall, Call slowCall, DataLabelPtr targetToCheck, CallLinkInfo::CallType callType, GPRReg callee, CodeOrigin codeOrigin)
{
- m_jsCalls.append(JSCallRecord(fastCall, slowCall, targetToCheck, callType, codeOrigin));
+ m_jsCalls.append(JSCallRecord(fastCall, slowCall, targetToCheck, callType, callee, codeOrigin));
}
void addWeakReference(JSCell* target)
@@ -440,11 +440,12 @@
Vector<CallExceptionRecord> m_exceptionChecks;
struct JSCallRecord {
- JSCallRecord(Call fastCall, Call slowCall, DataLabelPtr targetToCheck, CallLinkInfo::CallType callType, CodeOrigin codeOrigin)
+ JSCallRecord(Call fastCall, Call slowCall, DataLabelPtr targetToCheck, CallLinkInfo::CallType callType, GPRReg callee, CodeOrigin codeOrigin)
: m_fastCall(fastCall)
, m_slowCall(slowCall)
, m_targetToCheck(targetToCheck)
, m_callType(callType)
+ , m_callee(callee)
, m_codeOrigin(codeOrigin)
{
}
@@ -453,6 +454,7 @@
Call m_slowCall;
DataLabelPtr m_targetToCheck;
CallLinkInfo::CallType m_callType;
+ GPRReg m_callee;
CodeOrigin m_codeOrigin;
};
diff --git a/Source/JavaScriptCore/dfg/DFGOperations.cpp b/Source/JavaScriptCore/dfg/DFGOperations.cpp
index b2c337d..bc0074f 100644
--- a/Source/JavaScriptCore/dfg/DFGOperations.cpp
+++ b/Source/JavaScriptCore/dfg/DFGOperations.cpp
@@ -1062,14 +1062,14 @@
return linkFor(execCallee, CodeForConstruct);
}
-inline char* virtualFor(ExecState* execCallee, CodeSpecializationKind kind)
+inline char* virtualForWithFunction(ExecState* execCallee, CodeSpecializationKind kind, JSCell*& calleeAsFunctionCell)
{
ExecState* exec = execCallee->callerFrame();
JSGlobalData* globalData = &exec->globalData();
NativeCallFrameTracer tracer(globalData, exec);
JSValue calleeAsValue = execCallee->calleeAsValue();
- JSCell* calleeAsFunctionCell = getJSFunction(calleeAsValue);
+ calleeAsFunctionCell = getJSFunction(calleeAsValue);
if (UNLIKELY(!calleeAsFunctionCell))
return reinterpret_cast<char*>(handleHostCall(execCallee, calleeAsValue, kind));
@@ -1087,6 +1087,56 @@
return reinterpret_cast<char*>(executable->generatedJITCodeWithArityCheckFor(kind).executableAddress());
}
+inline char* virtualFor(ExecState* execCallee, CodeSpecializationKind kind)
+{
+ JSCell* calleeAsFunctionCellIgnored;
+ return virtualForWithFunction(execCallee, kind, calleeAsFunctionCellIgnored);
+}
+
+static bool attemptToOptimizeClosureCall(ExecState* execCallee, JSCell* calleeAsFunctionCell, CallLinkInfo& callLinkInfo)
+{
+ if (!calleeAsFunctionCell)
+ return false;
+
+ JSFunction* callee = jsCast<JSFunction*>(calleeAsFunctionCell);
+ JSFunction* oldCallee = callLinkInfo.callee.get();
+
+ if (!oldCallee
+ || oldCallee->structure() != callee->structure()
+ || oldCallee->executable() != callee->executable())
+ return false;
+
+ ASSERT(callee->executable()->hasJITCodeForCall());
+ MacroAssemblerCodePtr codePtr = callee->executable()->generatedJITCodeForCall().addressForCall();
+
+ CodeBlock* codeBlock;
+ if (callee->executable()->isHostFunction())
+ codeBlock = 0;
+ else {
+ codeBlock = &jsCast<FunctionExecutable*>(callee->executable())->generatedBytecodeForCall();
+ if (execCallee->argumentCountIncludingThis() < static_cast<size_t>(codeBlock->numParameters()))
+ return false;
+ }
+
+ dfgLinkClosureCall(
+ execCallee, callLinkInfo, codeBlock,
+ callee->structure(), callee->executable(), codePtr);
+
+ return true;
+}
+
+char* DFG_OPERATION operationLinkClosureCall(ExecState* execCallee)
+{
+ JSCell* calleeAsFunctionCell;
+ char* result = virtualForWithFunction(execCallee, CodeForCall, calleeAsFunctionCell);
+ CallLinkInfo& callLinkInfo = execCallee->callerFrame()->codeBlock()->getCallLinkInfo(execCallee->returnPC());
+
+ if (!attemptToOptimizeClosureCall(execCallee, calleeAsFunctionCell, callLinkInfo))
+ dfgLinkSlowFor(execCallee, callLinkInfo, CodeForCall);
+
+ return result;
+}
+
char* DFG_OPERATION operationVirtualCall(ExecState* execCallee)
{
return virtualFor(execCallee, CodeForCall);
diff --git a/Source/JavaScriptCore/dfg/DFGOperations.h b/Source/JavaScriptCore/dfg/DFGOperations.h
index 77fa901..00e6b07 100644
--- a/Source/JavaScriptCore/dfg/DFGOperations.h
+++ b/Source/JavaScriptCore/dfg/DFGOperations.h
@@ -181,6 +181,7 @@
size_t DFG_OPERATION operationCompareStrictEq(ExecState*, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2) WTF_INTERNAL;
char* DFG_OPERATION operationVirtualCall(ExecState*) WTF_INTERNAL;
char* DFG_OPERATION operationLinkCall(ExecState*) WTF_INTERNAL;
+char* DFG_OPERATION operationLinkClosureCall(ExecState*) WTF_INTERNAL;
char* DFG_OPERATION operationVirtualConstruct(ExecState*) WTF_INTERNAL;
char* DFG_OPERATION operationLinkConstruct(ExecState*) WTF_INTERNAL;
JSCell* DFG_OPERATION operationCreateActivation(ExecState*) WTF_INTERNAL;
diff --git a/Source/JavaScriptCore/dfg/DFGRepatch.cpp b/Source/JavaScriptCore/dfg/DFGRepatch.cpp
index 06cfbde..a20eb54 100644
--- a/Source/JavaScriptCore/dfg/DFGRepatch.cpp
+++ b/Source/JavaScriptCore/dfg/DFGRepatch.cpp
@@ -1113,8 +1113,20 @@
dfgRepatchCall(exec->codeBlock(), stubInfo.callReturnLocation, appropriateGenericPutByIdFunction(slot, putKind));
}
+static void linkSlowFor(RepatchBuffer& repatchBuffer, JSGlobalData* globalData, CallLinkInfo& callLinkInfo, CodeSpecializationKind kind)
+{
+ if (kind == CodeForCall) {
+ repatchBuffer.relink(callLinkInfo.callReturnLocation, globalData->getCTIStub(virtualCallThunkGenerator).code());
+ return;
+ }
+ ASSERT(kind == CodeForConstruct);
+ repatchBuffer.relink(callLinkInfo.callReturnLocation, globalData->getCTIStub(virtualConstructThunkGenerator).code());
+}
+
void dfgLinkFor(ExecState* exec, CallLinkInfo& callLinkInfo, CodeBlock* calleeCodeBlock, JSFunction* callee, MacroAssemblerCodePtr codePtr, CodeSpecializationKind kind)
{
+ ASSERT(!callLinkInfo.stub);
+
CodeBlock* callerCodeBlock = exec->callerFrame()->codeBlock();
JSGlobalData* globalData = callerCodeBlock->globalData();
@@ -1129,11 +1141,110 @@
calleeCodeBlock->linkIncomingCall(&callLinkInfo);
if (kind == CodeForCall) {
- repatchBuffer.relink(callLinkInfo.callReturnLocation, globalData->getCTIStub(virtualCallThunkGenerator).code());
+ repatchBuffer.relink(callLinkInfo.callReturnLocation, globalData->getCTIStub(linkClosureCallThunkGenerator).code());
return;
}
+
ASSERT(kind == CodeForConstruct);
- repatchBuffer.relink(callLinkInfo.callReturnLocation, globalData->getCTIStub(virtualConstructThunkGenerator).code());
+ linkSlowFor(repatchBuffer, globalData, callLinkInfo, CodeForConstruct);
+}
+
+void dfgLinkSlowFor(ExecState* exec, CallLinkInfo& callLinkInfo, CodeSpecializationKind kind)
+{
+ CodeBlock* callerCodeBlock = exec->callerFrame()->codeBlock();
+ JSGlobalData* globalData = callerCodeBlock->globalData();
+
+ RepatchBuffer repatchBuffer(callerCodeBlock);
+
+ linkSlowFor(repatchBuffer, globalData, callLinkInfo, kind);
+}
+
+void dfgLinkClosureCall(ExecState* exec, CallLinkInfo& callLinkInfo, CodeBlock* calleeCodeBlock, Structure* structure, ExecutableBase* executable, MacroAssemblerCodePtr codePtr)
+{
+ ASSERT(!callLinkInfo.stub);
+
+ CodeBlock* callerCodeBlock = exec->callerFrame()->codeBlock();
+ JSGlobalData* globalData = callerCodeBlock->globalData();
+
+ GPRReg calleeGPR = static_cast<GPRReg>(callLinkInfo.calleeGPR);
+
+ CCallHelpers stubJit(globalData, callerCodeBlock);
+
+ CCallHelpers::JumpList slowPath;
+
+#if USE(JSVALUE64)
+ slowPath.append(
+ stubJit.branchTest64(
+ CCallHelpers::NonZero, calleeGPR, GPRInfo::tagMaskRegister));
+#else
+ // We would have already checked that the callee is a cell.
+#endif
+
+ slowPath.append(
+ stubJit.branchPtr(
+ CCallHelpers::NotEqual,
+ CCallHelpers::Address(calleeGPR, JSCell::structureOffset()),
+ CCallHelpers::TrustedImmPtr(structure)));
+
+ slowPath.append(
+ stubJit.branchPtr(
+ CCallHelpers::NotEqual,
+ CCallHelpers::Address(calleeGPR, JSFunction::offsetOfExecutable()),
+ CCallHelpers::TrustedImmPtr(executable)));
+
+ stubJit.loadPtr(
+ CCallHelpers::Address(calleeGPR, JSFunction::offsetOfScopeChain()),
+ GPRInfo::returnValueGPR);
+
+#if USE(JSVALUE64)
+ stubJit.store64(
+ GPRInfo::returnValueGPR,
+ CCallHelpers::Address(GPRInfo::callFrameRegister, static_cast<ptrdiff_t>(sizeof(Register) * JSStack::ScopeChain)));
+#else
+ stubJit.storePtr(
+ GPRInfo::returnValueGPR,
+ CCallHelpers::Address(GPRInfo::callFrameRegister, static_cast<ptrdiff_t>(sizeof(Register) * JSStack::ScopeChain) + OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.payload)));
+ stubJit.store32(
+ CCallHelpers::TrustedImm32(JSValue::CellTag),
+ CCallHelpers::Address(GPRInfo::callFrameRegister, static_cast<ptrdiff_t>(sizeof(Register) * JSStack::ScopeChain) + OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.tag)));
+#endif
+
+ JITCompiler::Call call = stubJit.nearCall();
+ JITCompiler::Jump done = stubJit.jump();
+
+ slowPath.link(&stubJit);
+ stubJit.move(CCallHelpers::TrustedImmPtr(callLinkInfo.callReturnLocation.executableAddress()), GPRInfo::nonArgGPR2);
+ stubJit.restoreReturnAddressBeforeReturn(GPRInfo::nonArgGPR2);
+ stubJit.move(calleeGPR, GPRInfo::nonArgGPR0);
+#if USE(JSVALUE32_64)
+ stubJit.move(CCallHelpers::TrustedImm32(JSValue::CellTag), GPRInfo::nonArgGPR1);
+#endif
+ JITCompiler::Jump slow = stubJit.jump();
+
+ LinkBuffer patchBuffer(*globalData, &stubJit, callerCodeBlock);
+
+ patchBuffer.link(call, FunctionPtr(codePtr.executableAddress()));
+ patchBuffer.link(done, callLinkInfo.callReturnLocation.labelAtOffset(0));
+ patchBuffer.link(slow, CodeLocationLabel(globalData->getCTIStub(virtualCallThunkGenerator).code()));
+
+ RefPtr<ClosureCallStubRoutine> stubRoutine = adoptRef(new ClosureCallStubRoutine(
+ FINALIZE_DFG_CODE(
+ patchBuffer,
+ ("DFG closure call stub for CodeBlock %p, return point %p, target %p (CodeBlock %p)",
+ callerCodeBlock, callLinkInfo.callReturnLocation.labelAtOffset(0).executableAddress(),
+ codePtr.executableAddress(), calleeCodeBlock)),
+ *globalData, callerCodeBlock->ownerExecutable(), structure, executable, callLinkInfo.codeOrigin));
+
+ RepatchBuffer repatchBuffer(callerCodeBlock);
+
+ repatchBuffer.replaceWithJump(
+ RepatchBuffer::startOfBranchPtrWithPatchOnRegister(callLinkInfo.hotPathBegin),
+ CodeLocationLabel(stubRoutine->code().code()));
+ linkSlowFor(repatchBuffer, globalData, callLinkInfo, CodeForCall);
+
+ callLinkInfo.stub = stubRoutine.release();
+
+ ASSERT(!calleeCodeBlock || calleeCodeBlock->isIncomingCallAlreadyLinked(&callLinkInfo));
}
void dfgResetGetByID(RepatchBuffer& repatchBuffer, StructureStubInfo& stubInfo)
diff --git a/Source/JavaScriptCore/dfg/DFGRepatch.h b/Source/JavaScriptCore/dfg/DFGRepatch.h
index 83d4e97..97d26aa 100644
--- a/Source/JavaScriptCore/dfg/DFGRepatch.h
+++ b/Source/JavaScriptCore/dfg/DFGRepatch.h
@@ -41,6 +41,8 @@
void dfgRepatchPutByID(ExecState*, JSValue, const Identifier&, const PutPropertySlot&, StructureStubInfo&, PutKind);
void dfgBuildPutByIdList(ExecState*, JSValue, const Identifier&, const PutPropertySlot&, StructureStubInfo&, PutKind);
void dfgLinkFor(ExecState*, CallLinkInfo&, CodeBlock*, JSFunction* callee, MacroAssemblerCodePtr, CodeSpecializationKind);
+void dfgLinkSlowFor(ExecState*, CallLinkInfo&, CodeSpecializationKind);
+void dfgLinkClosureCall(ExecState*, CallLinkInfo&, CodeBlock*, Structure*, ExecutableBase*, MacroAssemblerCodePtr);
void dfgResetGetByID(RepatchBuffer&, StructureStubInfo&);
void dfgResetPutByID(RepatchBuffer&, StructureStubInfo&);
diff --git a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp
index 1bcb5f3..a08e2ce 100644
--- a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp
+++ b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp
@@ -998,7 +998,6 @@
void SpeculativeJIT::emitCall(Node& node)
{
-
if (node.op() != Call)
ASSERT(node.op() == Construct);
@@ -1049,8 +1048,8 @@
m_jit.addPtr(TrustedImm32(m_jit.codeBlock()->m_numCalleeRegisters * sizeof(Register)), GPRInfo::callFrameRegister);
- slowPath.append(m_jit.branchPtrWithPatch(MacroAssembler::NotEqual, calleePayloadGPR, targetToCheck));
slowPath.append(m_jit.branch32(MacroAssembler::NotEqual, calleeTagGPR, TrustedImm32(JSValue::CellTag)));
+ slowPath.append(m_jit.branchPtrWithPatch(MacroAssembler::NotEqual, calleePayloadGPR, targetToCheck));
m_jit.loadPtr(MacroAssembler::Address(calleePayloadGPR, OBJECT_OFFSETOF(JSFunction, m_scope)), resultPayloadGPR);
m_jit.storePtr(resultPayloadGPR, MacroAssembler::Address(GPRInfo::callFrameRegister, static_cast<ptrdiff_t>(sizeof(Register)) * JSStack::ScopeChain + OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.payload)));
m_jit.store32(MacroAssembler::TrustedImm32(JSValue::CellTag), MacroAssembler::Address(GPRInfo::callFrameRegister, static_cast<ptrdiff_t>(sizeof(Register)) * JSStack::ScopeChain + OBJECT_OFFSETOF(EncodedValueDescriptor, asBits.tag)));
@@ -1084,7 +1083,7 @@
jsValueResult(resultTagGPR, resultPayloadGPR, m_compileIndex, DataFormatJS, UseChildrenCalledExplicitly);
- m_jit.addJSCall(fastCall, slowCall, targetToCheck, callType, at(m_compileIndex).codeOrigin);
+ m_jit.addJSCall(fastCall, slowCall, targetToCheck, callType, calleePayloadGPR, at(m_compileIndex).codeOrigin);
}
template<bool strict>
diff --git a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp
index f21dcaf..f26d638 100644
--- a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp
+++ b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp
@@ -1058,7 +1058,7 @@
jsValueResult(resultGPR, m_compileIndex, DataFormatJS, UseChildrenCalledExplicitly);
- m_jit.addJSCall(fastCall, slowCall, targetToCheck, callType, at(m_compileIndex).codeOrigin);
+ m_jit.addJSCall(fastCall, slowCall, targetToCheck, callType, calleeGPR, at(m_compileIndex).codeOrigin);
}
template<bool strict>
diff --git a/Source/JavaScriptCore/dfg/DFGThunks.cpp b/Source/JavaScriptCore/dfg/DFGThunks.cpp
index 74d1967..ac0b45f 100644
--- a/Source/JavaScriptCore/dfg/DFGThunks.cpp
+++ b/Source/JavaScriptCore/dfg/DFGThunks.cpp
@@ -213,6 +213,18 @@
return linkForThunkGenerator(globalData, CodeForConstruct);
}
+// For closure optimizations, we only include calls, since if you're using closures for
+// object construction then you're going to lose big time anyway.
+MacroAssemblerCodeRef linkClosureCallThunkGenerator(JSGlobalData* globalData)
+{
+ CCallHelpers jit(globalData);
+
+ slowPathFor(jit, globalData, operationLinkClosureCall);
+
+ LinkBuffer patchBuffer(*globalData, &jit, GLOBAL_THUNK_ID);
+ return FINALIZE_CODE(patchBuffer, ("DFG link closure call slow path thunk"));
+}
+
static MacroAssemblerCodeRef virtualForThunkGenerator(
JSGlobalData* globalData, CodeSpecializationKind kind)
{
diff --git a/Source/JavaScriptCore/dfg/DFGThunks.h b/Source/JavaScriptCore/dfg/DFGThunks.h
index 11a06d1..c97e3bf 100644
--- a/Source/JavaScriptCore/dfg/DFGThunks.h
+++ b/Source/JavaScriptCore/dfg/DFGThunks.h
@@ -45,6 +45,8 @@
MacroAssemblerCodeRef linkCallThunkGenerator(JSGlobalData*);
MacroAssemblerCodeRef linkConstructThunkGenerator(JSGlobalData*);
+MacroAssemblerCodeRef linkClosureCallThunkGenerator(JSGlobalData*);
+
MacroAssemblerCodeRef virtualCallThunkGenerator(JSGlobalData*);
MacroAssemblerCodeRef virtualConstructThunkGenerator(JSGlobalData*);
diff --git a/Source/JavaScriptCore/heap/Heap.h b/Source/JavaScriptCore/heap/Heap.h
index d0d0395..90c9f2a 100644
--- a/Source/JavaScriptCore/heap/Heap.h
+++ b/Source/JavaScriptCore/heap/Heap.h
@@ -174,6 +174,8 @@
bool isPagedOut(double deadline);
void didStartVMShutdown();
+
+ const JITStubRoutineSet& jitStubRoutines() { return m_jitStubRoutines; }
private:
friend class CodeBlock;
diff --git a/Source/JavaScriptCore/heap/JITStubRoutineSet.h b/Source/JavaScriptCore/heap/JITStubRoutineSet.h
index cb76ac8..2c2e9fa 100644
--- a/Source/JavaScriptCore/heap/JITStubRoutineSet.h
+++ b/Source/JavaScriptCore/heap/JITStubRoutineSet.h
@@ -65,6 +65,9 @@
void traceMarkedStubRoutines(SlotVisitor&);
+ unsigned size() const { return m_listOfRoutines.size(); }
+ GCAwareJITStubRoutine* at(unsigned i) const { return m_listOfRoutines[i]; }
+
private:
void markSlow(uintptr_t address);
diff --git a/Source/JavaScriptCore/jit/ClosureCallStubRoutine.cpp b/Source/JavaScriptCore/jit/ClosureCallStubRoutine.cpp
new file mode 100644
index 0000000..73704aa
--- /dev/null
+++ b/Source/JavaScriptCore/jit/ClosureCallStubRoutine.cpp
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2012 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.
+ */
+
+#include "config.h"
+#include "ClosureCallStubRoutine.h"
+
+#if ENABLE(JIT)
+
+#include "Executable.h"
+#include "Heap.h"
+#include "JSGlobalData.h"
+#include "SlotVisitor.h"
+#include "Structure.h"
+
+namespace JSC {
+
+ClosureCallStubRoutine::ClosureCallStubRoutine(
+ const MacroAssemblerCodeRef& code, JSGlobalData& globalData, const JSCell* owner,
+ Structure* structure, ExecutableBase* executable, const CodeOrigin& codeOrigin)
+ : GCAwareJITStubRoutine(code, globalData, true)
+ , m_structure(globalData, owner, structure)
+ , m_executable(globalData, owner, executable)
+ , m_codeOrigin(codeOrigin)
+{
+}
+
+ClosureCallStubRoutine::~ClosureCallStubRoutine()
+{
+}
+
+void ClosureCallStubRoutine::markRequiredObjectsInternal(SlotVisitor& visitor)
+{
+ visitor.append(&m_structure);
+ visitor.append(&m_executable);
+}
+
+} // namespace JSC
+
+#endif // ENABLE(JIT)
+
diff --git a/Source/JavaScriptCore/jit/ClosureCallStubRoutine.h b/Source/JavaScriptCore/jit/ClosureCallStubRoutine.h
new file mode 100644
index 0000000..3fd0206
--- /dev/null
+++ b/Source/JavaScriptCore/jit/ClosureCallStubRoutine.h
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2012 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.
+ */
+
+#ifndef ClosureCallStubRoutine_h
+#define ClosureCallStubRoutine_h
+
+#include <wtf/Platform.h>
+
+#if ENABLE(JIT)
+
+#include "CodeOrigin.h"
+#include "GCAwareJITStubRoutine.h"
+
+namespace JSC {
+
+class ClosureCallStubRoutine : public GCAwareJITStubRoutine {
+public:
+ ClosureCallStubRoutine(
+ const MacroAssemblerCodeRef&, JSGlobalData&, const JSCell* owner,
+ Structure*, ExecutableBase*, const CodeOrigin&);
+
+ virtual ~ClosureCallStubRoutine();
+
+ Structure* structure() const { return m_structure.get(); }
+ ExecutableBase* executable() const { return m_executable.get(); }
+ const CodeOrigin& codeOrigin() const { return m_codeOrigin; }
+
+protected:
+ virtual void markRequiredObjectsInternal(SlotVisitor&);
+
+private:
+ WriteBarrier<Structure> m_structure;
+ WriteBarrier<ExecutableBase> m_executable;
+ // This allows us to figure out who a call is linked to by searching through
+ // stub routines.
+ CodeOrigin m_codeOrigin;
+};
+
+} // namespace JSC
+
+#endif // ENABLE(JIT)
+
+#endif // ClosureCallStubRoutine_h
+
diff --git a/Source/JavaScriptCore/jit/GCAwareJITStubRoutine.cpp b/Source/JavaScriptCore/jit/GCAwareJITStubRoutine.cpp
index 0f0eb14..521e497 100644
--- a/Source/JavaScriptCore/jit/GCAwareJITStubRoutine.cpp
+++ b/Source/JavaScriptCore/jit/GCAwareJITStubRoutine.cpp
@@ -30,17 +30,17 @@
#include "Heap.h"
#include "JSGlobalData.h"
-
#include "SlotVisitor.h"
#include "Structure.h"
namespace JSC {
GCAwareJITStubRoutine::GCAwareJITStubRoutine(
- const MacroAssemblerCodeRef& code, JSGlobalData& globalData)
+ const MacroAssemblerCodeRef& code, JSGlobalData& globalData, bool isClosureCall)
: JITStubRoutine(code)
, m_mayBeExecuting(false)
, m_isJettisoned(false)
+ , m_isClosureCall(isClosureCall)
{
globalData.heap.m_jitStubRoutines.add(this);
}
diff --git a/Source/JavaScriptCore/jit/GCAwareJITStubRoutine.h b/Source/JavaScriptCore/jit/GCAwareJITStubRoutine.h
index 59bc76b..e5ce281 100644
--- a/Source/JavaScriptCore/jit/GCAwareJITStubRoutine.h
+++ b/Source/JavaScriptCore/jit/GCAwareJITStubRoutine.h
@@ -54,7 +54,7 @@
// list which does not get reclaimed all at once).
class GCAwareJITStubRoutine : public JITStubRoutine {
public:
- GCAwareJITStubRoutine(const MacroAssemblerCodeRef&, JSGlobalData&);
+ GCAwareJITStubRoutine(const MacroAssemblerCodeRef&, JSGlobalData&, bool isClosureCall = false);
virtual ~GCAwareJITStubRoutine();
void markRequiredObjects(SlotVisitor& visitor)
@@ -64,6 +64,8 @@
void deleteFromGC();
+ bool isClosureCall() const { return m_isClosureCall; }
+
protected:
virtual void observeZeroRefCount();
@@ -74,6 +76,7 @@
bool m_mayBeExecuting;
bool m_isJettisoned;
+ bool m_isClosureCall;
};
// Use this if you want to mark one additional object during GC if your stub
diff --git a/Source/JavaScriptCore/jit/JIT.cpp b/Source/JavaScriptCore/jit/JIT.cpp
index e222559..a73be38 100644
--- a/Source/JavaScriptCore/jit/JIT.cpp
+++ b/Source/JavaScriptCore/jit/JIT.cpp
@@ -781,10 +781,11 @@
for (unsigned i = 0; i < m_codeBlock->numberOfCallLinkInfos(); ++i) {
CallLinkInfo& info = m_codeBlock->callLinkInfo(i);
info.callType = m_callStructureStubCompilationInfo[i].callType;
- info.bytecodeIndex = m_callStructureStubCompilationInfo[i].bytecodeIndex;
+ info.codeOrigin = CodeOrigin(m_callStructureStubCompilationInfo[i].bytecodeIndex);
info.callReturnLocation = patchBuffer.locationOfNearCall(m_callStructureStubCompilationInfo[i].callReturnLocation);
info.hotPathBegin = patchBuffer.locationOf(m_callStructureStubCompilationInfo[i].hotPathBegin);
info.hotPathOther = patchBuffer.locationOfNearCall(m_callStructureStubCompilationInfo[i].hotPathOther);
+ info.calleeGPR = regT0;
}
#if ENABLE(DFG_JIT) || ENABLE(LLINT)