summaryrefslogtreecommitdiff
path: root/Source/JavaScriptCore
diff options
context:
space:
mode:
Diffstat (limited to 'Source/JavaScriptCore')
-rw-r--r--Source/JavaScriptCore/CMakeLists.txt1
-rw-r--r--Source/JavaScriptCore/ChangeLog422
-rw-r--r--Source/JavaScriptCore/Configurations/FeatureDefines.xcconfig3
-rw-r--r--Source/JavaScriptCore/GNUmakefile.list.am3
-rw-r--r--Source/JavaScriptCore/JavaScriptCore.gypi2
-rw-r--r--Source/JavaScriptCore/JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.vcproj8
-rw-r--r--Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj12
-rw-r--r--Source/JavaScriptCore/Target.pri1
-rw-r--r--Source/JavaScriptCore/bytecode/CodeBlock.cpp2
-rw-r--r--Source/JavaScriptCore/bytecode/CodeBlock.h7
-rw-r--r--Source/JavaScriptCore/dfg/DFGAbstractState.cpp194
-rw-r--r--Source/JavaScriptCore/dfg/DFGAbstractState.h8
-rw-r--r--Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp152
-rw-r--r--Source/JavaScriptCore/dfg/DFGCSEPhase.cpp49
-rw-r--r--Source/JavaScriptCore/dfg/DFGConstantFoldingPhase.cpp37
-rw-r--r--Source/JavaScriptCore/dfg/DFGJITCompiler.h4
-rw-r--r--Source/JavaScriptCore/dfg/DFGOperations.cpp25
-rw-r--r--Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp20
-rw-r--r--Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h15
-rw-r--r--Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp48
-rw-r--r--Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp48
-rw-r--r--Source/JavaScriptCore/heap/Heap.cpp11
-rw-r--r--Source/JavaScriptCore/heap/Heap.h8
-rw-r--r--Source/JavaScriptCore/heap/IncrementalSweeper.cpp107
-rw-r--r--Source/JavaScriptCore/heap/IncrementalSweeper.h51
-rw-r--r--Source/JavaScriptCore/heap/MarkedBlock.h7
-rw-r--r--Source/JavaScriptCore/interpreter/Interpreter.cpp2
-rw-r--r--Source/JavaScriptCore/llint/LLIntSlowPaths.cpp12
-rw-r--r--Source/JavaScriptCore/llint/LowLevelInterpreter32_64.asm8
-rw-r--r--Source/JavaScriptCore/parser/Nodes.h2
-rw-r--r--Source/JavaScriptCore/parser/SourceCode.h7
-rw-r--r--Source/JavaScriptCore/parser/SourceProvider.h10
-rw-r--r--Source/JavaScriptCore/runtime/Executable.h2
-rw-r--r--Source/JavaScriptCore/runtime/JSGlobalObject.cpp12
-rw-r--r--Source/JavaScriptCore/runtime/JSGlobalObject.h3
-rw-r--r--Source/JavaScriptCore/runtime/JSONObject.cpp3
-rw-r--r--Source/JavaScriptCore/runtime/JSString.h11
-rw-r--r--Source/JavaScriptCore/runtime/WeakGCMap.h5
38 files changed, 1035 insertions, 287 deletions
diff --git a/Source/JavaScriptCore/CMakeLists.txt b/Source/JavaScriptCore/CMakeLists.txt
index cb58b0007..dc00849e3 100644
--- a/Source/JavaScriptCore/CMakeLists.txt
+++ b/Source/JavaScriptCore/CMakeLists.txt
@@ -97,6 +97,7 @@ SET(JavaScriptCore_SOURCES
heap/HandleSet.cpp
heap/HandleStack.cpp
heap/Heap.cpp
+ heap/IncrementalSweeper.cpp
heap/MachineStackMarker.cpp
heap/MarkedAllocator.cpp
heap/MarkedBlock.cpp
diff --git a/Source/JavaScriptCore/ChangeLog b/Source/JavaScriptCore/ChangeLog
index c80a45805..807d83297 100644
--- a/Source/JavaScriptCore/ChangeLog
+++ b/Source/JavaScriptCore/ChangeLog
@@ -1,3 +1,425 @@
+2012-05-31 Mark Hahnenberg <mhahnenberg@apple.com>
+
+ JSGlobalObject does not mark m_privateNameStructure
+ https://bugs.webkit.org/show_bug.cgi?id=88023
+
+ Rubber stamped by Gavin Barraclough.
+
+ * runtime/JSGlobalObject.cpp:
+ (JSC::JSGlobalObject::visitChildren): We need to mark this so it doesn't get
+ inadvertently garbage collected.
+
+2012-05-31 Erik Arvidsson <arv@chromium.org>
+
+ Make DOM Exceptions Errors
+ https://bugs.webkit.org/show_bug.cgi?id=85078
+
+ Reviewed by Oliver Hunt.
+
+ WebIDL mandates that exceptions should have Error.prototype on its prototype chain.
+
+ For JSC we have access to the Error.prototype from the binding code.
+
+ For V8 we set a field in the WrapperTypeInfo and when the constructor function is created we
+ set the prototype as needed.
+
+ Updated test: fast/dom/DOMException/prototype-object.html
+
+ * JavaScriptCore.xcodeproj/project.pbxproj:
+ * runtime/JSGlobalObject.cpp:
+ (JSC::JSGlobalObject::reset):
+ * runtime/JSGlobalObject.h:
+ (JSC):
+ (JSGlobalObject):
+ (JSC::JSGlobalObject::errorPrototype):
+
+2012-05-31 Andy Wingo <wingo@igalia.com>
+
+ Fix reference to unset variable in debug mode
+ https://bugs.webkit.org/show_bug.cgi?id=87981
+
+ Reviewed by Geoffrey Garen.
+
+ * runtime/JSONObject.cpp (Stringifier::Holder::Holder):
+ Initialize m_size in debug mode, as we check it later in an assert.
+
+2012-05-30 Mark Hahnenberg <mhahnenberg@apple.com>
+
+ Heap should sweep incrementally
+ https://bugs.webkit.org/show_bug.cgi?id=85429
+
+ We shouldn't have to wait for the opportunistic GC timer to fire in order
+ to call object destructors. Instead, we should incrementally sweep some
+ subset of the blocks requiring sweeping periodically. We tie this sweeping
+ to a timer rather than to collections because we want to reclaim this memory
+ even if we stop allocating. This way, our memory usage scales smoothly with
+ actual use, regardless of whether we've recently done an opportunistic GC or not.
+
+ Reviewed by Geoffrey Garen.
+
+ * CMakeLists.txt:
+ * GNUmakefile.list.am:
+ * JavaScriptCore.gypi:
+ * JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.vcproj:
+ * JavaScriptCore.xcodeproj/project.pbxproj:
+ * Target.pri:
+ * heap/Heap.cpp:
+ (JSC::Heap::Heap):
+ (JSC::Heap::collect): We no longer sweep during a full sweep. We only shrink now,
+ which we will switch over to being done during incremental sweeping too as soon as
+ all finalizers can be run lazily (and, by extension, incrementally).
+ (JSC::Heap::sweeper):
+ (JSC):
+ * heap/Heap.h:
+ (JSC):
+ (Heap):
+ * heap/IncrementalSweeper.cpp: Added.
+ (JSC):
+ (JSC::IncrementalSweeper::timerDidFire): The IncrementalSweeper works very similarly to
+ GCActivityCallback. It is tied to a run-loop based timer that fires periodically based
+ on how long the previous sweep increment took to run. The IncrementalSweeper doesn't do
+ anything if the platform doesn't support CoreFoundation.
+ (JSC::IncrementalSweeper::IncrementalSweeper):
+ (JSC::IncrementalSweeper::~IncrementalSweeper):
+ (JSC::IncrementalSweeper::create):
+ (JSC::IncrementalSweeper::scheduleTimer):
+ (JSC::IncrementalSweeper::cancelTimer):
+ (JSC::IncrementalSweeper::doSweep): Iterates over the snapshot of the MarkedSpace taken
+ during the last collection, checking to see which blocks need sweeping. If it successfully
+ gets to the end of the blocks that need sweeping then it cancels the timer.
+ (JSC::IncrementalSweeper::startSweeping): We take a snapshot of the Heap and store it in
+ a Vector that the incremental sweep will iterate over. We also reset our index into this Vector.
+ * heap/IncrementalSweeper.h: Added.
+ (JSC):
+ (IncrementalSweeper):
+ * heap/MarkedBlock.h:
+ (JSC::MarkedBlock::needsSweeping): If a block is in the Marked state it needs sweeping
+ to be usable and to run any destructors that need to be run.
+
+2012-05-30 Patrick Gansterer <paroga@webkit.org>
+
+ [WINCE] Fix JSString after r115516.
+ https://bugs.webkit.org/show_bug.cgi?id=87892
+
+ Reviewed by Geoffrey Garen.
+
+ r115516 splitted JSString into two classes, with addition nested classes.
+ Add a workaround for the WinCE compiler since it can't resolve the friend class
+ declerations corretly and denies the access to protected members of JSString.
+
+ * runtime/JSString.h:
+ (JSC::JSRopeString::RopeBuilder::append):
+ (JSC::JSRopeString::append):
+ (JSRopeString):
+
+2012-05-30 Oliver Hunt <oliver@apple.com>
+
+ Really provide error information with the inspector disabled
+ https://bugs.webkit.org/show_bug.cgi?id=87910
+
+ Reviewed by Filip Pizlo.
+
+ Don't bother checking for anything other than pre-existing error info.
+ In the absence of complete line number information you'll only get the
+ line a function starts on, but at least it's something.
+
+ * interpreter/Interpreter.cpp:
+ (JSC::Interpreter::throwException):
+
+2012-05-30 Filip Pizlo <fpizlo@apple.com>
+
+ LLInt broken on x86-32 with JIT turned off
+ https://bugs.webkit.org/show_bug.cgi?id=87906
+
+ Reviewed by Geoffrey Garen.
+
+ Fixed the code to not clobber registers that contain important things, like the call frame.
+
+ * llint/LowLevelInterpreter32_64.asm:
+
+2012-05-30 Filip Pizlo <fpizlo@apple.com>
+
+ ScriptDebugServer wants sourceIDs that are non-zero because that's what HashMaps want, so JSC should placate it
+ https://bugs.webkit.org/show_bug.cgi?id=87887
+
+ Reviewed by Darin Adler.
+
+ Better fix - we now never call SourceProvider::asID() if SourceProvider* is 0.
+
+ * parser/Nodes.h:
+ (JSC::ScopeNode::sourceID):
+ * parser/SourceCode.h:
+ (JSC::SourceCode::providerID):
+ (SourceCode):
+ * parser/SourceProvider.h:
+ (SourceProvider):
+ (JSC::SourceProvider::asID):
+ * runtime/Executable.h:
+ (JSC::ScriptExecutable::sourceID):
+
+2012-05-30 Filip Pizlo <fpizlo@apple.com>
+
+ ScriptDebugServer wants sourceIDs that are non-zero because that's what HashMaps want, so JSC should placate it
+ https://bugs.webkit.org/show_bug.cgi?id=87887
+
+ Reviewed by Geoffrey Garen.
+
+ * parser/SourceProvider.h:
+ (JSC::SourceProvider::asID):
+
+2012-05-30 Oliver Hunt <oliver@apple.com>
+
+ DFG does not correctly handle exceptions caught in the LLInt
+ https://bugs.webkit.org/show_bug.cgi?id=87885
+
+ Reviewed by Filip Pizlo.
+
+ Make the DFG use genericThrow, rather than reimplementing a small portion of it.
+ Also make the LLInt slow paths validate that their PC is correct.
+
+ * dfg/DFGOperations.cpp:
+ * llint/LLIntSlowPaths.cpp:
+ (LLInt):
+
+2012-05-29 Filip Pizlo <fpizlo@apple.com>
+
+ DFG CFA should infer types and values of captured variables
+ https://bugs.webkit.org/show_bug.cgi?id=87813
+
+ Reviewed by Gavin Barraclough.
+
+ Slight speed-up in V8/earley-boyer (~1%).
+
+ * bytecode/CodeBlock.h:
+ (JSC::CodeBlock::argumentsAreCaptured):
+ (JSC::CodeBlock::argumentIsCaptured):
+ (CodeBlock):
+ * dfg/DFGAbstractState.cpp:
+ (DFG):
+ (JSC::DFG::AbstractState::beginBasicBlock):
+ (JSC::DFG::AbstractState::initialize):
+ (JSC::DFG::AbstractState::endBasicBlock):
+ (JSC::DFG::AbstractState::execute):
+ (JSC::DFG::AbstractState::clobberWorld):
+ (JSC::DFG::AbstractState::clobberStructures):
+ (JSC::DFG::AbstractState::mergeStateAtTail):
+ (JSC::DFG::AbstractState::merge):
+ (JSC::DFG::AbstractState::mergeToSuccessors):
+ * dfg/DFGAbstractState.h:
+ (JSC::DFG::AbstractState::variables):
+ (AbstractState):
+ * dfg/DFGSpeculativeJIT32_64.cpp:
+ (JSC::DFG::SpeculativeJIT::compile):
+ * dfg/DFGSpeculativeJIT64.cpp:
+ (JSC::DFG::SpeculativeJIT::compile):
+
+2012-05-30 Patrick Gansterer <paroga@webkit.org>
+
+ Unreviewed. Build fix for !ENABLE(JIT) after r117823.
+
+ * bytecode/CodeBlock.cpp:
+ (JSC::CodeBlock::dump):
+
+2012-05-30 Sheriff Bot <webkit.review.bot@gmail.com>
+
+ Unreviewed, rolling out r118868.
+ http://trac.webkit.org/changeset/118868
+ https://bugs.webkit.org/show_bug.cgi?id=87828
+
+ introduced ~20 crashes on Mac and Qt bots (Requested by pizlo_
+ on #webkit).
+
+ * heap/Heap.cpp:
+ (JSC::Heap::collect):
+ * heap/MarkedBlock.cpp:
+ (JSC::MarkedBlock::sweep):
+ * heap/MarkedBlock.h:
+ (JSC::MarkedBlock::sweepWeakSet):
+ (JSC):
+ * heap/MarkedSpace.cpp:
+ (JSC::SweepWeakSet::operator()):
+ (JSC):
+ (JSC::MarkedSpace::sweepWeakSets):
+ * heap/MarkedSpace.h:
+ (MarkedSpace):
+
+2012-05-29 Geoffrey Garen <ggaren@apple.com>
+
+ Rolled back in r118646, now that
+ https://bugs.webkit.org/show_bug.cgi?id=87784 is fixed.
+
+ http://trac.webkit.org/changeset/118646
+ https://bugs.webkit.org/show_bug.cgi?id=87599
+
+ * heap/Heap.cpp:
+ (JSC::Heap::collect):
+ * heap/MarkedBlock.cpp:
+ (JSC::MarkedBlock::sweep):
+ * heap/MarkedBlock.h:
+ (JSC):
+ * heap/MarkedSpace.cpp:
+ (JSC):
+ * heap/MarkedSpace.h:
+ (MarkedSpace):
+
+2012-05-29 Filip Pizlo <fpizlo@apple.com>
+
+ DFG should keep captured variables alive until the (inline) return.
+ https://bugs.webkit.org/show_bug.cgi?id=87205
+
+ Reviewed by Gavin Barraclough.
+
+ Changes the way we do flushing for captured variables and arguments. Instead of flushing
+ each SetLocal immediately, we flush at kill points. So a SetLocal will cause a Flush of
+ whatever was live in the variable previously, and a return will cause a Flush of all
+ captured variables and all arguments.
+
+ * dfg/DFGByteCodeParser.cpp:
+ (JSC::DFG::ByteCodeParser::setDirect):
+ (JSC::DFG::ByteCodeParser::set):
+ (JSC::DFG::ByteCodeParser::setLocal):
+ (JSC::DFG::ByteCodeParser::getArgument):
+ (JSC::DFG::ByteCodeParser::setArgument):
+ (JSC::DFG::ByteCodeParser::findArgumentPositionForArgument):
+ (ByteCodeParser):
+ (JSC::DFG::ByteCodeParser::findArgumentPositionForLocal):
+ (JSC::DFG::ByteCodeParser::findArgumentPosition):
+ (JSC::DFG::ByteCodeParser::flush):
+ (JSC::DFG::ByteCodeParser::flushDirect):
+ (JSC::DFG::ByteCodeParser::flushArgumentsAndCapturedVariables):
+ (JSC::DFG::ByteCodeParser::handleInlining):
+ (JSC::DFG::ByteCodeParser::parseBlock):
+ (JSC::DFG::ByteCodeParser::InlineStackEntry::InlineStackEntry):
+ * dfg/DFGCSEPhase.cpp:
+ (JSC::DFG::CSEPhase::setLocalStoreElimination):
+ (JSC::DFG::CSEPhase::performNodeCSE):
+ * dfg/DFGSpeculativeJIT.cpp:
+ (JSC::DFG::SpeculativeJIT::compile):
+ * dfg/DFGSpeculativeJIT.h:
+ (JSC::DFG::SpeculativeJIT::forwardSpeculationCheck):
+
+2012-05-29 Geoffrey Garen <ggaren@apple.com>
+
+ WeakGCMap should be lazy-finalization-safe
+ https://bugs.webkit.org/show_bug.cgi?id=87784
+
+ Reviewed by Darin Adler.
+
+ * runtime/WeakGCMap.h:
+ (JSC::WeakGCMap::get): Since this is a map of raw WeakImpl pointers, and
+ not Weak<T>, we need to verify manually that the WeakImpl is live before
+ we return its payload.
+
+2012-05-29 Mark Hahnenberg <mhahnenberg@apple.com>
+
+ CopiedSpace::doneCopying could start another collection
+ https://bugs.webkit.org/show_bug.cgi?id=86538
+
+ Reviewed by Geoffrey Garen.
+
+ It's possible that if we don't have anything at the head of to-space
+ after a collection and the BlockAllocator doesn't have any fresh blocks
+ to give us right now we could start another collection while still in
+ the middle of the first collection when we call CopiedSpace::addNewBlock().
+
+ One way to resolve this would be to have Heap::shouldCollect() check that
+ m_operationInProgress is NoOperation. This would prevent the path in
+ getFreshBlock() that starts the collection if we're already in the middle of one.
+
+ I could not come up with a test case to reproduce this crash on ToT.
+
+ * heap/Heap.h:
+ (JSC::Heap::shouldCollect): We shouldn't collect if we're already in the middle
+ of a collection, i.e. the current operation should be NoOperation.
+
+2012-05-29 David Barr <davidbarr@chromium.org>
+
+ Introduce ENABLE_CSS_IMAGE_RESOLUTION compile flag
+ https://bugs.webkit.org/show_bug.cgi?id=87685
+
+ Reviewed by Eric Seidel.
+
+ Add a configuration option for CSS image-resolution support, disabling it by default.
+
+ * Configurations/FeatureDefines.xcconfig:
+
+2012-05-28 Sheriff Bot <webkit.review.bot@gmail.com>
+
+ Unreviewed, rolling out r118646.
+ http://trac.webkit.org/changeset/118646
+ https://bugs.webkit.org/show_bug.cgi?id=87691
+
+ broke V8 raytrace benchmark (Requested by pizlo_ on #webkit).
+
+ * heap/Heap.cpp:
+ (JSC::Heap::collect):
+ * heap/MarkedBlock.cpp:
+ (JSC::MarkedBlock::sweep):
+ * heap/MarkedBlock.h:
+ (JSC::MarkedBlock::sweepWeakSet):
+ (JSC):
+ * heap/MarkedSpace.cpp:
+ (JSC::SweepWeakSet::operator()):
+ (JSC):
+ (JSC::MarkedSpace::sweepWeakSets):
+ * heap/MarkedSpace.h:
+ (MarkedSpace):
+
+2012-05-28 Filip Pizlo <fpizlo@apple.com>
+
+ DFG should not generate code for code that the CFA proves to be unreachable
+ https://bugs.webkit.org/show_bug.cgi?id=87682
+
+ Reviewed by Sam Weinig.
+
+ This also fixes a small performance bug where CFA was not marking blocks
+ as having constants (and hence not triggering constant folding) if the only
+ constants were on GetLocals.
+
+ And fixing that bug revealed another bug: constant folding was assuming that
+ a GetLocal must be the first access to a local in a basic block. This isn't
+ true. The first access may be a Flush. This patch fixes that issue using the
+ safest approach possible, since we don't need to be clever for something that
+ only happens in one of our benchmarks.
+
+ * dfg/DFGAbstractState.cpp:
+ (JSC::DFG::AbstractState::execute):
+ * dfg/DFGConstantFoldingPhase.cpp:
+ (JSC::DFG::ConstantFoldingPhase::run):
+ * dfg/DFGJITCompiler.h:
+ (JSC::DFG::JITCompiler::noticeOSREntry):
+ * dfg/DFGSpeculativeJIT.cpp:
+ (JSC::DFG::SpeculativeJIT::compile):
+
+2012-05-28 Carlos Garcia Campos <cgarcia@igalia.com>
+
+ Unreviewed. Fix make distcheck.
+
+ * GNUmakefile.list.am: Add missing header file.
+
+2012-05-27 Geoffrey Garen <ggaren@apple.com>
+
+ Weak pointer finalization should be lazy
+ https://bugs.webkit.org/show_bug.cgi?id=87599
+
+ Reviewed by Darin Adler.
+
+ * heap/Heap.cpp:
+ (JSC::Heap::collect): Don't force immediate finalization -- it will
+ happen lazily.
+
+ * heap/MarkedBlock.cpp:
+ (JSC::MarkedBlock::sweep): Sweep a block's weak set when sweeping the
+ block. The weak set may not have been swept yet, and this is our last
+ chance to run weak finalizers before we recycle the memory they reference.
+
+ * heap/MarkedBlock.h:
+ * heap/MarkedSpace.cpp:
+ (JSC::MarkedBlock::sweepWeakSets):
+ * heap/MarkedSpace.h:
+ (JSC::MarkedSpace::sweepWeakSets): Nixed sweepWeakSets because it's unused
+ now.
+
2012-05-26 Geoffrey Garen <ggaren@apple.com>
WebKit should be lazy-finalization-safe (esp. the DOM) v2
diff --git a/Source/JavaScriptCore/Configurations/FeatureDefines.xcconfig b/Source/JavaScriptCore/Configurations/FeatureDefines.xcconfig
index fc1a6952f..76440b0a6 100644
--- a/Source/JavaScriptCore/Configurations/FeatureDefines.xcconfig
+++ b/Source/JavaScriptCore/Configurations/FeatureDefines.xcconfig
@@ -39,6 +39,7 @@ ENABLE_CHANNEL_MESSAGING = ENABLE_CHANNEL_MESSAGING;
ENABLE_CSS3_FLEXBOX = ENABLE_CSS3_FLEXBOX;
ENABLE_CSS_EXCLUSIONS = ENABLE_CSS_EXCLUSIONS;
ENABLE_CSS_FILTERS = ENABLE_CSS_FILTERS;
+ENABLE_CSS_IMAGE_RESOLUTION = ;
ENABLE_CSS_REGIONS = ENABLE_CSS_REGIONS;
ENABLE_CSS_VARIABLES = ;
ENABLE_DASHBOARD_SUPPORT = $(ENABLE_DASHBOARD_SUPPORT_$(REAL_PLATFORM_NAME));
@@ -126,4 +127,4 @@ ENABLE_WEB_TIMING = ;
ENABLE_WORKERS = ENABLE_WORKERS;
ENABLE_XSLT = ENABLE_XSLT;
-FEATURE_DEFINES = $(ENABLE_3D_RENDERING) $(ENABLE_ACCELERATED_2D_CANVAS) $(ENABLE_ANIMATION_API) $(ENABLE_BLOB) $(ENABLE_CHANNEL_MESSAGING) $(ENABLE_CSS3_FLEXBOX) $(ENABLE_CSS_EXCLUSIONS) $(ENABLE_CSS_FILTERS) $(ENABLE_CSS_REGIONS) $(ENABLE_CSS_SHADERS) $(ENABLE_CSS_VARIABLES) $(ENABLE_DASHBOARD_SUPPORT) $(ENABLE_DATALIST) $(ENABLE_DATA_TRANSFER_ITEMS) $(ENABLE_DETAILS) $(ENABLE_DEVICE_ORIENTATION) $(ENABLE_DIRECTORY_UPLOAD) $(ENABLE_FILE_SYSTEM) $(ENABLE_FILTERS) $(ENABLE_FONT_BOOSTING) $(ENABLE_FULLSCREEN_API) $(ENABLE_GAMEPAD) $(ENABLE_GEOLOCATION) $(ENABLE_HIGH_DPI_CANVAS) $(ENABLE_ICONDATABASE) $(ENABLE_IFRAME_SEAMLESS) $(ENABLE_INDEXED_DATABASE) $(ENABLE_INPUT_TYPE_COLOR) $(ENABLE_INPUT_SPEECH) $(ENABLE_INPUT_TYPE_DATE) $(ENABLE_INPUT_TYPE_DATETIME) $(ENABLE_INPUT_TYPE_DATETIMELOCAL) $(ENABLE_INPUT_TYPE_MONTH) $(ENABLE_INPUT_TYPE_TIME) $(ENABLE_INPUT_TYPE_WEEK) $(ENABLE_JAVASCRIPT_DEBUGGER) $(ENABLE_LEGACY_NOTIFICATIONS) $(ENABLE_LINK_PREFETCH) $(ENABLE_LINK_PRERENDER) $(ENABLE_MATHML) $(ENABLE_MEDIA_SOURCE) $(ENABLE_MEDIA_STATISTICS) $(ENABLE_METER_TAG) $(ENABLE_MICRODATA) $(ENABLE_MUTATION_OBSERVERS) $(ENABLE_NOTIFICATIONS) $(ENABLE_PAGE_VISIBILITY_API) $(ENABLE_PROGRESS_TAG) $(ENABLE_QUOTA) $(ENABLE_REGISTER_PROTOCOL_HANDLER) $(ENABLE_REQUEST_ANIMATION_FRAME) $(ENABLE_SCRIPTED_SPEECH) $(ENABLE_SHADOW_DOM) $(ENABLE_SHARED_WORKERS) $(ENABLE_SQL_DATABASE) $(ENABLE_STYLE_SCOPED) $(ENABLE_SVG) $(ENABLE_SVG_DOM_OBJC_BINDINGS) $(ENABLE_SVG_FONTS) $(ENABLE_TEXT_NOTIFICATIONS_ONLY) $(ENABLE_TOUCH_ICON_LOADING) $(ENABLE_VIDEO) $(ENABLE_VIDEO_TRACK) $(ENABLE_WEBGL) $(ENABLE_WEB_AUDIO) $(ENABLE_WEB_SOCKETS) $(ENABLE_WEB_TIMING) $(ENABLE_WORKERS) $(ENABLE_XSLT);
+FEATURE_DEFINES = $(ENABLE_3D_RENDERING) $(ENABLE_ACCELERATED_2D_CANVAS) $(ENABLE_ANIMATION_API) $(ENABLE_BLOB) $(ENABLE_CHANNEL_MESSAGING) $(ENABLE_CSS3_FLEXBOX) $(ENABLE_CSS_EXCLUSIONS) $(ENABLE_CSS_FILTERS) $(ENABLE_CSS_IMAGE_RESOLUTION) $(ENABLE_CSS_REGIONS) $(ENABLE_CSS_SHADERS) $(ENABLE_CSS_VARIABLES) $(ENABLE_DASHBOARD_SUPPORT) $(ENABLE_DATALIST) $(ENABLE_DATA_TRANSFER_ITEMS) $(ENABLE_DETAILS) $(ENABLE_DEVICE_ORIENTATION) $(ENABLE_DIRECTORY_UPLOAD) $(ENABLE_FILE_SYSTEM) $(ENABLE_FILTERS) $(ENABLE_FONT_BOOSTING) $(ENABLE_FULLSCREEN_API) $(ENABLE_GAMEPAD) $(ENABLE_GEOLOCATION) $(ENABLE_HIGH_DPI_CANVAS) $(ENABLE_ICONDATABASE) $(ENABLE_IFRAME_SEAMLESS) $(ENABLE_INDEXED_DATABASE) $(ENABLE_INPUT_TYPE_COLOR) $(ENABLE_INPUT_SPEECH) $(ENABLE_INPUT_TYPE_DATE) $(ENABLE_INPUT_TYPE_DATETIME) $(ENABLE_INPUT_TYPE_DATETIMELOCAL) $(ENABLE_INPUT_TYPE_MONTH) $(ENABLE_INPUT_TYPE_TIME) $(ENABLE_INPUT_TYPE_WEEK) $(ENABLE_JAVASCRIPT_DEBUGGER) $(ENABLE_LEGACY_NOTIFICATIONS) $(ENABLE_LINK_PREFETCH) $(ENABLE_LINK_PRERENDER) $(ENABLE_MATHML) $(ENABLE_MEDIA_SOURCE) $(ENABLE_MEDIA_STATISTICS) $(ENABLE_METER_TAG) $(ENABLE_MICRODATA) $(ENABLE_MUTATION_OBSERVERS) $(ENABLE_NOTIFICATIONS) $(ENABLE_PAGE_VISIBILITY_API) $(ENABLE_PROGRESS_TAG) $(ENABLE_QUOTA) $(ENABLE_REGISTER_PROTOCOL_HANDLER) $(ENABLE_REQUEST_ANIMATION_FRAME) $(ENABLE_SCRIPTED_SPEECH) $(ENABLE_SHADOW_DOM) $(ENABLE_SHARED_WORKERS) $(ENABLE_SQL_DATABASE) $(ENABLE_STYLE_SCOPED) $(ENABLE_SVG) $(ENABLE_SVG_DOM_OBJC_BINDINGS) $(ENABLE_SVG_FONTS) $(ENABLE_TEXT_NOTIFICATIONS_ONLY) $(ENABLE_TOUCH_ICON_LOADING) $(ENABLE_VIDEO) $(ENABLE_VIDEO_TRACK) $(ENABLE_WEBGL) $(ENABLE_WEB_AUDIO) $(ENABLE_WEB_SOCKETS) $(ENABLE_WEB_TIMING) $(ENABLE_WORKERS) $(ENABLE_XSLT);
diff --git a/Source/JavaScriptCore/GNUmakefile.list.am b/Source/JavaScriptCore/GNUmakefile.list.am
index a25aa698d..efd4b5fd8 100644
--- a/Source/JavaScriptCore/GNUmakefile.list.am
+++ b/Source/JavaScriptCore/GNUmakefile.list.am
@@ -232,6 +232,8 @@ javascriptcore_sources += \
Source/JavaScriptCore/heap/HandleSet.cpp \
Source/JavaScriptCore/heap/HandleSet.h \
Source/JavaScriptCore/heap/HeapBlock.h \
+ Source/JavaScriptCore/heap/IncrementalSweeper.h \
+ Source/JavaScriptCore/heap/IncrementalSweeper.cpp \
Source/JavaScriptCore/heap/SlotVisitor.h \
Source/JavaScriptCore/heap/HandleStack.cpp \
Source/JavaScriptCore/heap/HandleStack.h \
@@ -537,6 +539,7 @@ javascriptcore_sources += \
Source/JavaScriptCore/runtime/Operations.h \
Source/JavaScriptCore/runtime/Options.cpp \
Source/JavaScriptCore/runtime/Options.h \
+ Source/JavaScriptCore/runtime/PrivateName.h \
Source/JavaScriptCore/runtime/PropertyDescriptor.cpp \
Source/JavaScriptCore/runtime/PropertyDescriptor.h \
Source/JavaScriptCore/runtime/PropertyMapHashTable.h \
diff --git a/Source/JavaScriptCore/JavaScriptCore.gypi b/Source/JavaScriptCore/JavaScriptCore.gypi
index 1c3bb0a83..6f4598f41 100644
--- a/Source/JavaScriptCore/JavaScriptCore.gypi
+++ b/Source/JavaScriptCore/JavaScriptCore.gypi
@@ -134,6 +134,7 @@
'heap/Heap.h',
'heap/HeapBlock.h',
'heap/HeapRootVisitor.h',
+ 'heap/IncrementalSweeper.h',
'heap/ListableHandler.h',
'heap/Local.h',
'heap/LocalScope.h',
@@ -406,6 +407,7 @@
'heap/HandleStack.cpp',
'heap/BlockAllocator.cpp',
'heap/Heap.cpp',
+ 'heap/IncrementalSweeper.cpp',
'heap/MachineStackMarker.cpp',
'heap/MarkedAllocator.cpp',
'heap/MarkedBlock.cpp',
diff --git a/Source/JavaScriptCore/JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.vcproj b/Source/JavaScriptCore/JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.vcproj
index 254e2d070..21884df96 100644
--- a/Source/JavaScriptCore/JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.vcproj
+++ b/Source/JavaScriptCore/JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.vcproj
@@ -2158,6 +2158,14 @@
>
</File>
<File
+ RelativePath="..\..\heap\IncrementalSweeper.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\heap\IncrementalSweeper.cpp"
+ >
+ </File>
+ <File
RelativePath="..\..\heap\WeakBlock.cpp"
>
</File>
diff --git a/Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj b/Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj
index 360c96890..386fcd391 100644
--- a/Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj
+++ b/Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj
@@ -524,10 +524,10 @@
A7FB61001040C38B0017A286 /* PropertyDescriptor.h in Headers */ = {isa = PBXBuildFile; fileRef = A7FB604B103F5EAB0017A286 /* PropertyDescriptor.h */; settings = {ATTRIBUTES = (Private, ); }; };
A8A4748E151A8306004123FF /* libWTF.a in Frameworks */ = {isa = PBXBuildFile; fileRef = A8A4748D151A8306004123FF /* libWTF.a */; };
BC02E90D0E1839DB000F9297 /* ErrorConstructor.h in Headers */ = {isa = PBXBuildFile; fileRef = BC02E9050E1839DB000F9297 /* ErrorConstructor.h */; };
- BC02E90F0E1839DB000F9297 /* ErrorPrototype.h in Headers */ = {isa = PBXBuildFile; fileRef = BC02E9070E1839DB000F9297 /* ErrorPrototype.h */; };
+ BC02E90F0E1839DB000F9297 /* ErrorPrototype.h in Headers */ = {isa = PBXBuildFile; fileRef = BC02E9070E1839DB000F9297 /* ErrorPrototype.h */; settings = {ATTRIBUTES = (Private, ); }; };
BC02E9110E1839DB000F9297 /* NativeErrorConstructor.h in Headers */ = {isa = PBXBuildFile; fileRef = BC02E9090E1839DB000F9297 /* NativeErrorConstructor.h */; };
BC02E9130E1839DB000F9297 /* NativeErrorPrototype.h in Headers */ = {isa = PBXBuildFile; fileRef = BC02E90B0E1839DB000F9297 /* NativeErrorPrototype.h */; };
- BC02E98D0E183E38000F9297 /* ErrorInstance.h in Headers */ = {isa = PBXBuildFile; fileRef = BC02E98B0E183E38000F9297 /* ErrorInstance.h */; };
+ BC02E98D0E183E38000F9297 /* ErrorInstance.h in Headers */ = {isa = PBXBuildFile; fileRef = BC02E98B0E183E38000F9297 /* ErrorInstance.h */; settings = {ATTRIBUTES = (Private, ); }; };
BC1166020E1997B4008066DD /* DateInstance.h in Headers */ = {isa = PBXBuildFile; fileRef = BC1166010E1997B1008066DD /* DateInstance.h */; settings = {ATTRIBUTES = (Private, ); }; };
BC11667B0E199C05008066DD /* InternalFunction.h in Headers */ = {isa = PBXBuildFile; fileRef = BC11667A0E199C05008066DD /* InternalFunction.h */; settings = {ATTRIBUTES = (Private, ); }; };
BC1167DA0E19BCC9008066DD /* JSCell.h in Headers */ = {isa = PBXBuildFile; fileRef = BC1167D80E19BCC9008066DD /* JSCell.h */; settings = {ATTRIBUTES = (Private, ); }; };
@@ -637,6 +637,8 @@
BCFD8C930EEB2EE700283848 /* JumpTable.h in Headers */ = {isa = PBXBuildFile; fileRef = BCFD8C910EEB2EE700283848 /* JumpTable.h */; };
C22B31B9140577D700DB475A /* SamplingCounter.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F77008E1402FDD60078EB39 /* SamplingCounter.h */; settings = {ATTRIBUTES = (Private, ); }; };
C240305514B404E60079EB64 /* CopiedSpace.cpp in Sources */ = {isa = PBXBuildFile; fileRef = C240305314B404C90079EB64 /* CopiedSpace.cpp */; };
+ C25F8BCD157544A900245B71 /* IncrementalSweeper.cpp in Sources */ = {isa = PBXBuildFile; fileRef = C25F8BCB157544A900245B71 /* IncrementalSweeper.cpp */; };
+ C25F8BCE157544A900245B71 /* IncrementalSweeper.h in Headers */ = {isa = PBXBuildFile; fileRef = C25F8BCC157544A900245B71 /* IncrementalSweeper.h */; settings = {ATTRIBUTES = (Private, ); }; };
C2B916C214DA014E00CBAC86 /* MarkedAllocator.h in Headers */ = {isa = PBXBuildFile; fileRef = C2B916C114DA014E00CBAC86 /* MarkedAllocator.h */; settings = {ATTRIBUTES = (Private, ); }; };
C2B916C514DA040C00CBAC86 /* MarkedAllocator.cpp in Sources */ = {isa = PBXBuildFile; fileRef = C2B916C414DA040C00CBAC86 /* MarkedAllocator.cpp */; };
C2C8D02D14A3C6E000578E65 /* CopiedSpaceInlineMethods.h in Headers */ = {isa = PBXBuildFile; fileRef = C2C8D02B14A3C6B200578E65 /* CopiedSpaceInlineMethods.h */; settings = {ATTRIBUTES = (Private, ); }; };
@@ -1331,6 +1333,8 @@
BCFD8C900EEB2EE700283848 /* JumpTable.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JumpTable.cpp; sourceTree = "<group>"; };
BCFD8C910EEB2EE700283848 /* JumpTable.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JumpTable.h; sourceTree = "<group>"; };
C240305314B404C90079EB64 /* CopiedSpace.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = CopiedSpace.cpp; sourceTree = "<group>"; };
+ C25F8BCB157544A900245B71 /* IncrementalSweeper.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = IncrementalSweeper.cpp; sourceTree = "<group>"; };
+ C25F8BCC157544A900245B71 /* IncrementalSweeper.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IncrementalSweeper.h; sourceTree = "<group>"; };
C2B916C114DA014E00CBAC86 /* MarkedAllocator.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MarkedAllocator.h; sourceTree = "<group>"; };
C2B916C414DA040C00CBAC86 /* MarkedAllocator.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = MarkedAllocator.cpp; sourceTree = "<group>"; };
C2C8D02B14A3C6B200578E65 /* CopiedSpaceInlineMethods.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CopiedSpaceInlineMethods.h; sourceTree = "<group>"; };
@@ -1609,6 +1613,8 @@
142E312A134FF0A600AFADB5 /* heap */ = {
isa = PBXGroup;
children = (
+ C25F8BCB157544A900245B71 /* IncrementalSweeper.cpp */,
+ C25F8BCC157544A900245B71 /* IncrementalSweeper.h */,
14816E19154CC56C00B8054C /* BlockAllocator.cpp */,
14816E1A154CC56C00B8054C /* BlockAllocator.h */,
A7521E121429169A003C8D0C /* CardSet.h */,
@@ -2310,6 +2316,7 @@
86ADD1450FDDEA980006EEC2 /* ARMv7Assembler.h in Headers */,
C2EAD2FC14F0249800A4B159 /* CopiedAllocator.h in Headers */,
C2B916C214DA014E00CBAC86 /* MarkedAllocator.h in Headers */,
+ C25F8BCE157544A900245B71 /* IncrementalSweeper.h in Headers */,
BC18C3E60E16F5CD00B34460 /* ArrayConstructor.h in Headers */,
BC18C3E70E16F5CD00B34460 /* ArrayPrototype.h in Headers */,
BC18C5240E16FC8A00B34460 /* ArrayPrototype.lut.h in Headers */,
@@ -3221,6 +3228,7 @@
0F3B3A2B15475000003ED0FF /* DFGValidate.cpp in Sources */,
0FD81AD2154FB4EE00983E72 /* DFGDominators.cpp in Sources */,
0F16015D156198C900C2587C /* DFGArgumentsSimplificationPhase.cpp in Sources */,
+ C25F8BCD157544A900245B71 /* IncrementalSweeper.cpp in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
diff --git a/Source/JavaScriptCore/Target.pri b/Source/JavaScriptCore/Target.pri
index 234078d31..ed682d94a 100644
--- a/Source/JavaScriptCore/Target.pri
+++ b/Source/JavaScriptCore/Target.pri
@@ -78,6 +78,7 @@ SOURCES += \
heap/HandleStack.cpp \
heap/BlockAllocator.cpp \
heap/Heap.cpp \
+ heap/IncrementalSweeper.cpp \
heap/MachineStackMarker.cpp \
heap/MarkStack.cpp \
heap/MarkedAllocator.cpp \
diff --git a/Source/JavaScriptCore/bytecode/CodeBlock.cpp b/Source/JavaScriptCore/bytecode/CodeBlock.cpp
index e3ee2ed41..8ef716028 100644
--- a/Source/JavaScriptCore/bytecode/CodeBlock.cpp
+++ b/Source/JavaScriptCore/bytecode/CodeBlock.cpp
@@ -1021,6 +1021,7 @@ void CodeBlock::dump(ExecState* exec, const Vector<Instruction>::const_iterator&
}
case op_method_check: {
dataLog("[%4d] method_check", location);
+#if ENABLE(JIT)
if (numberOfMethodCallLinkInfos()) {
MethodCallLinkInfo& methodCall = getMethodCallLinkInfo(location);
dataLog(" jit(");
@@ -1046,6 +1047,7 @@ void CodeBlock::dump(ExecState* exec, const Vector<Instruction>::const_iterator&
}
dataLog(")");
}
+#endif
dataLog("\n");
++it;
printGetByIdOp(exec, location, it);
diff --git a/Source/JavaScriptCore/bytecode/CodeBlock.h b/Source/JavaScriptCore/bytecode/CodeBlock.h
index ccaca3373..cdc6a19e8 100644
--- a/Source/JavaScriptCore/bytecode/CodeBlock.h
+++ b/Source/JavaScriptCore/bytecode/CodeBlock.h
@@ -462,11 +462,16 @@ namespace JSC {
return needsFullScopeChain() && codeType() != GlobalCode;
}
- bool argumentIsCaptured(int) const
+ bool argumentsAreCaptured() const
{
return needsActivation() || usesArguments();
}
+ bool argumentIsCaptured(int) const
+ {
+ return argumentsAreCaptured();
+ }
+
bool localIsCaptured(InlineCallFrame* inlineCallFrame, int operand) const
{
if (!inlineCallFrame)
diff --git a/Source/JavaScriptCore/dfg/DFGAbstractState.cpp b/Source/JavaScriptCore/dfg/DFGAbstractState.cpp
index ff737cf1d..a0849acea 100644
--- a/Source/JavaScriptCore/dfg/DFGAbstractState.cpp
+++ b/Source/JavaScriptCore/dfg/DFGAbstractState.cpp
@@ -33,21 +33,6 @@
namespace JSC { namespace DFG {
-#define CFA_PROFILING 0
-
-#if CFA_PROFILING
-#define PROFILE(flag) SamplingFlags::ScopedFlag scopedFlag(flag)
-#else
-#define PROFILE(flag) do { } while (false)
-#endif
-
-// Profiling flags
-#define FLAG_FOR_BLOCK_INITIALIZATION 17
-#define FLAG_FOR_BLOCK_END 18
-#define FLAG_FOR_EXECUTION 19
-#define FLAG_FOR_MERGE_TO_SUCCESSORS 20
-#define FLAG_FOR_STRUCTURE_CLOBBERING 21
-
AbstractState::AbstractState(Graph& graph)
: m_codeBlock(graph.m_codeBlock)
, m_graph(graph)
@@ -61,8 +46,6 @@ AbstractState::~AbstractState() { }
void AbstractState::beginBasicBlock(BasicBlock* basicBlock)
{
- PROFILE(FLAG_FOR_BLOCK_INITIALIZATION);
-
ASSERT(!m_block);
ASSERT(basicBlock->variablesAtHead.numberOfLocals() == basicBlock->valuesAtHead.numberOfLocals());
@@ -97,7 +80,6 @@ void AbstractState::beginBasicBlock(BasicBlock* basicBlock)
void AbstractState::initialize(Graph& graph)
{
- PROFILE(FLAG_FOR_BLOCK_INITIALIZATION);
BasicBlock* root = graph.m_blocks[0].get();
root->cfaShouldRevisit = true;
root->cfaHasVisited = false;
@@ -177,7 +159,6 @@ void AbstractState::initialize(Graph& graph)
bool AbstractState::endBasicBlock(MergeMode mergeMode, BranchDirection* branchDirectionPtr)
{
- PROFILE(FLAG_FOR_BLOCK_END);
ASSERT(m_block);
BasicBlock* block = m_block; // Save the block for successor merging.
@@ -197,14 +178,7 @@ bool AbstractState::endBasicBlock(MergeMode mergeMode, BranchDirection* branchDi
dataLog(" Merging state for argument %zu.\n", argument);
#endif
AbstractValue& destination = block->valuesAtTail.argument(argument);
- NodeIndex nodeIndex = block->variablesAtTail.argument(argument);
- if (nodeIndex != NoNode && m_graph[nodeIndex].variableAccessData()->isCaptured()) {
- if (!destination.isTop()) {
- destination.makeTop();
- changed = true;
- }
- } else
- changed |= mergeStateAtTail(destination, m_variables.argument(argument), block->variablesAtTail.argument(argument));
+ changed |= mergeStateAtTail(destination, m_variables.argument(argument), block->variablesAtTail.argument(argument));
}
for (size_t local = 0; local < block->variablesAtTail.numberOfLocals(); ++local) {
@@ -212,14 +186,7 @@ bool AbstractState::endBasicBlock(MergeMode mergeMode, BranchDirection* branchDi
dataLog(" Merging state for local %zu.\n", local);
#endif
AbstractValue& destination = block->valuesAtTail.local(local);
- NodeIndex nodeIndex = block->variablesAtTail.local(local);
- if (nodeIndex != NoNode && m_graph[nodeIndex].variableAccessData()->isCaptured()) {
- if (!destination.isTop()) {
- destination.makeTop();
- changed = true;
- }
- } else
- changed |= mergeStateAtTail(destination, m_variables.local(local), block->variablesAtTail.local(local));
+ changed |= mergeStateAtTail(destination, m_variables.local(local), block->variablesAtTail.local(local));
}
}
@@ -250,7 +217,6 @@ void AbstractState::reset()
bool AbstractState::execute(unsigned indexInBlock)
{
- PROFILE(FLAG_FOR_EXECUTION);
ASSERT(m_block);
ASSERT(m_isValid);
@@ -274,11 +240,13 @@ bool AbstractState::execute(unsigned indexInBlock)
bool canExit = false;
canExit |= variableAccessData->prediction() == PredictNone;
if (variableAccessData->isCaptured())
- forNode(nodeIndex).makeTop();
+ forNode(nodeIndex) = m_variables.operand(variableAccessData->local());
else {
AbstractValue value = m_variables.operand(variableAccessData->local());
if (value.isClear())
canExit |= true;
+ if (value.value())
+ m_foundConstants = true;
forNode(nodeIndex) = value;
}
node.setCanExit(canExit);
@@ -286,13 +254,14 @@ bool AbstractState::execute(unsigned indexInBlock)
}
case GetLocalUnlinked: {
- forNode(nodeIndex).makeTop();
+ forNode(nodeIndex) = m_variables.operand(node.unlinkedLocal());
node.setCanExit(false);
break;
}
case SetLocal: {
if (node.variableAccessData()->isCaptured()) {
+ m_variables.operand(node.local()) = forNode(node.child1());
node.setCanExit(false);
break;
}
@@ -466,7 +435,7 @@ bool AbstractState::execute(unsigned indexInBlock)
break;
}
if (node.op() == ValueAdd) {
- clobberStructures(indexInBlock);
+ clobberWorld(node.codeOrigin, indexInBlock);
forNode(nodeIndex).set(PredictString | PredictInt32 | PredictNumber);
node.setCanExit(false);
break;
@@ -772,12 +741,12 @@ bool AbstractState::execute(unsigned indexInBlock)
} else {
filter = PredictTop;
checker = isAnyPrediction;
- clobberStructures(indexInBlock);
+ clobberWorld(node.codeOrigin, indexInBlock);
}
} else {
filter = PredictTop;
checker = isAnyPrediction;
- clobberStructures(indexInBlock);
+ clobberWorld(node.codeOrigin, indexInBlock);
}
node.setCanExit(
!checker(forNode(node.child1()).m_type)
@@ -864,7 +833,7 @@ bool AbstractState::execute(unsigned indexInBlock)
break;
}
if (!isActionableArrayPrediction(m_graph[node.child1()].prediction()) || !m_graph[node.child2()].shouldSpeculateInteger()) {
- clobberStructures(indexInBlock);
+ clobberWorld(node.codeOrigin, indexInBlock);
forNode(nodeIndex).makeTop();
break;
}
@@ -958,7 +927,7 @@ bool AbstractState::execute(unsigned indexInBlock)
#endif
) {
ASSERT(node.op() == PutByVal);
- clobberStructures(indexInBlock);
+ clobberWorld(node.codeOrigin, indexInBlock);
forNode(nodeIndex).makeTop();
break;
}
@@ -1241,7 +1210,10 @@ bool AbstractState::execute(unsigned indexInBlock)
break;
case CheckArgumentsNotCreated:
- node.setCanExit(true);
+ node.setCanExit(
+ !isEmptyPrediction(
+ m_variables.operand(
+ m_graph.argumentsRegisterFor(node.codeOrigin)).m_type));
break;
case GetMyArgumentsLength:
@@ -1249,20 +1221,21 @@ bool AbstractState::execute(unsigned indexInBlock)
// the arguments a bit. Note that this is not sufficient to force constant folding
// of GetMyArgumentsLength, because GetMyArgumentsLength is a clobbering operation.
// We perform further optimizations on this later on.
- if (node.codeOrigin.inlineCallFrame) {
+ if (node.codeOrigin.inlineCallFrame)
forNode(nodeIndex).set(jsNumber(node.codeOrigin.inlineCallFrame->arguments.size() - 1));
- node.setCanExit(false);
- break;
- }
- node.setCanExit(true);
- forNode(nodeIndex).set(PredictInt32);
+ else
+ forNode(nodeIndex).set(PredictInt32);
+ node.setCanExit(
+ !isEmptyPrediction(
+ m_variables.operand(
+ m_graph.argumentsRegisterFor(node.codeOrigin)).m_type));
break;
case GetMyArgumentsLengthSafe:
node.setCanExit(false);
// This potentially clobbers all structures if the arguments object had a getter
// installed on the length property.
- clobberStructures(indexInBlock);
+ clobberWorld(node.codeOrigin, indexInBlock);
// We currently make no guarantee about what this returns because it does not
// speculate that the length property is actually a length.
forNode(nodeIndex).makeTop();
@@ -1278,10 +1251,10 @@ bool AbstractState::execute(unsigned indexInBlock)
break;
case GetMyArgumentByValSafe:
- node.setCanExit(false);
+ node.setCanExit(true);
// This potentially clobbers all structures if the property we're accessing has
// a getter. We don't speculate against this.
- clobberStructures(indexInBlock);
+ clobberWorld(node.codeOrigin, indexInBlock);
// But we do speculate that the index is an integer.
forNode(node.child1()).filter(PredictInt32);
// And the result is unknown.
@@ -1324,7 +1297,7 @@ bool AbstractState::execute(unsigned indexInBlock)
}
if (isCellPrediction(m_graph[node.child1()].prediction()))
forNode(node.child1()).filter(PredictCell);
- clobberStructures(indexInBlock);
+ clobberWorld(node.codeOrigin, indexInBlock);
forNode(nodeIndex).makeTop();
break;
@@ -1502,7 +1475,7 @@ bool AbstractState::execute(unsigned indexInBlock)
case PutByIdDirect:
node.setCanExit(true);
forNode(node.child1()).filter(PredictCell);
- clobberStructures(indexInBlock);
+ clobberWorld(node.codeOrigin, indexInBlock);
break;
case GetGlobalVar:
@@ -1545,7 +1518,7 @@ bool AbstractState::execute(unsigned indexInBlock)
case ResolveBaseStrictPut:
case ResolveGlobal:
node.setCanExit(true);
- clobberStructures(indexInBlock);
+ clobberWorld(node.codeOrigin, indexInBlock);
forNode(nodeIndex).makeTop();
break;
@@ -1568,16 +1541,35 @@ bool AbstractState::execute(unsigned indexInBlock)
return m_isValid;
}
+inline void AbstractState::clobberWorld(const CodeOrigin& codeOrigin, unsigned indexInBlock)
+{
+ if (codeOrigin.inlineCallFrame) {
+ const BitVector& capturedVars = codeOrigin.inlineCallFrame->capturedVars;
+ for (size_t i = capturedVars.size(); i--;) {
+ if (!capturedVars.quickGet(i))
+ continue;
+ m_variables.local(i).makeTop();
+ }
+ } else {
+ for (size_t i = m_codeBlock->m_numCapturedVars; i--;)
+ m_variables.local(i).makeTop();
+ }
+ if (m_codeBlock->argumentsAreCaptured()) {
+ for (size_t i = m_variables.numberOfArguments(); i--;)
+ m_variables.argument(i).makeTop();
+ }
+ clobberStructures(indexInBlock);
+}
+
inline void AbstractState::clobberStructures(unsigned indexInBlock)
{
- PROFILE(FLAG_FOR_STRUCTURE_CLOBBERING);
if (!m_haveStructures)
return;
for (size_t i = indexInBlock + 1; i--;)
forNode(m_block->at(i)).clobberStructures();
- for (size_t i = 0; i < m_variables.numberOfArguments(); ++i)
+ for (size_t i = m_variables.numberOfArguments(); i--;)
m_variables.argument(i).clobberStructures();
- for (size_t i = 0; i < m_variables.numberOfLocals(); ++i)
+ for (size_t i = m_variables.numberOfLocals(); i--;)
m_variables.local(i).clobberStructures();
m_haveStructures = false;
}
@@ -1597,46 +1589,56 @@ inline bool AbstractState::mergeStateAtTail(AbstractValue& destination, Abstract
dataLog(" It's live, node @%u.\n", nodeIndex);
#endif
- switch (node.op()) {
- case Phi:
- case SetArgument:
- case Flush:
- // The block transfers the value from head to tail.
+ if (node.variableAccessData()->isCaptured()) {
source = inVariable;
#if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE)
dataLog(" Transfering ");
source.dump(WTF::dataFile());
- dataLog(" from head to tail.\n");
+ dataLog(" from last access due to captured variable.\n");
#endif
- break;
+ } else {
+ switch (node.op()) {
+ case Phi:
+ case SetArgument:
+ case Flush:
+ // The block transfers the value from head to tail.
+ source = inVariable;
+#if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE)
+ dataLog(" Transfering ");
+ source.dump(WTF::dataFile());
+ dataLog(" from head to tail.\n");
+#endif
+ break;
- case GetLocal:
- // The block refines the value with additional speculations.
- source = forNode(nodeIndex);
+ case GetLocal:
+ // The block refines the value with additional speculations.
+ source = forNode(nodeIndex);
#if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE)
- dataLog(" Refining to ");
- source.dump(WTF::dataFile());
- dataLog("\n");
+ dataLog(" Refining to ");
+ source.dump(WTF::dataFile());
+ dataLog("\n");
#endif
- break;
+ break;
- case SetLocal:
- // The block sets the variable, and potentially refines it, both
- // before and after setting it.
- if (node.variableAccessData()->shouldUseDoubleFormat())
- source.set(PredictDouble);
- else
- source = forNode(node.child1());
+ case SetLocal:
+ // The block sets the variable, and potentially refines it, both
+ // before and after setting it.
+ if (node.variableAccessData()->shouldUseDoubleFormat()) {
+ // FIXME: This unnecessarily loses precision.
+ source.set(PredictDouble);
+ } else
+ source = forNode(node.child1());
#if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE)
- dataLog(" Setting to ");
- source.dump(WTF::dataFile());
- dataLog("\n");
+ dataLog(" Setting to ");
+ source.dump(WTF::dataFile());
+ dataLog("\n");
#endif
- break;
+ break;
- default:
- ASSERT_NOT_REACHED();
- break;
+ default:
+ ASSERT_NOT_REACHED();
+ break;
+ }
}
if (destination == source) {
@@ -1667,27 +1669,11 @@ inline bool AbstractState::merge(BasicBlock* from, BasicBlock* to)
for (size_t argument = 0; argument < from->variablesAtTail.numberOfArguments(); ++argument) {
AbstractValue& destination = to->valuesAtHead.argument(argument);
- NodeIndex nodeIndex = from->variablesAtTail.argument(argument);
- if (nodeIndex != NoNode && m_graph[nodeIndex].variableAccessData()->isCaptured()) {
- if (destination.isTop())
- continue;
- destination.makeTop();
- changed = true;
- continue;
- }
changed |= mergeVariableBetweenBlocks(destination, from->valuesAtTail.argument(argument), to->variablesAtHead.argument(argument), from->variablesAtTail.argument(argument));
}
for (size_t local = 0; local < from->variablesAtTail.numberOfLocals(); ++local) {
AbstractValue& destination = to->valuesAtHead.local(local);
- NodeIndex nodeIndex = from->variablesAtTail.local(local);
- if (nodeIndex != NoNode && m_graph[nodeIndex].variableAccessData()->isCaptured()) {
- if (destination.isTop())
- continue;
- destination.makeTop();
- changed = true;
- continue;
- }
changed |= mergeVariableBetweenBlocks(destination, from->valuesAtTail.local(local), to->variablesAtHead.local(local), from->variablesAtTail.local(local));
}
@@ -1702,8 +1688,6 @@ inline bool AbstractState::merge(BasicBlock* from, BasicBlock* to)
inline bool AbstractState::mergeToSuccessors(
Graph& graph, BasicBlock* basicBlock, BranchDirection branchDirection)
{
- PROFILE(FLAG_FOR_MERGE_TO_SUCCESSORS);
-
Node& terminal = graph[basicBlock->last()];
ASSERT(terminal.isTerminal());
diff --git a/Source/JavaScriptCore/dfg/DFGAbstractState.h b/Source/JavaScriptCore/dfg/DFGAbstractState.h
index 4ce3df19b..4b0a248f3 100644
--- a/Source/JavaScriptCore/dfg/DFGAbstractState.h
+++ b/Source/JavaScriptCore/dfg/DFGAbstractState.h
@@ -136,6 +136,11 @@ public:
return forNode(nodeUse.index());
}
+ Operands<AbstractValue>& variables()
+ {
+ return m_variables;
+ }
+
// Call this before beginning CFA to initialize the abstract values of
// arguments, and to indicate which blocks should be listed for CFA
// execution.
@@ -208,7 +213,8 @@ public:
void dump(FILE* out);
private:
- void clobberStructures(unsigned);
+ void clobberWorld(const CodeOrigin&, unsigned indexInBlock);
+ void clobberStructures(unsigned indexInBlock);
bool mergeStateAtTail(AbstractValue& destination, AbstractValue& inVariable, NodeIndex);
diff --git a/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp b/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp
index 43157963c..358171029 100644
--- a/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp
+++ b/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp
@@ -142,20 +142,21 @@ private:
{
return getDirect(m_inlineStackTop->remapOperand(operand));
}
- void setDirect(int operand, NodeIndex value)
+ enum SetMode { NormalSet, SetOnEntry };
+ void setDirect(int operand, NodeIndex value, SetMode setMode = NormalSet)
{
// Is this an argument?
if (operandIsArgument(operand)) {
- setArgument(operand, value);
+ setArgument(operand, value, setMode);
return;
}
// Must be a local.
- setLocal((unsigned)operand, value);
+ setLocal((unsigned)operand, value, setMode);
}
- void set(int operand, NodeIndex value)
+ void set(int operand, NodeIndex value, SetMode setMode = NormalSet)
{
- setDirect(m_inlineStackTop->remapOperand(operand), value);
+ setDirect(m_inlineStackTop->remapOperand(operand), value, setMode);
}
NodeIndex injectLazyOperandPrediction(NodeIndex nodeIndex)
@@ -236,37 +237,19 @@ private:
return nodeIndex;
}
- void setLocal(unsigned operand, NodeIndex value)
+ void setLocal(unsigned operand, NodeIndex value, SetMode setMode = NormalSet)
{
bool isCaptured = m_codeBlock->localIsCaptured(m_inlineStackTop->m_inlineCallFrame, operand);
+ if (setMode == NormalSet) {
+ ArgumentPosition* argumentPosition = findArgumentPositionForLocal(operand);
+ if (isCaptured || argumentPosition)
+ flushDirect(operand, argumentPosition);
+ }
+
VariableAccessData* variableAccessData = newVariableAccessData(operand, isCaptured);
NodeIndex nodeIndex = addToGraph(SetLocal, OpInfo(variableAccessData), value);
m_currentBlock->variablesAtTail.local(operand) = nodeIndex;
-
- bool shouldFlush = isCaptured;
-
- if (!shouldFlush) {
- // If this is in argument position, then it should be flushed.
- for (InlineStackEntry* stack = m_inlineStackTop; ; stack = stack->m_caller) {
- InlineCallFrame* inlineCallFrame = stack->m_inlineCallFrame;
- if (!inlineCallFrame)
- break;
- if (static_cast<int>(operand) >= inlineCallFrame->stackOffset - RegisterFile::CallFrameHeaderSize)
- continue;
- if (static_cast<int>(operand) == inlineCallFrame->stackOffset + CallFrame::thisArgumentOffset())
- continue;
- if (operand < inlineCallFrame->stackOffset - RegisterFile::CallFrameHeaderSize - inlineCallFrame->arguments.size())
- continue;
- int argument = operandToArgument(operand - inlineCallFrame->stackOffset);
- stack->m_argumentPositions[argument]->addVariable(variableAccessData);
- shouldFlush = true;
- break;
- }
- }
-
- if (shouldFlush)
- addToGraph(Flush, OpInfo(variableAccessData), nodeIndex);
}
// Used in implementing get/set, above, where the operand is an argument.
@@ -292,7 +275,7 @@ private:
VariableAccessData* variableAccessData = flushChild.variableAccessData();
variableAccessData->mergeIsCaptured(isCaptured);
nodeIndex = injectLazyOperandPrediction(addToGraph(GetLocal, OpInfo(variableAccessData), nodeIndex));
- m_currentBlock->variablesAtTail.local(operand) = nodeIndex;
+ m_currentBlock->variablesAtTail.argument(argument) = nodeIndex;
return nodeIndex;
}
nodePtr = &flushChild;
@@ -336,31 +319,70 @@ private:
return nodeIndex;
}
- void setArgument(int operand, NodeIndex value)
+ void setArgument(int operand, NodeIndex value, SetMode setMode = NormalSet)
{
unsigned argument = operandToArgument(operand);
bool isCaptured = m_codeBlock->argumentIsCaptured(argument);
ASSERT(argument < m_numArguments);
+ // Always flush arguments, except for 'this'.
+ if (argument && setMode == NormalSet)
+ flushDirect(operand);
+
VariableAccessData* variableAccessData = newVariableAccessData(operand, isCaptured);
- InlineStackEntry* stack = m_inlineStackTop;
- while (stack->m_inlineCallFrame) // find the machine stack entry.
- stack = stack->m_caller;
- stack->m_argumentPositions[argument]->addVariable(variableAccessData);
NodeIndex nodeIndex = addToGraph(SetLocal, OpInfo(variableAccessData), value);
m_currentBlock->variablesAtTail.argument(argument) = nodeIndex;
- // Always flush arguments, except for 'this'.
- if (argument)
- addToGraph(Flush, OpInfo(variableAccessData), nodeIndex);
}
- VariableAccessData* flushArgument(int operand)
+ ArgumentPosition* findArgumentPositionForArgument(int argument)
+ {
+ InlineStackEntry* stack = m_inlineStackTop;
+ while (stack->m_inlineCallFrame)
+ stack = stack->m_caller;
+ return stack->m_argumentPositions[argument];
+ }
+
+ ArgumentPosition* findArgumentPositionForLocal(int operand)
+ {
+ for (InlineStackEntry* stack = m_inlineStackTop; ; stack = stack->m_caller) {
+ InlineCallFrame* inlineCallFrame = stack->m_inlineCallFrame;
+ if (!inlineCallFrame)
+ break;
+ if (operand >= inlineCallFrame->stackOffset - RegisterFile::CallFrameHeaderSize)
+ continue;
+ if (operand == inlineCallFrame->stackOffset + CallFrame::thisArgumentOffset())
+ continue;
+ if (static_cast<unsigned>(operand) < inlineCallFrame->stackOffset - RegisterFile::CallFrameHeaderSize - inlineCallFrame->arguments.size())
+ continue;
+ int argument = operandToArgument(operand - inlineCallFrame->stackOffset);
+ return stack->m_argumentPositions[argument];
+ }
+ return 0;
+ }
+
+ ArgumentPosition* findArgumentPosition(int operand)
+ {
+ if (operandIsArgument(operand))
+ return findArgumentPositionForArgument(operandToArgument(operand));
+ return findArgumentPositionForLocal(operand);
+ }
+
+ void flush(int operand)
+ {
+ flushDirect(m_inlineStackTop->remapOperand(operand));
+ }
+
+ void flushDirect(int operand)
+ {
+ flushDirect(operand, findArgumentPosition(operand));
+ }
+
+ void flushDirect(int operand, ArgumentPosition* argumentPosition)
{
// FIXME: This should check if the same operand had already been flushed to
// some other local variable.
- operand = m_inlineStackTop->remapOperand(operand);
bool isCaptured = m_codeBlock->isCaptured(m_inlineStackTop->m_inlineCallFrame, operand);
ASSERT(operand < FirstConstantRegisterIndex);
@@ -398,7 +420,9 @@ private:
VariableAccessData* variableAccessData = node.variableAccessData();
variableAccessData->mergeIsCaptured(isCaptured);
addToGraph(Flush, OpInfo(variableAccessData), nodeIndex);
- return variableAccessData;
+ if (argumentPosition)
+ argumentPosition->addVariable(variableAccessData);
+ return;
}
VariableAccessData* variableAccessData = newVariableAccessData(operand, isCaptured);
@@ -413,7 +437,21 @@ private:
m_currentBlock->variablesAtTail.local(index) = nodeIndex;
m_currentBlock->variablesAtHead.setLocalFirstTime(index, nodeIndex);
}
- return variableAccessData;
+ if (argumentPosition)
+ argumentPosition->addVariable(variableAccessData);
+ }
+
+ void flushArgumentsAndCapturedVariables()
+ {
+ int numArguments;
+ if (m_inlineStackTop->m_inlineCallFrame)
+ numArguments = m_inlineStackTop->m_inlineCallFrame->arguments.size();
+ else
+ numArguments = m_inlineStackTop->m_codeBlock->numParameters();
+ for (unsigned argument = numArguments; argument-- > 1;)
+ flush(argumentToOperand(argument));
+ for (unsigned local = m_inlineStackTop->m_codeBlock->m_numCapturedVars; local--;)
+ flush(local);
}
// Get an operand, and perform a ToInt32/ToNumber conversion on it.
@@ -1219,17 +1257,6 @@ bool ByteCodeParser::handleInlining(bool usesResult, int callTarget, NodeIndex c
// FIXME: Don't flush constants!
- Vector<VariableAccessData*, 8> arguments;
- for (int i = 1; i < argumentCountIncludingThis; ++i) {
- VariableAccessData* variableAccessData =
- flushArgument(registerOffset + argumentToOperand(i));
- arguments.append(variableAccessData);
-
- // Are we going to be capturing arguments? If so make sure we record this fact.
- if (codeBlock->argumentIsCaptured(i))
- variableAccessData->mergeIsCaptured(true);
- }
-
int inlineCallFrameStart = m_inlineStackTop->remapOperand(registerOffset) - RegisterFile::CallFrameHeaderSize;
// Make sure that the area used by the call frame is reserved.
@@ -1251,13 +1278,6 @@ bool ByteCodeParser::handleInlining(bool usesResult, int callTarget, NodeIndex c
usesResult ? resultOperand : InvalidVirtualRegister),
(VirtualRegister)inlineCallFrameStart, argumentCountIncludingThis, kind);
- // Link up the argument variable access datas to their argument positions.
- for (int i = 1; i < argumentCountIncludingThis; ++i) {
- if (static_cast<size_t>(i) >= inlineStackEntry.m_argumentPositions.size())
- break;
- inlineStackEntry.m_argumentPositions[i]->addVariable(arguments[i - 1]);
- }
-
// This is where the actual inlining really happens.
unsigned oldIndex = m_currentIndex;
unsigned oldProfilingIndex = m_currentProfilingIndex;
@@ -1578,7 +1598,7 @@ bool ByteCodeParser::parseBlock(unsigned limit)
case op_enter:
// Initialize all locals to undefined.
for (int i = 0; i < m_inlineStackTop->m_codeBlock->m_numVars; ++i)
- set(i, constantUndefined());
+ set(i, constantUndefined(), SetOnEntry);
NEXT_OPCODE(op_enter);
case op_convert_this: {
@@ -2352,6 +2372,7 @@ bool ByteCodeParser::parseBlock(unsigned limit)
}
case op_ret:
+ flushArgumentsAndCapturedVariables();
if (m_inlineStackTop->m_inlineCallFrame) {
if (m_inlineStackTop->m_returnValue != InvalidVirtualRegister)
setDirect(m_inlineStackTop->m_returnValue, get(currentInstruction[1].u.operand));
@@ -2379,15 +2400,18 @@ bool ByteCodeParser::parseBlock(unsigned limit)
LAST_OPCODE(op_ret);
case op_end:
+ flushArgumentsAndCapturedVariables();
ASSERT(!m_inlineStackTop->m_inlineCallFrame);
addToGraph(Return, get(currentInstruction[1].u.operand));
LAST_OPCODE(op_end);
case op_throw:
+ flushArgumentsAndCapturedVariables();
addToGraph(Throw, get(currentInstruction[1].u.operand));
LAST_OPCODE(op_throw);
case op_throw_reference_error:
+ flushArgumentsAndCapturedVariables();
addToGraph(ThrowReferenceError);
LAST_OPCODE(op_throw_reference_error);
@@ -2818,8 +2842,8 @@ ByteCodeParser::InlineStackEntry::InlineStackEntry(
, m_didEarlyReturn(false)
, m_caller(byteCodeParser->m_inlineStackTop)
{
- m_argumentPositions.resize(codeBlock->numParameters());
- for (unsigned i = codeBlock->numParameters(); i--;) {
+ m_argumentPositions.resize(argumentCountIncludingThis);
+ for (unsigned i = argumentCountIncludingThis; i--;) {
byteCodeParser->m_graph.m_argumentPositions.append(ArgumentPosition());
ArgumentPosition* argumentPosition = &byteCodeParser->m_graph.m_argumentPositions.last();
m_argumentPositions[i] = argumentPosition;
diff --git a/Source/JavaScriptCore/dfg/DFGCSEPhase.cpp b/Source/JavaScriptCore/dfg/DFGCSEPhase.cpp
index 3eeb70e05..31488cb1c 100644
--- a/Source/JavaScriptCore/dfg/DFGCSEPhase.cpp
+++ b/Source/JavaScriptCore/dfg/DFGCSEPhase.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2011 Apple Inc. All rights reserved.
+ * Copyright (C) 2011, 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
@@ -620,7 +620,7 @@ private:
}
// This returns the Flush node that is keeping a SetLocal alive.
- NodeIndex setLocalStoreElimination(VirtualRegister local)
+ NodeIndex setLocalStoreElimination(VirtualRegister local, NodeIndex expectedNodeIndex)
{
for (unsigned i = m_indexInBlock; i--;) {
NodeIndex index = m_currentBlock->at(i);
@@ -629,7 +629,7 @@ private:
continue;
switch (node.op()) {
case GetLocal:
- case SetLocal:
+ case Flush:
if (node.local() == local)
return NoNode;
break;
@@ -639,19 +639,13 @@ private:
return NoNode;
break;
- case Flush: {
+ case SetLocal: {
if (node.local() != local)
break;
- if (!i)
- break;
- NodeIndex prevIndex = m_currentBlock->at(i - 1);
- if (prevIndex != node.child1().index())
- break;
- ASSERT(m_graph[prevIndex].local() == local);
- ASSERT(m_graph[prevIndex].variableAccessData() == node.variableAccessData());
- ASSERT(m_graph[prevIndex].shouldGenerate());
- if (m_graph[prevIndex].refCount() > 1)
- break;
+ if (index != expectedNodeIndex)
+ return NoNode;
+ if (m_graph[index].refCount() > 1)
+ return NoNode;
return index;
}
@@ -660,6 +654,14 @@ private:
return NoNode;
break;
+ case TearOffActivation:
+ case TearOffArguments:
+ // If an activation is being torn off then it means that captured variables
+ // are live. We could be clever here and check if the local qualifies as an
+ // argument register. But that seems like it would buy us very little since
+ // any kind of tear offs are rare to begin with.
+ return NoNode;
+
default:
if (m_graph.clobbersWorld(index))
return NoNode;
@@ -855,27 +857,26 @@ private:
break;
}
- case SetLocal: {
+ case Flush: {
if (m_fixpointState == FixpointNotConverged)
break;
VariableAccessData* variableAccessData = node.variableAccessData();
if (!variableAccessData->isCaptured())
break;
VirtualRegister local = variableAccessData->local();
- NodeIndex replacementIndex = setLocalStoreElimination(local);
+ NodeIndex replacementIndex = setLocalStoreElimination(local, node.child1().index());
if (replacementIndex == NoNode)
break;
Node& replacement = m_graph[replacementIndex];
- ASSERT(replacement.op() == Flush);
+ ASSERT(replacement.op() == SetLocal);
ASSERT(replacement.refCount() == 1);
ASSERT(replacement.shouldGenerate());
- ASSERT(replacement.mustGenerate());
- replacement.setOpAndDefaultFlags(Phantom);
- NodeIndex setLocalIndex = replacement.child1().index();
- ASSERT(m_graph[setLocalIndex].op() == SetLocal);
- m_graph.clearAndDerefChild1(replacement);
- replacement.children.child1() = m_graph[setLocalIndex].child1();
- m_graph.ref(replacement.child1());
+ node.setOpAndDefaultFlags(Phantom);
+ NodeIndex dataNodeIndex = replacement.child1().index();
+ ASSERT(m_graph[dataNodeIndex].hasResult());
+ m_graph.clearAndDerefChild1(node);
+ node.children.child1() = Edge(dataNodeIndex);
+ m_graph.ref(dataNodeIndex);
break;
}
diff --git a/Source/JavaScriptCore/dfg/DFGConstantFoldingPhase.cpp b/Source/JavaScriptCore/dfg/DFGConstantFoldingPhase.cpp
index b2b74ba04..1e75ddea1 100644
--- a/Source/JavaScriptCore/dfg/DFGConstantFoldingPhase.cpp
+++ b/Source/JavaScriptCore/dfg/DFGConstantFoldingPhase.cpp
@@ -77,13 +77,42 @@ public:
ASSERT(m_graph[node.child1()].op() == Phi);
ASSERT(!m_graph[node.child1()].hasResult());
- ASSERT(block->variablesAtHead.operand(node.local()) == nodeIndex);
- ASSERT(block->isInPhis(node.child1().index()));
- block->variablesAtHead.operand(node.local()) = node.child1().index();
+ NodeIndex previousLocalAccess = NoNode;
+ if (block->variablesAtHead.operand(node.local()) == nodeIndex) {
+ // We expect this to be the common case.
+ ASSERT(block->isInPhis(node.child1().index()));
+ previousLocalAccess = node.child1().index();
+ block->variablesAtHead.operand(node.local()) = previousLocalAccess;
+ } else {
+ ASSERT(indexInBlock > 0);
+ // Must search for the previous access to this local.
+ for (BlockIndex subIndexInBlock = indexInBlock - 1; subIndexInBlock--;) {
+ NodeIndex subNodeIndex = block->at(subIndexInBlock);
+ Node& subNode = m_graph[subNodeIndex];
+ if (!subNode.shouldGenerate())
+ continue;
+ if (!subNode.hasVariableAccessData())
+ continue;
+ if (subNode.local() != node.local())
+ continue;
+ // The two must have been unified.
+ ASSERT(subNode.variableAccessData() == node.variableAccessData());
+ // Currently, the previous node must be a flush.
+ // NOTE: This assertion should be removed if we ever do
+ // constant folding on captured variables. In particular,
+ // this code does not require the previous node to be a flush,
+ // but we are asserting this anyway because it is a constraint
+ // of the IR and this is as good a place as any to assert it.
+ ASSERT(subNode.op() == Flush);
+ previousLocalAccess = subNodeIndex;
+ break;
+ }
+ ASSERT(previousLocalAccess != NoNode);
+ }
NodeIndex tailNodeIndex = block->variablesAtTail.operand(node.local());
if (tailNodeIndex == nodeIndex)
- block->variablesAtTail.operand(node.local()) = node.child1().index();
+ block->variablesAtTail.operand(node.local()) = previousLocalAccess;
else {
ASSERT(m_graph[tailNodeIndex].op() == Flush
|| m_graph[tailNodeIndex].op() == SetLocal);
diff --git a/Source/JavaScriptCore/dfg/DFGJITCompiler.h b/Source/JavaScriptCore/dfg/DFGJITCompiler.h
index 360165b24..d3ff3be07 100644
--- a/Source/JavaScriptCore/dfg/DFGJITCompiler.h
+++ b/Source/JavaScriptCore/dfg/DFGJITCompiler.h
@@ -304,6 +304,10 @@ public:
void noticeOSREntry(BasicBlock& basicBlock, JITCompiler::Label blockHead, LinkBuffer& linkBuffer)
{
#if DFG_ENABLE(OSR_ENTRY)
+ // OSR entry is not allowed into blocks deemed unreachable by control flow analysis.
+ if (!basicBlock.cfaHasVisited)
+ return;
+
OSREntryData* entry = codeBlock()->appendDFGOSREntryData(basicBlock.bytecodeBegin, linkBuffer.offsetOf(blockHead));
entry->m_expectedValues = basicBlock.valuesAtHead;
diff --git a/Source/JavaScriptCore/dfg/DFGOperations.cpp b/Source/JavaScriptCore/dfg/DFGOperations.cpp
index f95b993d7..b5ac4601a 100644
--- a/Source/JavaScriptCore/dfg/DFGOperations.cpp
+++ b/Source/JavaScriptCore/dfg/DFGOperations.cpp
@@ -34,6 +34,7 @@
#include "GetterSetter.h"
#include <wtf/InlineASM.h>
#include "Interpreter.h"
+#include "JITExceptions.h"
#include "JSActivation.h"
#include "JSGlobalData.h"
#include "JSStaticScopeObject.h"
@@ -1149,35 +1150,31 @@ DFGHandlerEncoded DFG_OPERATION lookupExceptionHandler(ExecState* exec, uint32_t
{
JSGlobalData* globalData = &exec->globalData();
NativeCallFrameTracer tracer(globalData, exec);
-
+
JSValue exceptionValue = exec->exception();
ASSERT(exceptionValue);
-
+
unsigned vPCIndex = exec->codeBlock()->bytecodeOffsetForCallAtIndex(callIndex);
- HandlerInfo* handler = exec->globalData().interpreter->throwException(exec, exceptionValue, vPCIndex);
-
- void* catchRoutine = handler ? handler->nativeCode.executableAddress() : (void*)ctiOpThrowNotCaught;
- ASSERT(catchRoutine);
- return dfgHandlerEncoded(exec, catchRoutine);
+ ExceptionHandler handler = genericThrow(globalData, exec, exceptionValue, vPCIndex);
+ ASSERT(handler.catchRoutine);
+ return dfgHandlerEncoded(handler.callFrame, handler.catchRoutine);
}
DFGHandlerEncoded DFG_OPERATION lookupExceptionHandlerInStub(ExecState* exec, StructureStubInfo* stubInfo)
{
JSGlobalData* globalData = &exec->globalData();
NativeCallFrameTracer tracer(globalData, exec);
-
+
JSValue exceptionValue = exec->exception();
ASSERT(exceptionValue);
CodeOrigin codeOrigin = stubInfo->codeOrigin;
while (codeOrigin.inlineCallFrame)
codeOrigin = codeOrigin.inlineCallFrame->caller;
-
- HandlerInfo* handler = exec->globalData().interpreter->throwException(exec, exceptionValue, codeOrigin.bytecodeIndex);
-
- void* catchRoutine = handler ? handler->nativeCode.executableAddress() : (void*)ctiOpThrowNotCaught;
- ASSERT(catchRoutine);
- return dfgHandlerEncoded(exec, catchRoutine);
+
+ ExceptionHandler handler = genericThrow(globalData, exec, exceptionValue, codeOrigin.bytecodeIndex);
+ ASSERT(handler.catchRoutine);
+ return dfgHandlerEncoded(handler.callFrame, handler.catchRoutine);
}
double DFG_OPERATION dfgConvertJSValueToNumber(ExecState* exec, EncodedJSValue value)
diff --git a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp
index caa21aabf..9b82121b3 100644
--- a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp
+++ b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp
@@ -967,6 +967,16 @@ void SpeculativeJIT::compile(BasicBlock& block)
if (!block.isReachable)
return;
+
+ if (!block.cfaHasVisited) {
+ // Don't generate code for basic blocks that are unreachable according to CFA.
+ // But to be sure that nobody has generated a jump to this block, drop in a
+ // breakpoint here.
+#if !ASSERT_DISABLED
+ m_jit.breakpoint();
+#endif
+ return;
+ }
m_blockHeads[m_block] = m_jit.label();
#if DFG_ENABLE(JIT_BREAK_ON_EVERY_BLOCK)
@@ -990,20 +1000,18 @@ void SpeculativeJIT::compile(BasicBlock& block)
ASSERT(m_variables.size() == block.variablesAtHead.numberOfLocals());
for (size_t i = 0; i < m_variables.size(); ++i) {
NodeIndex nodeIndex = block.variablesAtHead.local(i);
- // FIXME: Use the variable access data, not the first node in the block.
- // https://bugs.webkit.org/show_bug.cgi?id=87205
- if (m_jit.codeBlock()->localIsCaptured(at(block[0]).codeOrigin.inlineCallFrame, i))
- m_variables[i] = ValueSource(ValueInRegisterFile);
- else if (nodeIndex == NoNode)
+ if (nodeIndex == NoNode)
m_variables[i] = ValueSource(SourceIsDead);
else if (at(nodeIndex).variableAccessData()->isArgumentsAlias())
m_variables[i] = ValueSource(ArgumentsSource);
+ else if (at(nodeIndex).variableAccessData()->isCaptured())
+ m_variables[i] = ValueSource(ValueInRegisterFile);
else if (!at(nodeIndex).refCount())
m_variables[i] = ValueSource(SourceIsDead);
else if (at(nodeIndex).variableAccessData()->shouldUseDoubleFormat())
m_variables[i] = ValueSource(DoubleInRegisterFile);
else
- m_variables[i] = ValueSource::forPrediction(at(nodeIndex).variableAccessData()->prediction());
+ m_variables[i] = ValueSource::forPrediction(at(nodeIndex).variableAccessData()->argumentAwarePrediction());
}
m_lastSetOperand = std::numeric_limits<int>::max();
diff --git a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h
index 912078a79..56a1a1861 100644
--- a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h
+++ b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h
@@ -2191,22 +2191,23 @@ public:
unsigned setLocalIndexInBlock = m_indexInBlock + 1;
Node* setLocal = &at(m_jit.graph().m_blocks[m_block]->at(setLocalIndexInBlock));
+ bool hadInt32ToDouble = false;
if (setLocal->op() == Int32ToDouble) {
setLocal = &at(m_jit.graph().m_blocks[m_block]->at(++setLocalIndexInBlock));
+ hadInt32ToDouble = true;
+ }
+ if (setLocal->op() == Flush)
+ setLocal = &at(m_jit.graph().m_blocks[m_block]->at(++setLocalIndexInBlock));
+
+ if (hadInt32ToDouble)
ASSERT(at(setLocal->child1()).child1() == m_compileIndex);
- } else
+ else
ASSERT(setLocal->child1() == m_compileIndex);
-
ASSERT(setLocal->op() == SetLocal);
ASSERT(setLocal->codeOrigin == at(m_compileIndex).codeOrigin);
Node* nextNode = &at(m_jit.graph().m_blocks[m_block]->at(setLocalIndexInBlock + 1));
- if (nextNode->codeOrigin == at(m_compileIndex).codeOrigin) {
- ASSERT(nextNode->op() == Flush);
- nextNode = &at(m_jit.graph().m_blocks[m_block]->at(setLocalIndexInBlock + 2));
- ASSERT(nextNode->codeOrigin != at(m_compileIndex).codeOrigin); // duplicate the same assertion as below so that if we fail, we'll know we came down this path.
- }
ASSERT(nextNode->codeOrigin != at(m_compileIndex).codeOrigin);
OSRExit& exit = m_jit.codeBlock()->lastOSRExit();
diff --git a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp
index 6c0093e41..00a83000a 100644
--- a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp
+++ b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp
@@ -3858,12 +3858,16 @@ void SpeculativeJIT::compile(Node& node)
}
case CheckArgumentsNotCreated: {
- speculationCheck(
- Uncountable, JSValueRegs(), NoNode,
- m_jit.branch32(
- JITCompiler::NotEqual,
- JITCompiler::tagFor(m_jit.argumentsRegisterFor(node.codeOrigin)),
- TrustedImm32(JSValue::EmptyValueTag)));
+ if (!isEmptyPrediction(
+ m_state.variables().operand(
+ m_jit.graph().argumentsRegisterFor(node.codeOrigin)).m_type)) {
+ speculationCheck(
+ Uncountable, JSValueRegs(), NoNode,
+ m_jit.branch32(
+ JITCompiler::NotEqual,
+ JITCompiler::tagFor(m_jit.argumentsRegisterFor(node.codeOrigin)),
+ TrustedImm32(JSValue::EmptyValueTag)));
+ }
noResult(m_compileIndex);
break;
}
@@ -3872,12 +3876,16 @@ void SpeculativeJIT::compile(Node& node)
GPRTemporary result(this);
GPRReg resultGPR = result.gpr();
- speculationCheck(
- ArgumentsEscaped, JSValueRegs(), NoNode,
- m_jit.branch32(
- JITCompiler::NotEqual,
- JITCompiler::tagFor(m_jit.argumentsRegisterFor(node.codeOrigin)),
- TrustedImm32(JSValue::EmptyValueTag)));
+ if (!isEmptyPrediction(
+ m_state.variables().operand(
+ m_jit.graph().argumentsRegisterFor(node.codeOrigin)).m_type)) {
+ speculationCheck(
+ ArgumentsEscaped, JSValueRegs(), NoNode,
+ m_jit.branch32(
+ JITCompiler::NotEqual,
+ JITCompiler::tagFor(m_jit.argumentsRegisterFor(node.codeOrigin)),
+ TrustedImm32(JSValue::EmptyValueTag)));
+ }
ASSERT(!node.codeOrigin.inlineCallFrame);
m_jit.load32(JITCompiler::payloadFor(RegisterFile::ArgumentCount), resultGPR);
@@ -3929,12 +3937,16 @@ void SpeculativeJIT::compile(Node& node)
GPRReg resultPayloadGPR = resultPayload.gpr();
GPRReg resultTagGPR = resultTag.gpr();
- speculationCheck(
- ArgumentsEscaped, JSValueRegs(), NoNode,
- m_jit.branch32(
- JITCompiler::NotEqual,
- JITCompiler::tagFor(m_jit.argumentsRegisterFor(node.codeOrigin)),
- TrustedImm32(JSValue::EmptyValueTag)));
+ if (!isEmptyPrediction(
+ m_state.variables().operand(
+ m_jit.graph().argumentsRegisterFor(node.codeOrigin)).m_type)) {
+ speculationCheck(
+ ArgumentsEscaped, JSValueRegs(), NoNode,
+ m_jit.branch32(
+ JITCompiler::NotEqual,
+ JITCompiler::tagFor(m_jit.argumentsRegisterFor(node.codeOrigin)),
+ TrustedImm32(JSValue::EmptyValueTag)));
+ }
m_jit.add32(TrustedImm32(1), indexGPR, resultPayloadGPR);
diff --git a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp
index e4939b23a..ca57743a6 100644
--- a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp
+++ b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp
@@ -3880,12 +3880,16 @@ void SpeculativeJIT::compile(Node& node)
GPRTemporary result(this);
GPRReg resultGPR = result.gpr();
- speculationCheck(
- ArgumentsEscaped, JSValueRegs(), NoNode,
- m_jit.branchTestPtr(
- JITCompiler::NonZero,
- JITCompiler::addressFor(
- m_jit.argumentsRegisterFor(node.codeOrigin))));
+ if (!isEmptyPrediction(
+ m_state.variables().operand(
+ m_jit.graph().argumentsRegisterFor(node.codeOrigin)).m_type)) {
+ speculationCheck(
+ ArgumentsEscaped, JSValueRegs(), NoNode,
+ m_jit.branchTestPtr(
+ JITCompiler::NonZero,
+ JITCompiler::addressFor(
+ m_jit.argumentsRegisterFor(node.codeOrigin))));
+ }
ASSERT(!node.codeOrigin.inlineCallFrame);
m_jit.load32(JITCompiler::payloadFor(RegisterFile::ArgumentCount), resultGPR);
@@ -3935,12 +3939,16 @@ void SpeculativeJIT::compile(Node& node)
GPRReg indexGPR = index.gpr();
GPRReg resultGPR = result.gpr();
- speculationCheck(
- ArgumentsEscaped, JSValueRegs(), NoNode,
- m_jit.branchTestPtr(
- JITCompiler::NonZero,
- JITCompiler::addressFor(
- m_jit.argumentsRegisterFor(node.codeOrigin))));
+ if (!isEmptyPrediction(
+ m_state.variables().operand(
+ m_jit.graph().argumentsRegisterFor(node.codeOrigin)).m_type)) {
+ speculationCheck(
+ ArgumentsEscaped, JSValueRegs(), NoNode,
+ m_jit.branchTestPtr(
+ JITCompiler::NonZero,
+ JITCompiler::addressFor(
+ m_jit.argumentsRegisterFor(node.codeOrigin))));
+ }
m_jit.add32(TrustedImm32(1), indexGPR, resultGPR);
if (node.codeOrigin.inlineCallFrame) {
@@ -4024,12 +4032,16 @@ void SpeculativeJIT::compile(Node& node)
}
case CheckArgumentsNotCreated: {
- speculationCheck(
- ArgumentsEscaped, JSValueRegs(), NoNode,
- m_jit.branchTestPtr(
- JITCompiler::NonZero,
- JITCompiler::addressFor(
- m_jit.argumentsRegisterFor(node.codeOrigin))));
+ if (!isEmptyPrediction(
+ m_state.variables().operand(
+ m_jit.graph().argumentsRegisterFor(node.codeOrigin)).m_type)) {
+ speculationCheck(
+ ArgumentsEscaped, JSValueRegs(), NoNode,
+ m_jit.branchTestPtr(
+ JITCompiler::NonZero,
+ JITCompiler::addressFor(
+ m_jit.argumentsRegisterFor(node.codeOrigin))));
+ }
noResult(m_compileIndex);
break;
}
diff --git a/Source/JavaScriptCore/heap/Heap.cpp b/Source/JavaScriptCore/heap/Heap.cpp
index 9b68fb10a..90c4bb72c 100644
--- a/Source/JavaScriptCore/heap/Heap.cpp
+++ b/Source/JavaScriptCore/heap/Heap.cpp
@@ -27,6 +27,7 @@
#include "ConservativeRoots.h"
#include "GCActivityCallback.h"
#include "HeapRootVisitor.h"
+#include "IncrementalSweeper.h"
#include "Interpreter.h"
#include "JSGlobalData.h"
#include "JSGlobalObject.h"
@@ -245,6 +246,7 @@ Heap::Heap(JSGlobalData* globalData, HeapType heapType)
, m_objectSpace(this)
, m_storageSpace(this)
, m_activityCallback(DefaultGCActivityCallback::create(this))
+ , m_sweeper(IncrementalSweeper::create(this))
, m_machineThreads(this)
, m_sharedData(globalData)
, m_slotVisitor(m_sharedData)
@@ -703,9 +705,11 @@ void Heap::collect(SweepToggle sweepToggle)
GCPHASE(Sweeping);
m_objectSpace.sweep();
m_objectSpace.shrink();
- m_bytesAbandoned = 0;
}
+ m_sweeper->startSweeping(m_objectSpace.blocks().set());
+ m_bytesAbandoned = 0;
+
{
GCPHASE(ResetAllocators);
m_objectSpace.resetAllocators();
@@ -737,6 +741,11 @@ GCActivityCallback* Heap::activityCallback()
return m_activityCallback.get();
}
+IncrementalSweeper* Heap::sweeper()
+{
+ return m_sweeper.get();
+}
+
void Heap::setGarbageCollectionTimerEnabled(bool enable)
{
activityCallback()->setEnabled(enable);
diff --git a/Source/JavaScriptCore/heap/Heap.h b/Source/JavaScriptCore/heap/Heap.h
index edfd91483..296447d7b 100644
--- a/Source/JavaScriptCore/heap/Heap.h
+++ b/Source/JavaScriptCore/heap/Heap.h
@@ -47,6 +47,7 @@ namespace JSC {
class GlobalCodeBlock;
class Heap;
class HeapRootVisitor;
+ class IncrementalSweeper;
class JSCell;
class JSGlobalData;
class JSValue;
@@ -100,6 +101,8 @@ namespace JSC {
JS_EXPORT_PRIVATE void setActivityCallback(PassOwnPtr<GCActivityCallback>);
JS_EXPORT_PRIVATE void setGarbageCollectionTimerEnabled(bool);
+ IncrementalSweeper* sweeper();
+
// true if an allocation or collection is in progress
inline bool isBusy();
@@ -217,6 +220,7 @@ namespace JSC {
OwnPtr<HashSet<MarkedArgumentBuffer*> > m_markListSet;
OwnPtr<GCActivityCallback> m_activityCallback;
+ OwnPtr<IncrementalSweeper> m_sweeper;
MachineThreads m_machineThreads;
@@ -240,9 +244,9 @@ namespace JSC {
inline bool Heap::shouldCollect()
{
#if ENABLE(GGC)
- return m_objectSpace.nurseryWaterMark() >= m_minBytesPerCycle && m_isSafeToCollect;
+ return m_objectSpace.nurseryWaterMark() >= m_minBytesPerCycle && m_isSafeToCollect && m_operationInProgress == NoOperation;
#else
- return m_bytesAllocated > m_bytesAllocatedLimit && m_isSafeToCollect;
+ return m_bytesAllocated > m_bytesAllocatedLimit && m_isSafeToCollect && m_operationInProgress == NoOperation;
#endif
}
diff --git a/Source/JavaScriptCore/heap/IncrementalSweeper.cpp b/Source/JavaScriptCore/heap/IncrementalSweeper.cpp
new file mode 100644
index 000000000..08a9f6c73
--- /dev/null
+++ b/Source/JavaScriptCore/heap/IncrementalSweeper.cpp
@@ -0,0 +1,107 @@
+#include "config.h"
+#include "IncrementalSweeper.h"
+
+#include "APIShims.h"
+#include "Heap.h"
+#include "JSObject.h"
+#include "JSString.h"
+#include "MarkedBlock.h"
+#include "ScopeChain.h"
+#include <wtf/HashSet.h>
+#include <wtf/WTFThreadData.h>
+
+namespace JSC {
+
+#if USE(CF)
+
+static const CFTimeInterval decade = 60 * 60 * 24 * 365 * 10;
+static const CFTimeInterval sweepTimeSlicePerBlock = 0.01;
+static const CFTimeInterval sweepTimeMultiplier = 1.0 / sweepTimeSlicePerBlock;
+
+void IncrementalSweeper::timerDidFire(CFRunLoopTimerRef, void* info)
+{
+ Heap* heap = static_cast<Heap*>(info);
+ APIEntryShim shim(heap->globalData());
+ heap->sweeper()->doSweep(WTF::monotonicallyIncreasingTime());
+}
+
+IncrementalSweeper::IncrementalSweeper(Heap* heap, CFRunLoopRef runLoop)
+ : m_heap(heap)
+ , m_currentBlockToSweepIndex(0)
+ , m_lengthOfLastSweepIncrement(0.0)
+{
+ memset(&m_context, 0, sizeof(CFRunLoopTimerContext));
+ m_context.info = m_heap;
+ m_runLoop = runLoop;
+ m_timer.adoptCF(CFRunLoopTimerCreate(0, CFAbsoluteTimeGetCurrent(), decade, 0, 0, &timerDidFire, &m_context));
+ CFRunLoopAddTimer(m_runLoop.get(), m_timer.get(), kCFRunLoopCommonModes);
+}
+
+IncrementalSweeper::~IncrementalSweeper()
+{
+ CFRunLoopRemoveTimer(m_runLoop.get(), m_timer.get(), kCFRunLoopCommonModes);
+ CFRunLoopTimerInvalidate(m_timer.get());
+}
+
+PassOwnPtr<IncrementalSweeper> IncrementalSweeper::create(Heap* heap)
+{
+ return adoptPtr(new IncrementalSweeper(heap, CFRunLoopGetCurrent()));
+}
+
+void IncrementalSweeper::scheduleTimer()
+{
+ CFRunLoopTimerSetNextFireDate(m_timer.get(), CFAbsoluteTimeGetCurrent() + (m_lengthOfLastSweepIncrement * sweepTimeMultiplier));
+}
+
+void IncrementalSweeper::cancelTimer()
+{
+ CFRunLoopTimerSetNextFireDate(m_timer.get(), CFAbsoluteTimeGetCurrent() + decade);
+}
+
+void IncrementalSweeper::doSweep(double sweepBeginTime)
+{
+ for (; m_currentBlockToSweepIndex < m_blocksToSweep.size(); m_currentBlockToSweepIndex++) {
+ MarkedBlock* nextBlock = m_blocksToSweep[m_currentBlockToSweepIndex];
+ if (!nextBlock->needsSweeping())
+ continue;
+
+ nextBlock->sweep();
+ m_blocksToSweep[m_currentBlockToSweepIndex++] = 0;
+ m_lengthOfLastSweepIncrement = WTF::monotonicallyIncreasingTime() - sweepBeginTime;
+ scheduleTimer();
+ return;
+ }
+
+ m_blocksToSweep.clear();
+ cancelTimer();
+}
+
+void IncrementalSweeper::startSweeping(const HashSet<MarkedBlock*>& blockSnapshot)
+{
+ WTF::copyToVector(blockSnapshot, m_blocksToSweep);
+ m_currentBlockToSweepIndex = 0;
+ scheduleTimer();
+}
+
+#else
+
+IncrementalSweeper::IncrementalSweeper()
+{
+}
+
+IncrementalSweeper::~IncrementalSweeper()
+{
+}
+
+PassOwnPtr<IncrementalSweeper> IncrementalSweeper::create(Heap*)
+{
+ return adoptPtr(new IncrementalSweeper());
+}
+
+void IncrementalSweeper::startSweeping(const HashSet<MarkedBlock*>&)
+{
+}
+
+#endif
+
+} // namespace JSC
diff --git a/Source/JavaScriptCore/heap/IncrementalSweeper.h b/Source/JavaScriptCore/heap/IncrementalSweeper.h
new file mode 100644
index 000000000..48f040409
--- /dev/null
+++ b/Source/JavaScriptCore/heap/IncrementalSweeper.h
@@ -0,0 +1,51 @@
+#ifndef IncrementalSweeper_h
+#define IncrementalSweeper_h
+
+#include "MarkedBlock.h"
+#include <wtf/HashSet.h>
+#include <wtf/PassOwnPtr.h>
+#include <wtf/RetainPtr.h>
+#include <wtf/Vector.h>
+
+#if USE(CF)
+#include <CoreFoundation/CoreFoundation.h>
+#endif
+
+namespace JSC {
+
+class Heap;
+
+class IncrementalSweeper {
+public:
+ ~IncrementalSweeper();
+
+ static PassOwnPtr<IncrementalSweeper> create(Heap*);
+ void startSweeping(const HashSet<MarkedBlock*>& blockSnapshot);
+
+private:
+#if USE(CF)
+ IncrementalSweeper(Heap*, CFRunLoopRef);
+
+ static void timerDidFire(CFRunLoopTimerRef, void*);
+ void doSweep(double startTime);
+ void scheduleTimer();
+ void cancelTimer();
+
+ Heap* m_heap;
+ unsigned m_currentBlockToSweepIndex;
+ RetainPtr<CFRunLoopTimerRef> m_timer;
+ RetainPtr<CFRunLoopRef> m_runLoop;
+ CFRunLoopTimerContext m_context;
+
+ double m_lengthOfLastSweepIncrement;
+ Vector<MarkedBlock*> m_blocksToSweep;
+#else
+
+ IncrementalSweeper();
+
+#endif
+};
+
+} // namespace JSC
+
+#endif
diff --git a/Source/JavaScriptCore/heap/MarkedBlock.h b/Source/JavaScriptCore/heap/MarkedBlock.h
index c21e20b19..b94c1e2b0 100644
--- a/Source/JavaScriptCore/heap/MarkedBlock.h
+++ b/Source/JavaScriptCore/heap/MarkedBlock.h
@@ -157,6 +157,8 @@ namespace JSC {
bool isLiveCell(const void*);
void setMarked(const void*);
+ bool needsSweeping();
+
#if ENABLE(GGC)
void setDirtyObject(const void* atom)
{
@@ -416,6 +418,11 @@ namespace JSC {
}
}
+ inline bool MarkedBlock::needsSweeping()
+ {
+ return m_state == Marked;
+ }
+
#if ENABLE(GGC)
template <int _cellSize> void MarkedBlock::gatherDirtyCellsWithSize(DirtyCellVector& dirtyCells)
{
diff --git a/Source/JavaScriptCore/interpreter/Interpreter.cpp b/Source/JavaScriptCore/interpreter/Interpreter.cpp
index 5eaed9657..ba72e9bba 100644
--- a/Source/JavaScriptCore/interpreter/Interpreter.cpp
+++ b/Source/JavaScriptCore/interpreter/Interpreter.cpp
@@ -1024,7 +1024,7 @@ NEVER_INLINE HandlerInfo* Interpreter::throwException(CallFrame*& callFrame, JSV
if (exception->isErrorInstance() && static_cast<ErrorInstance*>(exception)->appendSourceToMessage())
appendSourceToError(callFrame, static_cast<ErrorInstance*>(exception), bytecodeOffset);
- if (codeBlock->hasLineInfo() && !hasErrorInfo(callFrame, exception)) {
+ if (!hasErrorInfo(callFrame, exception)) {
// FIXME: should only really be adding these properties to VM generated exceptions,
// but the inspector currently requires these for all thrown objects.
addErrorInfo(callFrame, exception, codeBlock->lineNumberForBytecodeOffset(bytecodeOffset), codeBlock->ownerExecutable()->source());
diff --git a/Source/JavaScriptCore/llint/LLIntSlowPaths.cpp b/Source/JavaScriptCore/llint/LLIntSlowPaths.cpp
index 5cba5ea70..b13e84b53 100644
--- a/Source/JavaScriptCore/llint/LLIntSlowPaths.cpp
+++ b/Source/JavaScriptCore/llint/LLIntSlowPaths.cpp
@@ -53,8 +53,16 @@ namespace JSC { namespace LLInt {
JSGlobalData& globalData = exec->globalData(); \
NativeCallFrameTracer tracer(&globalData, exec)
-#define LLINT_SET_PC_FOR_STUBS() \
- exec->setCurrentVPC(pc + 1)
+#ifndef NDEBUG
+#define LLINT_SET_PC_FOR_STUBS() do { \
+ exec->codeBlock()->bytecodeOffset(pc); \
+ exec->setCurrentVPC(pc + 1); \
+ } while (false)
+#else
+#define LLINT_SET_PC_FOR_STUBS() do { \
+ exec->setCurrentVPC(pc + 1); \
+ } while (false)
+#endif
#define LLINT_BEGIN() \
LLINT_BEGIN_NO_SET_PC(); \
diff --git a/Source/JavaScriptCore/llint/LowLevelInterpreter32_64.asm b/Source/JavaScriptCore/llint/LowLevelInterpreter32_64.asm
index dd5ab674a..95b26d42f 100644
--- a/Source/JavaScriptCore/llint/LowLevelInterpreter32_64.asm
+++ b/Source/JavaScriptCore/llint/LowLevelInterpreter32_64.asm
@@ -1668,8 +1668,8 @@ macro nativeCallTrampoline(executableOffsetToFunction)
storei CellTag, ScopeChain + TagOffset[cfr]
storei t1, ScopeChain + PayloadOffset[cfr]
if X86
- loadp JITStackFrame::globalData + 4[sp], t0 # Additional offset for return address
- storep cfr, JSGlobalData::topCallFrame[t0]
+ loadp JITStackFrame::globalData + 4[sp], t3 # Additional offset for return address
+ storep cfr, JSGlobalData::topCallFrame[t3]
peek 0, t1
storep t1, ReturnPC[cfr]
move cfr, t2 # t2 = ecx
@@ -1681,8 +1681,8 @@ macro nativeCallTrampoline(executableOffsetToFunction)
addp 16 - 4, sp
loadp JITStackFrame::globalData + 4[sp], t3
elsif ARMv7
- loadp JITStackFrame::globalData[sp], t1
- storep cfr, JSGlobalData::topCallFrame[t1]
+ loadp JITStackFrame::globalData[sp], t3
+ storep cfr, JSGlobalData::topCallFrame[t3]
move t0, t2
preserveReturnAddressAfterCall(t3)
storep t3, ReturnPC[cfr]
diff --git a/Source/JavaScriptCore/parser/Nodes.h b/Source/JavaScriptCore/parser/Nodes.h
index 26c829da6..5c90bb9fe 100644
--- a/Source/JavaScriptCore/parser/Nodes.h
+++ b/Source/JavaScriptCore/parser/Nodes.h
@@ -1399,7 +1399,7 @@ namespace JSC {
const SourceCode& source() const { return m_source; }
const UString& sourceURL() const { return m_source.provider()->url(); }
- intptr_t sourceID() const { return m_source.provider()->asID(); }
+ intptr_t sourceID() const { return m_source.providerID(); }
void setFeatures(CodeFeatures features) { m_features = features; }
CodeFeatures features() { return m_features; }
diff --git a/Source/JavaScriptCore/parser/SourceCode.h b/Source/JavaScriptCore/parser/SourceCode.h
index a33ffea72..11a00337d 100644
--- a/Source/JavaScriptCore/parser/SourceCode.h
+++ b/Source/JavaScriptCore/parser/SourceCode.h
@@ -67,6 +67,13 @@ namespace JSC {
return m_provider->getRange(m_startChar, m_endChar);
}
+ intptr_t providerID() const
+ {
+ if (!m_provider)
+ return SourceProvider::nullID;
+ return m_provider->asID();
+ }
+
bool isNull() const { return !m_provider; }
SourceProvider* provider() const { return m_provider.get(); }
int firstLine() const { return m_firstLine; }
diff --git a/Source/JavaScriptCore/parser/SourceProvider.h b/Source/JavaScriptCore/parser/SourceProvider.h
index 20be63cac..946792b2c 100644
--- a/Source/JavaScriptCore/parser/SourceProvider.h
+++ b/Source/JavaScriptCore/parser/SourceProvider.h
@@ -40,6 +40,8 @@ namespace JSC {
class SourceProvider : public RefCounted<SourceProvider> {
public:
+ static const intptr_t nullID = 1;
+
SourceProvider(const UString& url, const TextPosition& startPosition, SourceProviderCache* cache = 0)
: m_url(url)
, m_startPosition(startPosition)
@@ -61,7 +63,13 @@ namespace JSC {
const UString& url() { return m_url; }
TextPosition startPosition() const { return m_startPosition; }
- intptr_t asID() { return reinterpret_cast<intptr_t>(this); }
+ intptr_t asID()
+ {
+ ASSERT(this);
+ if (!this) // Be defensive in release mode.
+ return nullID;
+ return reinterpret_cast<intptr_t>(this);
+ }
bool isValid() const { return m_validated; }
void setValid() { m_validated = true; }
diff --git a/Source/JavaScriptCore/runtime/Executable.h b/Source/JavaScriptCore/runtime/Executable.h
index debb3e369..e999d3a08 100644
--- a/Source/JavaScriptCore/runtime/Executable.h
+++ b/Source/JavaScriptCore/runtime/Executable.h
@@ -285,7 +285,7 @@ namespace JSC {
#endif
const SourceCode& source() { return m_source; }
- intptr_t sourceID() const { return m_source.provider()->asID(); }
+ intptr_t sourceID() const { return m_source.providerID(); }
const UString& sourceURL() const { return m_source.provider()->url(); }
int lineNo() const { return m_firstLine; }
int lastLine() const { return m_lastLine; }
diff --git a/Source/JavaScriptCore/runtime/JSGlobalObject.cpp b/Source/JavaScriptCore/runtime/JSGlobalObject.cpp
index 8c8aa9079..86186b7e1 100644
--- a/Source/JavaScriptCore/runtime/JSGlobalObject.cpp
+++ b/Source/JavaScriptCore/runtime/JSGlobalObject.cpp
@@ -244,8 +244,8 @@ void JSGlobalObject::reset(JSValue prototype)
m_methodCallDummy.set(exec->globalData(), this, constructEmptyObject(exec));
- ErrorPrototype* errorPrototype = ErrorPrototype::create(exec, this, ErrorPrototype::createStructure(exec->globalData(), this, m_objectPrototype.get()));
- m_errorStructure.set(exec->globalData(), this, ErrorInstance::createStructure(exec->globalData(), this, errorPrototype));
+ m_errorPrototype.set(exec->globalData(), this, ErrorPrototype::create(exec, this, ErrorPrototype::createStructure(exec->globalData(), this, m_objectPrototype.get())));
+ m_errorStructure.set(exec->globalData(), this, ErrorInstance::createStructure(exec->globalData(), this, m_errorPrototype.get()));
// Constructors
@@ -259,9 +259,9 @@ void JSGlobalObject::reset(JSValue prototype)
m_regExpConstructor.set(exec->globalData(), this, RegExpConstructor::create(exec, this, RegExpConstructor::createStructure(exec->globalData(), this, m_functionPrototype.get()), m_regExpPrototype.get()));
- m_errorConstructor.set(exec->globalData(), this, ErrorConstructor::create(exec, this, ErrorConstructor::createStructure(exec->globalData(), this, m_functionPrototype.get()), errorPrototype));
+ m_errorConstructor.set(exec->globalData(), this, ErrorConstructor::create(exec, this, ErrorConstructor::createStructure(exec->globalData(), this, m_functionPrototype.get()), m_errorPrototype.get()));
- Structure* nativeErrorPrototypeStructure = NativeErrorPrototype::createStructure(exec->globalData(), this, errorPrototype);
+ Structure* nativeErrorPrototypeStructure = NativeErrorPrototype::createStructure(exec->globalData(), this, m_errorPrototype.get());
Structure* nativeErrorStructure = NativeErrorConstructor::createStructure(exec->globalData(), this, m_functionPrototype.get());
m_evalErrorConstructor.set(exec->globalData(), this, NativeErrorConstructor::create(exec, this, nativeErrorStructure, nativeErrorPrototypeStructure, "EvalError"));
m_rangeErrorConstructor.set(exec->globalData(), this, NativeErrorConstructor::create(exec, this, nativeErrorStructure, nativeErrorPrototypeStructure, "RangeError"));
@@ -278,7 +278,7 @@ void JSGlobalObject::reset(JSValue prototype)
m_numberPrototype->putDirectWithoutTransition(exec->globalData(), exec->propertyNames().constructor, numberConstructor, DontEnum);
m_datePrototype->putDirectWithoutTransition(exec->globalData(), exec->propertyNames().constructor, dateConstructor, DontEnum);
m_regExpPrototype->putDirectWithoutTransition(exec->globalData(), exec->propertyNames().constructor, m_regExpConstructor.get(), DontEnum);
- errorPrototype->putDirectWithoutTransition(exec->globalData(), exec->propertyNames().constructor, m_errorConstructor.get(), DontEnum);
+ m_errorPrototype->putDirectWithoutTransition(exec->globalData(), exec->propertyNames().constructor, m_errorConstructor.get(), DontEnum);
putDirectWithoutTransition(exec->globalData(), Identifier(exec, "Object"), objectConstructor, DontEnum);
putDirectWithoutTransition(exec->globalData(), Identifier(exec, "Function"), functionConstructor, DontEnum);
@@ -374,6 +374,7 @@ void JSGlobalObject::visitChildren(JSCell* cell, SlotVisitor& visitor)
visitIfNeeded(visitor, &thisObject->m_numberPrototype);
visitIfNeeded(visitor, &thisObject->m_datePrototype);
visitIfNeeded(visitor, &thisObject->m_regExpPrototype);
+ visitIfNeeded(visitor, &thisObject->m_errorPrototype);
visitIfNeeded(visitor, &thisObject->m_argumentsStructure);
visitIfNeeded(visitor, &thisObject->m_arrayStructure);
@@ -389,6 +390,7 @@ void JSGlobalObject::visitChildren(JSCell* cell, SlotVisitor& visitor)
visitIfNeeded(visitor, &thisObject->m_boundFunctionStructure);
visitIfNeeded(visitor, &thisObject->m_namedFunctionStructure);
visitIfNeeded(visitor, &thisObject->m_numberObjectStructure);
+ visitIfNeeded(visitor, &thisObject->m_privateNameStructure);
visitIfNeeded(visitor, &thisObject->m_regExpMatchesArrayStructure);
visitIfNeeded(visitor, &thisObject->m_regExpStructure);
visitIfNeeded(visitor, &thisObject->m_stringObjectStructure);
diff --git a/Source/JavaScriptCore/runtime/JSGlobalObject.h b/Source/JavaScriptCore/runtime/JSGlobalObject.h
index 59b49755b..1e75b7267 100644
--- a/Source/JavaScriptCore/runtime/JSGlobalObject.h
+++ b/Source/JavaScriptCore/runtime/JSGlobalObject.h
@@ -41,6 +41,7 @@ namespace JSC {
class DatePrototype;
class Debugger;
class ErrorConstructor;
+ class ErrorPrototype;
class FunctionPrototype;
class GetterSetter;
class GlobalCodeBlock;
@@ -117,6 +118,7 @@ namespace JSC {
WriteBarrier<NumberPrototype> m_numberPrototype;
WriteBarrier<DatePrototype> m_datePrototype;
WriteBarrier<RegExpPrototype> m_regExpPrototype;
+ WriteBarrier<ErrorPrototype> m_errorPrototype;
WriteBarrier<Structure> m_argumentsStructure;
WriteBarrier<Structure> m_arrayStructure;
@@ -252,6 +254,7 @@ namespace JSC {
NumberPrototype* numberPrototype() const { return m_numberPrototype.get(); }
DatePrototype* datePrototype() const { return m_datePrototype.get(); }
RegExpPrototype* regExpPrototype() const { return m_regExpPrototype.get(); }
+ ErrorPrototype* errorPrototype() const { return m_errorPrototype.get(); }
JSObject* methodCallDummy() const { return m_methodCallDummy.get(); }
diff --git a/Source/JavaScriptCore/runtime/JSONObject.cpp b/Source/JavaScriptCore/runtime/JSONObject.cpp
index de9977d6e..065ae3828 100644
--- a/Source/JavaScriptCore/runtime/JSONObject.cpp
+++ b/Source/JavaScriptCore/runtime/JSONObject.cpp
@@ -471,6 +471,9 @@ inline Stringifier::Holder::Holder(JSGlobalData& globalData, JSObject* object)
: m_object(globalData, object)
, m_isArray(object->inherits(&JSArray::s_info))
, m_index(0)
+#ifndef NDEBUG
+ , m_size(0)
+#endif
{
}
diff --git a/Source/JavaScriptCore/runtime/JSString.h b/Source/JavaScriptCore/runtime/JSString.h
index 5079e8583..111853c39 100644
--- a/Source/JavaScriptCore/runtime/JSString.h
+++ b/Source/JavaScriptCore/runtime/JSString.h
@@ -200,9 +200,7 @@ namespace JSC {
{
if (m_index == JSRopeString::s_maxInternalRopeLength)
expand();
- m_jsString->m_fibers[m_index++].set(m_globalData, m_jsString, jsString);
- m_jsString->m_length += jsString->m_length;
- m_jsString->m_is8Bit = m_jsString->m_is8Bit && jsString->m_is8Bit;
+ m_jsString->append(m_globalData, m_index++, jsString);
}
JSRopeString* release()
@@ -252,6 +250,13 @@ namespace JSC {
JSString::finishCreation(globalData);
}
+ void append(JSGlobalData& globalData, size_t index, JSString* jsString)
+ {
+ m_fibers[index].set(globalData, this, jsString);
+ m_length += jsString->m_length;
+ m_is8Bit = m_is8Bit && jsString->m_is8Bit;
+ }
+
static JSRopeString* createNull(JSGlobalData& globalData)
{
JSRopeString* newString = new (NotNull, allocateCell<JSRopeString>(globalData.heap)) JSRopeString(globalData);
diff --git a/Source/JavaScriptCore/runtime/WeakGCMap.h b/Source/JavaScriptCore/runtime/WeakGCMap.h
index 98483c312..9e8db4d60 100644
--- a/Source/JavaScriptCore/runtime/WeakGCMap.h
+++ b/Source/JavaScriptCore/runtime/WeakGCMap.h
@@ -69,7 +69,10 @@ public:
ExternalType get(const KeyType& key) const
{
- return HandleTypes<MappedType>::getFromSlot(const_cast<JSValue*>(&m_map.get(key)->jsValue()));
+ WeakImpl* impl = m_map.get(key);
+ if (!impl || impl->state() != WeakImpl::Live)
+ return ExternalType();
+ return HandleTypes<MappedType>::getFromSlot(const_cast<JSValue*>(&impl->jsValue()));
}
void set(JSGlobalData&, const KeyType& key, ExternalType value)