diff --git a/LayoutTests/ChangeLog b/LayoutTests/ChangeLog index be5a725dd617971046937b6d3168a57a9646eefc..3e227e4e18b578a1fa1cfb5206ca980b8d31149c 100644 --- a/LayoutTests/ChangeLog +++ b/LayoutTests/ChangeLog @@ -1,3 +1,19 @@ +2013-12-04 Filip Pizlo + + Fold constant typed arrays + https://bugs.webkit.org/show_bug.cgi?id=125205 + + Reviewed by Oliver Hunt and Mark Hahnenberg. + + * js/regress/fixed-typed-array-storage-expected.txt: Added. + * js/regress/fixed-typed-array-storage-var-index-expected.txt: Added. + * js/regress/fixed-typed-array-storage-var-index.html: Added. + * js/regress/fixed-typed-array-storage.html: Added. + * js/regress/script-tests/fixed-typed-array-storage-var-index.js: Added. + (foo): + * js/regress/script-tests/fixed-typed-array-storage.js: Added. + (foo): + 2013-12-04 Zoltan Horvath [CSS Shapes] Support inset for shape-outside diff --git a/LayoutTests/js/regress/fixed-typed-array-storage-expected.txt b/LayoutTests/js/regress/fixed-typed-array-storage-expected.txt new file mode 100644 index 0000000000000000000000000000000000000000..33f09f3c1bf52d74c70c37b97c6bd6975524aca8 --- /dev/null +++ b/LayoutTests/js/regress/fixed-typed-array-storage-expected.txt @@ -0,0 +1,10 @@ +JSRegress/fixed-typed-array-storage + +On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE". + + +PASS no exception thrown +PASS successfullyParsed is true + +TEST COMPLETE + diff --git a/LayoutTests/js/regress/fixed-typed-array-storage-var-index-expected.txt b/LayoutTests/js/regress/fixed-typed-array-storage-var-index-expected.txt new file mode 100644 index 0000000000000000000000000000000000000000..e3d0e610f674eaad23498bedece2d2855543cb79 --- /dev/null +++ b/LayoutTests/js/regress/fixed-typed-array-storage-var-index-expected.txt @@ -0,0 +1,10 @@ +JSRegress/fixed-typed-array-storage-var-index + +On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE". + + +PASS no exception thrown +PASS successfullyParsed is true + +TEST COMPLETE + diff --git a/LayoutTests/js/regress/fixed-typed-array-storage-var-index.html b/LayoutTests/js/regress/fixed-typed-array-storage-var-index.html new file mode 100644 index 0000000000000000000000000000000000000000..9635c22ee84dda491eae219f6b729f323d77c9ad --- /dev/null +++ b/LayoutTests/js/regress/fixed-typed-array-storage-var-index.html @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/LayoutTests/js/regress/fixed-typed-array-storage.html b/LayoutTests/js/regress/fixed-typed-array-storage.html new file mode 100644 index 0000000000000000000000000000000000000000..fedfb19dc31d9537850dc275d8f1353601cb9fd1 --- /dev/null +++ b/LayoutTests/js/regress/fixed-typed-array-storage.html @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/LayoutTests/js/regress/script-tests/fixed-typed-array-storage-var-index.js b/LayoutTests/js/regress/script-tests/fixed-typed-array-storage-var-index.js new file mode 100644 index 0000000000000000000000000000000000000000..1c58c37e1db2dd560f1bd504355ccf51aae61077 --- /dev/null +++ b/LayoutTests/js/regress/script-tests/fixed-typed-array-storage-var-index.js @@ -0,0 +1,10 @@ +var array = new Int8Array(new ArrayBuffer(100)); + +function foo(i) { + return array[i]; +} + +for (var i = 0; i < 100000; ++i) { + if (foo(i % 100) != 0) + throw "Error"; +} diff --git a/LayoutTests/js/regress/script-tests/fixed-typed-array-storage.js b/LayoutTests/js/regress/script-tests/fixed-typed-array-storage.js new file mode 100644 index 0000000000000000000000000000000000000000..6a26ff141b0303fcac5bd5bc02ccd77703b73095 --- /dev/null +++ b/LayoutTests/js/regress/script-tests/fixed-typed-array-storage.js @@ -0,0 +1,10 @@ +var array = new Int8Array(new ArrayBuffer(100)); + +function foo() { + return array[0]; +} + +for (var i = 0; i < 100000; ++i) { + if (foo() != 0) + throw "Error"; +} diff --git a/Source/JavaScriptCore/CMakeLists.txt b/Source/JavaScriptCore/CMakeLists.txt index 92656c330608ec28d68f53561a931c1022e91117..690939dea5aadd5f28344f4942cbcadebcb42524 100644 --- a/Source/JavaScriptCore/CMakeLists.txt +++ b/Source/JavaScriptCore/CMakeLists.txt @@ -281,6 +281,7 @@ set(JavaScriptCore_SOURCES runtime/ArgumentsIteratorConstructor.cpp runtime/ArgumentsIteratorPrototype.cpp runtime/ArrayBuffer.cpp + runtime/ArrayBufferNeuteringWatchpoint.cpp runtime/ArrayBufferView.cpp runtime/ArrayConstructor.cpp runtime/ArrayIteratorConstructor.cpp diff --git a/Source/JavaScriptCore/ChangeLog b/Source/JavaScriptCore/ChangeLog index 00b9630d75edf532ed6aa3be82eafe8363a5a01d..9e9d396c22998988bf82c78a67d6430ef0311b3e 100644 --- a/Source/JavaScriptCore/ChangeLog +++ b/Source/JavaScriptCore/ChangeLog @@ -1,3 +1,80 @@ +2013-12-04 Filip Pizlo + + Fold constant typed arrays + https://bugs.webkit.org/show_bug.cgi?id=125205 + + Reviewed by Oliver Hunt and Mark Hahnenberg. + + If by some other mechanism we have a typed array access on a compile-time constant + typed array pointer, then fold: + + - Array bounds checks. Specifically, fold the load of length. + + - Loading the vector. + + This needs to install a watchpoint on the array itself because of the possibility of + neutering. Neutering is ridiculous. We do this without bloating the size of + ArrayBuffer or JSArrayBufferView in the common case (i.e. the case where you + allocated an array that didn't end up becoming a compile-time constant). To install + the watchpoint, we slowDownAndWasteMemory and then create an incoming reference to + the ArrayBuffer, where that incoming reference is from a watchpoint object. The + ArrayBuffer already knows about such incoming references and can fire the + watchpoints that way. + + * CMakeLists.txt: + * GNUmakefile.list.am: + * JavaScriptCore.vcxproj/JavaScriptCore.vcxproj: + * JavaScriptCore.xcodeproj/project.pbxproj: + * dfg/DFGDesiredWatchpoints.cpp: + (JSC::DFG::ArrayBufferViewWatchpointAdaptor::add): + (JSC::DFG::DesiredWatchpoints::addLazily): + * dfg/DFGDesiredWatchpoints.h: + (JSC::DFG::GenericSetAdaptor::add): + (JSC::DFG::GenericSetAdaptor::hasBeenInvalidated): + (JSC::DFG::ArrayBufferViewWatchpointAdaptor::hasBeenInvalidated): + (JSC::DFG::GenericDesiredWatchpoints::reallyAdd): + (JSC::DFG::GenericDesiredWatchpoints::areStillValid): + (JSC::DFG::GenericDesiredWatchpoints::isStillValid): + (JSC::DFG::GenericDesiredWatchpoints::shouldAssumeMixedState): + (JSC::DFG::DesiredWatchpoints::isStillValid): + (JSC::DFG::DesiredWatchpoints::shouldAssumeMixedState): + (JSC::DFG::DesiredWatchpoints::isValidOrMixed): + * dfg/DFGGraph.cpp: + (JSC::DFG::Graph::tryGetFoldableView): + * dfg/DFGGraph.h: + * dfg/DFGSpeculativeJIT.cpp: + (JSC::DFG::SpeculativeJIT::jumpForTypedArrayOutOfBounds): + (JSC::DFG::SpeculativeJIT::emitTypedArrayBoundsCheck): + (JSC::DFG::SpeculativeJIT::compileGetByValOnIntTypedArray): + (JSC::DFG::SpeculativeJIT::compilePutByValForIntTypedArray): + (JSC::DFG::SpeculativeJIT::compileGetByValOnFloatTypedArray): + (JSC::DFG::SpeculativeJIT::compilePutByValForFloatTypedArray): + (JSC::DFG::SpeculativeJIT::compileConstantIndexedPropertyStorage): + (JSC::DFG::SpeculativeJIT::compileGetIndexedPropertyStorage): + * dfg/DFGSpeculativeJIT.h: + * dfg/DFGWatchpointCollectionPhase.cpp: + (JSC::DFG::WatchpointCollectionPhase::handle): + (JSC::DFG::WatchpointCollectionPhase::addLazily): + * ftl/FTLLowerDFGToLLVM.cpp: + (JSC::FTL::LowerDFGToLLVM::compileGetIndexedPropertyStorage): + (JSC::FTL::LowerDFGToLLVM::compileGetByVal): + (JSC::FTL::LowerDFGToLLVM::compilePutByVal): + (JSC::FTL::LowerDFGToLLVM::typedArrayLength): + * runtime/ArrayBuffer.cpp: + (JSC::ArrayBuffer::transfer): + * runtime/ArrayBufferNeuteringWatchpoint.cpp: Added. + (JSC::ArrayBufferNeuteringWatchpoint::ArrayBufferNeuteringWatchpoint): + (JSC::ArrayBufferNeuteringWatchpoint::~ArrayBufferNeuteringWatchpoint): + (JSC::ArrayBufferNeuteringWatchpoint::finishCreation): + (JSC::ArrayBufferNeuteringWatchpoint::destroy): + (JSC::ArrayBufferNeuteringWatchpoint::create): + (JSC::ArrayBufferNeuteringWatchpoint::createStructure): + * runtime/ArrayBufferNeuteringWatchpoint.h: Added. + (JSC::ArrayBufferNeuteringWatchpoint::set): + * runtime/VM.cpp: + (JSC::VM::VM): + * runtime/VM.h: + 2013-12-04 Commit Queue Unreviewed, rolling out r160116. diff --git a/Source/JavaScriptCore/GNUmakefile.list.am b/Source/JavaScriptCore/GNUmakefile.list.am index e1929b8b0983eaeb43583fccfb2749ed59d008db..7faabbeddc2022f44b78ec0d3a5e6dccab35d4a7 100644 --- a/Source/JavaScriptCore/GNUmakefile.list.am +++ b/Source/JavaScriptCore/GNUmakefile.list.am @@ -782,6 +782,8 @@ javascriptcore_sources += \ Source/JavaScriptCore/runtime/ArgumentsIteratorPrototype.h \ Source/JavaScriptCore/runtime/ArrayBuffer.cpp \ Source/JavaScriptCore/runtime/ArrayBuffer.h \ + Source/JavaScriptCore/runtime/ArrayBufferNeuteringWatchpoint.cpp \ + Source/JavaScriptCore/runtime/ArrayBufferNeuteringWatchpoint.h \ Source/JavaScriptCore/runtime/ArrayBufferView.cpp \ Source/JavaScriptCore/runtime/ArrayBufferView.h \ Source/JavaScriptCore/runtime/ArrayConstructor.cpp \ diff --git a/Source/JavaScriptCore/JavaScriptCore.vcxproj/JavaScriptCore.vcxproj b/Source/JavaScriptCore/JavaScriptCore.vcxproj/JavaScriptCore.vcxproj index 0f60fce7efd6c37c4b76d72c9d62172ef4e20228..5367076d81b98c7d63b4585cc802fdea1164ff30 100644 --- a/Source/JavaScriptCore/JavaScriptCore.vcxproj/JavaScriptCore.vcxproj +++ b/Source/JavaScriptCore/JavaScriptCore.vcxproj/JavaScriptCore.vcxproj @@ -524,6 +524,7 @@ + @@ -1090,6 +1091,7 @@ + diff --git a/Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj b/Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj index 0ac18981e8a2d99dc70dbc7bf06804c29f77cc70..92157e64da8c7ec01ba69c1d22f9af1ad53e1db9 100644 --- a/Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj +++ b/Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj @@ -541,6 +541,8 @@ 0FFB921E16D02F470055A5DB /* DFGVariadicFunction.h in Headers */ = {isa = PBXBuildFile; fileRef = 0F85A31E16AB76AE0077571E /* DFGVariadicFunction.h */; settings = {ATTRIBUTES = (Private, ); }; }; 0FFB921F16D033050055A5DB /* (null) in Headers */ = {isa = PBXBuildFile; settings = {ATTRIBUTES = (Private, ); }; }; 0FFB922016D033B70055A5DB /* NodeConstructors.h in Headers */ = {isa = PBXBuildFile; fileRef = 930DAD030FB1EB1A0082D205 /* NodeConstructors.h */; settings = {ATTRIBUTES = (Private, ); }; }; + 0FFC99D4184EE318009C10AB /* ArrayBufferNeuteringWatchpoint.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0FFC99D2184EE318009C10AB /* ArrayBufferNeuteringWatchpoint.cpp */; }; + 0FFC99D5184EE318009C10AB /* ArrayBufferNeuteringWatchpoint.h in Headers */ = {isa = PBXBuildFile; fileRef = 0FFC99D3184EE318009C10AB /* ArrayBufferNeuteringWatchpoint.h */; settings = {ATTRIBUTES = (Private, ); }; }; 0FFC99D1184EC8AD009C10AB /* ConstantMode.h in Headers */ = {isa = PBXBuildFile; fileRef = 0FFC99D0184EC8AD009C10AB /* ConstantMode.h */; settings = {ATTRIBUTES = (Private, ); }; }; 0FFFC95714EF90A000C72532 /* DFGCFAPhase.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0FFFC94B14EF909500C72532 /* DFGCFAPhase.cpp */; }; 0FFFC95814EF90A200C72532 /* DFGCFAPhase.h in Headers */ = {isa = PBXBuildFile; fileRef = 0FFFC94C14EF909500C72532 /* DFGCFAPhase.h */; settings = {ATTRIBUTES = (Private, ); }; }; @@ -1846,6 +1848,8 @@ 0FF729A1166AD347000F5BA3 /* ProfilerOriginStack.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = ProfilerOriginStack.cpp; path = profiler/ProfilerOriginStack.cpp; sourceTree = ""; }; 0FF729A2166AD347000F5BA3 /* ProfilerOriginStack.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ProfilerOriginStack.h; path = profiler/ProfilerOriginStack.h; sourceTree = ""; }; 0FF922CF14F46B130041A24E /* JSCLLIntOffsetsExtractor */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = JSCLLIntOffsetsExtractor; sourceTree = BUILT_PRODUCTS_DIR; }; + 0FFC99D2184EE318009C10AB /* ArrayBufferNeuteringWatchpoint.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ArrayBufferNeuteringWatchpoint.cpp; sourceTree = ""; }; + 0FFC99D3184EE318009C10AB /* ArrayBufferNeuteringWatchpoint.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ArrayBufferNeuteringWatchpoint.h; sourceTree = ""; }; 0FFC99D0184EC8AD009C10AB /* ConstantMode.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ConstantMode.h; sourceTree = ""; }; 0FFFC94B14EF909500C72532 /* DFGCFAPhase.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = DFGCFAPhase.cpp; path = dfg/DFGCFAPhase.cpp; sourceTree = ""; }; 0FFFC94C14EF909500C72532 /* DFGCFAPhase.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DFGCFAPhase.h; path = dfg/DFGCFAPhase.h; sourceTree = ""; }; @@ -3366,6 +3370,8 @@ A76140CA182982CB00750624 /* ArgumentsIteratorPrototype.h */, A7A8AF2517ADB5F2005AB174 /* ArrayBuffer.cpp */, A7A8AF2617ADB5F3005AB174 /* ArrayBuffer.h */, + 0FFC99D2184EE318009C10AB /* ArrayBufferNeuteringWatchpoint.cpp */, + 0FFC99D3184EE318009C10AB /* ArrayBufferNeuteringWatchpoint.h */, A7A8AF2717ADB5F3005AB174 /* ArrayBufferView.cpp */, A7A8AF2817ADB5F3005AB174 /* ArrayBufferView.h */, BC7952060E15E8A800A898AB /* ArrayConstructor.cpp */, @@ -4478,6 +4484,7 @@ A7A8AF3817ADB5F3005AB174 /* Float32Array.h in Headers */, A7A8AF3917ADB5F3005AB174 /* Float64Array.h in Headers */, 0F24E54317EA9F5900ABB217 /* FPRInfo.h in Headers */, + 0FFC99D5184EE318009C10AB /* ArrayBufferNeuteringWatchpoint.h in Headers */, 0FDB2CC9173DA520007B3C1B /* FTLAbbreviatedTypes.h in Headers */, 0FEA0A08170513DB00BB722C /* FTLAbbreviations.h in Headers */, 0FEA0A1D1708B00700BB722C /* FTLAbstractHeap.h in Headers */, @@ -5641,6 +5648,7 @@ 1428083A107EC0750013E7B2 /* JSStack.cpp in Sources */, 147F39D5107EC37600427A48 /* JSString.cpp in Sources */, 2600B5A6152BAAA70091EE5F /* JSStringJoiner.cpp in Sources */, + 0FFC99D4184EE318009C10AB /* ArrayBufferNeuteringWatchpoint.cpp in Sources */, 1482B74E0A43032800517CFC /* JSStringRef.cpp in Sources */, 146AAB380B66A94400E55F16 /* JSStringRefCF.cpp in Sources */, 0F919D0C157EE09F004A4E7D /* JSSymbolTableObject.cpp in Sources */, diff --git a/Source/JavaScriptCore/dfg/DFGDesiredWatchpoints.cpp b/Source/JavaScriptCore/dfg/DFGDesiredWatchpoints.cpp index bfc50b670753c3e011d3a20316fd7f5dc49672eb..80400cb265448edb3c002d75bcec6c5ab08dbc40 100644 --- a/Source/JavaScriptCore/dfg/DFGDesiredWatchpoints.cpp +++ b/Source/JavaScriptCore/dfg/DFGDesiredWatchpoints.cpp @@ -28,8 +28,22 @@ #if ENABLE(DFG_JIT) +#include "ArrayBufferNeuteringWatchpoint.h" +#include "CodeBlock.h" +#include "Operations.h" + namespace JSC { namespace DFG { +void ArrayBufferViewWatchpointAdaptor::add( + CodeBlock* codeBlock, JSArrayBufferView* view, Watchpoint* watchpoint) +{ + ArrayBufferNeuteringWatchpoint* neuteringWatchpoint = + ArrayBufferNeuteringWatchpoint::create(*codeBlock->vm()); + neuteringWatchpoint->set()->add(watchpoint); + codeBlock->addConstant(neuteringWatchpoint); + codeBlock->vm()->heap.addReference(neuteringWatchpoint, view->buffer()); +} + DesiredWatchpoints::DesiredWatchpoints() { } DesiredWatchpoints::~DesiredWatchpoints() { } @@ -43,6 +57,11 @@ void DesiredWatchpoints::addLazily(InlineWatchpointSet& set) m_inlineSets.addLazily(&set); } +void DesiredWatchpoints::addLazily(JSArrayBufferView* view) +{ + m_bufferViews.addLazily(view); +} + void DesiredWatchpoints::addLazily(CodeOrigin codeOrigin, ExitKind exitKind, WatchpointSet* set) { m_sets.addLazily(codeOrigin, exitKind, set); @@ -57,11 +76,14 @@ void DesiredWatchpoints::reallyAdd(CodeBlock* codeBlock, CommonData& commonData) { m_sets.reallyAdd(codeBlock, commonData); m_inlineSets.reallyAdd(codeBlock, commonData); + m_bufferViews.reallyAdd(codeBlock, commonData); } bool DesiredWatchpoints::areStillValid() const { - return m_sets.areStillValid() && m_inlineSets.areStillValid(); + return m_sets.areStillValid() + && m_inlineSets.areStillValid() + && m_bufferViews.areStillValid(); } } } // namespace JSC::DFG diff --git a/Source/JavaScriptCore/dfg/DFGDesiredWatchpoints.h b/Source/JavaScriptCore/dfg/DFGDesiredWatchpoints.h index 909bd93eaab1496d5f0fd64af019f8fa5c7e738f..64e88c7649bb5c18ea46f175e98b6011a8f82e45 100644 --- a/Source/JavaScriptCore/dfg/DFGDesiredWatchpoints.h +++ b/Source/JavaScriptCore/dfg/DFGDesiredWatchpoints.h @@ -32,6 +32,7 @@ #include "CodeOrigin.h" #include "DFGCommonData.h" +#include "JSArrayBufferView.h" #include "Watchpoint.h" #include #include @@ -61,7 +62,26 @@ struct WatchpointForGenericWatchpointSet { WatchpointSetType* m_set; }; -template +template +struct GenericSetAdaptor { + static void add(CodeBlock*, T* set, Watchpoint* watchpoint) + { + return set->add(watchpoint); + } + static bool hasBeenInvalidated(T* set) { return set->hasBeenInvalidated(); } +}; + +struct ArrayBufferViewWatchpointAdaptor { + static void add(CodeBlock*, JSArrayBufferView*, Watchpoint*); + static bool hasBeenInvalidated(JSArrayBufferView* view) + { + bool result = !view->length(); + WTF::loadLoadFence(); + return result; + } +}; + +template> class GenericDesiredWatchpoints { WTF_MAKE_NONCOPYABLE(GenericDesiredWatchpoints); #if !ASSERT_DISABLED @@ -92,7 +112,7 @@ public: typename HashSet::iterator end = m_sets.end(); for (; iter != end; ++iter) { common.watchpoints.append(CodeBlockJettisoningWatchpoint(codeBlock)); - (*iter)->add(&common.watchpoints.last()); + Adaptor::add(codeBlock, *iter, &common.watchpoints.last()); } for (unsigned i = m_profiledWatchpoints.size(); i--;) { @@ -100,7 +120,7 @@ public: m_profiledWatchpoints[i]; common.profiledWatchpoints.append( ProfiledCodeBlockJettisoningWatchpoint(watchpoint.m_codeOrigin, watchpoint.m_exitKind, codeBlock)); - watchpoint.m_set->add(&common.profiledWatchpoints.last()); + Adaptor::add(codeBlock, watchpoint.m_set, &common.profiledWatchpoints.last()); } m_reallyAdded = true; @@ -111,12 +131,12 @@ public: typename HashSet::iterator iter = m_sets.begin(); typename HashSet::iterator end = m_sets.end(); for (; iter != end; ++iter) { - if ((*iter)->hasBeenInvalidated()) + if (Adaptor::hasBeenInvalidated(*iter)) return false; } for (unsigned i = m_profiledWatchpoints.size(); i--;) { - if (m_profiledWatchpoints[i].m_set->hasBeenInvalidated()) + if (Adaptor::hasBeenInvalidated(m_profiledWatchpoints[i].m_set)) return false; } @@ -126,7 +146,7 @@ public: #if ASSERT_DISABLED bool isStillValid(WatchpointSetType* set) { - return set->isStillValid(); + return !Adaptor::hasBeenInvalidated(set); } bool shouldAssumeMixedState(WatchpointSetType*) @@ -136,7 +156,7 @@ public: #else bool isStillValid(WatchpointSetType* set) { - bool result = set->isStillValid(); + bool result = !Adaptor::hasBeenInvalidated(set); m_firstKnownState.add(set, result); return result; } @@ -147,7 +167,7 @@ public: if (iter == m_firstKnownState.end()) return false; - return iter->value != set->isStillValid(); + return iter->value != !Adaptor::hasBeenInvalidated(set); } #endif @@ -172,6 +192,7 @@ public: void addLazily(WatchpointSet*); void addLazily(InlineWatchpointSet&); + void addLazily(JSArrayBufferView*); void addLazily(CodeOrigin, ExitKind, WatchpointSet*); void addLazily(CodeOrigin, ExitKind, InlineWatchpointSet&); @@ -187,6 +208,10 @@ public: { return m_inlineSets.isStillValid(&set); } + bool isStillValid(JSArrayBufferView* view) + { + return m_bufferViews.isStillValid(view); + } bool shouldAssumeMixedState(WatchpointSet* set) { return m_sets.shouldAssumeMixedState(set); @@ -195,6 +220,10 @@ public: { return m_inlineSets.shouldAssumeMixedState(&set); } + bool shouldAssumeMixedState(JSArrayBufferView* view) + { + return m_bufferViews.shouldAssumeMixedState(view); + } bool isValidOrMixed(WatchpointSet* set) { return m_sets.isValidOrMixed(set); @@ -203,10 +232,15 @@ public: { return m_inlineSets.isValidOrMixed(&set); } + bool isValidOrMixed(JSArrayBufferView* view) + { + return m_bufferViews.isValidOrMixed(view); + } private: GenericDesiredWatchpoints m_sets; GenericDesiredWatchpoints m_inlineSets; + GenericDesiredWatchpoints m_bufferViews; }; } } // namespace JSC::DFG diff --git a/Source/JavaScriptCore/dfg/DFGGraph.cpp b/Source/JavaScriptCore/dfg/DFGGraph.cpp index a3581eda366fd613c3046d5f05a65dc803b8507f..3b30edf93507295558301ab45ad5fe096e3db9c6 100644 --- a/Source/JavaScriptCore/dfg/DFGGraph.cpp +++ b/Source/JavaScriptCore/dfg/DFGGraph.cpp @@ -740,6 +740,20 @@ WriteBarrierBase* Graph::tryGetRegisters(Node* node) return activation->registers(); } +JSArrayBufferView* Graph::tryGetFoldableView(Node* node, ArrayMode arrayMode) +{ + if (arrayMode.typedArrayType() == NotTypedArray) + return 0; + if (!node->hasConstant()) + return 0; + JSArrayBufferView* view = jsDynamicCast(valueOfJSConstant(node)); + if (!view) + return 0; + if (!watchpoints().isStillValid(view)) + return 0; + return view; +} + } } // namespace JSC::DFG #endif diff --git a/Source/JavaScriptCore/dfg/DFGGraph.h b/Source/JavaScriptCore/dfg/DFGGraph.h index 31ee5b081da02fb7148445504a5dfa0d9d81a3ed..ba73ac9f84b2bfe12316f21bb6c33ccc4d5de4d0 100644 --- a/Source/JavaScriptCore/dfg/DFGGraph.h +++ b/Source/JavaScriptCore/dfg/DFGGraph.h @@ -794,6 +794,8 @@ public: JSActivation* tryGetActivation(Node*); WriteBarrierBase* tryGetRegisters(Node*); + JSArrayBufferView* tryGetFoldableView(Node*, ArrayMode); + VM& m_vm; Plan& m_plan; CodeBlock* m_codeBlock; diff --git a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp index 64d7abfef624f02fb57e479e50efeed49cf01879..2b86e08db6b319a109c4f53a8a853ab658d23f8a 100644 --- a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp +++ b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp @@ -2325,6 +2325,31 @@ static void compileClampDoubleToByte(JITCompiler& jit, GPRReg result, FPRReg sou } +JITCompiler::Jump SpeculativeJIT::jumpForTypedArrayOutOfBounds(Node* node, GPRReg baseGPR, GPRReg indexGPR) +{ + if (node->op() == PutByValAlias) + return JITCompiler::Jump(); + if (JSArrayBufferView* view = m_jit.graph().tryGetFoldableView(m_jit.graph().child(node, 0).node(), node->arrayMode())) { + uint32_t length = view->length(); + Node* indexNode = m_jit.graph().child(node, 1).node(); + if (m_jit.graph().isInt32Constant(indexNode) && static_cast(m_jit.graph().valueOfInt32Constant(indexNode)) < length) + return JITCompiler::Jump(); + return m_jit.branch32( + MacroAssembler::AboveOrEqual, indexGPR, MacroAssembler::Imm32(length)); + } + return m_jit.branch32( + MacroAssembler::AboveOrEqual, indexGPR, + MacroAssembler::Address(baseGPR, JSArrayBufferView::offsetOfLength())); +} + +void SpeculativeJIT::emitTypedArrayBoundsCheck(Node* node, GPRReg baseGPR, GPRReg indexGPR) +{ + JITCompiler::Jump jump = jumpForTypedArrayOutOfBounds(node, baseGPR, indexGPR); + if (!jump.isSet()) + return; + speculationCheck(OutOfBounds, JSValueRegs(), 0, jump); +} + void SpeculativeJIT::compileGetByValOnIntTypedArray(Node* node, TypedArrayType type) { ASSERT(isInt(type)); @@ -2342,11 +2367,7 @@ void SpeculativeJIT::compileGetByValOnIntTypedArray(Node* node, TypedArrayType t ASSERT(node->arrayMode().alreadyChecked(m_jit.graph(), node, m_state.forNode(node->child1()))); - speculationCheck( - Uncountable, JSValueRegs(), 0, - m_jit.branch32( - MacroAssembler::AboveOrEqual, propertyReg, - MacroAssembler::Address(baseReg, JSArrayBufferView::offsetOfLength()))); + emitTypedArrayBoundsCheck(node, baseReg, propertyReg); switch (elementSize(type)) { case 1: if (isSigned(type)) @@ -2509,9 +2530,7 @@ void SpeculativeJIT::compilePutByValForIntTypedArray(GPRReg base, GPRReg propert ASSERT_UNUSED(valueGPR, valueGPR != property); ASSERT(valueGPR != base); ASSERT(valueGPR != storageReg); - MacroAssembler::Jump outOfBounds; - if (node->op() == PutByVal) - outOfBounds = m_jit.branch32(MacroAssembler::AboveOrEqual, property, MacroAssembler::Address(base, JSArrayBufferView::offsetOfLength())); + MacroAssembler::Jump outOfBounds = jumpForTypedArrayOutOfBounds(node, base, property); switch (elementSize(type)) { case 1: @@ -2526,7 +2545,7 @@ void SpeculativeJIT::compilePutByValForIntTypedArray(GPRReg base, GPRReg propert default: CRASH(); } - if (node->op() == PutByVal) + if (outOfBounds.isSet()) outOfBounds.link(&m_jit); noResult(node); } @@ -2547,11 +2566,7 @@ void SpeculativeJIT::compileGetByValOnFloatTypedArray(Node* node, TypedArrayType FPRTemporary result(this); FPRReg resultReg = result.fpr(); - speculationCheck( - Uncountable, JSValueRegs(), 0, - m_jit.branch32( - MacroAssembler::AboveOrEqual, propertyReg, - MacroAssembler::Address(baseReg, JSArrayBufferView::offsetOfLength()))); + emitTypedArrayBoundsCheck(node, baseReg, propertyReg); switch (elementSize(type)) { case 4: m_jit.loadFloat(MacroAssembler::BaseIndex(storageReg, propertyReg, MacroAssembler::TimesFour), resultReg); @@ -2590,12 +2605,7 @@ void SpeculativeJIT::compilePutByValForFloatTypedArray(GPRReg base, GPRReg prope ASSERT_UNUSED(baseUse, node->arrayMode().alreadyChecked(m_jit.graph(), node, m_state.forNode(baseUse))); - MacroAssembler::Jump outOfBounds; - if (node->op() == PutByVal) { - outOfBounds = m_jit.branch32( - MacroAssembler::AboveOrEqual, property, - MacroAssembler::Address(base, JSArrayBufferView::offsetOfLength())); - } + MacroAssembler::Jump outOfBounds = jumpForTypedArrayOutOfBounds(node, base, property); switch (elementSize(type)) { case 4: { @@ -2610,7 +2620,7 @@ void SpeculativeJIT::compilePutByValForFloatTypedArray(GPRReg base, GPRReg prope default: RELEASE_ASSERT_NOT_REACHED(); } - if (node->op() == PutByVal) + if (outOfBounds.isSet()) outOfBounds.link(&m_jit); noResult(node); } @@ -4035,8 +4045,27 @@ void SpeculativeJIT::compileStringZeroLength(Node* node) #endif } +bool SpeculativeJIT::compileConstantIndexedPropertyStorage(Node* node) +{ + JSArrayBufferView* view = m_jit.graph().tryGetFoldableView( + node->child1().node(), node->arrayMode()); + if (!view) + return false; + if (view->mode() == FastTypedArray) + return false; + + GPRTemporary storage(this); + GPRReg storageGPR = storage.gpr(); + m_jit.move(TrustedImmPtr(view->vector()), storageGPR); + storageResult(storageGPR, node); + return true; +} + void SpeculativeJIT::compileGetIndexedPropertyStorage(Node* node) { + if (compileConstantIndexedPropertyStorage(node)) + return; + SpeculateCellOperand base(this, node->child1()); GPRReg baseReg = base.gpr(); diff --git a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h index 66cafffe32cd1d966e0d7e0e390e4a5cd00013df..dcd8572c66db46f07d70125d9400de3c1d2f6ba2 100644 --- a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h +++ b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h @@ -2027,7 +2027,10 @@ public: void compileArithIMul(Node*); void compileArithDiv(Node*); void compileArithMod(Node*); + bool compileConstantIndexedPropertyStorage(Node*); void compileGetIndexedPropertyStorage(Node*); + JITCompiler::Jump jumpForTypedArrayOutOfBounds(Node*, GPRReg baseGPR, GPRReg indexGPR); + void emitTypedArrayBoundsCheck(Node*, GPRReg baseGPR, GPRReg indexGPR); void compileGetTypedArrayByteOffset(Node*); void compileGetByValOnIntTypedArray(Node*, TypedArrayType); void compilePutByValForIntTypedArray(GPRReg base, GPRReg property, Node*, TypedArrayType); diff --git a/Source/JavaScriptCore/dfg/DFGWatchpointCollectionPhase.cpp b/Source/JavaScriptCore/dfg/DFGWatchpointCollectionPhase.cpp index 4d4bf0b405597b47edc0ff486cfc52633cbc1c41..afb37e4395156b44fbcf04cce23f730e75312b52 100644 --- a/Source/JavaScriptCore/dfg/DFGWatchpointCollectionPhase.cpp +++ b/Source/JavaScriptCore/dfg/DFGWatchpointCollectionPhase.cpp @@ -94,6 +94,19 @@ private: if (m_node->arrayMode().type() == Array::String) handleStringGetByVal(); + + if (JSArrayBufferView* view = m_graph.tryGetFoldableView(m_node->child1().node(), m_node->arrayMode())) + addLazily(view); + break; + + case PutByVal: + if (JSArrayBufferView* view = m_graph.tryGetFoldableView(m_graph.varArgChild(m_node, 0).node(), m_node->arrayMode())) + addLazily(view); + break; + + case GetArrayLength: + if (JSArrayBufferView* view = m_graph.tryGetFoldableView(m_node->child1().node(), m_node->arrayMode())) + addLazily(view); break; case StringCharAt: @@ -130,6 +143,18 @@ private: addLazily(m_node->symbolTable()->m_functionEnteredOnce); break; + case GetIndexedPropertyStorage: + if (JSArrayBufferView* view = m_graph.tryGetFoldableView(m_node->child1().node(), m_node->arrayMode())) { + // FIXME: It would be awesome to be able to fold the property storage for + // these GC-allocated typed arrays. For now it doesn't matter because the + // most common use-cases for constant typed arrays involve large arrays with + // aliased buffer views. + if (view->mode() == FastTypedArray) + break; + addLazily(view); + } + break; + default: break; } @@ -179,6 +204,10 @@ private: { m_graph.watchpoints().addLazily(set); } + void addLazily(JSArrayBufferView* view) + { + m_graph.watchpoints().addLazily(view); + } JSGlobalObject* globalObject() { diff --git a/Source/JavaScriptCore/ftl/FTLLowerDFGToLLVM.cpp b/Source/JavaScriptCore/ftl/FTLLowerDFGToLLVM.cpp index 06aa8b20b1ebf695fe78c6725c1b85a5298f0246..024a15a72a7119db0c4d3379404ca85dfe62c988 100644 --- a/Source/JavaScriptCore/ftl/FTLLowerDFGToLLVM.cpp +++ b/Source/JavaScriptCore/ftl/FTLLowerDFGToLLVM.cpp @@ -1335,6 +1335,13 @@ private: return; } + if (JSArrayBufferView* view = m_graph.tryGetFoldableView(m_node->child1().node(), m_node->arrayMode())) { + if (view->mode() != FastTypedArray) { + setStorage(m_out.constIntPtr(view->vector())); + return; + } + } + setStorage(m_out.loadPtr(cell, m_heaps.JSArrayBufferView_vector)); } @@ -1451,12 +1458,10 @@ private: TypedArrayType type = m_node->arrayMode().typedArrayType(); if (isTypedView(type)) { - LValue array = lowCell(m_node->child1()); - speculate( OutOfBounds, noValue(), 0, m_out.aboveOrEqual( - index, m_out.load32(array, m_heaps.JSArrayBufferView_length))); + index, typedArrayLength(m_node->child1(), m_node->arrayMode()))); TypedPointer pointer = TypedPointer( m_heaps.typedArrayProperties, @@ -1624,7 +1629,8 @@ private: speculate( OutOfBounds, noValue(), 0, m_out.aboveOrEqual( - index, m_out.load32(base, m_heaps.JSArrayBufferView_length))); + index, + typedArrayLength(child1.node(), m_node->arrayMode(), base))); } TypedPointer pointer = TypedPointer( @@ -2765,6 +2771,18 @@ private: m_out.phi(m_out.intPtr, fastButterfly, slowButterfly)); } + LValue typedArrayLength(Node* baseNode, ArrayMode arrayMode, LValue base) + { + if (JSArrayBufferView* view = m_graph.tryGetFoldableView(baseNode, arrayMode)) + return m_out.constInt32(view->length()); + return m_out.load32(base, m_heaps.JSArrayBufferView_length); + } + + LValue typedArrayLength(Edge baseEdge, ArrayMode arrayMode) + { + return typedArrayLength(baseEdge.node(), arrayMode, lowCell(baseEdge)); + } + LValue boolify(Edge edge) { switch (edge.useKind()) { diff --git a/Source/JavaScriptCore/runtime/ArrayBuffer.cpp b/Source/JavaScriptCore/runtime/ArrayBuffer.cpp index a4322b2258748d4e4864e19f94c127507296a825..2c49b69767d77bb46cffab0c90953a7d3d7f4803 100644 --- a/Source/JavaScriptCore/runtime/ArrayBuffer.cpp +++ b/Source/JavaScriptCore/runtime/ArrayBuffer.cpp @@ -26,6 +26,7 @@ #include "config.h" #include "ArrayBuffer.h" +#include "ArrayBufferNeuteringWatchpoint.h" #include "JSArrayBufferView.h" #include "Operations.h" #include @@ -52,9 +53,11 @@ bool ArrayBuffer::transfer(ArrayBufferContents& result) } for (size_t i = numberOfIncomingReferences(); i--;) { - JSArrayBufferView* view = jsDynamicCast(incomingReferenceAt(i)); - if (view) + JSCell* cell = incomingReferenceAt(i); + if (JSArrayBufferView* view = jsDynamicCast(cell)) view->neuter(); + else if (ArrayBufferNeuteringWatchpoint* watchpoint = jsDynamicCast(cell)) + watchpoint->set()->fireAll(); } return true; } diff --git a/Source/JavaScriptCore/runtime/ArrayBufferNeuteringWatchpoint.cpp b/Source/JavaScriptCore/runtime/ArrayBufferNeuteringWatchpoint.cpp new file mode 100644 index 0000000000000000000000000000000000000000..b11a0ad3ae61dfaa138dbf4249a07602cb6e11d4 --- /dev/null +++ b/Source/JavaScriptCore/runtime/ArrayBufferNeuteringWatchpoint.cpp @@ -0,0 +1,64 @@ +/* + * Copyright (C) 2013 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "ArrayBufferNeuteringWatchpoint.h" + +#include "Operations.h" + +namespace JSC { + +const ClassInfo ArrayBufferNeuteringWatchpoint::s_info = { + "ArrayBufferNeuteringWatchpoint", 0, 0, 0, + CREATE_METHOD_TABLE(ArrayBufferNeuteringWatchpoint) +}; + +ArrayBufferNeuteringWatchpoint::ArrayBufferNeuteringWatchpoint(VM& vm) + : Base(vm, vm.arrayBufferNeuteringWatchpointStructure.get()) + , m_set(adoptRef(new WatchpointSet(IsWatched))) +{ +} + +void ArrayBufferNeuteringWatchpoint::destroy(JSCell* cell) +{ + static_cast(cell)->ArrayBufferNeuteringWatchpoint::~ArrayBufferNeuteringWatchpoint(); +} + +ArrayBufferNeuteringWatchpoint* ArrayBufferNeuteringWatchpoint::create(VM& vm) +{ + ArrayBufferNeuteringWatchpoint* result = new + (NotNull, allocateCell(vm.heap)) + ArrayBufferNeuteringWatchpoint(vm); + result->finishCreation(vm); + return result; +} + +Structure* ArrayBufferNeuteringWatchpoint::createStructure(VM& vm) +{ + return Structure::create(vm, 0, jsNull(), TypeInfo(CompoundType, StructureFlags), info()); +} + +} // namespace JSC + diff --git a/Source/JavaScriptCore/runtime/ArrayBufferNeuteringWatchpoint.h b/Source/JavaScriptCore/runtime/ArrayBufferNeuteringWatchpoint.h new file mode 100644 index 0000000000000000000000000000000000000000..96dbd69c77063b8d7952badda6496a68732a779c --- /dev/null +++ b/Source/JavaScriptCore/runtime/ArrayBufferNeuteringWatchpoint.h @@ -0,0 +1,60 @@ +/* + * Copyright (C) 2013 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef ArrayBufferNeuteringWatchpoint_h +#define ArrayBufferNeuteringWatchpoint_h + +#include "JSCell.h" +#include "Watchpoint.h" + +namespace JSC { + +class ArrayBufferNeuteringWatchpoint : public JSCell { +public: + typedef JSCell Base; + +private: + ArrayBufferNeuteringWatchpoint(VM&); + +public: + DECLARE_INFO; + + static ArrayBufferNeuteringWatchpoint* create(VM&); + + static const bool needsDestruction = true; + static const bool hasImmortalStructure = true; + static void destroy(JSCell*); + + static Structure* createStructure(VM&); + + WatchpointSet* set() { return m_set.get(); } + +private: + RefPtr m_set; +}; + +} // namespace JSC + +#endif // ArrayBufferNeuteringWatchpoint_h diff --git a/Source/JavaScriptCore/runtime/VM.cpp b/Source/JavaScriptCore/runtime/VM.cpp index 4548292905a0b75838eb90a2e296fd0117359110..61c05fafce939f369354d8a9a334a337c54d2563 100644 --- a/Source/JavaScriptCore/runtime/VM.cpp +++ b/Source/JavaScriptCore/runtime/VM.cpp @@ -30,6 +30,7 @@ #include "VM.h" #include "ArgList.h" +#include "ArrayBufferNeuteringWatchpoint.h" #include "CallFrameInlines.h" #include "CodeBlock.h" #include "CodeCache.h" @@ -248,6 +249,7 @@ VM::VM(VMType vmType, HeapType heapType) symbolTableStructure.set(*this, SymbolTable::createStructure(*this, 0, jsNull())); structureChainStructure.set(*this, StructureChain::createStructure(*this, 0, jsNull())); sparseArrayValueMapStructure.set(*this, SparseArrayValueMap::createStructure(*this, 0, jsNull())); + arrayBufferNeuteringWatchpointStructure.set(*this, ArrayBufferNeuteringWatchpoint::createStructure(*this)); withScopeStructure.set(*this, JSWithScope::createStructure(*this, 0, jsNull())); unlinkedFunctionExecutableStructure.set(*this, UnlinkedFunctionExecutable::createStructure(*this, 0, jsNull())); unlinkedProgramCodeBlockStructure.set(*this, UnlinkedProgramCodeBlock::createStructure(*this, 0, jsNull())); diff --git a/Source/JavaScriptCore/runtime/VM.h b/Source/JavaScriptCore/runtime/VM.h index 14da055febd7d4b3abe8faa00f2ad9d4714fc4bb..d1f5582c9300e4f2eb4f3269680ad362a011d354 100644 --- a/Source/JavaScriptCore/runtime/VM.h +++ b/Source/JavaScriptCore/runtime/VM.h @@ -267,6 +267,7 @@ namespace JSC { Strong symbolTableStructure; Strong structureChainStructure; Strong sparseArrayValueMapStructure; + Strong arrayBufferNeuteringWatchpointStructure; Strong withScopeStructure; Strong unlinkedFunctionExecutableStructure; Strong unlinkedProgramCodeBlockStructure;