Commit 3811e215 authored by mhahnenberg@apple.com's avatar mhahnenberg@apple.com

CodeBlocks should be able to determine bytecode liveness

https://bugs.webkit.org/show_bug.cgi?id=118546

Reviewed by Filip Pizlo.

This will simplify some things in the DFG related to OSR exits and determining 
which bytecode variables are live at which points during execution. It will
also be useful for making our conservative GC scan more precise. Currently it 
doesn't properly account for liveness while the DFG is running, so it will be 
off by default behing a runtime Options flag.

* JavaScriptCore.xcodeproj/project.pbxproj:
* bytecode/BytecodeBasicBlock.cpp: Added.
(JSC::isBranch): Used to determine the end of basic blocks.
(JSC::isUnconditionalBranch): Used to determine when a branch at the end of a 
basic block can't possibly fall through to the next basic block in program order.
(JSC::isTerminal): Also used to detect the end of a block.
(JSC::isThrow):
(JSC::isJumpTarget): Used to correctly separate basic blocks. Any jump destination 
must be the head of its own basic block.
(JSC::linkBlocks): Links two blocks together in a bi-direcitonal fashion.
(JSC::computeBytecodeBasicBlocks): Creates a set of basic blocks given a particular 
CodeBlock and links them together.
* bytecode/BytecodeBasicBlock.h: Added.
(JSC::BytecodeBasicBlock::isEntryBlock): Entry blocks are a special basic blocks 
that indicate the beginning of the function.
(JSC::BytecodeBasicBlock::isExitBlock): Exit blocks are a special basic block that 
all blocks that exit the function have as a successor. Entry and exit blocks allows 
the various code paths to be more regular.
(JSC::BytecodeBasicBlock::leaderBytecodeOffset): The leader bytecode offset is the 
bytecode offset of the first instruction in the block.
(JSC::BytecodeBasicBlock::totalBytecodeLength): The total length of all the bytecodes 
in this block.
(JSC::BytecodeBasicBlock::bytecodeOffsets): The bytecode offsets in this particular 
basic block. This Vector allows us to iterate over the bytecodes in reverse order 
which wouldn't be possible normally since they are of variable size.
(JSC::BytecodeBasicBlock::addPredecessor): Links a block to a specified predecessor. 
Only creates one direction of the link.
(JSC::BytecodeBasicBlock::addSuccessor): Same as addPredecessor, but for successors.
(JSC::BytecodeBasicBlock::predecessors): Getter for predecessors.
(JSC::BytecodeBasicBlock::successors): Getter for successors.
(JSC::BytecodeBasicBlock::in): Getter for the liveness info at the head of the block.
(JSC::BytecodeBasicBlock::out): Getter for the liveness info at  the tail of the block.
(JSC::BytecodeBasicBlock::BytecodeBasicBlock):
(JSC::BytecodeBasicBlock::addBytecodeLength): When creating basic blocks we call 
this function when we want to add the next bytecode in program order to this block.
* bytecode/BytecodeLivenessAnalysis.cpp: Added.
(JSC::BytecodeLivenessAnalysis::BytecodeLivenessAnalysis):
(JSC::numberOfCapturedVariables): Convenience wrapper. Returns the
number of captured variables for a particular CodeBlock, or 0 if 
the CodeBlock has no SymbolTable.
(JSC::captureStart): Ditto, but for captureStart().
(JSC::captureEnd): Ditto, but for captureEnd().
(JSC::isValidRegisterForLiveness): Returns true if the liveness analysis should 
track the liveness of a particular operand. We ignore constants, arguments, and 
captured variables. We ignore arguments because they're live for the duration of 
a function call. We ignore captured variables because we also treat them as live 
for the duration of the function. This could probably be improved to be more precise, 
but it didn't seem worth it for now.
(JSC::setForOperand): Convenience wrapper that sets the bit in the provided bit 
vector for the provided operand. It handles skipping over captured variables.
(JSC::computeUsesForBytecodeOffset): Computes which operands are used by a particular bytecode.
(JSC::computeDefsForBytecodeOffset): Computes which operands are defined by a particular 
bytecode. Typically this is just the left-most operand.
(JSC::findBasicBlockWithLeaderOffset): 
(JSC::findBasicBlockForBytecodeOffset): Scans over basic blocks to find the block 
which contains a particular bytecode offset.
(JSC::computeLocalLivenessForBytecodeOffset): Computes block-local liveness from the 
bottom of the block until a specified bytecode offset is reached. 
(JSC::computeLocalLivenessForBlock): Computes liveness for the entire block and 
stores the resulting liveness at the head.
(JSC::BytecodeLivenessAnalysis::runLivenessFixpoint): Runs backward flow liveness 
analysis to fixpoint.
(JSC::BytecodeLivenessAnalysis::getLivenessInfoForNonCapturedVarsAtBytecodeOffset): 
Slow path to get liveness info for non-captured, non-argument variable.
(JSC::BytecodeLivenessAnalysis::operandIsLiveAtBytecodeOffset): 
(JSC::BytecodeLivenessAnalysis::getLivenessInfoAtBytecodeOffset): Returns the liveness 
info for both captured and non-captured vars at a particular bytecode offset.
(JSC::BytecodeLivenessAnalysis::dumpResults): Dumps the output of the liveness analysis. 
Controlled by new flag in Options.h/.cpp.
(JSC::BytecodeLivenessAnalysis::compute): Creates bytecode basic blocks and runs 
full liveness analysis.
* bytecode/BytecodeLivenessAnalysis.h: Added.
(JSC::BytecodeLivenessAnalysis::hasBeenComputed):
(JSC::BytecodeLivenessAnalysis::computeIfNecessary):
* bytecode/CodeBlock.cpp:
(JSC::CodeBlock::CodeBlock):
* bytecode/CodeBlock.h:
(JSC::CodeBlock::livenessAnalysis):
* bytecode/PreciseJumpTargets.cpp: Refactored to be able to get the jump targets for 
a particular bytecode offset for use during bytecode basic block construction.
(JSC::getJumpTargetsForBytecodeOffset):
(JSC::computePreciseJumpTargets):
(JSC::findJumpTargetsForBytecodeOffset):
* bytecode/PreciseJumpTargets.h:
* runtime/Options.cpp:
(JSC::Options::initialize):
* runtime/Options.h:


git-svn-id: http://svn.webkit.org/repository/webkit/trunk@159136 268f45cc-cd09-0410-ab3c-d52691b4dbfc
parent 7368f1e7
......@@ -46,6 +46,8 @@ set(JavaScriptCore_SOURCES
bytecode/ArrayAllocationProfile.cpp
bytecode/ArrayProfile.cpp
bytecode/BytecodeBasicBlock.cpp
bytecode/BytecodeLivenessAnalysis.cpp
bytecode/CallLinkInfo.cpp
bytecode/CallLinkStatus.cpp
bytecode/CodeBlock.cpp
......
2013-08-02 Mark Hahnenberg <mhahnenberg@apple.com>
CodeBlocks should be able to determine bytecode liveness
https://bugs.webkit.org/show_bug.cgi?id=118546
Reviewed by Filip Pizlo.
This will simplify some things in the DFG related to OSR exits and determining
which bytecode variables are live at which points during execution. It will
also be useful for making our conservative GC scan more precise. Currently it
doesn't properly account for liveness while the DFG is running, so it will be
off by default behing a runtime Options flag.
* JavaScriptCore.xcodeproj/project.pbxproj:
* bytecode/BytecodeBasicBlock.cpp: Added.
(JSC::isBranch): Used to determine the end of basic blocks.
(JSC::isUnconditionalBranch): Used to determine when a branch at the end of a
basic block can't possibly fall through to the next basic block in program order.
(JSC::isTerminal): Also used to detect the end of a block.
(JSC::isThrow):
(JSC::isJumpTarget): Used to correctly separate basic blocks. Any jump destination
must be the head of its own basic block.
(JSC::linkBlocks): Links two blocks together in a bi-direcitonal fashion.
(JSC::computeBytecodeBasicBlocks): Creates a set of basic blocks given a particular
CodeBlock and links them together.
* bytecode/BytecodeBasicBlock.h: Added.
(JSC::BytecodeBasicBlock::isEntryBlock): Entry blocks are a special basic blocks
that indicate the beginning of the function.
(JSC::BytecodeBasicBlock::isExitBlock): Exit blocks are a special basic block that
all blocks that exit the function have as a successor. Entry and exit blocks allows
the various code paths to be more regular.
(JSC::BytecodeBasicBlock::leaderBytecodeOffset): The leader bytecode offset is the
bytecode offset of the first instruction in the block.
(JSC::BytecodeBasicBlock::totalBytecodeLength): The total length of all the bytecodes
in this block.
(JSC::BytecodeBasicBlock::bytecodeOffsets): The bytecode offsets in this particular
basic block. This Vector allows us to iterate over the bytecodes in reverse order
which wouldn't be possible normally since they are of variable size.
(JSC::BytecodeBasicBlock::addPredecessor): Links a block to a specified predecessor.
Only creates one direction of the link.
(JSC::BytecodeBasicBlock::addSuccessor): Same as addPredecessor, but for successors.
(JSC::BytecodeBasicBlock::predecessors): Getter for predecessors.
(JSC::BytecodeBasicBlock::successors): Getter for successors.
(JSC::BytecodeBasicBlock::in): Getter for the liveness info at the head of the block.
(JSC::BytecodeBasicBlock::out): Getter for the liveness info at the tail of the block.
(JSC::BytecodeBasicBlock::BytecodeBasicBlock):
(JSC::BytecodeBasicBlock::addBytecodeLength): When creating basic blocks we call
this function when we want to add the next bytecode in program order to this block.
* bytecode/BytecodeLivenessAnalysis.cpp: Added.
(JSC::BytecodeLivenessAnalysis::BytecodeLivenessAnalysis):
(JSC::numberOfCapturedVariables): Convenience wrapper. Returns the
number of captured variables for a particular CodeBlock, or 0 if
the CodeBlock has no SymbolTable.
(JSC::captureStart): Ditto, but for captureStart().
(JSC::captureEnd): Ditto, but for captureEnd().
(JSC::isValidRegisterForLiveness): Returns true if the liveness analysis should
track the liveness of a particular operand. We ignore constants, arguments, and
captured variables. We ignore arguments because they're live for the duration of
a function call. We ignore captured variables because we also treat them as live
for the duration of the function. This could probably be improved to be more precise,
but it didn't seem worth it for now.
(JSC::setForOperand): Convenience wrapper that sets the bit in the provided bit
vector for the provided operand. It handles skipping over captured variables.
(JSC::computeUsesForBytecodeOffset): Computes which operands are used by a particular bytecode.
(JSC::computeDefsForBytecodeOffset): Computes which operands are defined by a particular
bytecode. Typically this is just the left-most operand.
(JSC::findBasicBlockWithLeaderOffset):
(JSC::findBasicBlockForBytecodeOffset): Scans over basic blocks to find the block
which contains a particular bytecode offset.
(JSC::computeLocalLivenessForBytecodeOffset): Computes block-local liveness from the
bottom of the block until a specified bytecode offset is reached.
(JSC::computeLocalLivenessForBlock): Computes liveness for the entire block and
stores the resulting liveness at the head.
(JSC::BytecodeLivenessAnalysis::runLivenessFixpoint): Runs backward flow liveness
analysis to fixpoint.
(JSC::BytecodeLivenessAnalysis::getLivenessInfoForNonCapturedVarsAtBytecodeOffset):
Slow path to get liveness info for non-captured, non-argument variable.
(JSC::BytecodeLivenessAnalysis::operandIsLiveAtBytecodeOffset):
(JSC::BytecodeLivenessAnalysis::getLivenessInfoAtBytecodeOffset): Returns the liveness
info for both captured and non-captured vars at a particular bytecode offset.
(JSC::BytecodeLivenessAnalysis::dumpResults): Dumps the output of the liveness analysis.
Controlled by new flag in Options.h/.cpp.
(JSC::BytecodeLivenessAnalysis::compute): Creates bytecode basic blocks and runs
full liveness analysis.
* bytecode/BytecodeLivenessAnalysis.h: Added.
(JSC::BytecodeLivenessAnalysis::hasBeenComputed):
(JSC::BytecodeLivenessAnalysis::computeIfNecessary):
* bytecode/CodeBlock.cpp:
(JSC::CodeBlock::CodeBlock):
* bytecode/CodeBlock.h:
(JSC::CodeBlock::livenessAnalysis):
* bytecode/PreciseJumpTargets.cpp: Refactored to be able to get the jump targets for
a particular bytecode offset for use during bytecode basic block construction.
(JSC::getJumpTargetsForBytecodeOffset):
(JSC::computePreciseJumpTargets):
(JSC::findJumpTargetsForBytecodeOffset):
* bytecode/PreciseJumpTargets.h:
* runtime/Options.cpp:
(JSC::Options::initialize):
* runtime/Options.h:
2013-11-11 Andy Estes <aestes@apple.com>
[iOS] Define JSC_OBJC_API_ENABLED
......
......@@ -100,6 +100,10 @@ javascriptcore_sources += \
Source/JavaScriptCore/bytecode/ArrayProfile.cpp \
Source/JavaScriptCore/bytecode/ArrayProfile.h \
Source/JavaScriptCore/bytecode/ByValInfo.h \
Source/JavaScriptCore/bytecode/BytecodeBasicBlock.cpp \
Source/JavaScriptCore/bytecode/BytecodeBasicBlock.h \
Source/JavaScriptCore/bytecode/BytecodeLivenessAnalysis.cpp \
Source/JavaScriptCore/bytecode/BytecodeLivenessAnalysis.h \
Source/JavaScriptCore/bytecode/BytecodeConventions.h \
Source/JavaScriptCore/bytecode/CallLinkInfo.cpp \
Source/JavaScriptCore/bytecode/CallLinkInfo.h \
......
......@@ -296,6 +296,8 @@
<ClInclude Include="..\assembler\MacroAssemblerX86Common.cpp" />
<ClCompile Include="..\bytecode\ArrayAllocationProfile.cpp" />
<ClCompile Include="..\bytecode\ArrayProfile.cpp" />
<ClCompile Include="..\bytecode\BytecodeBasicBlock.cpp" />
<ClCompile Include="..\bytecode\BytecodeLivenessAnalysis.cpp" />
<ClCompile Include="..\bytecode\CallLinkInfo.cpp" />
<ClCompile Include="..\bytecode\CallLinkStatus.cpp" />
<ClCompile Include="..\bytecode\CodeBlock.cpp" />
......@@ -741,6 +743,8 @@
<ClInclude Include="..\bytecode\ArrayAllocationProfile.h" />
<ClInclude Include="..\bytecode\ArrayProfile.h" />
<ClInclude Include="..\bytecode\ByValInfo.h" />
<ClInclude Include="..\bytecode\BytecodeBasicBlock.h" />
<ClInclude Include="..\bytecode\BytecodeLivenessAnalysis.h" />
<ClInclude Include="..\bytecode\CallLinkInfo.h" />
<ClInclude Include="..\bytecode\CallLinkStatus.h" />
<ClInclude Include="..\bytecode\CallReturnOffsetToBytecodeOffset.h" />
......@@ -1324,4 +1328,4 @@
<ImportGroup Label="ExtensionTargets">
<Import Project="$(VCTargetsPath)\BuildCustomizations\masm.targets" />
</ImportGroup>
</Project>
\ No newline at end of file
</Project>
......@@ -108,6 +108,12 @@
<ClCompile Include="..\bytecode\ArrayProfile.cpp">
<Filter>bytecode</Filter>
</ClCompile>
<ClCompile Include="..\bytecode\BytecodeBasicBlock.cpp">
<Filter>bytecode</Filter>
</ClCompile>
<ClCompile Include="..\bytecode\BytecodeLivenessAnalysis.cpp">
<Filter>bytecode</Filter>
</ClCompile>
<ClCompile Include="..\bytecode\CallLinkInfo.cpp">
<Filter>bytecode</Filter>
</ClCompile>
......@@ -1364,6 +1370,12 @@
<ClInclude Include="..\bytecode\ByValInfo.h">
<Filter>bytecode</Filter>
</ClInclude>
<ClInclude Include="..\bytecode\BytecodeBasicBlock.h">
<Filter>bytecode</Filter>
</ClInclude>
<ClInclude Include="..\bytecode\BytecodeLivenessAnalysis.h">
<Filter>bytecode</Filter>
</ClInclude>
<ClInclude Include="..\bytecode\CallLinkInfo.h">
<Filter>bytecode</Filter>
</ClInclude>
......@@ -3104,4 +3116,4 @@
<Filter>jit</Filter>
</MASM>
</ItemGroup>
</Project>
\ No newline at end of file
</Project>
......@@ -1216,6 +1216,10 @@
C2EAD2FC14F0249800A4B159 /* CopiedAllocator.h in Headers */ = {isa = PBXBuildFile; fileRef = C2EAD2FB14F0249800A4B159 /* CopiedAllocator.h */; settings = {ATTRIBUTES = (Private, ); }; };
C2F0F2D116BAEEE900187C19 /* StructureRareData.cpp in Sources */ = {isa = PBXBuildFile; fileRef = C2F0F2D016BAEEE900187C19 /* StructureRareData.cpp */; };
C2FC9BD316644DFB00810D33 /* CopiedBlockInlines.h in Headers */ = {isa = PBXBuildFile; fileRef = C2FC9BD216644DFB00810D33 /* CopiedBlockInlines.h */; settings = {ATTRIBUTES = (Private, ); }; };
C2FCAE1017A9C24E0034C735 /* BytecodeBasicBlock.cpp in Sources */ = {isa = PBXBuildFile; fileRef = C2FCAE0C17A9C24E0034C735 /* BytecodeBasicBlock.cpp */; };
C2FCAE1117A9C24E0034C735 /* BytecodeBasicBlock.h in Headers */ = {isa = PBXBuildFile; fileRef = C2FCAE0D17A9C24E0034C735 /* BytecodeBasicBlock.h */; };
C2FCAE1217A9C24E0034C735 /* BytecodeLivenessAnalysis.cpp in Sources */ = {isa = PBXBuildFile; fileRef = C2FCAE0E17A9C24E0034C735 /* BytecodeLivenessAnalysis.cpp */; };
C2FCAE1317A9C24E0034C735 /* BytecodeLivenessAnalysis.h in Headers */ = {isa = PBXBuildFile; fileRef = C2FCAE0F17A9C24E0034C735 /* BytecodeLivenessAnalysis.h */; };
C2FE18A416BAEC4000AF3061 /* StructureRareData.h in Headers */ = {isa = PBXBuildFile; fileRef = C2FE18A316BAEC4000AF3061 /* StructureRareData.h */; settings = {ATTRIBUTES = (Private, ); }; };
DDF7ABD411F60ED200108E36 /* GCActivityCallback.h in Headers */ = {isa = PBXBuildFile; fileRef = DDF7ABD211F60ED200108E36 /* GCActivityCallback.h */; settings = {ATTRIBUTES = (Private, ); }; };
E124A8F70E555775003091F1 /* OpaqueJSString.h in Headers */ = {isa = PBXBuildFile; fileRef = E124A8F50E555775003091F1 /* OpaqueJSString.h */; settings = {ATTRIBUTES = (Private, ); }; };
......@@ -2502,6 +2506,10 @@
C2EAD2FB14F0249800A4B159 /* CopiedAllocator.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CopiedAllocator.h; sourceTree = "<group>"; };
C2F0F2D016BAEEE900187C19 /* StructureRareData.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = StructureRareData.cpp; sourceTree = "<group>"; };
C2FC9BD216644DFB00810D33 /* CopiedBlockInlines.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CopiedBlockInlines.h; sourceTree = "<group>"; };
C2FCAE0C17A9C24E0034C735 /* BytecodeBasicBlock.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = BytecodeBasicBlock.cpp; sourceTree = "<group>"; };
C2FCAE0D17A9C24E0034C735 /* BytecodeBasicBlock.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BytecodeBasicBlock.h; sourceTree = "<group>"; };
C2FCAE0E17A9C24E0034C735 /* BytecodeLivenessAnalysis.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = BytecodeLivenessAnalysis.cpp; sourceTree = "<group>"; };
C2FCAE0F17A9C24E0034C735 /* BytecodeLivenessAnalysis.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BytecodeLivenessAnalysis.h; sourceTree = "<group>"; };
C2FE18A316BAEC4000AF3061 /* StructureRareData.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = StructureRareData.h; sourceTree = "<group>"; };
D21202280AD4310C00ED79B6 /* DateConversion.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = DateConversion.cpp; sourceTree = "<group>"; };
D21202290AD4310C00ED79B6 /* DateConversion.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = DateConversion.h; sourceTree = "<group>"; };
......@@ -4023,6 +4031,10 @@
969A078F0ED1D3AE00F1F681 /* bytecode */ = {
isa = PBXGroup;
children = (
C2FCAE0C17A9C24E0034C735 /* BytecodeBasicBlock.cpp */,
C2FCAE0D17A9C24E0034C735 /* BytecodeBasicBlock.h */,
C2FCAE0E17A9C24E0034C735 /* BytecodeLivenessAnalysis.cpp */,
C2FCAE0F17A9C24E0034C735 /* BytecodeLivenessAnalysis.h */,
0F8335B41639C1E3001443B5 /* ArrayAllocationProfile.cpp */,
0F8335B51639C1E3001443B5 /* ArrayAllocationProfile.h */,
0F63945115D07051006A597C /* ArrayProfile.cpp */,
......@@ -4161,6 +4173,7 @@
A7A8AF3717ADB5F3005AB174 /* ArrayBufferView.h in Headers */,
BC18C3E60E16F5CD00B34460 /* ArrayConstructor.h in Headers */,
0FB7F39515ED8E4600F167B2 /* ArrayConventions.h in Headers */,
C2FCAE1117A9C24E0034C735 /* BytecodeBasicBlock.h in Headers */,
A7BDAEC717F4EA1400F6140C /* ArrayIteratorConstructor.h in Headers */,
A7BDAEC917F4EA1400F6140C /* ArrayIteratorPrototype.h in Headers */,
0F63945515D07057006A597C /* ArrayProfile.h in Headers */,
......@@ -4751,6 +4764,7 @@
A730B6121250068F009D25B1 /* StrictEvalActivation.h in Headers */,
BC18C4660E16F5CD00B34460 /* StringConstructor.h in Headers */,
BC18C4680E16F5CD00B34460 /* StringObject.h in Headers */,
C2FCAE1317A9C24E0034C735 /* BytecodeLivenessAnalysis.h in Headers */,
BC18C46A0E16F5CD00B34460 /* StringPrototype.h in Headers */,
142E313B134FF0A600AFADB5 /* Strong.h in Headers */,
145722861437E140005FDE26 /* StrongInlines.h in Headers */,
......@@ -5287,6 +5301,7 @@
147F39C4107EC37600427A48 /* DateConversion.cpp in Sources */,
147F39C5107EC37600427A48 /* DateInstance.cpp in Sources */,
147F39C6107EC37600427A48 /* DatePrototype.cpp in Sources */,
C2FCAE1217A9C24E0034C735 /* BytecodeLivenessAnalysis.cpp in Sources */,
14280823107EC02C0013E7B2 /* Debugger.cpp in Sources */,
BC3135650F302FA3003DFD3A /* DebuggerActivation.cpp in Sources */,
149559EE0DDCDDF700648087 /* DebuggerCallFrame.cpp in Sources */,
......@@ -5606,6 +5621,7 @@
0FF729B2166AD35C000F5BA3 /* ProfilerDatabase.cpp in Sources */,
0FF729B3166AD35C000F5BA3 /* ProfilerOrigin.cpp in Sources */,
0FF729B4166AD35C000F5BA3 /* ProfilerOriginStack.cpp in Sources */,
C2FCAE1017A9C24E0034C735 /* BytecodeBasicBlock.cpp in Sources */,
0FB1058B1675483100F8AB6E /* ProfilerOSRExit.cpp in Sources */,
0FB1058D1675483700F8AB6E /* ProfilerOSRExitSite.cpp in Sources */,
0F13912B16771C3A009CCB07 /* ProfilerProfiledBytecodes.cpp in Sources */,
......
/*
* Copyright (C) 2013 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. AND ITS CONTRIBUTORS ``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 ITS 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 "BytecodeBasicBlock.h"
#include "CodeBlock.h"
#include "PreciseJumpTargets.h"
namespace JSC {
static bool isBranch(OpcodeID opcodeID)
{
switch (opcodeID) {
case op_jmp:
case op_jtrue:
case op_jfalse:
case op_jeq_null:
case op_jneq_null:
case op_jneq_ptr:
case op_jless:
case op_jlesseq:
case op_jgreater:
case op_jgreatereq:
case op_jnless:
case op_jnlesseq:
case op_jngreater:
case op_jngreatereq:
case op_switch_imm:
case op_switch_char:
case op_switch_string:
case op_get_pnames:
case op_next_pname:
case op_check_has_instance:
return true;
default:
return false;
}
}
static bool isUnconditionalBranch(OpcodeID opcodeID)
{
switch (opcodeID) {
case op_jmp:
return true;
default:
return false;
}
}
static bool isTerminal(OpcodeID opcodeID)
{
switch (opcodeID) {
case op_ret:
case op_ret_object_or_this:
case op_end:
return true;
default:
return false;
}
}
static bool isThrow(OpcodeID opcodeID)
{
switch (opcodeID) {
case op_throw:
case op_throw_static_error:
return true;
default:
return false;
}
}
static bool isJumpTarget(OpcodeID opcodeID, Vector<unsigned, 32>& jumpTargets, unsigned bytecodeOffset)
{
if (opcodeID == op_catch)
return true;
for (unsigned i = 0; i < jumpTargets.size(); i++) {
if (bytecodeOffset == jumpTargets[i])
return true;
}
return false;
}
static void linkBlocks(BytecodeBasicBlock* predecessor, BytecodeBasicBlock* successor)
{
predecessor->addSuccessor(successor);
successor->addPredecessor(predecessor);
}
void computeBytecodeBasicBlocks(CodeBlock* codeBlock, Vector<RefPtr<BytecodeBasicBlock> >& basicBlocks)
{
Vector<unsigned, 32> jumpTargets;
computePreciseJumpTargets(codeBlock, jumpTargets);
// Create the entry and exit basic blocks.
BytecodeBasicBlock* entry = new BytecodeBasicBlock(BytecodeBasicBlock::EntryBlock);
basicBlocks.append(adoptRef(entry));
BytecodeBasicBlock* exit = new BytecodeBasicBlock(BytecodeBasicBlock::ExitBlock);
// Find basic block boundaries.
BytecodeBasicBlock* current = new BytecodeBasicBlock(0, 0);
linkBlocks(entry, current);
basicBlocks.append(adoptRef(current));
bool nextInstructionIsLeader = false;
Interpreter* interpreter = codeBlock->vm()->interpreter;
Instruction* instructionsBegin = codeBlock->instructions().begin();
unsigned instructionCount = codeBlock->instructions().size();
for (unsigned bytecodeOffset = 0; bytecodeOffset < instructionCount;) {
OpcodeID opcodeID = interpreter->getOpcodeID(instructionsBegin[bytecodeOffset].u.opcode);
unsigned opcodeLength = opcodeLengths[opcodeID];
bool createdBlock = false;
// If the current bytecode is a jump target, then it's the leader of its own basic block.
if (isJumpTarget(opcodeID, jumpTargets, bytecodeOffset) || nextInstructionIsLeader) {
BytecodeBasicBlock* block = new BytecodeBasicBlock(bytecodeOffset, opcodeLength);
basicBlocks.append(adoptRef(block));
current = block;
createdBlock = true;
nextInstructionIsLeader = false;
bytecodeOffset += opcodeLength;
}
// If the current bytecode is a branch or a return, then the next instruction is the leader of its own basic block.
if (isBranch(opcodeID) || isTerminal(opcodeID) || isThrow(opcodeID))
nextInstructionIsLeader = true;
if (createdBlock)
continue;
// Otherwise, just add to the length of the current block.
current->addBytecodeLength(opcodeLength);
bytecodeOffset += opcodeLength;
}
// Link basic blocks together.
for (unsigned i = 0; i < basicBlocks.size(); i++) {
BytecodeBasicBlock* block = basicBlocks[i].get();
if (block->isEntryBlock() || block->isExitBlock())
continue;
bool fallsThrough = true;
for (unsigned bytecodeOffset = block->leaderBytecodeOffset(); bytecodeOffset < block->leaderBytecodeOffset() + block->totalBytecodeLength();) {
const Instruction& currentInstruction = instructionsBegin[bytecodeOffset];
OpcodeID opcodeID = interpreter->getOpcodeID(currentInstruction.u.opcode);
unsigned opcodeLength = opcodeLengths[opcodeID];
// If we found a terminal bytecode, link to the exit block.
if (isTerminal(opcodeID)) {
ASSERT(bytecodeOffset + opcodeLength == block->leaderBytecodeOffset() + block->totalBytecodeLength());
linkBlocks(block, exit);
fallsThrough = false;
break;
}
// If we found a throw, get the HandlerInfo for this instruction to see where we will jump.
// If there isn't one, treat this throw as a terminal. This is true even if we have a finally
// block because the finally block will create its own catch, which will generate a HandlerInfo.
if (isThrow(opcodeID)) {
ASSERT(bytecodeOffset + opcodeLength == block->leaderBytecodeOffset() + block->totalBytecodeLength());
HandlerInfo* handler = codeBlock->handlerForBytecodeOffset(bytecodeOffset);
fallsThrough = false;
if (!handler) {
linkBlocks(block, exit);
break;
}
for (unsigned i = 0; i < basicBlocks.size(); i++) {
BytecodeBasicBlock* otherBlock = basicBlocks[i].get();
if (handler->target == otherBlock->leaderBytecodeOffset()) {
linkBlocks(block, otherBlock);
break;
}
}
break;
}
// If we found a branch, link to the block(s) that we jump to.
if (isBranch(opcodeID)) {
ASSERT(bytecodeOffset + opcodeLength == block->leaderBytecodeOffset() + block->totalBytecodeLength());
Vector<unsigned, 1> bytecodeOffsetsJumpedTo;
findJumpTargetsForBytecodeOffset(codeBlock, bytecodeOffset, bytecodeOffsetsJumpedTo);
for (unsigned i = 0; i < basicBlocks.size(); i++) {
BytecodeBasicBlock* otherBlock = basicBlocks[i].get();
if (bytecodeOffsetsJumpedTo.contains(otherBlock->leaderBytecodeOffset()))
linkBlocks(block, otherBlock);
}
if (isUnconditionalBranch(opcodeID))
fallsThrough = false;
break;
}
bytecodeOffset += opcodeLength;
}
// If we fall through then link to the next block in program order.
if (fallsThrough) {
ASSERT(i + 1 < basicBlocks.size());
BytecodeBasicBlock* nextBlock = basicBlocks[i + 1].get();
linkBlocks(block, nextBlock);
}
}
basicBlocks.append(adoptRef(exit));
}
} // namespace JSC
/*
* Copyright (C) 2013 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. AND ITS CONTRIBUTORS ``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 ITS 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 BytecodeBasicBlock_h
#define BytecodeBasicBlock_h
#include <limits.h>
#include <wtf/FastBitVector.h>
#include <wtf/HashMap.h>
#include <wtf/RefCounted.h>
#include <wtf/Vector.h>
namespace JSC {
class CodeBlock;
typedef HashMap<unsigned, FastBitVector, WTF::IntHash<unsigned>, WTF::UnsignedWithZeroKeyHashTraits<unsigned> > BytecodeToBitmapMap;
class BytecodeBasicBlock : public RefCounted<BytecodeBasicBlock> {
public:
enum SpecialBlockType { EntryBlock, ExitBlock };
BytecodeBasicBlock(unsigned start, unsigned length);
BytecodeBasicBlock(SpecialBlockType);
bool isEntryBlock() { return !m_leaderBytecodeOffset && !m_totalBytecodeLength; }
bool isExitBlock() { return m_leaderBytecodeOffset == UINT_MAX && m_totalBytecodeLength == UINT_MAX; }
unsigned leaderBytecodeOffset() { return m_leaderBytecodeOffset; }
unsigned totalBytecodeLength() { return m_totalBytecodeLength; }
Vector<unsigned>& bytecodeOffsets() { return m_bytecodeOffsets; }
void addBytecodeLength(unsigned);
void addPredecessor(BytecodeBasicBlock* block) { m_predecessors.append(block); }
void addSuccessor(BytecodeBasicBlock* block) { m_successors.append(block); }
Vector<BytecodeBasicBlock*>& predecessors() { return m_predecessors; }
Vector<BytecodeBasicBlock*>& successors() { return m_successors; }
FastBitVector& in() { return m_in; }
FastBitVector& out() { return m_out; }
private:
unsigned m_leaderBytecodeOffset;
unsigned m_totalBytecodeLength;
Vector<unsigned> m_bytecodeOffsets;
Vector<BytecodeBasicBlock*> m_predecessors;
Vector<BytecodeBasicBlock*> m_successors;
FastBitVector m_in;
FastBitVector m_out;
};
void computeBytecodeBasicBlocks(CodeBlock*, Vector<RefPtr<BytecodeBasicBlock> >&);
inline BytecodeBasicBlock::BytecodeBasicBlock(unsigned start, unsigned length)
: m_leaderBytecodeOffset(start)
, m_totalBytecodeLength(length)
{
m_bytecodeOffsets.append(m_leaderBytecodeOffset);
}
inline BytecodeBasicBlock::BytecodeBasicBlock(BytecodeBasicBlock::SpecialBlockType blockType)
: m_leaderBytecodeOffset(blockType == BytecodeBasicBlock::EntryBlock ? 0 : UINT_MAX)
, m_totalBytecodeLength(blockType == BytecodeBasicBlock::EntryBlock ? 0 : UINT_MAX)
{
}
inline void BytecodeBasicBlock::addBytecodeLength(unsigned bytecodeLength)
{
m_bytecodeOffsets.append(m_leaderBytecodeOffset + m_totalBytecodeLength);
m_totalBytecodeLength += bytecodeLength;
}
} // namespace JSC
#endif // BytecodeBasicBlock_h
This diff is collapsed.
/*
* Copyright (C) 2013 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. AND ITS CONTRIBUTORS ``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 ITS 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 BytecodeLivenessAnalysis_h
#define BytecodeLivenessAnalysis_h
#include "BytecodeBasicBlock.h"
#include <wtf/FastBitVector.h>
#include <wtf/HashMap.h>
#include <wtf/Vector.h>
namespace JSC {
class CodeBlock;
class BytecodeLivenessAnalysis {
public:
BytecodeLivenessAnalysis(CodeBlock*);
BytecodeLivenessAnalysis(const BytecodeLivenessAnalysis&);
bool operandIsLiveAtBytecodeOffset(int operand, unsigned bytecodeOffset);
FastBitVector getLivenessInfoAtBytecodeOffset(unsigned bytecodeOffset);
bool hasBeenComputed() { return m_computed; }
void compute();
void computeIfNecessary()
{
if (m_computed)
return;
compute();
}
private:
void runLivenessFixpoint();
void dumpResults();
void getLivenessInfoForNonCapturedVarsAtBytecodeOffset(unsigned bytecodeOffset, FastBitVector&);
CodeBlock* m_codeBlock;
Vector<RefPtr<BytecodeBasicBlock> > m_basicBlocks;
bool m_computed;
};
} // namespace JSC
#endif // BytecodeLivenessAnalysis_h
......@@ -1572,6 +1572,7 @@ CodeBlock::CodeBlock(CopyParsedBlockTag, CodeBlock& other)
, m_optimizationDelayCounter(0)
, m_reoptimizationRetryCounter(0)
, m_hash(other.m_hash)
, m_livenessAnalysis(other.m_livenessAnalysis)
#if ENABLE(JIT)
, m_capabilityLevelState(DFG::CapabilityLevelNotSet)
#endif
......@@ -1617,6 +1618,7 @@ CodeBlock::CodeBlock(ScriptExecutable* ownerExecutable, UnlinkedCodeBlock* unlin
, m_osrExitCounter(0)
, m_optimizationDelayCounter(0)
, m_reoptimizationRetryCounter(0)
, m_livenessAnalysis(this)
#if ENABLE(JIT)
, m_capabilityLevelState(DFG::CapabilityLevelNotSet)
#endif
......@@ -1919,6 +1921,7 @@ CodeBlock::CodeBlock(ScriptExecutable* ownerExecutable, UnlinkedCodeBlock* unlin
if (Options::dumpGeneratedBytecodes())
dumpBytecode();
m_heap->m_codeBlocks.add(this);
m_heap->reportExtraMemoryCost(sizeof(CodeBlock) + m_instructions.size() * sizeof(Instruction));
}
......
......@@ -33,6 +33,7 @@
#include "ArrayProfile.h"