diff options
Diffstat (limited to 'Source/JavaScriptCore')
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) |