diff options
| author | Simon Hausmann <simon.hausmann@nokia.com> | 2012-08-23 17:03:15 +0200 |
|---|---|---|
| committer | Simon Hausmann <simon.hausmann@nokia.com> | 2012-08-23 17:03:15 +0200 |
| commit | a73d1c176f2f3e0458861de8590dc20321a501ae (patch) | |
| tree | d897fc5974797c3cb300d7f5916f258df765401f /Source/JavaScriptCore/dfg | |
| parent | c311cf639cc1d6570d67b0a80a8ba04dc992a658 (diff) | |
| download | qtwebkit-a73d1c176f2f3e0458861de8590dc20321a501ae.tar.gz | |
Imported WebKit commit a5ae8a56a48e44ebfb9b81aaa5488affaffdb175 (http://svn.webkit.org/repository/webkit/trunk@126420)
New snapshot with OS X 10.6 build fix
Diffstat (limited to 'Source/JavaScriptCore/dfg')
17 files changed, 1251 insertions, 1364 deletions
diff --git a/Source/JavaScriptCore/dfg/DFGAbstractState.cpp b/Source/JavaScriptCore/dfg/DFGAbstractState.cpp index 5c53f6d78..cfe915947 100644 --- a/Source/JavaScriptCore/dfg/DFGAbstractState.cpp +++ b/Source/JavaScriptCore/dfg/DFGAbstractState.cpp @@ -868,65 +868,66 @@ bool AbstractState::execute(unsigned indexInBlock) case GetByVal: { node.setCanExit(true); - if (!node.prediction() || !m_graph[node.child1()].prediction() || !m_graph[node.child2()].prediction()) { + switch (node.arrayMode()) { + case Array::Undecided: + ASSERT_NOT_REACHED(); + break; + case Array::ForceExit: m_isValid = false; break; - } - if (!m_graph[node.child2()].shouldSpeculateInteger() || (!node.child3() && !m_graph[node.child1()].shouldSpeculateArguments())) { + case Array::Generic: clobberWorld(node.codeOrigin, indexInBlock); forNode(nodeIndex).makeTop(); break; - } - if (m_graph[node.child1()].shouldSpeculateArguments()) { + case Array::String: + forNode(node.child1()).filter(SpecString); + forNode(node.child2()).filter(SpecInt32); + forNode(nodeIndex).set(SpecString); + break; + case Array::Arguments: forNode(node.child1()).filter(SpecArguments); forNode(node.child2()).filter(SpecInt32); forNode(nodeIndex).makeTop(); break; - } - if (m_graph[node.child1()].prediction() == SpecString) { - forNode(node.child1()).filter(SpecString); + case Array::JSArray: + case Array::JSArrayOutOfBounds: + // FIXME: We should have more conservative handling of the out-of-bounds + // case. + forNode(node.child1()).filter(SpecCell); forNode(node.child2()).filter(SpecInt32); - forNode(nodeIndex).set(SpecString); + forNode(nodeIndex).makeTop(); break; - } - - if (m_graph[node.child1()].shouldSpeculateInt8Array()) { + case Array::Int8Array: forNode(node.child1()).filter(SpecInt8Array); forNode(node.child2()).filter(SpecInt32); forNode(nodeIndex).set(SpecInt32); break; - } - if (m_graph[node.child1()].shouldSpeculateInt16Array()) { + case Array::Int16Array: forNode(node.child1()).filter(SpecInt16Array); forNode(node.child2()).filter(SpecInt32); forNode(nodeIndex).set(SpecInt32); break; - } - if (m_graph[node.child1()].shouldSpeculateInt32Array()) { + case Array::Int32Array: forNode(node.child1()).filter(SpecInt32Array); forNode(node.child2()).filter(SpecInt32); forNode(nodeIndex).set(SpecInt32); break; - } - if (m_graph[node.child1()].shouldSpeculateUint8Array()) { + case Array::Uint8Array: forNode(node.child1()).filter(SpecUint8Array); forNode(node.child2()).filter(SpecInt32); forNode(nodeIndex).set(SpecInt32); break; - } - if (m_graph[node.child1()].shouldSpeculateUint8ClampedArray()) { + case Array::Uint8ClampedArray: forNode(node.child1()).filter(SpecUint8ClampedArray); forNode(node.child2()).filter(SpecInt32); forNode(nodeIndex).set(SpecInt32); break; - } - if (m_graph[node.child1()].shouldSpeculateUint16Array()) { + case Array::Uint16Array: forNode(node.child1()).filter(SpecUint16Array); forNode(node.child2()).filter(SpecInt32); forNode(nodeIndex).set(SpecInt32); break; - } - if (m_graph[node.child1()].shouldSpeculateUint32Array()) { + case Array::Uint32Array: forNode(node.child1()).filter(SpecUint32Array); forNode(node.child2()).filter(SpecInt32); if (node.shouldSpeculateInteger()) @@ -934,55 +935,47 @@ bool AbstractState::execute(unsigned indexInBlock) else forNode(nodeIndex).set(SpecDouble); break; - } - if (m_graph[node.child1()].shouldSpeculateFloat32Array()) { + case Array::Float32Array: forNode(node.child1()).filter(SpecFloat32Array); forNode(node.child2()).filter(SpecInt32); forNode(nodeIndex).set(SpecDouble); break; - } - if (m_graph[node.child1()].shouldSpeculateFloat64Array()) { + case Array::Float64Array: forNode(node.child1()).filter(SpecFloat64Array); forNode(node.child2()).filter(SpecInt32); forNode(nodeIndex).set(SpecDouble); break; } - forNode(node.child1()).filter(SpecCell); - forNode(node.child2()).filter(SpecInt32); - forNode(nodeIndex).makeTop(); break; } case PutByVal: - case PutByValAlias: - case PutByValSafe: { + case PutByValAlias: { node.setCanExit(true); - Edge child1 = m_graph.varArgChild(node, 0); Edge child2 = m_graph.varArgChild(node, 1); Edge child3 = m_graph.varArgChild(node, 2); - - if (!m_graph[child1].prediction() || !m_graph[child2].prediction()) { + switch (modeForPut(node.arrayMode())) { + case Array::ForceExit: m_isValid = false; break; - } - if (!m_graph[child2].shouldSpeculateInteger() -#if USE(JSVALUE32_64) - || m_graph[child1].shouldSpeculateArguments() -#endif - ) { - ASSERT(node.op() == PutByVal || node.op() == PutByValSafe); + case Array::Generic: clobberWorld(node.codeOrigin, indexInBlock); - forNode(nodeIndex).makeTop(); break; - } - - if (m_graph[child1].shouldSpeculateArguments()) { + case Array::JSArray: + forNode(child1).filter(SpecCell); + forNode(child2).filter(SpecInt32); + break; + case Array::JSArrayOutOfBounds: + forNode(child1).filter(SpecCell); + forNode(child2).filter(SpecInt32); + clobberWorld(node.codeOrigin, indexInBlock); + break; + case Array::Arguments: forNode(child1).filter(SpecArguments); forNode(child2).filter(SpecInt32); break; - } - if (m_graph[child1].shouldSpeculateInt8Array()) { + case Array::Int8Array: forNode(child1).filter(SpecInt8Array); forNode(child2).filter(SpecInt32); if (m_graph[child3].shouldSpeculateInteger()) @@ -990,8 +983,7 @@ bool AbstractState::execute(unsigned indexInBlock) else forNode(child3).filter(SpecNumber); break; - } - if (m_graph[child1].shouldSpeculateInt16Array()) { + case Array::Int16Array: forNode(child1).filter(SpecInt16Array); forNode(child2).filter(SpecInt32); if (m_graph[child3].shouldSpeculateInteger()) @@ -999,8 +991,7 @@ bool AbstractState::execute(unsigned indexInBlock) else forNode(child3).filter(SpecNumber); break; - } - if (m_graph[child1].shouldSpeculateInt32Array()) { + case Array::Int32Array: forNode(child1).filter(SpecInt32Array); forNode(child2).filter(SpecInt32); if (m_graph[child3].shouldSpeculateInteger()) @@ -1008,8 +999,7 @@ bool AbstractState::execute(unsigned indexInBlock) else forNode(child3).filter(SpecNumber); break; - } - if (m_graph[child1].shouldSpeculateUint8Array()) { + case Array::Uint8Array: forNode(child1).filter(SpecUint8Array); forNode(child2).filter(SpecInt32); if (m_graph[child3].shouldSpeculateInteger()) @@ -1017,8 +1007,7 @@ bool AbstractState::execute(unsigned indexInBlock) else forNode(child3).filter(SpecNumber); break; - } - if (m_graph[child1].shouldSpeculateUint8ClampedArray()) { + case Array::Uint8ClampedArray: forNode(child1).filter(SpecUint8ClampedArray); forNode(child2).filter(SpecInt32); if (m_graph[child3].shouldSpeculateInteger()) @@ -1026,8 +1015,7 @@ bool AbstractState::execute(unsigned indexInBlock) else forNode(child3).filter(SpecNumber); break; - } - if (m_graph[child1].shouldSpeculateUint16Array()) { + case Array::Uint16Array: forNode(child1).filter(SpecUint16Array); forNode(child2).filter(SpecInt32); if (m_graph[child3].shouldSpeculateInteger()) @@ -1035,8 +1023,7 @@ bool AbstractState::execute(unsigned indexInBlock) else forNode(child3).filter(SpecNumber); break; - } - if (m_graph[child1].shouldSpeculateUint32Array()) { + case Array::Uint32Array: forNode(child1).filter(SpecUint32Array); forNode(child2).filter(SpecInt32); if (m_graph[child3].shouldSpeculateInteger()) @@ -1044,23 +1031,20 @@ bool AbstractState::execute(unsigned indexInBlock) else forNode(child3).filter(SpecNumber); break; - } - if (m_graph[child1].shouldSpeculateFloat32Array()) { + case Array::Float32Array: forNode(child1).filter(SpecFloat32Array); forNode(child2).filter(SpecInt32); forNode(child3).filter(SpecNumber); break; - } - if (m_graph[child1].shouldSpeculateFloat64Array()) { + case Array::Float64Array: forNode(child1).filter(SpecFloat64Array); forNode(child2).filter(SpecInt32); forNode(child3).filter(SpecNumber); break; + default: + ASSERT_NOT_REACHED(); + break; } - forNode(child1).filter(SpecCell); - forNode(child2).filter(SpecInt32); - if (node.op() == PutByValSafe) - clobberWorld(node.codeOrigin, indexInBlock); break; } @@ -1356,69 +1340,82 @@ bool AbstractState::execute(unsigned indexInBlock) break; case GetArrayLength: - node.setCanExit(true); - forNode(node.child1()).filter(SpecCell); - forNode(nodeIndex).set(SpecInt32); - break; - - case GetArgumentsLength: - node.setCanExit(true); - forNode(node.child1()).filter(SpecArguments); - forNode(nodeIndex).set(SpecInt32); + switch (node.arrayMode()) { + case Array::Undecided: + ASSERT_NOT_REACHED(); + break; + case Array::ForceExit: + m_isValid = false; + break; + case Array::Generic: + ASSERT_NOT_REACHED(); + break; + case Array::String: + node.setCanExit(!isStringSpeculation(forNode(node.child1()).m_type)); + forNode(node.child1()).filter(SpecString); + forNode(nodeIndex).set(SpecInt32); + break; + case Array::JSArray: + node.setCanExit(true); + forNode(node.child1()).filter(SpecCell); + forNode(nodeIndex).set(SpecInt32); + break; + case Array::JSArrayOutOfBounds: + ASSERT_NOT_REACHED(); + break; + case Array::Arguments: + node.setCanExit(true); + forNode(node.child1()).filter(SpecArguments); + forNode(nodeIndex).set(SpecInt32); + break; + case Array::Int8Array: + node.setCanExit(!isInt8ArraySpeculation(forNode(node.child1()).m_type)); + forNode(node.child1()).filter(SpecInt8Array); + forNode(nodeIndex).set(SpecInt32); + break; + case Array::Int16Array: + node.setCanExit(!isInt16ArraySpeculation(forNode(node.child1()).m_type)); + forNode(node.child1()).filter(SpecInt16Array); + forNode(nodeIndex).set(SpecInt32); + break; + case Array::Int32Array: + node.setCanExit(!isInt32ArraySpeculation(forNode(node.child1()).m_type)); + forNode(node.child1()).filter(SpecInt32Array); + forNode(nodeIndex).set(SpecInt32); + break; + case Array::Uint8Array: + node.setCanExit(!isUint8ArraySpeculation(forNode(node.child1()).m_type)); + forNode(node.child1()).filter(SpecUint8Array); + forNode(nodeIndex).set(SpecInt32); + break; + case Array::Uint8ClampedArray: + node.setCanExit(!isUint8ClampedArraySpeculation(forNode(node.child1()).m_type)); + forNode(node.child1()).filter(SpecUint8ClampedArray); + forNode(nodeIndex).set(SpecInt32); + break; + case Array::Uint16Array: + node.setCanExit(!isUint16ArraySpeculation(forNode(node.child1()).m_type)); + forNode(node.child1()).filter(SpecUint16Array); + forNode(nodeIndex).set(SpecInt32); + break; + case Array::Uint32Array: + node.setCanExit(!isUint32ArraySpeculation(forNode(node.child1()).m_type)); + forNode(node.child1()).filter(SpecUint32Array); + forNode(nodeIndex).set(SpecInt32); + break; + case Array::Float32Array: + node.setCanExit(!isFloat32ArraySpeculation(forNode(node.child1()).m_type)); + forNode(node.child1()).filter(SpecFloat32Array); + forNode(nodeIndex).set(SpecInt32); + break; + case Array::Float64Array: + node.setCanExit(!isFloat64ArraySpeculation(forNode(node.child1()).m_type)); + forNode(node.child1()).filter(SpecFloat64Array); + forNode(nodeIndex).set(SpecInt32); + break; + } break; - case GetStringLength: - node.setCanExit(!isStringSpeculation(forNode(node.child1()).m_type)); - forNode(node.child1()).filter(SpecString); - forNode(nodeIndex).set(SpecInt32); - break; - - case GetInt8ArrayLength: - node.setCanExit(!isInt8ArraySpeculation(forNode(node.child1()).m_type)); - forNode(node.child1()).filter(SpecInt8Array); - forNode(nodeIndex).set(SpecInt32); - break; - case GetInt16ArrayLength: - node.setCanExit(!isInt16ArraySpeculation(forNode(node.child1()).m_type)); - forNode(node.child1()).filter(SpecInt16Array); - forNode(nodeIndex).set(SpecInt32); - break; - case GetInt32ArrayLength: - node.setCanExit(!isInt32ArraySpeculation(forNode(node.child1()).m_type)); - forNode(node.child1()).filter(SpecInt32Array); - forNode(nodeIndex).set(SpecInt32); - break; - case GetUint8ArrayLength: - node.setCanExit(!isUint8ArraySpeculation(forNode(node.child1()).m_type)); - forNode(node.child1()).filter(SpecUint8Array); - forNode(nodeIndex).set(SpecInt32); - break; - case GetUint8ClampedArrayLength: - node.setCanExit(!isUint8ClampedArraySpeculation(forNode(node.child1()).m_type)); - forNode(node.child1()).filter(SpecUint8ClampedArray); - forNode(nodeIndex).set(SpecInt32); - break; - case GetUint16ArrayLength: - node.setCanExit(!isUint16ArraySpeculation(forNode(node.child1()).m_type)); - forNode(node.child1()).filter(SpecUint16Array); - forNode(nodeIndex).set(SpecInt32); - break; - case GetUint32ArrayLength: - node.setCanExit(!isUint32ArraySpeculation(forNode(node.child1()).m_type)); - forNode(node.child1()).filter(SpecUint32Array); - forNode(nodeIndex).set(SpecInt32); - break; - case GetFloat32ArrayLength: - node.setCanExit(!isFloat32ArraySpeculation(forNode(node.child1()).m_type)); - forNode(node.child1()).filter(SpecFloat32Array); - forNode(nodeIndex).set(SpecInt32); - break; - case GetFloat64ArrayLength: - node.setCanExit(!isFloat64ArraySpeculation(forNode(node.child1()).m_type)); - forNode(node.child1()).filter(SpecFloat64Array); - forNode(nodeIndex).set(SpecInt32); - break; - case CheckStructure: case ForwardCheckStructure: { // FIXME: We should be able to propagate the structure sets of constants (i.e. prototypes). @@ -1489,65 +1486,48 @@ bool AbstractState::execute(unsigned indexInBlock) forNode(nodeIndex).clear(); // The result is not a JS value. break; case GetIndexedPropertyStorage: { - ASSERT(m_graph[node.child1()].prediction()); - ASSERT(m_graph[node.child2()].shouldSpeculateInteger()); node.setCanExit(true); // Lies, but this is (almost) always followed by GetByVal, which does exit. So no point in trying to be more precise. - if (m_graph[node.child1()].shouldSpeculateArguments()) { - ASSERT_NOT_REACHED(); - break; - } - if (m_graph[node.child1()].prediction() == SpecString) { + switch (node.arrayMode()) { + case Array::String: forNode(node.child1()).filter(SpecString); - forNode(nodeIndex).clear(); break; - } - - if (m_graph[node.child1()].shouldSpeculateInt8Array()) { + case Array::JSArray: + case Array::JSArrayOutOfBounds: + // This doesn't filter anything meaningful right now. We may want to add + // CFA tracking of array mode speculations, but we don't have that, yet. + forNode(node.child1()).filter(SpecCell); + break; + case Array::Int8Array: forNode(node.child1()).filter(SpecInt8Array); - forNode(nodeIndex).clear(); break; - } - if (m_graph[node.child1()].shouldSpeculateInt16Array()) { + case Array::Int16Array: forNode(node.child1()).filter(SpecInt16Array); - forNode(nodeIndex).clear(); break; - } - if (m_graph[node.child1()].shouldSpeculateInt32Array()) { + case Array::Int32Array: forNode(node.child1()).filter(SpecInt32Array); - forNode(nodeIndex).clear(); break; - } - if (m_graph[node.child1()].shouldSpeculateUint8Array()) { + case Array::Uint8Array: forNode(node.child1()).filter(SpecUint8Array); - forNode(nodeIndex).clear(); break; - } - if (m_graph[node.child1()].shouldSpeculateUint8ClampedArray()) { + case Array::Uint8ClampedArray: forNode(node.child1()).filter(SpecUint8ClampedArray); - forNode(nodeIndex).clear(); break; - } - if (m_graph[node.child1()].shouldSpeculateUint16Array()) { + case Array::Uint16Array: forNode(node.child1()).filter(SpecUint16Array); - forNode(nodeIndex).set(SpecOther); break; - } - if (m_graph[node.child1()].shouldSpeculateUint32Array()) { + case Array::Uint32Array: forNode(node.child1()).filter(SpecUint32Array); - forNode(nodeIndex).clear(); break; - } - if (m_graph[node.child1()].shouldSpeculateFloat32Array()) { + case Array::Float32Array: forNode(node.child1()).filter(SpecFloat32Array); - forNode(nodeIndex).clear(); break; - } - if (m_graph[node.child1()].shouldSpeculateFloat64Array()) { + case Array::Float64Array: forNode(node.child1()).filter(SpecFloat64Array); - forNode(nodeIndex).clear(); + break; + default: + ASSERT_NOT_REACHED(); break; } - forNode(node.child1()).filter(SpecCell); forNode(nodeIndex).clear(); break; } diff --git a/Source/JavaScriptCore/dfg/DFGArgumentsSimplificationPhase.cpp b/Source/JavaScriptCore/dfg/DFGArgumentsSimplificationPhase.cpp index 000e1a938..2f535ba22 100644 --- a/Source/JavaScriptCore/dfg/DFGArgumentsSimplificationPhase.cpp +++ b/Source/JavaScriptCore/dfg/DFGArgumentsSimplificationPhase.cpp @@ -145,7 +145,7 @@ public: } // Figure out which variables alias the arguments and nothing else, and are - // used only for GetByVal and GetArgumentsLength accesses. At the same time, + // used only for GetByVal and GetArrayLength accesses. At the same time, // identify uses of CreateArguments that are not consistent with the arguments // being aliased only to variables that satisfy these constraints. for (BlockIndex blockIndex = 0; blockIndex < m_graph.m_blocks.size(); ++blockIndex) { @@ -277,34 +277,25 @@ public: } case GetByVal: { - if (!node.prediction() - || !m_graph[node.child1()].prediction() - || !m_graph[node.child2()].prediction()) { + if (node.arrayMode() != Array::Arguments) { observeBadArgumentsUses(node); break; } + + // That's so awful and pretty much impossible since it would + // imply that the arguments were predicted integer, but it's + // good to be defensive and thorough. + observeBadArgumentsUse(node.child2()); + observeProperArgumentsUse(node, node.child1()); + break; + } - if (!isActionableArraySpeculation(m_graph[node.child1()].prediction()) - || !m_graph[node.child2()].shouldSpeculateInteger()) { + case GetArrayLength: { + if (node.arrayMode() != Array::Arguments) { observeBadArgumentsUses(node); break; } - - if (m_graph[node.child1()].shouldSpeculateArguments()) { - // If arguments is used as an index, then it's an escaping use. - // That's so awful and pretty much impossible since it would - // imply that the arguments were predicted integer, but it's - // good to be defensive and thorough. - observeBadArgumentsUse(node.child2()); - observeProperArgumentsUse(node, node.child1()); - break; - } - - observeBadArgumentsUses(node); - break; - } - - case GetArgumentsLength: { + observeProperArgumentsUse(node, node.child1()); break; } @@ -496,38 +487,32 @@ public: } case GetByVal: { - if (!node.prediction() - || !m_graph[node.child1()].prediction() - || !m_graph[node.child2()].prediction()) + if (node.arrayMode() != Array::Arguments) break; + + // This can be simplified to GetMyArgumentByVal if we know that + // it satisfies either condition (1) or (2): + // 1) Its first child is a valid ArgumentsAliasingData and the + // InlineCallFrame* is not marked as creating arguments. + // 2) Its first child is CreateArguments and its InlineCallFrame* + // is not marked as creating arguments. - if (!isActionableArraySpeculation(m_graph[node.child1()].prediction()) - || !m_graph[node.child2()].shouldSpeculateInteger()) + if (!isOKToOptimize(m_graph[node.child1()])) break; - if (m_graph[node.child1()].shouldSpeculateArguments()) { - // This can be simplified to GetMyArgumentByVal if we know that - // it satisfies either condition (1) or (2): - // 1) Its first child is a valid ArgumentsAliasingData and the - // InlineCallFrame* is not marked as creating arguments. - // 2) Its first child is CreateArguments and its InlineCallFrame* - // is not marked as creating arguments. - - if (!isOKToOptimize(m_graph[node.child1()])) - break; - - m_graph.deref(node.child1()); - node.children.child1() = node.children.child2(); - node.children.child2() = Edge(); - node.setOpAndDefaultFlags(GetMyArgumentByVal); - changed = true; - --indexInBlock; // Force reconsideration of this op now that it's a GetMyArgumentByVal. - break; - } + m_graph.deref(node.child1()); + node.children.child1() = node.children.child2(); + node.children.child2() = Edge(); + node.setOpAndDefaultFlags(GetMyArgumentByVal); + changed = true; + --indexInBlock; // Force reconsideration of this op now that it's a GetMyArgumentByVal. break; } - case GetArgumentsLength: { + case GetArrayLength: { + if (node.arrayMode() != Array::Arguments) + break; + if (!isOKToOptimize(m_graph[node.child1()])) break; diff --git a/Source/JavaScriptCore/dfg/DFGArrayMode.cpp b/Source/JavaScriptCore/dfg/DFGArrayMode.cpp new file mode 100644 index 000000000..ec4edc2e8 --- /dev/null +++ b/Source/JavaScriptCore/dfg/DFGArrayMode.cpp @@ -0,0 +1,217 @@ +/* + * Copyright (C) 2012 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "DFGArrayMode.h" + +#if ENABLE(DFG_JIT) + +#include "DFGAbstractValue.h" + +namespace JSC { namespace DFG { + +Array::Mode fromObserved(ArrayModes modes, bool makeSafe) +{ + // FIXME: we may want to add some polymorphic support in the future. That's why this + // is a switch statement right now. + + switch (modes) { + case 0: + return Array::Undecided; + case IsJSArray: + return makeSafe ? Array::JSArrayOutOfBounds : Array::JSArray; + default: + // We know that this is possibly a kind of array for which, though there is no + // useful data in the array profile, we may be able to extract useful data from + // the value profiles of the inputs. Hence, we leave it as undecided, and let + // the predictions propagator decide later. + return Array::Undecided; + } +} + +Array::Mode refineArrayMode(Array::Mode arrayMode, SpeculatedType base, SpeculatedType index) +{ + if (!base || !index) { + // It can be that we had a legitimate arrayMode but no incoming predictions. That'll + // happen if we inlined code based on, say, a global variable watchpoint, but later + // realized that the callsite could not have possibly executed. It may be worthwhile + // to fix that, but for now I'm leaving it as-is. + return Array::ForceExit; + } + + if (!isInt32Speculation(index) || !isCellSpeculation(base)) + return Array::Generic; + + // Pass through any array modes that would have been decided by the array profile, since + // the predictions of the inputs will not tell us anything useful that we didn't already + // get from the array profile. + switch (arrayMode) { + case Array::ForceExit: + case Array::JSArray: + case Array::JSArrayOutOfBounds: + return arrayMode; + default: + break; + } + + if (isStringSpeculation(base)) + return Array::String; + + if (isArgumentsSpeculation(base)) + return Array::Arguments; + + if (isInt8ArraySpeculation(base)) + return Array::Int8Array; + + if (isInt16ArraySpeculation(base)) + return Array::Int16Array; + + if (isInt32ArraySpeculation(base)) + return Array::Int32Array; + + if (isUint8ArraySpeculation(base)) + return Array::Uint8Array; + + if (isUint8ClampedArraySpeculation(base)) + return Array::Uint8ClampedArray; + + if (isUint16ArraySpeculation(base)) + return Array::Uint16Array; + + if (isUint32ArraySpeculation(base)) + return Array::Uint32Array; + + if (isFloat32ArraySpeculation(base)) + return Array::Float32Array; + + if (isFloat64ArraySpeculation(base)) + return Array::Float64Array; + + return Array::Generic; +} + +bool modeAlreadyChecked(AbstractValue& value, Array::Mode arrayMode) +{ + switch (arrayMode) { + case Array::Generic: + return true; + + case Array::ForceExit: + return false; + + case Array::String: + return isStringSpeculation(value.m_type); + + case Array::JSArray: + case Array::JSArrayOutOfBounds: + return value.m_currentKnownStructure.hasSingleton() + && value.m_currentKnownStructure.singleton()->classInfo() == &JSArray::s_info; + + case Array::Arguments: + return isArgumentsSpeculation(value.m_type); + + case Array::Int8Array: + return isInt8ArraySpeculation(value.m_type); + + case Array::Int16Array: + return isInt16ArraySpeculation(value.m_type); + + case Array::Int32Array: + return isInt32ArraySpeculation(value.m_type); + + case Array::Uint8Array: + return isUint8ArraySpeculation(value.m_type); + + case Array::Uint8ClampedArray: + return isUint8ClampedArraySpeculation(value.m_type); + + case Array::Uint16Array: + return isUint16ArraySpeculation(value.m_type); + + case Array::Uint32Array: + return isUint32ArraySpeculation(value.m_type); + + case Array::Float32Array: + return isFloat32ArraySpeculation(value.m_type); + + case Array::Float64Array: + return isFloat64ArraySpeculation(value.m_type); + + case Array::Undecided: + break; + } + + ASSERT_NOT_REACHED(); + return false; +} + +const char* modeToString(Array::Mode mode) +{ + switch (mode) { + case Array::Undecided: + return "Undecided"; + case Array::Generic: + return "Generic"; + case Array::ForceExit: + return "ForceExit"; + case Array::String: + return "String"; + case Array::JSArray: + return "JSArray"; + case Array::JSArrayOutOfBounds: + return "JSArrayOutOfBounds"; + case Array::Arguments: + return "Arguments"; + case Array::Int8Array: + return "Int8Array"; + case Array::Int16Array: + return "Int16Array"; + case Array::Int32Array: + return "Int32Array"; + case Array::Uint8Array: + return "Uint8Array"; + case Array::Uint8ClampedArray: + return "Uint8ClampedArray"; + case Array::Uint16Array: + return "Uint16Array"; + case Array::Uint32Array: + return "Uint32Array"; + case Array::Float32Array: + return "Float32Array"; + case Array::Float64Array: + return "Float64Array"; + default: + // Better to return something then it is to crash. Remember, this method + // is being called from our main diagnostic tool, the IR dumper. It's like + // a stack trace. So if we get here then probably something has already + // gone wrong. + return "Unknown!"; + } +} + +} } // namespace JSC::DFG + +#endif // ENABLE(DFG_JIT) + diff --git a/Source/JavaScriptCore/dfg/DFGArrayMode.h b/Source/JavaScriptCore/dfg/DFGArrayMode.h new file mode 100644 index 000000000..6ce62ae72 --- /dev/null +++ b/Source/JavaScriptCore/dfg/DFGArrayMode.h @@ -0,0 +1,135 @@ +/* + * Copyright (C) 2012 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef DFGArrayMode_h +#define DFGArrayMode_h + +#include <wtf/Platform.h> + +#if ENABLE(DFG_JIT) + +#include "ArrayProfile.h" +#include "SpeculatedType.h" + +namespace JSC { namespace DFG { + +struct AbstractValue; + +// Use a namespace + enum instead of enum alone to avoid the namespace collision +// that would otherwise occur, since we say things like "Int8Array" and "JSArray" +// in lots of other places, to mean subtly different things. +namespace Array { +enum Mode { + Undecided, // Implies that we need predictions to decide. We will never get to the backend in this mode. + ForceExit, // Implies that we have no idea how to execute this operation, so we should just give up. + Generic, + String, + JSArray, + JSArrayOutOfBounds, + Arguments, + Int8Array, + Int16Array, + Int32Array, + Uint8Array, + Uint8ClampedArray, + Uint16Array, + Uint32Array, + Float32Array, + Float64Array +}; +} // namespace Array + +Array::Mode fromObserved(ArrayModes modes, bool makeSafe); + +Array::Mode refineArrayMode(Array::Mode, SpeculatedType base, SpeculatedType index); + +bool modeAlreadyChecked(AbstractValue&, Array::Mode); + +const char* modeToString(Array::Mode); + +inline bool canCSEStorage(Array::Mode arrayMode) +{ + switch (arrayMode) { + case Array::Undecided: + case Array::ForceExit: + case Array::Generic: + case Array::Arguments: + return false; + default: + return true; + } +} + +inline Array::Mode modeForPut(Array::Mode arrayMode) +{ + switch (arrayMode) { + case Array::String: + return Array::Generic; +#if USE(JSVALUE32_64) + case Array::Arguments: + return Array::Generic; +#endif + default: + return arrayMode; + } +} + +inline bool modesCompatibleForStorageLoad(Array::Mode left, Array::Mode right) +{ + if (left == right) + return true; + + bool leftIsJSArray = + left == Array::JSArray + || left == Array::JSArrayOutOfBounds; + + bool rightIsJSArray = + right == Array::JSArray + || right == Array::JSArrayOutOfBounds; + + if (leftIsJSArray && rightIsJSArray) + return true; + + return false; +} + +inline bool modeSupportsLength(Array::Mode mode) +{ + switch (mode) { + case Array::Undecided: + case Array::ForceExit: + case Array::Generic: + return false; + default: + return true; + } +} + +} } // namespace JSC::DFG + +#endif // ENABLE(DFG_JIT) + +#endif // DFGArrayMode_h + diff --git a/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp b/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp index f7536f87f..f9b1db9ab 100644 --- a/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp +++ b/Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp @@ -31,6 +31,7 @@ #include "ArrayConstructor.h" #include "CallLinkStatus.h" #include "CodeBlock.h" +#include "DFGArrayMode.h" #include "DFGByteCodeCache.h" #include "DFGCapabilities.h" #include "GetByIdStatus.h" @@ -816,6 +817,36 @@ private: { return getPrediction(m_graph.size(), m_currentProfilingIndex); } + + Array::Mode getArrayModeWithoutOSRExit(Instruction* currentInstruction, NodeIndex base) + { + ArrayProfile* profile = currentInstruction[4].u.arrayProfile; + profile->computeUpdatedPrediction(); + if (profile->hasDefiniteStructure()) + addToGraph(CheckStructure, OpInfo(m_graph.addStructureSet(profile->expectedStructure())), base); + +#if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE) + if (m_inlineStackTop->m_profiledBlock->numberOfRareCaseProfiles()) + dataLog("Slow case profile for bc#%u: %u\n", m_currentIndex, m_inlineStackTop->m_profiledBlock->rareCaseProfileForBytecodeOffset(m_currentIndex)->m_counter); + dataLog("Array profile for bc#%u: %p%s, %u\n", m_currentIndex, profile->expectedStructure(), profile->structureIsPolymorphic() ? " (polymorphic)" : "", profile->observedArrayModes()); +#endif + + bool makeSafe = + m_inlineStackTop->m_profiledBlock->couldTakeSlowCase(m_currentIndex) + || m_inlineStackTop->m_exitProfile.hasExitSite(m_currentIndex, OutOfBounds); + + return fromObserved(profile->observedArrayModes(), makeSafe); + } + + Array::Mode getArrayMode(Instruction* currentInstruction, NodeIndex base) + { + Array::Mode result = getArrayModeWithoutOSRExit(currentInstruction, base); + + if (result == Array::ForceExit) + addToGraph(ForceOSRExit); + + return result; + } NodeIndex makeSafe(NodeIndex nodeIndex) { @@ -1548,8 +1579,7 @@ bool ByteCodeParser::handleIntrinsic(bool usesResult, int resultOperand, Intrins return false; int indexOperand = registerOffset + argumentToOperand(1); - NodeIndex storage = addToGraph(GetIndexedPropertyStorage, get(thisOperand), getToInt32(indexOperand)); - NodeIndex charCode = addToGraph(StringCharCodeAt, get(thisOperand), getToInt32(indexOperand), storage); + NodeIndex charCode = addToGraph(StringCharCodeAt, OpInfo(Array::String), get(thisOperand), getToInt32(indexOperand)); if (usesResult) set(resultOperand, charCode); @@ -1565,8 +1595,7 @@ bool ByteCodeParser::handleIntrinsic(bool usesResult, int resultOperand, Intrins return false; int indexOperand = registerOffset + argumentToOperand(1); - NodeIndex storage = addToGraph(GetIndexedPropertyStorage, get(thisOperand), getToInt32(indexOperand)); - NodeIndex charCode = addToGraph(StringCharAt, get(thisOperand), getToInt32(indexOperand), storage); + NodeIndex charCode = addToGraph(StringCharAt, OpInfo(Array::String), get(thisOperand), getToInt32(indexOperand)); if (usesResult) set(resultOperand, charCode); @@ -2148,13 +2177,9 @@ bool ByteCodeParser::parseBlock(unsigned limit) SpeculatedType prediction = getPrediction(); NodeIndex base = get(currentInstruction[2].u.operand); + Array::Mode arrayMode = getArrayMode(currentInstruction, base); NodeIndex property = get(currentInstruction[3].u.operand); - ArrayProfile* profile = currentInstruction[4].u.arrayProfile; - profile->computeUpdatedPrediction(); - if (profile->hasDefiniteStructure()) - addToGraph(CheckStructure, OpInfo(m_graph.addStructureSet(profile->expectedStructure())), base); - NodeIndex propertyStorage = addToGraph(GetIndexedPropertyStorage, base, property); - NodeIndex getByVal = addToGraph(GetByVal, OpInfo(0), OpInfo(prediction), base, property, propertyStorage); + NodeIndex getByVal = addToGraph(GetByVal, OpInfo(arrayMode), OpInfo(prediction), base, property); set(currentInstruction[1].u.operand, getByVal); NEXT_OPCODE(op_get_by_val); @@ -2162,26 +2187,16 @@ bool ByteCodeParser::parseBlock(unsigned limit) case op_put_by_val: { NodeIndex base = get(currentInstruction[1].u.operand); + + Array::Mode arrayMode = getArrayMode(currentInstruction, base); + NodeIndex property = get(currentInstruction[2].u.operand); NodeIndex value = get(currentInstruction[3].u.operand); - ArrayProfile* profile = currentInstruction[4].u.arrayProfile; - profile->computeUpdatedPrediction(); - if (profile->hasDefiniteStructure()) - addToGraph(CheckStructure, OpInfo(m_graph.addStructureSet(profile->expectedStructure())), base); - -#if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE) - dataLog("Slow case profile for bc#%u: %u\n", m_currentIndex, m_inlineStackTop->m_profiledBlock->rareCaseProfileForBytecodeOffset(m_currentIndex)->m_counter); -#endif - - bool makeSafe = - m_inlineStackTop->m_profiledBlock->couldTakeSlowCase(m_currentIndex) - || m_inlineStackTop->m_exitProfile.hasExitSite(m_currentIndex, OutOfBounds); - addVarArgChild(base); addVarArgChild(property); addVarArgChild(value); - addToGraph(Node::VarArg, makeSafe ? PutByValSafe : PutByVal, OpInfo(0), OpInfo(0)); + addToGraph(Node::VarArg, PutByVal, OpInfo(arrayMode), OpInfo(0)); NEXT_OPCODE(op_put_by_val); } diff --git a/Source/JavaScriptCore/dfg/DFGCSEPhase.cpp b/Source/JavaScriptCore/dfg/DFGCSEPhase.cpp index b78ddc89d..dce57d520 100644 --- a/Source/JavaScriptCore/dfg/DFGCSEPhase.cpp +++ b/Source/JavaScriptCore/dfg/DFGCSEPhase.cpp @@ -284,8 +284,7 @@ private: return index; break; case PutByVal: - case PutByValAlias: - case PutByValSafe: { + case PutByValAlias: { if (!m_graph.byValIsPure(node)) return NoNode; if (m_graph.varArgChild(node, 0) == child1 && canonicalize(m_graph.varArgChild(node, 1)) == canonicalize(child2)) @@ -365,7 +364,6 @@ private: case PutByVal: case PutByValAlias: - case PutByValSafe: if (m_graph.byValIsPure(node)) { // If PutByVal speculates that it's accessing an array with an // integer index, then it's impossible for it to cause a structure @@ -409,7 +407,6 @@ private: case PutByVal: case PutByValAlias: - case PutByValSafe: if (m_graph.byValIsPure(node)) { // If PutByVal speculates that it's accessing an array with an // integer index, then it's impossible for it to cause a structure @@ -515,7 +512,6 @@ private: case PutByVal: case PutByValAlias: - case PutByValSafe: if (m_graph.byValIsPure(node)) { // If PutByVal speculates that it's accessing an array with an // integer index, then it's impossible for it to cause a structure @@ -560,7 +556,6 @@ private: case PutByVal: case PutByValAlias: case GetByVal: - case PutByValSafe: if (m_graph.byValIsPure(node)) { // If PutByVal speculates that it's accessing an array with an // integer index, then it's impossible for it to cause a structure @@ -613,7 +608,6 @@ private: case PutByVal: case PutByValAlias: - case PutByValSafe: if (m_graph.byValIsPure(node)) { // If PutByVal speculates that it's accessing an array with an // integer index, then it's impossible for it to cause a structure @@ -925,17 +919,7 @@ private: case ArithMin: case ArithMax: case ArithSqrt: - case GetInt8ArrayLength: - case GetInt16ArrayLength: - case GetInt32ArrayLength: - case GetUint8ArrayLength: - case GetUint8ClampedArrayLength: - case GetUint16ArrayLength: - case GetUint32ArrayLength: - case GetFloat32ArrayLength: - case GetFloat64ArrayLength: case GetCallee: - case GetStringLength: case StringCharAt: case StringCharCodeAt: case Int32ToDouble: @@ -1103,8 +1087,7 @@ private: setReplacement(getByValLoadElimination(node.child1().index(), node.child2().index())); break; - case PutByVal: - case PutByValSafe: { + case PutByVal: { Edge child1 = m_graph.varArgChild(node, 0); Edge child2 = m_graph.varArgChild(node, 1); if (isActionableMutableArraySpeculation(m_graph[child1].prediction()) diff --git a/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp b/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp index f7b10fc43..fe7cae8a9 100644 --- a/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp +++ b/Source/JavaScriptCore/dfg/DFGFixupPhase.cpp @@ -74,97 +74,89 @@ private: switch (op) { case GetById: { + Node* nodePtr = &node; + if (!isInt32Speculation(m_graph[m_compileIndex].prediction())) break; - if (codeBlock()->identifier(node.identifierNumber()) != globalData().propertyNames->length) - break; - bool isArray = isArraySpeculation(m_graph[node.child1()].prediction()); - bool isArguments = isArgumentsSpeculation(m_graph[node.child1()].prediction()); - bool isString = isStringSpeculation(m_graph[node.child1()].prediction()); - bool isInt8Array = m_graph[node.child1()].shouldSpeculateInt8Array(); - bool isInt16Array = m_graph[node.child1()].shouldSpeculateInt16Array(); - bool isInt32Array = m_graph[node.child1()].shouldSpeculateInt32Array(); - bool isUint8Array = m_graph[node.child1()].shouldSpeculateUint8Array(); - bool isUint8ClampedArray = m_graph[node.child1()].shouldSpeculateUint8ClampedArray(); - bool isUint16Array = m_graph[node.child1()].shouldSpeculateUint16Array(); - bool isUint32Array = m_graph[node.child1()].shouldSpeculateUint32Array(); - bool isFloat32Array = m_graph[node.child1()].shouldSpeculateFloat32Array(); - bool isFloat64Array = m_graph[node.child1()].shouldSpeculateFloat64Array(); - if (!isArray && !isArguments && !isString && !isInt8Array && !isInt16Array && !isInt32Array && !isUint8Array && !isUint8ClampedArray && !isUint16Array && !isUint32Array && !isFloat32Array && !isFloat64Array) + if (codeBlock()->identifier(nodePtr->identifierNumber()) != globalData().propertyNames->length) break; - -#if DFG_ENABLE(DEBUG_PROPAGATION_VERBOSE) - dataLog(" @%u -> %s", m_compileIndex, isArray ? "GetArrayLength" : "GetStringLength"); -#endif - if (isArray) { - node.setOp(GetArrayLength); - ASSERT(node.flags() & NodeMustGenerate); - node.clearFlags(NodeMustGenerate); - m_graph.deref(m_compileIndex); - - ArrayProfile* arrayProfile = - m_graph.baselineCodeBlockFor(node.codeOrigin)->getArrayProfile( - node.codeOrigin.bytecodeIndex); - if (!arrayProfile) - break; + ArrayProfile* arrayProfile = + m_graph.baselineCodeBlockFor(nodePtr->codeOrigin)->getArrayProfile( + nodePtr->codeOrigin.bytecodeIndex); + Array::Mode arrayMode = Array::Undecided; + if (arrayProfile) { arrayProfile->computeUpdatedPrediction(); - if (!arrayProfile->hasDefiniteStructure()) - break; - m_graph.ref(node.child1()); - Node checkStructure(CheckStructure, node.codeOrigin, OpInfo(m_graph.addStructureSet(arrayProfile->expectedStructure())), node.child1().index()); - checkStructure.ref(); - NodeIndex checkStructureIndex = m_graph.size(); - m_graph.append(checkStructure); - m_insertionSet.append(m_indexInBlock, checkStructureIndex); - break; + arrayMode = refineArrayMode( + fromObserved(arrayProfile->observedArrayModes(), false), + m_graph[node.child1()].prediction(), + m_graph[m_compileIndex].prediction()); + if (modeSupportsLength(arrayMode) + && arrayProfile->hasDefiniteStructure()) { + m_graph.ref(nodePtr->child1()); + Node checkStructure(CheckStructure, nodePtr->codeOrigin, OpInfo(m_graph.addStructureSet(arrayProfile->expectedStructure())), nodePtr->child1().index()); + checkStructure.ref(); + NodeIndex checkStructureIndex = m_graph.size(); + m_graph.append(checkStructure); + m_insertionSet.append(m_indexInBlock, checkStructureIndex); + nodePtr = &m_graph[m_compileIndex]; + } + } else { + arrayMode = refineArrayMode( + arrayMode, + m_graph[node.child1()].prediction(), + m_graph[m_compileIndex].prediction()); } - if (isArguments) - node.setOp(GetArgumentsLength); - else if (isString) - node.setOp(GetStringLength); - else if (isInt8Array) - node.setOp(GetInt8ArrayLength); - else if (isInt16Array) - node.setOp(GetInt16ArrayLength); - else if (isInt32Array) - node.setOp(GetInt32ArrayLength); - else if (isUint8Array) - node.setOp(GetUint8ArrayLength); - else if (isUint8ClampedArray) - node.setOp(GetUint8ClampedArrayLength); - else if (isUint16Array) - node.setOp(GetUint16ArrayLength); - else if (isUint32Array) - node.setOp(GetUint32ArrayLength); - else if (isFloat32Array) - node.setOp(GetFloat32ArrayLength); - else if (isFloat64Array) - node.setOp(GetFloat64ArrayLength); - else - ASSERT_NOT_REACHED(); - // No longer MustGenerate - ASSERT(node.flags() & NodeMustGenerate); - node.clearFlags(NodeMustGenerate); + if (!modeSupportsLength(arrayMode)) + break; + nodePtr->setOp(GetArrayLength); + ASSERT(nodePtr->flags() & NodeMustGenerate); + nodePtr->clearFlags(NodeMustGenerate); m_graph.deref(m_compileIndex); + nodePtr->setArrayMode(arrayMode); break; } case GetIndexedPropertyStorage: { - if (!m_graph[node.child1()].prediction() - || !m_graph[node.child2()].shouldSpeculateInteger() - || m_graph[node.child1()].shouldSpeculateArguments()) { - node.setOpAndDefaultFlags(Nop); - m_graph.clearAndDerefChild1(node); - m_graph.clearAndDerefChild2(node); - m_graph.clearAndDerefChild3(node); - node.setRefCount(0); - } + node.setArrayMode( + refineArrayMode( + node.arrayMode(), + m_graph[node.child1()].prediction(), + m_graph[node.child2()].prediction())); + // Predictions should only become more, rather than less, refined. Hence + // if we were ever able to CSE the storage pointer for this operation, + // then we should always continue to be able to do so. + ASSERT(canCSEStorage(node.arrayMode())); break; } case GetByVal: case StringCharAt: case StringCharCodeAt: { - if (!!node.child3() && m_graph[node.child3()].op() == Nop) - node.children.child3() = Edge(); + node.setArrayMode( + refineArrayMode( + node.arrayMode(), + m_graph[node.child1()].prediction(), + m_graph[node.child2()].prediction())); + + if (canCSEStorage(node.arrayMode())) { + if (node.child3()) { + ASSERT(m_graph[node.child3()].op() == GetIndexedPropertyStorage); + ASSERT(modesCompatibleForStorageLoad(m_graph[node.child3()].arrayMode(), node.arrayMode())); + } else { + // Make sure we don't use the node reference after we do the append. + Node getIndexedPropertyStorage( + GetIndexedPropertyStorage, node.codeOrigin, OpInfo(node.arrayMode()), + node.child1().index(), node.child2().index()); + NodeIndex getIndexedPropertyStorageIndex = m_graph.size(); + node.children.child3() = Edge(getIndexedPropertyStorageIndex); + m_graph.append(getIndexedPropertyStorage); + m_graph.ref(getIndexedPropertyStorageIndex); // Once because it's MustGenerate. + m_graph.ref(getIndexedPropertyStorageIndex); // And again because it's referenced from the GetByVal. + m_insertionSet.append(m_indexInBlock, getIndexedPropertyStorageIndex); + } + } else { + // See above. Continued fixup of the graph should not regress our ability + // to speculate. + ASSERT(!node.child3()); + } break; } @@ -334,24 +326,30 @@ private: } case PutByVal: - case PutByValSafe: { + case PutByValAlias: { Edge child1 = m_graph.varArgChild(node, 0); Edge child2 = m_graph.varArgChild(node, 1); Edge child3 = m_graph.varArgChild(node, 2); - if (!m_graph[child1].prediction() || !m_graph[child2].prediction()) - break; - if (!m_graph[child2].shouldSpeculateInteger()) + node.setArrayMode( + refineArrayMode( + node.arrayMode(), m_graph[child1].prediction(), m_graph[child2].prediction())); + + switch (modeForPut(node.arrayMode())) { + case Array::Int8Array: + case Array::Int16Array: + case Array::Int32Array: + case Array::Uint8Array: + case Array::Uint8ClampedArray: + case Array::Uint16Array: + case Array::Uint32Array: + if (!m_graph[child3].shouldSpeculateInteger()) + fixDoubleEdge(2); break; - if (isActionableIntMutableArraySpeculation(m_graph[child1].prediction())) { - if (m_graph[child3].isConstant()) - break; - if (m_graph[child3].shouldSpeculateInteger()) - break; + case Array::Float32Array: + case Array::Float64Array: fixDoubleEdge(2); break; - } - if (isActionableFloatMutableArraySpeculation(m_graph[child1].prediction())) { - fixDoubleEdge(2); + default: break; } break; diff --git a/Source/JavaScriptCore/dfg/DFGGraph.cpp b/Source/JavaScriptCore/dfg/DFGGraph.cpp index 9ae0648b8..8e80ff2fc 100644 --- a/Source/JavaScriptCore/dfg/DFGGraph.cpp +++ b/Source/JavaScriptCore/dfg/DFGGraph.cpp @@ -211,6 +211,10 @@ void Graph::dump(const char* prefix, NodeIndex nodeIndex) dataLog("%s%s", hasPrinted ? ", " : "", nodeFlagsAsString(node.flags())); hasPrinted = true; } + if (node.hasArrayMode()) { + dataLog("%s%s", hasPrinted ? ", " : "", modeToString(node.arrayMode())); + hasPrinted = true; + } if (node.hasVarNumber()) { dataLog("%svar%u", hasPrinted ? ", " : "", node.varNumber()); hasPrinted = true; diff --git a/Source/JavaScriptCore/dfg/DFGGraph.h b/Source/JavaScriptCore/dfg/DFGGraph.h index 8d164a299..ba5d86f81 100644 --- a/Source/JavaScriptCore/dfg/DFGGraph.h +++ b/Source/JavaScriptCore/dfg/DFGGraph.h @@ -488,48 +488,20 @@ public: bool byValIsPure(Node& node) { - switch (node.op()) { - case PutByVal: { - if (!at(varArgChild(node, 1)).shouldSpeculateInteger()) - return false; - SpeculatedType prediction = at(varArgChild(node, 0)).prediction(); - if (!isActionableMutableArraySpeculation(prediction)) - return false; - return true; - } - - case PutByValSafe: { - if (!at(varArgChild(node, 1)).shouldSpeculateInteger()) - return false; - SpeculatedType prediction = at(varArgChild(node, 0)).prediction(); - if (!isActionableMutableArraySpeculation(prediction)) - return false; - if (isArraySpeculation(prediction)) - return false; - return true; - } - - case PutByValAlias: { - if (!at(varArgChild(node, 1)).shouldSpeculateInteger()) - return false; - SpeculatedType prediction = at(varArgChild(node, 0)).prediction(); - if (!isActionableMutableArraySpeculation(prediction)) - return false; - return true; - } - - case GetByVal: { - if (!at(node.child2()).shouldSpeculateInteger()) - return false; - SpeculatedType prediction = at(node.child1()).prediction(); - if (!isActionableArraySpeculation(prediction)) - return false; - return true; - } - - default: - ASSERT_NOT_REACHED(); + switch (node.arrayMode()) { + case Array::Generic: + case Array::JSArrayOutOfBounds: return false; + case Array::String: + return node.op() == GetByVal; +#if USE(JSVALUE32_64) + case Array::Arguments: + if (node.op() == GetByVal) + return true; + return false; +#endif // USE(JSVALUE32_64) + default: + return true; } } @@ -549,7 +521,6 @@ public: return !isPredictedNumerical(node); case GetByVal: case PutByVal: - case PutByValSafe: case PutByValAlias: return !byValIsPure(node); default: diff --git a/Source/JavaScriptCore/dfg/DFGNode.h b/Source/JavaScriptCore/dfg/DFGNode.h index dac855be0..7ca4d8d48 100644 --- a/Source/JavaScriptCore/dfg/DFGNode.h +++ b/Source/JavaScriptCore/dfg/DFGNode.h @@ -33,6 +33,7 @@ #include "CodeBlock.h" #include "CodeOrigin.h" #include "DFGAdjacencyList.h" +#include "DFGArrayMode.h" #include "DFGCommon.h" #include "DFGNodeFlags.h" #include "DFGNodeType.h" @@ -732,6 +733,34 @@ struct Node { return m_opInfo; } + bool hasArrayMode() + { + switch (op()) { + case GetIndexedPropertyStorage: + case GetArrayLength: + case PutByVal: + case PutByValAlias: + case GetByVal: + case StringCharAt: + case StringCharCodeAt: + return true; + default: + return false; + } + } + + Array::Mode arrayMode() + { + ASSERT(hasArrayMode()); + return static_cast<Array::Mode>(m_opInfo); + } + + void setArrayMode(Array::Mode arrayMode) + { + ASSERT(hasArrayMode()); + m_opInfo = arrayMode; + } + bool hasVirtualRegister() { return m_virtualRegister != InvalidVirtualRegister; diff --git a/Source/JavaScriptCore/dfg/DFGNodeType.h b/Source/JavaScriptCore/dfg/DFGNodeType.h index f0f8cb1d0..ee5ad9013 100644 --- a/Source/JavaScriptCore/dfg/DFGNodeType.h +++ b/Source/JavaScriptCore/dfg/DFGNodeType.h @@ -113,7 +113,6 @@ namespace JSC { namespace DFG { /* opcodes use VarArgs beause they may have up to 4 children. */\ macro(GetByVal, NodeResultJS | NodeMustGenerate | NodeMightClobber) \ macro(PutByVal, NodeMustGenerate | NodeHasVarArgs | NodeMightClobber) \ - macro(PutByValSafe, NodeMustGenerate | NodeHasVarArgs | NodeMightClobber) \ macro(PutByValAlias, NodeMustGenerate | NodeHasVarArgs | NodeMightClobber) \ macro(GetById, NodeResultJS | NodeMustGenerate | NodeClobbersWorld) \ macro(GetByIdFlush, NodeResultJS | NodeMustGenerate | NodeClobbersWorld) \ @@ -143,17 +142,6 @@ namespace JSC { namespace DFG { macro(GetByOffset, NodeResultJS) \ macro(PutByOffset, NodeMustGenerate) \ macro(GetArrayLength, NodeResultInt32) \ - macro(GetArgumentsLength, NodeResultInt32) \ - macro(GetStringLength, NodeResultInt32) \ - macro(GetInt8ArrayLength, NodeResultInt32) \ - macro(GetInt16ArrayLength, NodeResultInt32) \ - macro(GetInt32ArrayLength, NodeResultInt32) \ - macro(GetUint8ArrayLength, NodeResultInt32) \ - macro(GetUint8ClampedArrayLength, NodeResultInt32) \ - macro(GetUint16ArrayLength, NodeResultInt32) \ - macro(GetUint32ArrayLength, NodeResultInt32) \ - macro(GetFloat32ArrayLength, NodeResultInt32) \ - macro(GetFloat64ArrayLength, NodeResultInt32) \ macro(GetScopeChain, NodeResultJS) \ macro(GetScopedVar, NodeResultJS | NodeMustGenerate) \ macro(PutScopedVar, NodeMustGenerate | NodeClobbersWorld) \ diff --git a/Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp b/Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp index 1247528e8..258d1199a 100644 --- a/Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp +++ b/Source/JavaScriptCore/dfg/DFGPredictionPropagationPhase.cpp @@ -612,17 +612,6 @@ private: case PutByValAlias: case GetArrayLength: - case GetArgumentsLength: - case GetInt8ArrayLength: - case GetInt16ArrayLength: - case GetInt32ArrayLength: - case GetUint8ArrayLength: - case GetUint8ClampedArrayLength: - case GetUint16ArrayLength: - case GetUint32ArrayLength: - case GetFloat32ArrayLength: - case GetFloat64ArrayLength: - case GetStringLength: case Int32ToDouble: case DoubleAsInt32: case GetLocalUnlinked: @@ -637,7 +626,6 @@ private: } case PutByVal: - case PutByValSafe: changed |= m_graph[m_graph.varArgChild(node, 0)].mergeFlags(NodeUsedAsValue); changed |= m_graph[m_graph.varArgChild(node, 1)].mergeFlags(NodeUsedAsNumber | NodeUsedAsInt); changed |= m_graph[m_graph.varArgChild(node, 2)].mergeFlags(NodeUsedAsValue); diff --git a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp index 6c6615716..d74207420 100644 --- a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp +++ b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.cpp @@ -269,12 +269,82 @@ void SpeculativeJIT::clearGenerationInfo() m_fprs = RegisterBank<FPRInfo>(); } -void SpeculativeJIT::speculateArray(Edge edge, GPRReg baseReg) +const TypedArrayDescriptor* SpeculativeJIT::typedArrayDescriptor(Array::Mode arrayMode) +{ + switch (arrayMode) { + case Array::Int8Array: + return &m_jit.globalData()->int8ArrayDescriptor(); + case Array::Int16Array: + return &m_jit.globalData()->int16ArrayDescriptor(); + case Array::Int32Array: + return &m_jit.globalData()->int32ArrayDescriptor(); + case Array::Uint8Array: + return &m_jit.globalData()->uint8ArrayDescriptor(); + case Array::Uint8ClampedArray: + return &m_jit.globalData()->uint8ClampedArrayDescriptor(); + case Array::Uint16Array: + return &m_jit.globalData()->uint16ArrayDescriptor(); + case Array::Uint32Array: + return &m_jit.globalData()->uint32ArrayDescriptor(); + case Array::Float32Array: + return &m_jit.globalData()->float32ArrayDescriptor(); + case Array::Float64Array: + return &m_jit.globalData()->float32ArrayDescriptor(); + default: + return 0; + } +} + +const TypedArrayDescriptor* SpeculativeJIT::speculateArray(Array::Mode arrayMode, Edge edge, GPRReg baseReg) { - AbstractValue& arrayValue = m_state.forNode(edge); - if (arrayValue.m_currentKnownStructure.hasSingleton() - && arrayValue.m_currentKnownStructure.singleton()->classInfo() == &JSArray::s_info) - return; + const TypedArrayDescriptor* result = typedArrayDescriptor(arrayMode); + + if (modeAlreadyChecked(m_state.forNode(edge), arrayMode)) + return result; + + const ClassInfo* expectedClassInfo = 0; + + switch (arrayMode) { + case Array::ForceExit: + ASSERT_NOT_REACHED(); + terminateSpeculativeExecution(InadequateCoverage, JSValueRegs(), NoNode); + return result; + case Array::String: + expectedClassInfo = &JSString::s_info; + break; + case Array::JSArray: + case Array::JSArrayOutOfBounds: { + // This code duplicates the code below in anticipation of this code being + // substantially changed in the future. + GPRTemporary temp(this); + m_jit.loadPtr( + MacroAssembler::Address(baseReg, JSCell::structureOffset()), temp.gpr()); + speculationCheck( + Uncountable, JSValueRegs(), NoNode, + m_jit.branchPtr( + MacroAssembler::NotEqual, + MacroAssembler::Address(temp.gpr(), Structure::classInfoOffset()), + MacroAssembler::TrustedImmPtr(&JSArray::s_info))); + return result; + } + case Array::Arguments: + expectedClassInfo = &Arguments::s_info; + break; + case Array::Int8Array: + case Array::Int16Array: + case Array::Int32Array: + case Array::Uint8Array: + case Array::Uint8ClampedArray: + case Array::Uint16Array: + case Array::Uint32Array: + case Array::Float32Array: + case Array::Float64Array: + expectedClassInfo = result->m_classInfo; + break; + default: + ASSERT_NOT_REACHED(); + break; + } GPRTemporary temp(this); m_jit.loadPtr( @@ -284,7 +354,9 @@ void SpeculativeJIT::speculateArray(Edge edge, GPRReg baseReg) m_jit.branchPtr( MacroAssembler::NotEqual, MacroAssembler::Address(temp.gpr(), Structure::classInfoOffset()), - MacroAssembler::TrustedImmPtr(&JSArray::s_info))); + MacroAssembler::TrustedImmPtr(expectedClassInfo))); + + return result; } GPRReg SpeculativeJIT::fillStorage(NodeIndex nodeIndex) @@ -1620,11 +1692,7 @@ void SpeculativeJIT::compileGetByValOnString(Node& node) GPRReg propertyReg = property.gpr(); GPRReg storageReg = storage.gpr(); - if (!isStringSpeculation(m_state.forNode(node.child1()).m_type)) { - terminateSpeculativeExecution(Uncountable, JSValueRegs(), NoNode); - noResult(m_compileIndex); - return; - } + ASSERT(modeAlreadyChecked(m_state.forNode(node.child1()), Array::String)); // unsigned comparison so we can filter out negative indices and indices that are too large speculationCheck(Uncountable, JSValueRegs(), NoNode, m_jit.branch32(MacroAssembler::AboveOrEqual, propertyReg, MacroAssembler::Address(baseReg, JSString::offsetOfLength()))); @@ -2018,23 +2086,7 @@ static void compileClampDoubleToByte(JITCompiler& jit, GPRReg result, FPRReg sou } -void SpeculativeJIT::compileGetTypedArrayLength(const TypedArrayDescriptor& descriptor, Node& node, bool needsSpeculationCheck) -{ - SpeculateCellOperand base(this, node.child1()); - GPRTemporary result(this); - - GPRReg baseGPR = base.gpr(); - GPRReg resultGPR = result.gpr(); - - if (needsSpeculationCheck) - speculationCheck(BadType, JSValueSource::unboxedCell(baseGPR), node.child1(), m_jit.branchPtr(MacroAssembler::NotEqual, MacroAssembler::Address(baseGPR, JSCell::classInfoOffset()), MacroAssembler::TrustedImmPtr(descriptor.m_classInfo))); - - m_jit.load32(MacroAssembler::Address(baseGPR, descriptor.m_lengthOffset), resultGPR); - - integerResult(resultGPR, m_compileIndex); -} - -void SpeculativeJIT::compileGetByValOnIntTypedArray(const TypedArrayDescriptor& descriptor, Node& node, size_t elementSize, TypedArraySpeculationRequirements speculationRequirements, TypedArraySignedness signedness) +void SpeculativeJIT::compileGetByValOnIntTypedArray(const TypedArrayDescriptor& descriptor, Node& node, size_t elementSize, TypedArraySignedness signedness) { SpeculateCellOperand base(this, node.child1()); SpeculateStrictInt32Operand property(this, node.child2()); @@ -2047,12 +2099,7 @@ void SpeculativeJIT::compileGetByValOnIntTypedArray(const TypedArrayDescriptor& GPRTemporary result(this); GPRReg resultReg = result.gpr(); - if (speculationRequirements != NoTypedArrayTypeSpecCheck) { - ASSERT_NOT_REACHED(); - terminateSpeculativeExecution(Uncountable, JSValueRegs(), NoNode); - noResult(m_compileIndex); - return; - } + ASSERT(modeAlreadyChecked(m_state.forNode(node.child1()), node.arrayMode())); speculationCheck( Uncountable, JSValueRegs(), NoNode, @@ -2097,13 +2144,10 @@ void SpeculativeJIT::compileGetByValOnIntTypedArray(const TypedArrayDescriptor& doubleResult(fresult.fpr(), m_compileIndex); } -void SpeculativeJIT::compilePutByValForIntTypedArray(const TypedArrayDescriptor& descriptor, GPRReg base, GPRReg property, Node& node, size_t elementSize, TypedArraySpeculationRequirements speculationRequirements, TypedArraySignedness signedness, TypedArrayRounding rounding) +void SpeculativeJIT::compilePutByValForIntTypedArray(const TypedArrayDescriptor& descriptor, GPRReg base, GPRReg property, Node& node, size_t elementSize, TypedArraySignedness signedness, TypedArrayRounding rounding) { - Edge baseUse = m_jit.graph().varArgChild(node, 0); Edge valueUse = m_jit.graph().varArgChild(node, 2); - if (speculationRequirements != NoTypedArrayTypeSpecCheck) - speculationCheck(BadType, JSValueSource::unboxedCell(base), baseUse, m_jit.branchPtr(MacroAssembler::NotEqual, MacroAssembler::Address(base, JSCell::classInfoOffset()), MacroAssembler::TrustedImmPtr(descriptor.m_classInfo))); GPRTemporary value; GPRReg valueGPR; @@ -2174,7 +2218,7 @@ void SpeculativeJIT::compilePutByValForIntTypedArray(const TypedArrayDescriptor& ASSERT(valueGPR != storageReg); m_jit.loadPtr(MacroAssembler::Address(base, descriptor.m_storageOffset), storageReg); MacroAssembler::Jump outOfBounds; - if (speculationRequirements != NoTypedArraySpecCheck) + if (node.op() == PutByVal) outOfBounds = m_jit.branch32(MacroAssembler::AboveOrEqual, property, MacroAssembler::Address(base, descriptor.m_lengthOffset)); switch (elementSize) { @@ -2190,12 +2234,12 @@ void SpeculativeJIT::compilePutByValForIntTypedArray(const TypedArrayDescriptor& default: ASSERT_NOT_REACHED(); } - if (speculationRequirements != NoTypedArraySpecCheck) + if (node.op() == PutByVal) outOfBounds.link(&m_jit); noResult(m_compileIndex); } -void SpeculativeJIT::compileGetByValOnFloatTypedArray(const TypedArrayDescriptor& descriptor, Node& node, size_t elementSize, TypedArraySpeculationRequirements speculationRequirements) +void SpeculativeJIT::compileGetByValOnFloatTypedArray(const TypedArrayDescriptor& descriptor, Node& node, size_t elementSize) { SpeculateCellOperand base(this, node.child1()); SpeculateStrictInt32Operand property(this, node.child2()); @@ -2204,17 +2248,11 @@ void SpeculativeJIT::compileGetByValOnFloatTypedArray(const TypedArrayDescriptor GPRReg baseReg = base.gpr(); GPRReg propertyReg = property.gpr(); GPRReg storageReg = storage.gpr(); - - if (speculationRequirements != NoTypedArrayTypeSpecCheck) { - ASSERT_NOT_REACHED(); - terminateSpeculativeExecution(Uncountable, JSValueRegs(), NoNode); - noResult(m_compileIndex); - return; - } + + ASSERT(modeAlreadyChecked(m_state.forNode(node.child1()), node.arrayMode())); FPRTemporary result(this); FPRReg resultReg = result.fpr(); - ASSERT(speculationRequirements != NoTypedArraySpecCheck); speculationCheck( Uncountable, JSValueRegs(), NoNode, m_jit.branch32( @@ -2238,15 +2276,14 @@ void SpeculativeJIT::compileGetByValOnFloatTypedArray(const TypedArrayDescriptor doubleResult(resultReg, m_compileIndex); } -void SpeculativeJIT::compilePutByValForFloatTypedArray(const TypedArrayDescriptor& descriptor, GPRReg base, GPRReg property, Node& node, size_t elementSize, TypedArraySpeculationRequirements speculationRequirements) +void SpeculativeJIT::compilePutByValForFloatTypedArray(const TypedArrayDescriptor& descriptor, GPRReg base, GPRReg property, Node& node, size_t elementSize) { Edge baseUse = m_jit.graph().varArgChild(node, 0); Edge valueUse = m_jit.graph().varArgChild(node, 2); SpeculateDoubleOperand valueOp(this, valueUse); - if (speculationRequirements != NoTypedArrayTypeSpecCheck) - speculationCheck(BadType, JSValueSource::unboxedCell(base), baseUse.index(), m_jit.branchPtr(MacroAssembler::NotEqual, MacroAssembler::Address(base, JSCell::classInfoOffset()), MacroAssembler::TrustedImmPtr(descriptor.m_classInfo))); + ASSERT_UNUSED(baseUse, modeAlreadyChecked(m_state.forNode(baseUse), node.arrayMode())); GPRTemporary result(this); @@ -2255,7 +2292,7 @@ void SpeculativeJIT::compilePutByValForFloatTypedArray(const TypedArrayDescripto m_jit.loadPtr(MacroAssembler::Address(base, descriptor.m_storageOffset), storageReg); MacroAssembler::Jump outOfBounds; - if (speculationRequirements != NoTypedArraySpecCheck) + if (node.op() == PutByVal) outOfBounds = m_jit.branch32(MacroAssembler::AboveOrEqual, property, MacroAssembler::Address(base, descriptor.m_lengthOffset)); switch (elementSize) { @@ -2272,7 +2309,7 @@ void SpeculativeJIT::compilePutByValForFloatTypedArray(const TypedArrayDescripto default: ASSERT_NOT_REACHED(); } - if (speculationRequirements != NoTypedArraySpecCheck) + if (node.op() == PutByVal) outOfBounds.link(&m_jit); noResult(m_compileIndex); } @@ -3066,75 +3103,36 @@ bool SpeculativeJIT::compileStrictEq(Node& node) void SpeculativeJIT::compileGetIndexedPropertyStorage(Node& node) { - ASSERT(at(node.child1()).prediction()); - ASSERT(at(node.child2()).shouldSpeculateInteger()); - SpeculateCellOperand base(this, node.child1()); GPRReg baseReg = base.gpr(); GPRTemporary storage(this); GPRReg storageReg = storage.gpr(); - if (at(node.child1()).shouldSpeculateArguments()) { - ASSERT_NOT_REACHED(); - } else if (at(node.child1()).prediction() == SpecString) { - if (!isStringSpeculation(m_state.forNode(node.child1()).m_type)) - speculationCheck(BadType, JSValueSource::unboxedCell(baseReg), node.child1(), m_jit.branchPtr(MacroAssembler::NotEqual, MacroAssembler::Address(baseReg, JSCell::structureOffset()), MacroAssembler::TrustedImmPtr(m_jit.globalData()->stringStructure.get()))); - + + const TypedArrayDescriptor* descriptor = + speculateArray(node.arrayMode(), node.child1(), baseReg); + + switch (node.arrayMode()) { + case Array::String: m_jit.loadPtr(MacroAssembler::Address(baseReg, JSString::offsetOfValue()), storageReg); // Speculate that we're not accessing a rope speculationCheck(Uncountable, JSValueRegs(), NoNode, m_jit.branchTest32(MacroAssembler::Zero, storageReg)); m_jit.loadPtr(MacroAssembler::Address(storageReg, StringImpl::dataOffset()), storageReg); - } else if (at(node.child1()).shouldSpeculateInt8Array()) { - const TypedArrayDescriptor& descriptor = m_jit.globalData()->int8ArrayDescriptor(); - if (!isInt8ArraySpeculation(m_state.forNode(node.child1()).m_type)) - speculationCheck(BadType, JSValueSource::unboxedCell(baseReg), node.child1(), m_jit.branchPtr(MacroAssembler::NotEqual, MacroAssembler::Address(baseReg, JSCell::classInfoOffset()), MacroAssembler::TrustedImmPtr(descriptor.m_classInfo))); - m_jit.loadPtr(MacroAssembler::Address(baseReg, descriptor.m_storageOffset), storageReg); - } else if (at(node.child1()).shouldSpeculateInt16Array()) { - const TypedArrayDescriptor& descriptor = m_jit.globalData()->int16ArrayDescriptor(); - if (!isInt16ArraySpeculation(m_state.forNode(node.child1()).m_type)) - speculationCheck(BadType, JSValueSource::unboxedCell(baseReg), node.child1(), m_jit.branchPtr(MacroAssembler::NotEqual, MacroAssembler::Address(baseReg, JSCell::classInfoOffset()), MacroAssembler::TrustedImmPtr(descriptor.m_classInfo))); - m_jit.loadPtr(MacroAssembler::Address(baseReg, descriptor.m_storageOffset), storageReg); - } else if (at(node.child1()).shouldSpeculateInt32Array()) { - const TypedArrayDescriptor& descriptor = m_jit.globalData()->int32ArrayDescriptor(); - if (!isInt32ArraySpeculation(m_state.forNode(node.child1()).m_type)) - speculationCheck(BadType, JSValueSource::unboxedCell(baseReg), node.child1(), m_jit.branchPtr(MacroAssembler::NotEqual, MacroAssembler::Address(baseReg, JSCell::classInfoOffset()), MacroAssembler::TrustedImmPtr(descriptor.m_classInfo))); - m_jit.loadPtr(MacroAssembler::Address(baseReg, descriptor.m_storageOffset), storageReg); - } else if (at(node.child1()).shouldSpeculateUint8Array()) { - const TypedArrayDescriptor& descriptor = m_jit.globalData()->uint8ArrayDescriptor(); - if (!isUint8ArraySpeculation(m_state.forNode(node.child1()).m_type)) - speculationCheck(BadType, JSValueSource::unboxedCell(baseReg), node.child1(), m_jit.branchPtr(MacroAssembler::NotEqual, MacroAssembler::Address(baseReg, JSCell::classInfoOffset()), MacroAssembler::TrustedImmPtr(descriptor.m_classInfo))); - m_jit.loadPtr(MacroAssembler::Address(baseReg, descriptor.m_storageOffset), storageReg); - } else if (at(node.child1()).shouldSpeculateUint8ClampedArray()) { - const TypedArrayDescriptor& descriptor = m_jit.globalData()->uint8ClampedArrayDescriptor(); - if (!isUint8ClampedArraySpeculation(m_state.forNode(node.child1()).m_type)) - speculationCheck(BadType, JSValueSource::unboxedCell(baseReg), node.child1(), m_jit.branchPtr(MacroAssembler::NotEqual, MacroAssembler::Address(baseReg), MacroAssembler::TrustedImmPtr(descriptor.m_classInfo))); - m_jit.loadPtr(MacroAssembler::Address(baseReg, descriptor.m_storageOffset), storageReg); - } else if (at(node.child1()).shouldSpeculateUint16Array()) { - const TypedArrayDescriptor& descriptor = m_jit.globalData()->uint16ArrayDescriptor(); - if (!isUint16ArraySpeculation(m_state.forNode(node.child1()).m_type)) - speculationCheck(BadType, JSValueSource::unboxedCell(baseReg), node.child1(), m_jit.branchPtr(MacroAssembler::NotEqual, MacroAssembler::Address(baseReg, JSCell::classInfoOffset()), MacroAssembler::TrustedImmPtr(descriptor.m_classInfo))); - m_jit.loadPtr(MacroAssembler::Address(baseReg, descriptor.m_storageOffset), storageReg); - } else if (at(node.child1()).shouldSpeculateUint32Array()) { - const TypedArrayDescriptor& descriptor = m_jit.globalData()->uint32ArrayDescriptor(); - if (!isUint32ArraySpeculation(m_state.forNode(node.child1()).m_type)) - speculationCheck(BadType, JSValueSource::unboxedCell(baseReg), node.child1(), m_jit.branchPtr(MacroAssembler::NotEqual, MacroAssembler::Address(baseReg, JSCell::classInfoOffset()), MacroAssembler::TrustedImmPtr(descriptor.m_classInfo))); - m_jit.loadPtr(MacroAssembler::Address(baseReg, descriptor.m_storageOffset), storageReg); - } else if (at(node.child1()).shouldSpeculateFloat32Array()) { - const TypedArrayDescriptor& descriptor = m_jit.globalData()->float32ArrayDescriptor(); - if (!isFloat32ArraySpeculation(m_state.forNode(node.child1()).m_type)) - speculationCheck(BadType, JSValueSource::unboxedCell(baseReg), node.child1(), m_jit.branchPtr(MacroAssembler::NotEqual, MacroAssembler::Address(baseReg, JSCell::classInfoOffset()), MacroAssembler::TrustedImmPtr(descriptor.m_classInfo))); - m_jit.loadPtr(MacroAssembler::Address(baseReg, descriptor.m_storageOffset), storageReg); - } else if (at(node.child1()).shouldSpeculateFloat64Array()) { - const TypedArrayDescriptor& descriptor = m_jit.globalData()->float64ArrayDescriptor(); - if (!isFloat64ArraySpeculation(m_state.forNode(node.child1()).m_type)) - speculationCheck(BadType, JSValueSource::unboxedCell(baseReg), node.child1(), m_jit.branchPtr(MacroAssembler::NotEqual, MacroAssembler::Address(baseReg, JSCell::classInfoOffset()), MacroAssembler::TrustedImmPtr(descriptor.m_classInfo))); - m_jit.loadPtr(MacroAssembler::Address(baseReg, descriptor.m_storageOffset), storageReg); - } else { - speculateArray(node.child1(), baseReg); + break; + + case Array::JSArray: + case Array::JSArrayOutOfBounds: m_jit.loadPtr(MacroAssembler::Address(baseReg, JSArray::storageOffset()), storageReg); + break; + + default: + ASSERT(descriptor); + m_jit.loadPtr(MacroAssembler::Address(baseReg, descriptor->m_storageOffset), storageReg); + break; } + storageResult(storageReg, m_compileIndex); } @@ -3252,6 +3250,42 @@ void SpeculativeJIT::compileGetArgumentsLength(Node& node) integerResult(resultReg, m_compileIndex); } +void SpeculativeJIT::compileGetArrayLength(Node& node) +{ + SpeculateCellOperand base(this, node.child1()); + GPRTemporary result(this); + + GPRReg baseGPR = base.gpr(); + GPRReg resultGPR = result.gpr(); + + const TypedArrayDescriptor* descriptor = + speculateArray(node.arrayMode(), node.child1(), baseGPR); + + switch (node.arrayMode()) { + case Array::JSArray: + case Array::JSArrayOutOfBounds: + m_jit.loadPtr(MacroAssembler::Address(baseGPR, JSArray::storageOffset()), resultGPR); + m_jit.load32(MacroAssembler::Address(resultGPR, OBJECT_OFFSETOF(ArrayStorage, m_length)), resultGPR); + + speculationCheck(Uncountable, JSValueRegs(), NoNode, m_jit.branch32(MacroAssembler::LessThan, resultGPR, MacroAssembler::TrustedImm32(0))); + + integerResult(resultGPR, m_compileIndex); + break; + case Array::String: + m_jit.load32(MacroAssembler::Address(baseGPR, JSString::offsetOfLength()), resultGPR); + integerResult(resultGPR, m_compileIndex); + break; + case Array::Arguments: + compileGetArgumentsLength(node); + break; + default: + ASSERT(descriptor); + m_jit.load32(MacroAssembler::Address(baseGPR, descriptor->m_lengthOffset), resultGPR); + integerResult(resultGPR, m_compileIndex); + break; + } +} + void SpeculativeJIT::compileNewFunctionNoCheck(Node& node) { GPRResult result(this); diff --git a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h index 073dbb42c..69a30a974 100644 --- a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h +++ b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT.h @@ -2082,6 +2082,8 @@ public: void compileGetByValOnArguments(Node&); void compileGetArgumentsLength(Node&); + void compileGetArrayLength(Node&); + void compileValueToInt32(Node&); void compileUInt32ToNumber(Node&); void compileDoubleAsInt32(Node&); @@ -2095,12 +2097,6 @@ public: #endif void compileArithMod(Node&); void compileSoftModulo(Node&); - void compileGetTypedArrayLength(const TypedArrayDescriptor&, Node&, bool needsSpeculationCheck); - enum TypedArraySpeculationRequirements { - NoTypedArraySpecCheck, - NoTypedArrayTypeSpecCheck, - AllTypedArraySpecChecks - }; enum TypedArraySignedness { SignedTypedArray, UnsignedTypedArray @@ -2110,10 +2106,10 @@ public: ClampRounding }; void compileGetIndexedPropertyStorage(Node&); - void compileGetByValOnIntTypedArray(const TypedArrayDescriptor&, Node&, size_t elementSize, TypedArraySpeculationRequirements, TypedArraySignedness); - void compilePutByValForIntTypedArray(const TypedArrayDescriptor&, GPRReg base, GPRReg property, Node&, size_t elementSize, TypedArraySpeculationRequirements, TypedArraySignedness, TypedArrayRounding = TruncateRounding); - void compileGetByValOnFloatTypedArray(const TypedArrayDescriptor&, Node&, size_t elementSize, TypedArraySpeculationRequirements); - void compilePutByValForFloatTypedArray(const TypedArrayDescriptor&, GPRReg base, GPRReg property, Node&, size_t elementSize, TypedArraySpeculationRequirements); + void compileGetByValOnIntTypedArray(const TypedArrayDescriptor&, Node&, size_t elementSize, TypedArraySignedness); + void compilePutByValForIntTypedArray(const TypedArrayDescriptor&, GPRReg base, GPRReg property, Node&, size_t elementSize, TypedArraySignedness, TypedArrayRounding = TruncateRounding); + void compileGetByValOnFloatTypedArray(const TypedArrayDescriptor&, Node&, size_t elementSize); + void compilePutByValForFloatTypedArray(const TypedArrayDescriptor&, GPRReg base, GPRReg property, Node&, size_t elementSize); void compileNewFunctionNoCheck(Node&); void compileNewFunctionExpression(Node&); bool compileRegExpExec(Node&); @@ -2199,7 +2195,9 @@ public: JumpReplacementWatchpoint* forwardSpeculationWatchpoint(ExitKind = UncountableWatchpoint); JumpReplacementWatchpoint* speculationWatchpointWithConditionalDirection(ExitKind, bool isForward); - void speculateArray(Edge baseEdge, GPRReg baseReg); + const TypedArrayDescriptor* typedArrayDescriptor(Array::Mode); + + const TypedArrayDescriptor* speculateArray(Array::Mode, Edge baseEdge, GPRReg baseReg); template<bool strict> GPRReg fillSpeculateIntInternal(NodeIndex, DataFormat& returnFormat); diff --git a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp index 7a9ba1e41..26a48dcec 100644 --- a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp +++ b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT32_64.cpp @@ -2341,12 +2341,13 @@ void SpeculativeJIT::compile(Node& node) } case GetByVal: { - if (!node.prediction() || !at(node.child1()).prediction() || !at(node.child2()).prediction()) { + switch (node.arrayMode()) { + case Array::Undecided: + case Array::ForceExit: + ASSERT_NOT_REACHED(); terminateSpeculativeExecution(InadequateCoverage, JSValueRegs(), NoNode); break; - } - - if (!at(node.child2()).shouldSpeculateInteger() || (!node.child3() && !at(node.child1()).shouldSpeculateArguments())) { + case Array::Generic: { SpeculateCellOperand base(this, node.child1()); // Save a register, speculate cell. We'll probably be right. JSValueOperand property(this, node.child2()); GPRReg baseGPR = base.gpr(); @@ -2361,125 +2362,94 @@ void SpeculativeJIT::compile(Node& node) jsValueResult(resultTag.gpr(), resultPayload.gpr(), m_compileIndex); break; } + case Array::JSArray: + case Array::JSArrayOutOfBounds: { + SpeculateStrictInt32Operand property(this, node.child2()); + StorageOperand storage(this, node.child3()); + GPRReg propertyReg = property.gpr(); + GPRReg storageReg = storage.gpr(); - if (at(node.child1()).shouldSpeculateArguments()) { - compileGetByValOnArguments(node); if (!m_compileOkay) return; + + // Check that base is an array, and that property is contained within m_vector (< m_vectorLength). + // If we have predicted the base to be type array, we can skip the check. + { + SpeculateCellOperand base(this, node.child1()); + GPRReg baseReg = base.gpr(); + // We've already speculated that it's some kind of array, at this point. + speculationCheck(Uncountable, JSValueRegs(), NoNode, m_jit.branch32(MacroAssembler::AboveOrEqual, propertyReg, MacroAssembler::Address(baseReg, JSArray::vectorLengthOffset()))); + } + + GPRTemporary resultTag(this); + GPRTemporary resultPayload(this); + + m_jit.load32(MacroAssembler::BaseIndex(storageReg, propertyReg, MacroAssembler::TimesEight, OBJECT_OFFSETOF(ArrayStorage, m_vector[0]) + OBJECT_OFFSETOF(JSValue, u.asBits.tag)), resultTag.gpr()); + speculationCheck(Uncountable, JSValueRegs(), NoNode, m_jit.branch32(MacroAssembler::Equal, resultTag.gpr(), TrustedImm32(JSValue::EmptyValueTag))); + m_jit.load32(MacroAssembler::BaseIndex(storageReg, propertyReg, MacroAssembler::TimesEight, OBJECT_OFFSETOF(ArrayStorage, m_vector[0]) + OBJECT_OFFSETOF(JSValue, u.asBits.payload)), resultPayload.gpr()); + + jsValueResult(resultTag.gpr(), resultPayload.gpr(), m_compileIndex); break; } - - if (at(node.child1()).prediction() == SpecString) { + case Array::String: compileGetByValOnString(node); - if (!m_compileOkay) - return; break; - } - - if (at(node.child1()).shouldSpeculateInt8Array()) { - compileGetByValOnIntTypedArray(m_jit.globalData()->int8ArrayDescriptor(), node, sizeof(int8_t), isInt8ArraySpeculation(m_state.forNode(node.child1()).m_type) ? NoTypedArrayTypeSpecCheck : AllTypedArraySpecChecks, SignedTypedArray); - if (!m_compileOkay) - return; - break; - } - - if (at(node.child1()).shouldSpeculateInt16Array()) { - compileGetByValOnIntTypedArray(m_jit.globalData()->int16ArrayDescriptor(), node, sizeof(int16_t), isInt16ArraySpeculation(m_state.forNode(node.child1()).m_type) ? NoTypedArrayTypeSpecCheck : AllTypedArraySpecChecks, SignedTypedArray); - if (!m_compileOkay) - return; - break; - } - - if (at(node.child1()).shouldSpeculateInt32Array()) { - compileGetByValOnIntTypedArray(m_jit.globalData()->int32ArrayDescriptor(), node, sizeof(int32_t), isInt32ArraySpeculation(m_state.forNode(node.child1()).m_type) ? NoTypedArrayTypeSpecCheck : AllTypedArraySpecChecks, SignedTypedArray); - if (!m_compileOkay) - return; - break; - } - - if (at(node.child1()).shouldSpeculateUint8Array()) { - compileGetByValOnIntTypedArray(m_jit.globalData()->uint8ArrayDescriptor(), node, sizeof(uint8_t), isUint8ArraySpeculation(m_state.forNode(node.child1()).m_type) ? NoTypedArrayTypeSpecCheck : AllTypedArraySpecChecks, UnsignedTypedArray); - if (!m_compileOkay) - return; - break; - } - - if (at(node.child1()).shouldSpeculateUint8ClampedArray()) { - compileGetByValOnIntTypedArray(m_jit.globalData()->uint8ClampedArrayDescriptor(), node, sizeof(uint8_t), isUint8ClampedArraySpeculation(m_state.forNode(node.child1()).m_type) ? NoTypedArrayTypeSpecCheck : AllTypedArraySpecChecks, UnsignedTypedArray); - if (!m_compileOkay) - return; + case Array::Arguments: + compileGetByValOnArguments(node); + break; + case Array::Int8Array: + compileGetByValOnIntTypedArray(m_jit.globalData()->int8ArrayDescriptor(), node, sizeof(int8_t), SignedTypedArray); + break; + case Array::Int16Array: + compileGetByValOnIntTypedArray(m_jit.globalData()->int16ArrayDescriptor(), node, sizeof(int16_t), SignedTypedArray); + break; + case Array::Int32Array: + compileGetByValOnIntTypedArray(m_jit.globalData()->int32ArrayDescriptor(), node, sizeof(int32_t), SignedTypedArray); + break; + case Array::Uint8Array: + compileGetByValOnIntTypedArray(m_jit.globalData()->uint8ArrayDescriptor(), node, sizeof(uint8_t), UnsignedTypedArray); + break; + case Array::Uint8ClampedArray: + compileGetByValOnIntTypedArray(m_jit.globalData()->uint8ClampedArrayDescriptor(), node, sizeof(uint8_t), UnsignedTypedArray); + break; + case Array::Uint16Array: + compileGetByValOnIntTypedArray(m_jit.globalData()->uint16ArrayDescriptor(), node, sizeof(uint16_t), UnsignedTypedArray); + break; + case Array::Uint32Array: + compileGetByValOnIntTypedArray(m_jit.globalData()->uint32ArrayDescriptor(), node, sizeof(uint32_t), UnsignedTypedArray); + break; + case Array::Float32Array: + compileGetByValOnFloatTypedArray(m_jit.globalData()->float32ArrayDescriptor(), node, sizeof(float)); + break; + case Array::Float64Array: + compileGetByValOnFloatTypedArray(m_jit.globalData()->float64ArrayDescriptor(), node, sizeof(double)); + break; + default: + ASSERT_NOT_REACHED(); break; } - - if (at(node.child1()).shouldSpeculateUint16Array()) { - compileGetByValOnIntTypedArray(m_jit.globalData()->uint16ArrayDescriptor(), node, sizeof(uint16_t), isUint16ArraySpeculation(m_state.forNode(node.child1()).m_type) ? NoTypedArrayTypeSpecCheck : AllTypedArraySpecChecks, UnsignedTypedArray); - if (!m_compileOkay) - return; - break; - } - - if (at(node.child1()).shouldSpeculateUint32Array()) { - compileGetByValOnIntTypedArray(m_jit.globalData()->uint32ArrayDescriptor(), node, sizeof(uint32_t), isUint32ArraySpeculation(m_state.forNode(node.child1()).m_type) ? NoTypedArrayTypeSpecCheck : AllTypedArraySpecChecks, UnsignedTypedArray); - if (!m_compileOkay) - return; - break; - } - - if (at(node.child1()).shouldSpeculateFloat32Array()) { - compileGetByValOnFloatTypedArray(m_jit.globalData()->float32ArrayDescriptor(), node, sizeof(float), isFloat32ArraySpeculation(m_state.forNode(node.child1()).m_type) ? NoTypedArrayTypeSpecCheck : AllTypedArraySpecChecks); - if (!m_compileOkay) - return; - break; - } - - if (at(node.child1()).shouldSpeculateFloat64Array()) { - compileGetByValOnFloatTypedArray(m_jit.globalData()->float64ArrayDescriptor(), node, sizeof(double), isFloat64ArraySpeculation(m_state.forNode(node.child1()).m_type) ? NoTypedArrayTypeSpecCheck : AllTypedArraySpecChecks); - if (!m_compileOkay) - return; - break; - } - - SpeculateStrictInt32Operand property(this, node.child2()); - StorageOperand storage(this, node.child3()); - GPRReg propertyReg = property.gpr(); - GPRReg storageReg = storage.gpr(); - - if (!m_compileOkay) - return; - - // Check that base is an array, and that property is contained within m_vector (< m_vectorLength). - // If we have predicted the base to be type array, we can skip the check. - { - SpeculateCellOperand base(this, node.child1()); - GPRReg baseReg = base.gpr(); - // We've already speculated that it's some kind of array, at this point. - speculationCheck(Uncountable, JSValueRegs(), NoNode, m_jit.branch32(MacroAssembler::AboveOrEqual, propertyReg, MacroAssembler::Address(baseReg, JSArray::vectorLengthOffset()))); - } - - GPRTemporary resultTag(this); - GPRTemporary resultPayload(this); - - m_jit.load32(MacroAssembler::BaseIndex(storageReg, propertyReg, MacroAssembler::TimesEight, OBJECT_OFFSETOF(ArrayStorage, m_vector[0]) + OBJECT_OFFSETOF(JSValue, u.asBits.tag)), resultTag.gpr()); - speculationCheck(Uncountable, JSValueRegs(), NoNode, m_jit.branch32(MacroAssembler::Equal, resultTag.gpr(), TrustedImm32(JSValue::EmptyValueTag))); - m_jit.load32(MacroAssembler::BaseIndex(storageReg, propertyReg, MacroAssembler::TimesEight, OBJECT_OFFSETOF(ArrayStorage, m_vector[0]) + OBJECT_OFFSETOF(JSValue, u.asBits.payload)), resultPayload.gpr()); - - jsValueResult(resultTag.gpr(), resultPayload.gpr(), m_compileIndex); break; } case PutByVal: - case PutByValSafe: { + case PutByValAlias: { Edge child1 = m_jit.graph().varArgChild(node, 0); Edge child2 = m_jit.graph().varArgChild(node, 1); Edge child3 = m_jit.graph().varArgChild(node, 2); - if (!at(child1).prediction() || !at(child2).prediction()) { + Array::Mode arrayMode = modeForPut(node.arrayMode()); + bool alreadyHandled = false; + + switch (arrayMode) { + case Array::Undecided: + case Array::ForceExit: + ASSERT_NOT_REACHED(); terminateSpeculativeExecution(InadequateCoverage, JSValueRegs(), NoNode); + alreadyHandled = true; break; - } - - if (!at(child2).shouldSpeculateInteger() - || at(child1).shouldSpeculateArguments()) { + case Array::Generic: { + ASSERT(node.op() == PutByVal); + SpeculateCellOperand base(this, child1); // Save a register, speculate cell. We'll probably be right. JSValueOperand property(this, child2); JSValueOperand value(this, child3); @@ -2493,233 +2463,144 @@ void SpeculativeJIT::compile(Node& node) callOperation(m_jit.codeBlock()->isStrictMode() ? operationPutByValCellStrict : operationPutByValCellNonStrict, baseGPR, propertyTagGPR, propertyPayloadGPR, valueTagGPR, valuePayloadGPR); noResult(m_compileIndex); + alreadyHandled = true; break; } - - SpeculateCellOperand base(this, child1); - SpeculateStrictInt32Operand property(this, child2); - if (at(child1).shouldSpeculateInt8Array()) { - compilePutByValForIntTypedArray(m_jit.globalData()->int8ArrayDescriptor(), base.gpr(), property.gpr(), node, sizeof(int8_t), isInt8ArraySpeculation(m_state.forNode(child1).m_type) ? NoTypedArrayTypeSpecCheck : AllTypedArraySpecChecks, SignedTypedArray); - if (!m_compileOkay) - return; - break; - } - - if (at(child1).shouldSpeculateInt16Array()) { - compilePutByValForIntTypedArray(m_jit.globalData()->int16ArrayDescriptor(), base.gpr(), property.gpr(), node, sizeof(int16_t), isInt16ArraySpeculation(m_state.forNode(child1).m_type) ? NoTypedArrayTypeSpecCheck : AllTypedArraySpecChecks, SignedTypedArray); - if (!m_compileOkay) - return; - break; - } - - if (at(child1).shouldSpeculateInt32Array()) { - compilePutByValForIntTypedArray(m_jit.globalData()->int32ArrayDescriptor(), base.gpr(), property.gpr(), node, sizeof(int32_t), isInt32ArraySpeculation(m_state.forNode(child1).m_type) ? NoTypedArrayTypeSpecCheck : AllTypedArraySpecChecks, SignedTypedArray); - if (!m_compileOkay) - return; - break; - } - - if (at(child1).shouldSpeculateUint8Array()) { - compilePutByValForIntTypedArray(m_jit.globalData()->uint8ArrayDescriptor(), base.gpr(), property.gpr(), node, sizeof(uint8_t), isUint8ArraySpeculation(m_state.forNode(child1).m_type) ? NoTypedArrayTypeSpecCheck : AllTypedArraySpecChecks, UnsignedTypedArray); - if (!m_compileOkay) - return; - break; - } - - if (at(child1).shouldSpeculateUint8ClampedArray()) { - compilePutByValForIntTypedArray(m_jit.globalData()->uint8ClampedArrayDescriptor(), base.gpr(), property.gpr(), node, sizeof(uint8_t), isUint8ClampedArraySpeculation(m_state.forNode(child1).m_type) ? NoTypedArrayTypeSpecCheck : AllTypedArraySpecChecks, UnsignedTypedArray, ClampRounding); - if (!m_compileOkay) - return; + default: break; } - - if (at(child1).shouldSpeculateUint16Array()) { - compilePutByValForIntTypedArray(m_jit.globalData()->uint16ArrayDescriptor(), base.gpr(), property.gpr(), node, sizeof(uint16_t), isUint16ArraySpeculation(m_state.forNode(child1).m_type) ? NoTypedArrayTypeSpecCheck : AllTypedArraySpecChecks, UnsignedTypedArray); - if (!m_compileOkay) - return; - break; - } - if (at(child1).shouldSpeculateUint32Array()) { - compilePutByValForIntTypedArray(m_jit.globalData()->uint32ArrayDescriptor(), base.gpr(), property.gpr(), node, sizeof(uint32_t), isUint32ArraySpeculation(m_state.forNode(child1).m_type) ? NoTypedArrayTypeSpecCheck : AllTypedArraySpecChecks, UnsignedTypedArray); - if (!m_compileOkay) - return; - break; - } - - if (at(child1).shouldSpeculateFloat32Array()) { - compilePutByValForFloatTypedArray(m_jit.globalData()->float32ArrayDescriptor(), base.gpr(), property.gpr(), node, sizeof(float), isFloat32ArraySpeculation(m_state.forNode(child1).m_type) ? NoTypedArrayTypeSpecCheck : AllTypedArraySpecChecks); - if (!m_compileOkay) - return; - break; - } + if (alreadyHandled) + break; - if (at(child1).shouldSpeculateFloat64Array()) { - compilePutByValForFloatTypedArray(m_jit.globalData()->float64ArrayDescriptor(), base.gpr(), property.gpr(), node, sizeof(double), isFloat64ArraySpeculation(m_state.forNode(child1).m_type) ? NoTypedArrayTypeSpecCheck : AllTypedArraySpecChecks); - if (!m_compileOkay) - return; - break; - } + SpeculateCellOperand base(this, child1); + SpeculateStrictInt32Operand property(this, child2); - JSValueOperand value(this, child3); - // Map base, property & value into registers, allocate a scratch register. GPRReg baseReg = base.gpr(); GPRReg propertyReg = property.gpr(); - GPRReg valueTagReg = value.tagGPR(); - GPRReg valuePayloadReg = value.payloadGPR(); - - if (!m_compileOkay) - return; - { - GPRTemporary scratch(this); - GPRReg scratchReg = scratch.gpr(); - writeBarrier(baseReg, valueTagReg, child3, WriteBarrierForPropertyAccess, scratchReg); - } + speculateArray(arrayMode, child1, baseReg); - speculateArray(child1, baseReg); - - MacroAssembler::Jump beyondArrayBounds = m_jit.branch32(MacroAssembler::AboveOrEqual, propertyReg, MacroAssembler::Address(baseReg, JSArray::vectorLengthOffset())); - if (node.op() == PutByVal) - speculationCheck(OutOfBounds, JSValueRegs(), NoNode, beyondArrayBounds); - - base.use(); - property.use(); - value.use(); - - // Get the array storage. - GPRTemporary storage(this); - GPRReg storageReg = storage.gpr(); - m_jit.loadPtr(MacroAssembler::Address(baseReg, JSArray::storageOffset()), storageReg); - - // Check if we're writing to a hole; if so increment m_numValuesInVector. - MacroAssembler::Jump notHoleValue = m_jit.branch32(MacroAssembler::NotEqual, MacroAssembler::BaseIndex(storageReg, propertyReg, MacroAssembler::TimesEight, OBJECT_OFFSETOF(ArrayStorage, m_vector[0]) + OBJECT_OFFSETOF(JSValue, u.asBits.tag)), TrustedImm32(JSValue::EmptyValueTag)); - m_jit.add32(TrustedImm32(1), MacroAssembler::Address(storageReg, OBJECT_OFFSETOF(ArrayStorage, m_numValuesInVector))); - - // If we're writing to a hole we might be growing the array; - MacroAssembler::Jump lengthDoesNotNeedUpdate = m_jit.branch32(MacroAssembler::Below, propertyReg, MacroAssembler::Address(storageReg, OBJECT_OFFSETOF(ArrayStorage, m_length))); - m_jit.add32(TrustedImm32(1), propertyReg); - m_jit.store32(propertyReg, MacroAssembler::Address(storageReg, OBJECT_OFFSETOF(ArrayStorage, m_length))); - m_jit.sub32(TrustedImm32(1), propertyReg); - - lengthDoesNotNeedUpdate.link(&m_jit); - notHoleValue.link(&m_jit); + switch (arrayMode) { + case Array::JSArray: + case Array::JSArrayOutOfBounds: { + JSValueOperand value(this, child3); - // Store the value to the array. - m_jit.store32(valueTagReg, MacroAssembler::BaseIndex(storageReg, propertyReg, MacroAssembler::TimesEight, OBJECT_OFFSETOF(ArrayStorage, m_vector[0]) + OBJECT_OFFSETOF(JSValue, u.asBits.tag))); - m_jit.store32(valuePayloadReg, MacroAssembler::BaseIndex(storageReg, propertyReg, MacroAssembler::TimesEight, OBJECT_OFFSETOF(ArrayStorage, m_vector[0]) + OBJECT_OFFSETOF(JSValue, u.asBits.payload))); - - if (node.op() == PutByValSafe) { - addSlowPathGenerator( - slowPathCall( - beyondArrayBounds, this, - m_jit.codeBlock()->isStrictMode() ? operationPutByValBeyondArrayBoundsStrict : operationPutByValBeyondArrayBoundsNonStrict, - NoResult, baseReg, propertyReg, valueTagReg, valuePayloadReg)); - } + GPRReg valueTagReg = value.tagGPR(); + GPRReg valuePayloadReg = value.payloadGPR(); - noResult(m_compileIndex, UseChildrenCalledExplicitly); - break; - } - - case PutByValAlias: { - Edge child1 = m_jit.graph().varArgChild(node, 0); - Edge child2 = m_jit.graph().varArgChild(node, 1); - Edge child3 = m_jit.graph().varArgChild(node, 2); - - if (!at(child1).prediction() || !at(child2).prediction()) { - terminateSpeculativeExecution(InadequateCoverage, JSValueRegs(), NoNode); - break; - } - - ASSERT(isActionableMutableArraySpeculation(at(child1).prediction())); - ASSERT(at(child2).shouldSpeculateInteger()); - - SpeculateCellOperand base(this, child1); - SpeculateStrictInt32Operand property(this, child2); - - if (at(child1).shouldSpeculateInt8Array()) { - compilePutByValForIntTypedArray(m_jit.globalData()->int8ArrayDescriptor(), base.gpr(), property.gpr(), node, sizeof(int8_t), NoTypedArraySpecCheck, SignedTypedArray); - if (!m_compileOkay) - return; - break; - } - - if (at(child1).shouldSpeculateInt16Array()) { - compilePutByValForIntTypedArray(m_jit.globalData()->int16ArrayDescriptor(), base.gpr(), property.gpr(), node, sizeof(int16_t), NoTypedArraySpecCheck, SignedTypedArray); - if (!m_compileOkay) - return; - break; - } - - if (at(child1).shouldSpeculateInt32Array()) { - compilePutByValForIntTypedArray(m_jit.globalData()->int32ArrayDescriptor(), base.gpr(), property.gpr(), node, sizeof(int32_t), NoTypedArraySpecCheck, SignedTypedArray); if (!m_compileOkay) return; - break; - } - - if (at(child1).shouldSpeculateUint8Array()) { - compilePutByValForIntTypedArray(m_jit.globalData()->uint8ArrayDescriptor(), base.gpr(), property.gpr(), node, sizeof(uint8_t), NoTypedArraySpecCheck, UnsignedTypedArray); - if (!m_compileOkay) - return; - break; - } + + { + GPRTemporary scratch(this); + GPRReg scratchReg = scratch.gpr(); + writeBarrier(baseReg, valueTagReg, child3, WriteBarrierForPropertyAccess, scratchReg); + } - if (at(child1).shouldSpeculateUint8ClampedArray()) { - compilePutByValForIntTypedArray(m_jit.globalData()->uint8ClampedArrayDescriptor(), base.gpr(), property.gpr(), node, sizeof(uint8_t), NoTypedArraySpecCheck, UnsignedTypedArray, ClampRounding); - if (!m_compileOkay) - return; - break; - } + if (node.op() == PutByValAlias) { + // Get the array storage. + GPRTemporary storage(this); + GPRReg storageReg = storage.gpr(); + m_jit.loadPtr(MacroAssembler::Address(baseReg, JSArray::storageOffset()), storageReg); + + // Store the value to the array. + GPRReg propertyReg = property.gpr(); + m_jit.store32(value.tagGPR(), MacroAssembler::BaseIndex(storageReg, propertyReg, MacroAssembler::TimesEight, OBJECT_OFFSETOF(ArrayStorage, m_vector[0]) + OBJECT_OFFSETOF(JSValue, u.asBits.tag))); + m_jit.store32(value.payloadGPR(), MacroAssembler::BaseIndex(storageReg, propertyReg, MacroAssembler::TimesEight, OBJECT_OFFSETOF(ArrayStorage, m_vector[0]) + OBJECT_OFFSETOF(JSValue, u.asBits.payload))); + + noResult(m_compileIndex); + break; + } - if (at(child1).shouldSpeculateUint16Array()) { - compilePutByValForIntTypedArray(m_jit.globalData()->uint16ArrayDescriptor(), base.gpr(), property.gpr(), node, sizeof(uint16_t), NoTypedArraySpecCheck, UnsignedTypedArray); - if (!m_compileOkay) - return; - break; - } - - if (at(child1).shouldSpeculateUint32Array()) { - compilePutByValForIntTypedArray(m_jit.globalData()->uint32ArrayDescriptor(), base.gpr(), property.gpr(), node, sizeof(uint32_t), NoTypedArraySpecCheck, UnsignedTypedArray); - if (!m_compileOkay) - return; - break; - } - - if (at(child1).shouldSpeculateFloat32Array()) { - compilePutByValForFloatTypedArray(m_jit.globalData()->float32ArrayDescriptor(), base.gpr(), property.gpr(), node, sizeof(float), NoTypedArraySpecCheck); - if (!m_compileOkay) - return; - break; + MacroAssembler::Jump beyondArrayBounds = m_jit.branch32(MacroAssembler::AboveOrEqual, propertyReg, MacroAssembler::Address(baseReg, JSArray::vectorLengthOffset())); + if (arrayMode == Array::JSArray) + speculationCheck(OutOfBounds, JSValueRegs(), NoNode, beyondArrayBounds); + + base.use(); + property.use(); + value.use(); + + // Get the array storage. + GPRTemporary storage(this); + GPRReg storageReg = storage.gpr(); + m_jit.loadPtr(MacroAssembler::Address(baseReg, JSArray::storageOffset()), storageReg); + + // Check if we're writing to a hole; if so increment m_numValuesInVector. + MacroAssembler::Jump notHoleValue = m_jit.branch32(MacroAssembler::NotEqual, MacroAssembler::BaseIndex(storageReg, propertyReg, MacroAssembler::TimesEight, OBJECT_OFFSETOF(ArrayStorage, m_vector[0]) + OBJECT_OFFSETOF(JSValue, u.asBits.tag)), TrustedImm32(JSValue::EmptyValueTag)); + m_jit.add32(TrustedImm32(1), MacroAssembler::Address(storageReg, OBJECT_OFFSETOF(ArrayStorage, m_numValuesInVector))); + + // If we're writing to a hole we might be growing the array; + MacroAssembler::Jump lengthDoesNotNeedUpdate = m_jit.branch32(MacroAssembler::Below, propertyReg, MacroAssembler::Address(storageReg, OBJECT_OFFSETOF(ArrayStorage, m_length))); + m_jit.add32(TrustedImm32(1), propertyReg); + m_jit.store32(propertyReg, MacroAssembler::Address(storageReg, OBJECT_OFFSETOF(ArrayStorage, m_length))); + m_jit.sub32(TrustedImm32(1), propertyReg); + + lengthDoesNotNeedUpdate.link(&m_jit); + notHoleValue.link(&m_jit); + + // Store the value to the array. + m_jit.store32(valueTagReg, MacroAssembler::BaseIndex(storageReg, propertyReg, MacroAssembler::TimesEight, OBJECT_OFFSETOF(ArrayStorage, m_vector[0]) + OBJECT_OFFSETOF(JSValue, u.asBits.tag))); + m_jit.store32(valuePayloadReg, MacroAssembler::BaseIndex(storageReg, propertyReg, MacroAssembler::TimesEight, OBJECT_OFFSETOF(ArrayStorage, m_vector[0]) + OBJECT_OFFSETOF(JSValue, u.asBits.payload))); + + if (arrayMode == Array::JSArrayOutOfBounds) { + addSlowPathGenerator( + slowPathCall( + beyondArrayBounds, this, + m_jit.codeBlock()->isStrictMode() ? operationPutByValBeyondArrayBoundsStrict : operationPutByValBeyondArrayBoundsNonStrict, + NoResult, baseReg, propertyReg, valueTagReg, valuePayloadReg)); + } + + noResult(m_compileIndex, UseChildrenCalledExplicitly); + break; } - - if (at(child1).shouldSpeculateFloat64Array()) { - compilePutByValForFloatTypedArray(m_jit.globalData()->float64ArrayDescriptor(), base.gpr(), property.gpr(), node, sizeof(double), NoTypedArraySpecCheck); - if (!m_compileOkay) - return; - break; + + case Array::Arguments: + // FIXME: we could at some point make this work. Right now we're assuming that the register + // pressure would be too great. + ASSERT_NOT_REACHED(); + break; + + case Array::Int8Array: + compilePutByValForIntTypedArray(m_jit.globalData()->int8ArrayDescriptor(), base.gpr(), property.gpr(), node, sizeof(int8_t), SignedTypedArray); + break; + + case Array::Int16Array: + compilePutByValForIntTypedArray(m_jit.globalData()->int16ArrayDescriptor(), base.gpr(), property.gpr(), node, sizeof(int16_t), SignedTypedArray); + break; + + case Array::Int32Array: + compilePutByValForIntTypedArray(m_jit.globalData()->int32ArrayDescriptor(), base.gpr(), property.gpr(), node, sizeof(int32_t), SignedTypedArray); + break; + + case Array::Uint8Array: + compilePutByValForIntTypedArray(m_jit.globalData()->uint8ArrayDescriptor(), base.gpr(), property.gpr(), node, sizeof(uint8_t), UnsignedTypedArray); + break; + + case Array::Uint8ClampedArray: + compilePutByValForIntTypedArray(m_jit.globalData()->uint8ClampedArrayDescriptor(), base.gpr(), property.gpr(), node, sizeof(uint8_t), UnsignedTypedArray, ClampRounding); + break; + + case Array::Uint16Array: + compilePutByValForIntTypedArray(m_jit.globalData()->uint16ArrayDescriptor(), base.gpr(), property.gpr(), node, sizeof(uint16_t), UnsignedTypedArray); + break; + + case Array::Uint32Array: + compilePutByValForIntTypedArray(m_jit.globalData()->uint32ArrayDescriptor(), base.gpr(), property.gpr(), node, sizeof(uint32_t), UnsignedTypedArray); + break; + + case Array::Float32Array: + compilePutByValForFloatTypedArray(m_jit.globalData()->float32ArrayDescriptor(), base.gpr(), property.gpr(), node, sizeof(float)); + break; + + case Array::Float64Array: + compilePutByValForFloatTypedArray(m_jit.globalData()->float64ArrayDescriptor(), base.gpr(), property.gpr(), node, sizeof(double)); + break; + + default: + ASSERT_NOT_REACHED(); + break; } - - ASSERT(at(child1).shouldSpeculateArray()); - - JSValueOperand value(this, child3); - GPRTemporary scratch(this, base); - - GPRReg baseReg = base.gpr(); - GPRReg scratchReg = scratch.gpr(); - - writeBarrier(baseReg, value.tagGPR(), child3, WriteBarrierForPropertyAccess, scratchReg); - - // Get the array storage. - GPRReg storageReg = scratchReg; - m_jit.loadPtr(MacroAssembler::Address(baseReg, JSArray::storageOffset()), storageReg); - - // Store the value to the array. - GPRReg propertyReg = property.gpr(); - m_jit.store32(value.tagGPR(), MacroAssembler::BaseIndex(storageReg, propertyReg, MacroAssembler::TimesEight, OBJECT_OFFSETOF(ArrayStorage, m_vector[0]) + OBJECT_OFFSETOF(JSValue, u.asBits.tag))); - m_jit.store32(value.payloadGPR(), MacroAssembler::BaseIndex(storageReg, propertyReg, MacroAssembler::TimesEight, OBJECT_OFFSETOF(ArrayStorage, m_vector[0]) + OBJECT_OFFSETOF(JSValue, u.asBits.payload))); - - noResult(m_compileIndex); break; } @@ -2787,7 +2668,7 @@ void SpeculativeJIT::compile(Node& node) writeBarrier(baseGPR, valueTagGPR, node.child2(), WriteBarrierForPropertyAccess, scratch.gpr(), storageLengthGPR); } - speculateArray(node.child1(), baseGPR); + speculateArray(Array::JSArray, node.child1(), baseGPR); GPRTemporary storage(this); GPRReg storageGPR = storage.gpr(); @@ -2827,7 +2708,7 @@ void SpeculativeJIT::compile(Node& node) GPRReg storageGPR = storage.gpr(); GPRReg storageLengthGPR = storageLength.gpr(); - speculateArray(node.child1(), baseGPR); + speculateArray(Array::JSArray, node.child1(), baseGPR); m_jit.loadPtr(MacroAssembler::Address(baseGPR, JSArray::storageOffset()), storageGPR); m_jit.load32(MacroAssembler::Address(storageGPR, OBJECT_OFFSETOF(ArrayStorage, m_length)), storageLengthGPR); @@ -3373,82 +3254,10 @@ void SpeculativeJIT::compile(Node& node) break; } - case GetArrayLength: { - SpeculateCellOperand base(this, node.child1()); - GPRReg baseGPR = base.gpr(); - - speculateArray(node.child1(), baseGPR); - - GPRTemporary result(this); - GPRReg resultGPR = result.gpr(); - - m_jit.loadPtr(MacroAssembler::Address(baseGPR, JSArray::storageOffset()), resultGPR); - m_jit.load32(MacroAssembler::Address(resultGPR, OBJECT_OFFSETOF(ArrayStorage, m_length)), resultGPR); - - speculationCheck(Uncountable, JSValueRegs(), NoNode, m_jit.branch32(MacroAssembler::LessThan, resultGPR, MacroAssembler::TrustedImm32(0))); - - integerResult(resultGPR, m_compileIndex); + case GetArrayLength: + compileGetArrayLength(node); break; - } - - case GetArgumentsLength: { - compileGetArgumentsLength(node); - break; - } - - case GetStringLength: { - SpeculateCellOperand base(this, node.child1()); - GPRTemporary result(this); - - GPRReg baseGPR = base.gpr(); - GPRReg resultGPR = result.gpr(); - - if (!isStringSpeculation(m_state.forNode(node.child1()).m_type)) - speculationCheck(BadType, JSValueSource::unboxedCell(baseGPR), node.child1(), m_jit.branchPtr(MacroAssembler::NotEqual, MacroAssembler::Address(baseGPR, JSCell::structureOffset()), MacroAssembler::TrustedImmPtr(m_jit.globalData()->stringStructure.get()))); - m_jit.load32(MacroAssembler::Address(baseGPR, JSString::offsetOfLength()), resultGPR); - - integerResult(resultGPR, m_compileIndex); - break; - } - - case GetInt8ArrayLength: { - compileGetTypedArrayLength(m_jit.globalData()->int8ArrayDescriptor(), node, !isInt8ArraySpeculation(m_state.forNode(node.child1()).m_type)); - break; - } - case GetInt16ArrayLength: { - compileGetTypedArrayLength(m_jit.globalData()->int16ArrayDescriptor(), node, !isInt16ArraySpeculation(m_state.forNode(node.child1()).m_type)); - break; - } - case GetInt32ArrayLength: { - compileGetTypedArrayLength(m_jit.globalData()->int32ArrayDescriptor(), node, !isInt32ArraySpeculation(m_state.forNode(node.child1()).m_type)); - break; - } - case GetUint8ArrayLength: { - compileGetTypedArrayLength(m_jit.globalData()->uint8ArrayDescriptor(), node, !isUint8ArraySpeculation(m_state.forNode(node.child1()).m_type)); - break; - } - case GetUint8ClampedArrayLength: { - compileGetTypedArrayLength(m_jit.globalData()->uint8ClampedArrayDescriptor(), node, !isUint8ClampedArraySpeculation(m_state.forNode(node.child1()).m_type)); - break; - } - case GetUint16ArrayLength: { - compileGetTypedArrayLength(m_jit.globalData()->uint16ArrayDescriptor(), node, !isUint16ArraySpeculation(m_state.forNode(node.child1()).m_type)); - break; - } - case GetUint32ArrayLength: { - compileGetTypedArrayLength(m_jit.globalData()->uint32ArrayDescriptor(), node, !isUint32ArraySpeculation(m_state.forNode(node.child1()).m_type)); - break; - } - case GetFloat32ArrayLength: { - compileGetTypedArrayLength(m_jit.globalData()->float32ArrayDescriptor(), node, !isFloat32ArraySpeculation(m_state.forNode(node.child1()).m_type)); - break; - } - case GetFloat64ArrayLength: { - compileGetTypedArrayLength(m_jit.globalData()->float64ArrayDescriptor(), node, !isFloat64ArraySpeculation(m_state.forNode(node.child1()).m_type)); - break; - } - case CheckFunction: { SpeculateCellOperand function(this, node.child1()); speculationCheck(BadCache, JSValueRegs(), NoNode, m_jit.branchWeakPtr(JITCompiler::NotEqual, function.gpr(), node.function())); diff --git a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp index c2151088c..c2e207264 100644 --- a/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp +++ b/Source/JavaScriptCore/dfg/DFGSpeculativeJIT64.cpp @@ -2374,12 +2374,13 @@ void SpeculativeJIT::compile(Node& node) } case GetByVal: { - if (!node.prediction() || !at(node.child1()).prediction() || !at(node.child2()).prediction()) { + switch (node.arrayMode()) { + case Array::Undecided: + case Array::ForceExit: + ASSERT_NOT_REACHED(); terminateSpeculativeExecution(InadequateCoverage, JSValueRegs(), NoNode); break; - } - - if (!at(node.child2()).shouldSpeculateInteger() || (!node.child3() && !at(node.child1()).shouldSpeculateArguments())) { + case Array::Generic: { JSValueOperand base(this, node.child1()); JSValueOperand property(this, node.child2()); GPRReg baseGPR = base.gpr(); @@ -2392,120 +2393,90 @@ void SpeculativeJIT::compile(Node& node) jsValueResult(result.gpr(), m_compileIndex); break; } - - if (at(node.child1()).shouldSpeculateArguments()) { - compileGetByValOnArguments(node); + case Array::JSArray: + case Array::JSArrayOutOfBounds: { + SpeculateCellOperand base(this, node.child1()); + SpeculateStrictInt32Operand property(this, node.child2()); + StorageOperand storage(this, node.child3()); + + GPRReg baseReg = base.gpr(); + GPRReg propertyReg = property.gpr(); + GPRReg storageReg = storage.gpr(); + if (!m_compileOkay) return; + + // We will have already speculated that the base is some kind of array, + // at this point. + + speculationCheck(Uncountable, JSValueRegs(), NoNode, m_jit.branch32(MacroAssembler::AboveOrEqual, propertyReg, MacroAssembler::Address(baseReg, JSArray::vectorLengthOffset()))); + + GPRTemporary result(this); + m_jit.loadPtr(MacroAssembler::BaseIndex(storageReg, propertyReg, MacroAssembler::ScalePtr, OBJECT_OFFSETOF(ArrayStorage, m_vector[0])), result.gpr()); + speculationCheck(Uncountable, JSValueRegs(), NoNode, m_jit.branchTestPtr(MacroAssembler::Zero, result.gpr())); + + jsValueResult(result.gpr(), m_compileIndex); break; } - - if (at(node.child1()).prediction() == SpecString) { + case Array::String: compileGetByValOnString(node); - if (!m_compileOkay) - return; break; - } - - if (at(node.child1()).shouldSpeculateInt8Array()) { - compileGetByValOnIntTypedArray(m_jit.globalData()->int8ArrayDescriptor(), node, sizeof(int8_t), isInt8ArraySpeculation(m_state.forNode(node.child1()).m_type) ? NoTypedArrayTypeSpecCheck : AllTypedArraySpecChecks, SignedTypedArray); - if (!m_compileOkay) - return; - break; - } - - if (at(node.child1()).shouldSpeculateInt16Array()) { - compileGetByValOnIntTypedArray(m_jit.globalData()->int16ArrayDescriptor(), node, sizeof(int16_t), isInt16ArraySpeculation(m_state.forNode(node.child1()).m_type) ? NoTypedArrayTypeSpecCheck : AllTypedArraySpecChecks, SignedTypedArray); - if (!m_compileOkay) - return; - break; - } - - if (at(node.child1()).shouldSpeculateInt32Array()) { - compileGetByValOnIntTypedArray(m_jit.globalData()->int32ArrayDescriptor(), node, sizeof(int32_t), isInt32ArraySpeculation(m_state.forNode(node.child1()).m_type) ? NoTypedArrayTypeSpecCheck : AllTypedArraySpecChecks, SignedTypedArray); - if (!m_compileOkay) - return; - break; - } - - if (at(node.child1()).shouldSpeculateUint8Array()) { - compileGetByValOnIntTypedArray(m_jit.globalData()->uint8ArrayDescriptor(), node, sizeof(uint8_t), isUint8ArraySpeculation(m_state.forNode(node.child1()).m_type) ? NoTypedArrayTypeSpecCheck : AllTypedArraySpecChecks, UnsignedTypedArray); - if (!m_compileOkay) - return; - break; - } - - if (at(node.child1()).shouldSpeculateUint8ClampedArray()) { - compileGetByValOnIntTypedArray(m_jit.globalData()->uint8ClampedArrayDescriptor(), node, sizeof(uint8_t), isUint8ClampedArraySpeculation(m_state.forNode(node.child1()).m_type) ? NoTypedArrayTypeSpecCheck : AllTypedArraySpecChecks, UnsignedTypedArray); - if (!m_compileOkay) - return; + case Array::Arguments: + compileGetByValOnArguments(node); + break; + case Array::Int8Array: + compileGetByValOnIntTypedArray(m_jit.globalData()->int8ArrayDescriptor(), node, sizeof(int8_t), SignedTypedArray); + break; + case Array::Int16Array: + compileGetByValOnIntTypedArray(m_jit.globalData()->int16ArrayDescriptor(), node, sizeof(int16_t), SignedTypedArray); + break; + case Array::Int32Array: + compileGetByValOnIntTypedArray(m_jit.globalData()->int32ArrayDescriptor(), node, sizeof(int32_t), SignedTypedArray); + break; + case Array::Uint8Array: + compileGetByValOnIntTypedArray(m_jit.globalData()->uint8ArrayDescriptor(), node, sizeof(uint8_t), UnsignedTypedArray); + break; + case Array::Uint8ClampedArray: + compileGetByValOnIntTypedArray(m_jit.globalData()->uint8ClampedArrayDescriptor(), node, sizeof(uint8_t), UnsignedTypedArray); + break; + case Array::Uint16Array: + compileGetByValOnIntTypedArray(m_jit.globalData()->uint16ArrayDescriptor(), node, sizeof(uint16_t), UnsignedTypedArray); + break; + case Array::Uint32Array: + compileGetByValOnIntTypedArray(m_jit.globalData()->uint32ArrayDescriptor(), node, sizeof(uint32_t), UnsignedTypedArray); + break; + case Array::Float32Array: + compileGetByValOnFloatTypedArray(m_jit.globalData()->float32ArrayDescriptor(), node, sizeof(float)); + break; + case Array::Float64Array: + compileGetByValOnFloatTypedArray(m_jit.globalData()->float64ArrayDescriptor(), node, sizeof(double)); + break; + default: + ASSERT_NOT_REACHED(); break; } - - if (at(node.child1()).shouldSpeculateUint16Array()) { - compileGetByValOnIntTypedArray(m_jit.globalData()->uint16ArrayDescriptor(), node, sizeof(uint16_t), isUint16ArraySpeculation(m_state.forNode(node.child1()).m_type) ? NoTypedArrayTypeSpecCheck : AllTypedArraySpecChecks, UnsignedTypedArray); - if (!m_compileOkay) - return; - break; - } - - if (at(node.child1()).shouldSpeculateUint32Array()) { - compileGetByValOnIntTypedArray(m_jit.globalData()->uint32ArrayDescriptor(), node, sizeof(uint32_t), isUint32ArraySpeculation(m_state.forNode(node.child1()).m_type) ? NoTypedArrayTypeSpecCheck : AllTypedArraySpecChecks, UnsignedTypedArray); - if (!m_compileOkay) - return; - break; - } - - if (at(node.child1()).shouldSpeculateFloat32Array()) { - compileGetByValOnFloatTypedArray(m_jit.globalData()->float32ArrayDescriptor(), node, sizeof(float), isFloat32ArraySpeculation(m_state.forNode(node.child1()).m_type) ? NoTypedArrayTypeSpecCheck : AllTypedArraySpecChecks); - if (!m_compileOkay) - return; - break; - } - - if (at(node.child1()).shouldSpeculateFloat64Array()) { - compileGetByValOnFloatTypedArray(m_jit.globalData()->float64ArrayDescriptor(), node, sizeof(double), isFloat64ArraySpeculation(m_state.forNode(node.child1()).m_type) ? NoTypedArrayTypeSpecCheck : AllTypedArraySpecChecks); - if (!m_compileOkay) - return; - break; - } - - SpeculateCellOperand base(this, node.child1()); - SpeculateStrictInt32Operand property(this, node.child2()); - StorageOperand storage(this, node.child3()); - - GPRReg baseReg = base.gpr(); - GPRReg propertyReg = property.gpr(); - GPRReg storageReg = storage.gpr(); - - if (!m_compileOkay) - return; - - // We will have already speculated that the base is some kind of array, - // at this point. - - speculationCheck(Uncountable, JSValueRegs(), NoNode, m_jit.branch32(MacroAssembler::AboveOrEqual, propertyReg, MacroAssembler::Address(baseReg, JSArray::vectorLengthOffset()))); - - GPRTemporary result(this); - m_jit.loadPtr(MacroAssembler::BaseIndex(storageReg, propertyReg, MacroAssembler::ScalePtr, OBJECT_OFFSETOF(ArrayStorage, m_vector[0])), result.gpr()); - speculationCheck(Uncountable, JSValueRegs(), NoNode, m_jit.branchTestPtr(MacroAssembler::Zero, result.gpr())); - - jsValueResult(result.gpr(), m_compileIndex); break; } case PutByVal: - case PutByValSafe: { + case PutByValAlias: { Edge child1 = m_jit.graph().varArgChild(node, 0); Edge child2 = m_jit.graph().varArgChild(node, 1); Edge child3 = m_jit.graph().varArgChild(node, 2); - if (!at(child1).prediction() || !at(child2).prediction()) { + Array::Mode arrayMode = modeForPut(node.arrayMode()); + bool alreadyHandled = false; + + switch (arrayMode) { + case Array::Undecided: + case Array::ForceExit: + ASSERT_NOT_REACHED(); terminateSpeculativeExecution(InadequateCoverage, JSValueRegs(), NoNode); + alreadyHandled = true; break; - } - - if (!at(child2).shouldSpeculateInteger()) { + case Array::Generic: { + ASSERT(node.op() == PutByVal); + JSValueOperand arg1(this, child1); JSValueOperand arg2(this, child2); JSValueOperand arg3(this, child3); @@ -2517,19 +2488,97 @@ void SpeculativeJIT::compile(Node& node) callOperation(m_jit.strictModeFor(node.codeOrigin) ? operationPutByValStrict : operationPutByValNonStrict, arg1GPR, arg2GPR, arg3GPR); noResult(m_compileIndex); + alreadyHandled = true; break; } - + default: + break; + } + + if (alreadyHandled) + break; + SpeculateCellOperand base(this, child1); SpeculateStrictInt32Operand property(this, child2); - if (at(child1).shouldSpeculateArguments()) { - dataLog(" in here "); + + GPRReg baseReg = base.gpr(); + GPRReg propertyReg = property.gpr(); + + speculateArray(arrayMode, child1, baseReg); + + switch (arrayMode) { + case Array::JSArray: + case Array::JSArrayOutOfBounds: { + JSValueOperand value(this, child3); + GPRTemporary scratch(this); + + // Map base, property & value into registers, allocate a scratch register. + GPRReg valueReg = value.gpr(); + GPRReg scratchReg = scratch.gpr(); + + if (!m_compileOkay) + return; + + writeBarrier(baseReg, value.gpr(), child3, WriteBarrierForPropertyAccess, scratchReg); + + if (node.op() == PutByValAlias) { + GPRReg storageReg = scratchReg; + m_jit.loadPtr(MacroAssembler::Address(baseReg, JSArray::storageOffset()), storageReg); + + // Store the value to the array. + GPRReg propertyReg = property.gpr(); + GPRReg valueReg = value.gpr(); + m_jit.storePtr(valueReg, MacroAssembler::BaseIndex(storageReg, propertyReg, MacroAssembler::ScalePtr, OBJECT_OFFSETOF(ArrayStorage, m_vector[0]))); + + noResult(m_compileIndex); + break; + } + + MacroAssembler::Jump beyondArrayBounds = m_jit.branch32(MacroAssembler::AboveOrEqual, propertyReg, MacroAssembler::Address(baseReg, JSArray::vectorLengthOffset())); + if (arrayMode == Array::JSArray) + speculationCheck(OutOfBounds, JSValueRegs(), NoNode, beyondArrayBounds); + + base.use(); + property.use(); + value.use(); + + // Get the array storage. + GPRReg storageReg = scratchReg; + m_jit.loadPtr(MacroAssembler::Address(baseReg, JSArray::storageOffset()), storageReg); + + // Check if we're writing to a hole; if so increment m_numValuesInVector. + MacroAssembler::Jump notHoleValue = m_jit.branchTestPtr(MacroAssembler::NonZero, MacroAssembler::BaseIndex(storageReg, propertyReg, MacroAssembler::ScalePtr, OBJECT_OFFSETOF(ArrayStorage, m_vector[0]))); + m_jit.add32(TrustedImm32(1), MacroAssembler::Address(storageReg, OBJECT_OFFSETOF(ArrayStorage, m_numValuesInVector))); + + // If we're writing to a hole we might be growing the array; + MacroAssembler::Jump lengthDoesNotNeedUpdate = m_jit.branch32(MacroAssembler::Below, propertyReg, MacroAssembler::Address(storageReg, OBJECT_OFFSETOF(ArrayStorage, m_length))); + m_jit.add32(TrustedImm32(1), propertyReg); + m_jit.store32(propertyReg, MacroAssembler::Address(storageReg, OBJECT_OFFSETOF(ArrayStorage, m_length))); + m_jit.sub32(TrustedImm32(1), propertyReg); + + lengthDoesNotNeedUpdate.link(&m_jit); + notHoleValue.link(&m_jit); + + // Store the value to the array. + m_jit.storePtr(valueReg, MacroAssembler::BaseIndex(storageReg, propertyReg, MacroAssembler::ScalePtr, OBJECT_OFFSETOF(ArrayStorage, m_vector[0]))); + + if (arrayMode == Array::JSArrayOutOfBounds) { + addSlowPathGenerator( + slowPathCall( + beyondArrayBounds, this, + m_jit.codeBlock()->isStrictMode() ? operationPutByValBeyondArrayBoundsStrict : operationPutByValBeyondArrayBoundsNonStrict, + NoResult, baseReg, propertyReg, valueReg)); + } + + noResult(m_compileIndex, UseChildrenCalledExplicitly); + break; + } + + case Array::Arguments: { JSValueOperand value(this, child3); GPRTemporary scratch(this); GPRTemporary scratch2(this); - GPRReg baseReg = base.gpr(); - GPRReg propertyReg = property.gpr(); GPRReg valueReg = value.gpr(); GPRReg scratchReg = scratch.gpr(); GPRReg scratch2Reg = scratch2.gpr(); @@ -2537,15 +2586,6 @@ void SpeculativeJIT::compile(Node& node) if (!m_compileOkay) return; - if (!isArgumentsSpeculation(m_state.forNode(child1).m_type)) { - speculationCheck( - BadType, JSValueSource::unboxedCell(baseReg), child1, - m_jit.branchPtr( - MacroAssembler::NotEqual, - MacroAssembler::Address(baseReg, JSCell::classInfoOffset()), - MacroAssembler::TrustedImmPtr(&Arguments::s_info))); - } - m_jit.loadPtr( MacroAssembler::Address(baseReg, Arguments::offsetOfData()), scratchReg); @@ -2579,225 +2619,51 @@ void SpeculativeJIT::compile(Node& node) noResult(m_compileIndex); break; } - - if (at(child1).shouldSpeculateInt8Array()) { - compilePutByValForIntTypedArray(m_jit.globalData()->int8ArrayDescriptor(), base.gpr(), property.gpr(), node, sizeof(int8_t), isInt8ArraySpeculation(m_state.forNode(child1).m_type) ? NoTypedArrayTypeSpecCheck : AllTypedArraySpecChecks, SignedTypedArray); - if (!m_compileOkay) - return; - break; - } - - if (at(child1).shouldSpeculateInt16Array()) { - compilePutByValForIntTypedArray(m_jit.globalData()->int16ArrayDescriptor(), base.gpr(), property.gpr(), node, sizeof(int16_t), isInt16ArraySpeculation(m_state.forNode(child1).m_type) ? NoTypedArrayTypeSpecCheck : AllTypedArraySpecChecks, SignedTypedArray); - if (!m_compileOkay) - return; - break; - } - - if (at(child1).shouldSpeculateInt32Array()) { - compilePutByValForIntTypedArray(m_jit.globalData()->int32ArrayDescriptor(), base.gpr(), property.gpr(), node, sizeof(int32_t), isInt32ArraySpeculation(m_state.forNode(child1).m_type) ? NoTypedArrayTypeSpecCheck : AllTypedArraySpecChecks, SignedTypedArray); - if (!m_compileOkay) - return; - break; - } - - if (at(child1).shouldSpeculateUint8Array()) { - compilePutByValForIntTypedArray(m_jit.globalData()->uint8ArrayDescriptor(), base.gpr(), property.gpr(), node, sizeof(uint8_t), isUint8ArraySpeculation(m_state.forNode(child1).m_type) ? NoTypedArrayTypeSpecCheck : AllTypedArraySpecChecks, UnsignedTypedArray); - if (!m_compileOkay) - return; - break; - } - - if (at(child1).shouldSpeculateUint8ClampedArray()) { - compilePutByValForIntTypedArray(m_jit.globalData()->uint8ClampedArrayDescriptor(), base.gpr(), property.gpr(), node, sizeof(uint8_t), isUint8ClampedArraySpeculation(m_state.forNode(child1).m_type) ? NoTypedArrayTypeSpecCheck : AllTypedArraySpecChecks, UnsignedTypedArray, ClampRounding); + + case Array::Int8Array: + compilePutByValForIntTypedArray(m_jit.globalData()->int8ArrayDescriptor(), base.gpr(), property.gpr(), node, sizeof(int8_t), SignedTypedArray); break; - } - - if (at(child1).shouldSpeculateUint16Array()) { - compilePutByValForIntTypedArray(m_jit.globalData()->uint16ArrayDescriptor(), base.gpr(), property.gpr(), node, sizeof(uint16_t), isUint16ArraySpeculation(m_state.forNode(child1).m_type) ? NoTypedArrayTypeSpecCheck : AllTypedArraySpecChecks, UnsignedTypedArray); - if (!m_compileOkay) - return; - break; - } - - if (at(child1).shouldSpeculateUint32Array()) { - compilePutByValForIntTypedArray(m_jit.globalData()->uint32ArrayDescriptor(), base.gpr(), property.gpr(), node, sizeof(uint32_t), isUint32ArraySpeculation(m_state.forNode(child1).m_type) ? NoTypedArrayTypeSpecCheck : AllTypedArraySpecChecks, UnsignedTypedArray); - if (!m_compileOkay) - return; - break; - } - - if (at(child1).shouldSpeculateFloat32Array()) { - compilePutByValForFloatTypedArray(m_jit.globalData()->float32ArrayDescriptor(), base.gpr(), property.gpr(), node, sizeof(float), isFloat32ArraySpeculation(m_state.forNode(child1).m_type) ? NoTypedArrayTypeSpecCheck : AllTypedArraySpecChecks); - if (!m_compileOkay) - return; - break; - } - - if (at(child1).shouldSpeculateFloat64Array()) { - compilePutByValForFloatTypedArray(m_jit.globalData()->float64ArrayDescriptor(), base.gpr(), property.gpr(), node, sizeof(double), isFloat64ArraySpeculation(m_state.forNode(child1).m_type) ? NoTypedArrayTypeSpecCheck : AllTypedArraySpecChecks); - if (!m_compileOkay) - return; - break; - } - JSValueOperand value(this, child3); - GPRTemporary scratch(this); - - // Map base, property & value into registers, allocate a scratch register. - GPRReg baseReg = base.gpr(); - GPRReg propertyReg = property.gpr(); - GPRReg valueReg = value.gpr(); - GPRReg scratchReg = scratch.gpr(); - - if (!m_compileOkay) - return; - - writeBarrier(baseReg, value.gpr(), child3, WriteBarrierForPropertyAccess, scratchReg); - - speculateArray(child1, baseReg); - - MacroAssembler::Jump beyondArrayBounds = m_jit.branch32(MacroAssembler::AboveOrEqual, propertyReg, MacroAssembler::Address(baseReg, JSArray::vectorLengthOffset())); - if (node.op() == PutByVal) - speculationCheck(OutOfBounds, JSValueRegs(), NoNode, beyondArrayBounds); - - base.use(); - property.use(); - value.use(); - - // Get the array storage. - GPRReg storageReg = scratchReg; - m_jit.loadPtr(MacroAssembler::Address(baseReg, JSArray::storageOffset()), storageReg); - - // Check if we're writing to a hole; if so increment m_numValuesInVector. - MacroAssembler::Jump notHoleValue = m_jit.branchTestPtr(MacroAssembler::NonZero, MacroAssembler::BaseIndex(storageReg, propertyReg, MacroAssembler::ScalePtr, OBJECT_OFFSETOF(ArrayStorage, m_vector[0]))); - m_jit.add32(TrustedImm32(1), MacroAssembler::Address(storageReg, OBJECT_OFFSETOF(ArrayStorage, m_numValuesInVector))); - - // If we're writing to a hole we might be growing the array; - MacroAssembler::Jump lengthDoesNotNeedUpdate = m_jit.branch32(MacroAssembler::Below, propertyReg, MacroAssembler::Address(storageReg, OBJECT_OFFSETOF(ArrayStorage, m_length))); - m_jit.add32(TrustedImm32(1), propertyReg); - m_jit.store32(propertyReg, MacroAssembler::Address(storageReg, OBJECT_OFFSETOF(ArrayStorage, m_length))); - m_jit.sub32(TrustedImm32(1), propertyReg); - - lengthDoesNotNeedUpdate.link(&m_jit); - notHoleValue.link(&m_jit); - - // Store the value to the array. - m_jit.storePtr(valueReg, MacroAssembler::BaseIndex(storageReg, propertyReg, MacroAssembler::ScalePtr, OBJECT_OFFSETOF(ArrayStorage, m_vector[0]))); - - if (node.op() == PutByValSafe) { - addSlowPathGenerator( - slowPathCall( - beyondArrayBounds, this, - m_jit.codeBlock()->isStrictMode() ? operationPutByValBeyondArrayBoundsStrict : operationPutByValBeyondArrayBoundsNonStrict, - NoResult, baseReg, propertyReg, valueReg)); - } - - noResult(m_compileIndex, UseChildrenCalledExplicitly); - break; - } - - case PutByValAlias: { - Edge child1 = m_jit.graph().varArgChild(node, 0); - Edge child2 = m_jit.graph().varArgChild(node, 1); - Edge child3 = m_jit.graph().varArgChild(node, 2); - - if (!at(child1).prediction() || !at(child2).prediction()) { - terminateSpeculativeExecution(InadequateCoverage, JSValueRegs(), NoNode); + case Array::Int16Array: + compilePutByValForIntTypedArray(m_jit.globalData()->int16ArrayDescriptor(), base.gpr(), property.gpr(), node, sizeof(int16_t), SignedTypedArray); break; - } - - ASSERT(isActionableMutableArraySpeculation(at(child1).prediction())); - ASSERT(at(child2).shouldSpeculateInteger()); - - SpeculateCellOperand base(this, child1); - SpeculateStrictInt32Operand property(this, child2); - if (at(child1).shouldSpeculateInt8Array()) { - compilePutByValForIntTypedArray(m_jit.globalData()->int8ArrayDescriptor(), base.gpr(), property.gpr(), node, sizeof(int8_t), NoTypedArraySpecCheck, SignedTypedArray); - if (!m_compileOkay) - return; - break; - } - - if (at(child1).shouldSpeculateInt16Array()) { - compilePutByValForIntTypedArray(m_jit.globalData()->int16ArrayDescriptor(), base.gpr(), property.gpr(), node, sizeof(int16_t), NoTypedArraySpecCheck, SignedTypedArray); - if (!m_compileOkay) - return; - break; - } - - if (at(child1).shouldSpeculateInt32Array()) { - compilePutByValForIntTypedArray(m_jit.globalData()->int32ArrayDescriptor(), base.gpr(), property.gpr(), node, sizeof(int32_t), NoTypedArraySpecCheck, SignedTypedArray); - if (!m_compileOkay) - return; - break; - } - - if (at(child1).shouldSpeculateUint8Array()) { - compilePutByValForIntTypedArray(m_jit.globalData()->uint8ArrayDescriptor(), base.gpr(), property.gpr(), node, sizeof(uint8_t), NoTypedArraySpecCheck, UnsignedTypedArray); - if (!m_compileOkay) - return; - break; - } - - if (at(child1).shouldSpeculateUint8ClampedArray()) { - compilePutByValForIntTypedArray(m_jit.globalData()->uint8ClampedArrayDescriptor(), base.gpr(), property.gpr(), node, sizeof(uint8_t), NoTypedArraySpecCheck, UnsignedTypedArray, ClampRounding); - if (!m_compileOkay) - return; + + case Array::Int32Array: + compilePutByValForIntTypedArray(m_jit.globalData()->int32ArrayDescriptor(), base.gpr(), property.gpr(), node, sizeof(int32_t), SignedTypedArray); + break; + + case Array::Uint8Array: + compilePutByValForIntTypedArray(m_jit.globalData()->uint8ArrayDescriptor(), base.gpr(), property.gpr(), node, sizeof(uint8_t), UnsignedTypedArray); + break; + + case Array::Uint8ClampedArray: + compilePutByValForIntTypedArray(m_jit.globalData()->uint8ClampedArrayDescriptor(), base.gpr(), property.gpr(), node, sizeof(uint8_t), UnsignedTypedArray, ClampRounding); + break; + + case Array::Uint16Array: + compilePutByValForIntTypedArray(m_jit.globalData()->uint16ArrayDescriptor(), base.gpr(), property.gpr(), node, sizeof(uint16_t), UnsignedTypedArray); + break; + + case Array::Uint32Array: + compilePutByValForIntTypedArray(m_jit.globalData()->uint32ArrayDescriptor(), base.gpr(), property.gpr(), node, sizeof(uint32_t), UnsignedTypedArray); + break; + + case Array::Float32Array: + compilePutByValForFloatTypedArray(m_jit.globalData()->float32ArrayDescriptor(), base.gpr(), property.gpr(), node, sizeof(float)); + break; + + case Array::Float64Array: + compilePutByValForFloatTypedArray(m_jit.globalData()->float64ArrayDescriptor(), base.gpr(), property.gpr(), node, sizeof(double)); + break; + + default: + ASSERT_NOT_REACHED(); break; } - if (at(child1).shouldSpeculateUint16Array()) { - compilePutByValForIntTypedArray(m_jit.globalData()->uint16ArrayDescriptor(), base.gpr(), property.gpr(), node, sizeof(uint16_t), NoTypedArraySpecCheck, UnsignedTypedArray); - if (!m_compileOkay) - return; - break; - } - - if (at(child1).shouldSpeculateUint32Array()) { - compilePutByValForIntTypedArray(m_jit.globalData()->uint32ArrayDescriptor(), base.gpr(), property.gpr(), node, sizeof(uint32_t), NoTypedArraySpecCheck, UnsignedTypedArray); - if (!m_compileOkay) - return; - break; - } - - if (at(child1).shouldSpeculateFloat32Array()) { - compilePutByValForFloatTypedArray(m_jit.globalData()->float32ArrayDescriptor(), base.gpr(), property.gpr(), node, sizeof(float), NoTypedArraySpecCheck); - if (!m_compileOkay) - return; - break; - } - - if (at(child1).shouldSpeculateFloat64Array()) { - compilePutByValForFloatTypedArray(m_jit.globalData()->float64ArrayDescriptor(), base.gpr(), property.gpr(), node, sizeof(double), NoTypedArraySpecCheck); - if (!m_compileOkay) - return; - break; - } - - ASSERT(at(child1).shouldSpeculateArray()); - - JSValueOperand value(this, child3); - GPRTemporary scratch(this); - - GPRReg baseReg = base.gpr(); - GPRReg scratchReg = scratch.gpr(); - - writeBarrier(base.gpr(), value.gpr(), child3, WriteBarrierForPropertyAccess, scratchReg); - - // Get the array storage. - GPRReg storageReg = scratchReg; - m_jit.loadPtr(MacroAssembler::Address(baseReg, JSArray::storageOffset()), storageReg); - - // Store the value to the array. - GPRReg propertyReg = property.gpr(); - GPRReg valueReg = value.gpr(); - m_jit.storePtr(valueReg, MacroAssembler::BaseIndex(storageReg, propertyReg, MacroAssembler::ScalePtr, OBJECT_OFFSETOF(ArrayStorage, m_vector[0]))); - - noResult(m_compileIndex); break; } - + case RegExpExec: { if (compileRegExpExec(node)) return; @@ -2859,7 +2725,7 @@ void SpeculativeJIT::compile(Node& node) writeBarrier(baseGPR, valueGPR, node.child2(), WriteBarrierForPropertyAccess, storageGPR, storageLengthGPR); - speculateArray(node.child1(), baseGPR); + speculateArray(Array::JSArray, node.child1(), baseGPR); m_jit.loadPtr(MacroAssembler::Address(baseGPR, JSArray::storageOffset()), storageGPR); m_jit.load32(MacroAssembler::Address(storageGPR, OBJECT_OFFSETOF(ArrayStorage, m_length)), storageLengthGPR); @@ -2896,7 +2762,7 @@ void SpeculativeJIT::compile(Node& node) GPRReg storageGPR = storage.gpr(); GPRReg storageLengthGPR = storageLength.gpr(); - speculateArray(node.child1(), baseGPR); + speculateArray(Array::JSArray, node.child1(), baseGPR); m_jit.loadPtr(MacroAssembler::Address(baseGPR, JSArray::storageOffset()), storageGPR); m_jit.load32(MacroAssembler::Address(storageGPR, OBJECT_OFFSETOF(ArrayStorage, m_length)), storageLengthGPR); @@ -3386,81 +3252,10 @@ void SpeculativeJIT::compile(Node& node) break; } - case GetArrayLength: { - SpeculateCellOperand base(this, node.child1()); - GPRTemporary result(this); - - GPRReg baseGPR = base.gpr(); - GPRReg resultGPR = result.gpr(); - - speculateArray(node.child1(), baseGPR); - - m_jit.loadPtr(MacroAssembler::Address(baseGPR, JSArray::storageOffset()), resultGPR); - m_jit.load32(MacroAssembler::Address(resultGPR, OBJECT_OFFSETOF(ArrayStorage, m_length)), resultGPR); - - speculationCheck(Uncountable, JSValueRegs(), NoNode, m_jit.branch32(MacroAssembler::LessThan, resultGPR, MacroAssembler::TrustedImm32(0))); - - integerResult(resultGPR, m_compileIndex); + case GetArrayLength: + compileGetArrayLength(node); break; - } - case GetArgumentsLength: { - compileGetArgumentsLength(node); - break; - } - - case GetStringLength: { - SpeculateCellOperand base(this, node.child1()); - GPRTemporary result(this); - - GPRReg baseGPR = base.gpr(); - GPRReg resultGPR = result.gpr(); - - if (!isStringSpeculation(m_state.forNode(node.child1()).m_type)) - speculationCheck(BadType, JSValueRegs(baseGPR), node.child1(), m_jit.branchPtr(MacroAssembler::NotEqual, MacroAssembler::Address(baseGPR, JSCell::structureOffset()), MacroAssembler::TrustedImmPtr(m_jit.globalData()->stringStructure.get()))); - - m_jit.load32(MacroAssembler::Address(baseGPR, JSString::offsetOfLength()), resultGPR); - - integerResult(resultGPR, m_compileIndex); - break; - } - - case GetInt8ArrayLength: { - compileGetTypedArrayLength(m_jit.globalData()->int8ArrayDescriptor(), node, !isInt8ArraySpeculation(m_state.forNode(node.child1()).m_type)); - break; - } - case GetInt16ArrayLength: { - compileGetTypedArrayLength(m_jit.globalData()->int16ArrayDescriptor(), node, !isInt16ArraySpeculation(m_state.forNode(node.child1()).m_type)); - break; - } - case GetInt32ArrayLength: { - compileGetTypedArrayLength(m_jit.globalData()->int32ArrayDescriptor(), node, !isInt32ArraySpeculation(m_state.forNode(node.child1()).m_type)); - break; - } - case GetUint8ArrayLength: { - compileGetTypedArrayLength(m_jit.globalData()->uint8ArrayDescriptor(), node, !isUint8ArraySpeculation(m_state.forNode(node.child1()).m_type)); - break; - } - case GetUint8ClampedArrayLength: { - compileGetTypedArrayLength(m_jit.globalData()->uint8ClampedArrayDescriptor(), node, !isUint8ClampedArraySpeculation(m_state.forNode(node.child1()).m_type)); - break; - } - case GetUint16ArrayLength: { - compileGetTypedArrayLength(m_jit.globalData()->uint16ArrayDescriptor(), node, !isUint16ArraySpeculation(m_state.forNode(node.child1()).m_type)); - break; - } - case GetUint32ArrayLength: { - compileGetTypedArrayLength(m_jit.globalData()->uint32ArrayDescriptor(), node, !isUint32ArraySpeculation(m_state.forNode(node.child1()).m_type)); - break; - } - case GetFloat32ArrayLength: { - compileGetTypedArrayLength(m_jit.globalData()->float32ArrayDescriptor(), node, !isFloat32ArraySpeculation(m_state.forNode(node.child1()).m_type)); - break; - } - case GetFloat64ArrayLength: { - compileGetTypedArrayLength(m_jit.globalData()->float64ArrayDescriptor(), node, !isFloat64ArraySpeculation(m_state.forNode(node.child1()).m_type)); - break; - } case CheckFunction: { SpeculateCellOperand function(this, node.child1()); speculationCheck(BadCache, JSValueRegs(), NoNode, m_jit.branchWeakPtr(JITCompiler::NotEqual, function.gpr(), node.function())); diff --git a/Source/JavaScriptCore/dfg/DFGStructureCheckHoistingPhase.cpp b/Source/JavaScriptCore/dfg/DFGStructureCheckHoistingPhase.cpp index 68627f95c..eb04a6747 100644 --- a/Source/JavaScriptCore/dfg/DFGStructureCheckHoistingPhase.cpp +++ b/Source/JavaScriptCore/dfg/DFGStructureCheckHoistingPhase.cpp @@ -98,7 +98,6 @@ public: case GetByVal: case PutByVal: case PutByValAlias: - case PutByValSafe: case GetArrayLength: case Phantom: // Don't count these uses. @@ -215,53 +214,12 @@ public: } case GetByVal: - if (!node.prediction() || !m_graph[node.child1()].prediction() || !m_graph[node.child2()].prediction()) - break; - if (!isActionableArraySpeculation(m_graph[node.child1()].prediction()) || !m_graph[node.child2()].shouldSpeculateInteger()) - clobber(live); - break; - case PutByVal: case PutByValAlias: - case PutByValSafe: { - Edge child1 = m_graph.varArgChild(node, 0); - Edge child2 = m_graph.varArgChild(node, 1); - - if (!m_graph[child1].prediction() || !m_graph[child2].prediction()) - break; - if (!m_graph[child2].shouldSpeculateInteger() -#if USE(JSVALUE32_64) - || m_graph[child1].shouldSpeculateArguments() -#endif - ) { - clobber(live); - break; - } - if (node.op() != PutByValSafe) - break; - if (m_graph[child1].shouldSpeculateArguments()) - break; - if (m_graph[child1].shouldSpeculateInt8Array()) - break; - if (m_graph[child1].shouldSpeculateInt16Array()) - break; - if (m_graph[child1].shouldSpeculateInt32Array()) - break; - if (m_graph[child1].shouldSpeculateUint8Array()) - break; - if (m_graph[child1].shouldSpeculateUint8ClampedArray()) - break; - if (m_graph[child1].shouldSpeculateUint16Array()) - break; - if (m_graph[child1].shouldSpeculateUint32Array()) - break; - if (m_graph[child1].shouldSpeculateFloat32Array()) - break; - if (m_graph[child1].shouldSpeculateFloat64Array()) + if (m_graph.byValIsPure(node)) break; clobber(live); break; - } case GetMyArgumentsLengthSafe: case GetMyArgumentByValSafe: |
