/* * 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(ArrayProfile* profile, Array::Action action, bool makeSafe) { switch (profile->observedArrayModes()) { case 0: return Array::Unprofiled; case asArrayModes(NonArray): if (action == Array::Write && !profile->mayInterceptIndexedAccesses()) return Array::BlankToArrayStorage; // FIXME: we don't know whether to go to slow put mode, or not. This is a decent guess. return Array::Undecided; case asArrayModes(NonArrayWithArrayStorage): return makeSafe ? Array::ArrayStorageOutOfBounds : (profile->mayStoreToHole() ? Array::ArrayStorageToHole : Array::ArrayStorage); case asArrayModes(NonArrayWithSlowPutArrayStorage): case asArrayModes(NonArrayWithArrayStorage) | asArrayModes(NonArrayWithSlowPutArrayStorage): return Array::SlowPutArrayStorage; case asArrayModes(ArrayWithArrayStorage): return makeSafe ? Array::ArrayWithArrayStorageOutOfBounds : (profile->mayStoreToHole() ? Array::ArrayWithArrayStorageToHole : Array::ArrayWithArrayStorage); case asArrayModes(ArrayWithSlowPutArrayStorage): case asArrayModes(ArrayWithArrayStorage) | asArrayModes(ArrayWithSlowPutArrayStorage): return Array::ArrayWithSlowPutArrayStorage; case asArrayModes(NonArrayWithArrayStorage) | asArrayModes(ArrayWithArrayStorage): return makeSafe ? Array::PossiblyArrayWithArrayStorageOutOfBounds : (profile->mayStoreToHole() ? Array::PossiblyArrayWithArrayStorageToHole : Array::PossiblyArrayWithArrayStorage); case asArrayModes(NonArrayWithSlowPutArrayStorage) | asArrayModes(ArrayWithSlowPutArrayStorage): case asArrayModes(NonArrayWithArrayStorage) | asArrayModes(ArrayWithArrayStorage) | asArrayModes(NonArrayWithSlowPutArrayStorage) | asArrayModes(ArrayWithSlowPutArrayStorage): return Array::PossiblyArrayWithSlowPutArrayStorage; case asArrayModes(NonArray) | asArrayModes(NonArrayWithArrayStorage): if (action == Array::Write && !profile->mayInterceptIndexedAccesses()) return Array::BlankToArrayStorage; return Array::Undecided; case asArrayModes(NonArray) | asArrayModes(NonArrayWithSlowPutArrayStorage): case asArrayModes(NonArray) | asArrayModes(NonArrayWithArrayStorage) | asArrayModes(NonArrayWithSlowPutArrayStorage): if (action == Array::Write && !profile->mayInterceptIndexedAccesses()) return Array::BlankToSlowPutArrayStorage; return Array::Undecided; 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; if (arrayMode == Array::Unprofiled) { // If the indexing type wasn't recorded in the array profile but the values are // base=cell property=int, then we know that this access didn't execute. return Array::ForceExit; } if (arrayMode != Array::Undecided) return arrayMode; 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::ArrayStorage: case Array::ArrayStorageToHole: case Array::ArrayStorageOutOfBounds: case Array::PossiblyArrayWithArrayStorage: case Array::PossiblyArrayWithArrayStorageToHole: case Array::PossiblyArrayWithArrayStorageOutOfBounds: return value.m_currentKnownStructure.hasSingleton() && (value.m_currentKnownStructure.singleton()->indexingType() & HasArrayStorage); case Array::SlowPutArrayStorage: case Array::PossiblyArrayWithSlowPutArrayStorage: return value.m_currentKnownStructure.hasSingleton() && (value.m_currentKnownStructure.singleton()->indexingType() & (HasArrayStorage | HasSlowPutArrayStorage)); case Array::ArrayWithArrayStorage: case Array::ArrayWithArrayStorageToHole: case Array::ArrayWithArrayStorageOutOfBounds: return value.m_currentKnownStructure.hasSingleton() && (value.m_currentKnownStructure.singleton()->indexingType() & HasArrayStorage) && (value.m_currentKnownStructure.singleton()->indexingType() & IsArray); case Array::ArrayWithSlowPutArrayStorage: return value.m_currentKnownStructure.hasSingleton() && (value.m_currentKnownStructure.singleton()->indexingType() & (HasArrayStorage | HasSlowPutArrayStorage)) && (value.m_currentKnownStructure.singleton()->indexingType() & IsArray); case ALL_EFFECTFUL_ARRAY_STORAGE_MODES: return false; 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: case Array::Unprofiled: break; } ASSERT_NOT_REACHED(); return false; } const char* modeToString(Array::Mode mode) { switch (mode) { case Array::Undecided: return "Undecided"; case Array::Unprofiled: return "Unprofiled"; case Array::Generic: return "Generic"; case Array::ForceExit: return "ForceExit"; case Array::String: return "String"; case Array::ArrayStorage: return "ArrayStorage"; case Array::ArrayStorageToHole: return "ArrayStorageToHole"; case Array::SlowPutArrayStorage: return "SlowPutArrayStorage"; case Array::ArrayStorageOutOfBounds: return "ArrayStorageOutOfBounds"; case Array::ArrayWithArrayStorage: return "ArrayWithArrayStorage"; case Array::ArrayWithArrayStorageToHole: return "ArrayWithArrayStorageToHole"; case Array::ArrayWithSlowPutArrayStorage: return "ArrayWithSlowPutArrayStorage"; case Array::ArrayWithArrayStorageOutOfBounds: return "ArrayWithArrayStorageOutOfBounds"; case Array::PossiblyArrayWithArrayStorage: return "PossiblyArrayWithArrayStorage"; case Array::PossiblyArrayWithArrayStorageToHole: return "PossiblyArrayWithArrayStorageToHole"; case Array::PossiblyArrayWithSlowPutArrayStorage: return "PossiblyArrayWithSlowPutArrayStorage"; case Array::PossiblyArrayWithArrayStorageOutOfBounds: return "PossiblyArrayWithArrayStorageOutOfBounds"; case Array::BlankToArrayStorage: return "BlankToArrayStorage"; case Array::BlankToSlowPutArrayStorage: return "BlankToSlowPutArrayStorage"; 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)