/*
- * Copyright (C) 2012 Apple Inc. All rights reserved.
+ * Copyright (C) 2012-2015 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
#include "DFGAbstractValue.h"
#include "DFGGraph.h"
-#include "Operations.h"
+#include "JSCInlines.h"
namespace JSC { namespace DFG {
-ArrayMode ArrayMode::fromObserved(ArrayProfile* profile, Array::Action action, bool makeSafe)
+ArrayMode ArrayMode::fromObserved(const ConcurrentJITLocker& locker, ArrayProfile* profile, Array::Action action, bool makeSafe)
{
- ArrayModes observed = profile->observedArrayModes();
+ Array::Class nonArray;
+ if (profile->usesOriginalArrayStructures(locker))
+ nonArray = Array::OriginalNonArray;
+ else
+ nonArray = Array::NonArray;
+
+ ArrayModes observed = profile->observedArrayModes(locker);
switch (observed) {
case 0:
return ArrayMode(Array::Unprofiled);
case asArrayModes(NonArray):
- if (action == Array::Write && !profile->mayInterceptIndexedAccesses())
- return ArrayMode(Array::Undecided, Array::NonArray, Array::OutOfBounds, Array::Convert);
- return ArrayMode(Array::SelectUsingPredictions);
+ if (action == Array::Write && !profile->mayInterceptIndexedAccesses(locker))
+ return ArrayMode(Array::Undecided, nonArray, Array::OutOfBounds, Array::Convert);
+ return ArrayMode(Array::SelectUsingPredictions, nonArray).withSpeculationFromProfile(locker, profile, makeSafe);
case asArrayModes(ArrayWithUndecided):
if (action == Array::Write)
return ArrayMode(Array::Generic);
case asArrayModes(NonArray) | asArrayModes(ArrayWithUndecided):
- if (action == Array::Write && !profile->mayInterceptIndexedAccesses())
+ if (action == Array::Write && !profile->mayInterceptIndexedAccesses(locker))
return ArrayMode(Array::Undecided, Array::PossiblyArray, Array::OutOfBounds, Array::Convert);
- return ArrayMode(Array::SelectUsingPredictions);
+ return ArrayMode(Array::SelectUsingPredictions).withSpeculationFromProfile(locker, profile, makeSafe);
case asArrayModes(NonArrayWithInt32):
- return ArrayMode(Array::Int32, Array::NonArray, Array::AsIs).withProfile(profile, makeSafe);
+ return ArrayMode(Array::Int32, nonArray, Array::AsIs).withProfile(locker, profile, makeSafe);
case asArrayModes(ArrayWithInt32):
- return ArrayMode(Array::Int32, Array::Array, Array::AsIs).withProfile(profile, makeSafe);
+ return ArrayMode(Array::Int32, Array::Array, Array::AsIs).withProfile(locker, profile, makeSafe);
case asArrayModes(NonArrayWithInt32) | asArrayModes(ArrayWithInt32):
- return ArrayMode(Array::Int32, Array::PossiblyArray, Array::AsIs).withProfile(profile, makeSafe);
+ return ArrayMode(Array::Int32, Array::PossiblyArray, Array::AsIs).withProfile(locker, profile, makeSafe);
case asArrayModes(NonArrayWithDouble):
- return ArrayMode(Array::Double, Array::NonArray, Array::AsIs).withProfile(profile, makeSafe);
+ return ArrayMode(Array::Double, nonArray, Array::AsIs).withProfile(locker, profile, makeSafe);
case asArrayModes(ArrayWithDouble):
- return ArrayMode(Array::Double, Array::Array, Array::AsIs).withProfile(profile, makeSafe);
+ return ArrayMode(Array::Double, Array::Array, Array::AsIs).withProfile(locker, profile, makeSafe);
case asArrayModes(NonArrayWithDouble) | asArrayModes(ArrayWithDouble):
- return ArrayMode(Array::Double, Array::PossiblyArray, Array::AsIs).withProfile(profile, makeSafe);
+ return ArrayMode(Array::Double, Array::PossiblyArray, Array::AsIs).withProfile(locker, profile, makeSafe);
case asArrayModes(NonArrayWithContiguous):
- return ArrayMode(Array::Contiguous, Array::NonArray, Array::AsIs).withProfile(profile, makeSafe);
+ return ArrayMode(Array::Contiguous, nonArray, Array::AsIs).withProfile(locker, profile, makeSafe);
case asArrayModes(ArrayWithContiguous):
- return ArrayMode(Array::Contiguous, Array::Array, Array::AsIs).withProfile(profile, makeSafe);
+ return ArrayMode(Array::Contiguous, Array::Array, Array::AsIs).withProfile(locker, profile, makeSafe);
case asArrayModes(NonArrayWithContiguous) | asArrayModes(ArrayWithContiguous):
- return ArrayMode(Array::Contiguous, Array::PossiblyArray, Array::AsIs).withProfile(profile, makeSafe);
+ return ArrayMode(Array::Contiguous, Array::PossiblyArray, Array::AsIs).withProfile(locker, profile, makeSafe);
case asArrayModes(NonArrayWithArrayStorage):
- return ArrayMode(Array::ArrayStorage, Array::NonArray, Array::AsIs).withProfile(profile, makeSafe);
+ return ArrayMode(Array::ArrayStorage, nonArray, Array::AsIs).withProfile(locker, profile, makeSafe);
case asArrayModes(NonArrayWithSlowPutArrayStorage):
case asArrayModes(NonArrayWithArrayStorage) | asArrayModes(NonArrayWithSlowPutArrayStorage):
- return ArrayMode(Array::SlowPutArrayStorage, Array::NonArray, Array::AsIs).withProfile(profile, makeSafe);
+ return ArrayMode(Array::SlowPutArrayStorage, nonArray, Array::AsIs).withProfile(locker, profile, makeSafe);
case asArrayModes(ArrayWithArrayStorage):
- return ArrayMode(Array::ArrayStorage, Array::Array, Array::AsIs).withProfile(profile, makeSafe);
+ return ArrayMode(Array::ArrayStorage, Array::Array, Array::AsIs).withProfile(locker, profile, makeSafe);
case asArrayModes(ArrayWithSlowPutArrayStorage):
case asArrayModes(ArrayWithArrayStorage) | asArrayModes(ArrayWithSlowPutArrayStorage):
- return ArrayMode(Array::SlowPutArrayStorage, Array::Array, Array::AsIs).withProfile(profile, makeSafe);
+ return ArrayMode(Array::SlowPutArrayStorage, Array::Array, Array::AsIs).withProfile(locker, profile, makeSafe);
case asArrayModes(NonArrayWithArrayStorage) | asArrayModes(ArrayWithArrayStorage):
- return ArrayMode(Array::ArrayStorage, Array::PossiblyArray, Array::AsIs).withProfile(profile, makeSafe);
+ return ArrayMode(Array::ArrayStorage, Array::PossiblyArray, Array::AsIs).withProfile(locker, profile, makeSafe);
case asArrayModes(NonArrayWithSlowPutArrayStorage) | asArrayModes(ArrayWithSlowPutArrayStorage):
case asArrayModes(NonArrayWithArrayStorage) | asArrayModes(ArrayWithArrayStorage) | asArrayModes(NonArrayWithSlowPutArrayStorage) | asArrayModes(ArrayWithSlowPutArrayStorage):
- return ArrayMode(Array::SlowPutArrayStorage, Array::PossiblyArray, Array::AsIs).withProfile(profile, makeSafe);
+ return ArrayMode(Array::SlowPutArrayStorage, Array::PossiblyArray, Array::AsIs).withProfile(locker, profile, makeSafe);
+ case Int8ArrayMode:
+ return ArrayMode(Array::Int8Array, nonArray, Array::AsIs).withProfile(locker, profile, makeSafe);
+ case Int16ArrayMode:
+ return ArrayMode(Array::Int16Array, nonArray, Array::AsIs).withProfile(locker, profile, makeSafe);
+ case Int32ArrayMode:
+ return ArrayMode(Array::Int32Array, nonArray, Array::AsIs).withProfile(locker, profile, makeSafe);
+ case Uint8ArrayMode:
+ return ArrayMode(Array::Uint8Array, nonArray, Array::AsIs).withProfile(locker, profile, makeSafe);
+ case Uint8ClampedArrayMode:
+ return ArrayMode(Array::Uint8ClampedArray, nonArray, Array::AsIs).withProfile(locker, profile, makeSafe);
+ case Uint16ArrayMode:
+ return ArrayMode(Array::Uint16Array, nonArray, Array::AsIs).withProfile(locker, profile, makeSafe);
+ case Uint32ArrayMode:
+ return ArrayMode(Array::Uint32Array, nonArray, Array::AsIs).withProfile(locker, profile, makeSafe);
+ case Float32ArrayMode:
+ return ArrayMode(Array::Float32Array, nonArray, Array::AsIs).withProfile(locker, profile, makeSafe);
+ case Float64ArrayMode:
+ return ArrayMode(Array::Float64Array, nonArray, Array::AsIs).withProfile(locker, profile, makeSafe);
default:
- if ((observed & asArrayModes(NonArray)) && profile->mayInterceptIndexedAccesses())
- return ArrayMode(Array::SelectUsingPredictions);
+ if ((observed & asArrayModes(NonArray)) && profile->mayInterceptIndexedAccesses(locker))
+ return ArrayMode(Array::SelectUsingPredictions).withSpeculationFromProfile(locker, profile, makeSafe);
Array::Type type;
Array::Class arrayClass;
else if (hasSeenArray(observed))
arrayClass = Array::Array;
else if (hasSeenNonArray(observed))
- arrayClass = Array::NonArray;
+ arrayClass = nonArray;
else
arrayClass = Array::PossiblyArray;
- return ArrayMode(type, arrayClass, Array::Convert).withProfile(profile, makeSafe);
+ return ArrayMode(type, arrayClass, Array::Convert).withProfile(locker, profile, makeSafe);
}
}
-ArrayMode ArrayMode::refine(SpeculatedType base, SpeculatedType index, SpeculatedType value, NodeFlags flags) const
+ArrayMode ArrayMode::refine(
+ Graph& graph, Node* node,
+ SpeculatedType base, SpeculatedType index, SpeculatedType value) const
{
if (!base || !index) {
// It can be that we had a legitimate arrayMode but no incoming predictions. That'll
if (!isInt32Speculation(index))
return ArrayMode(Array::Generic);
+ // If we had exited because of an exotic object behavior, then don't try to specialize.
+ if (graph.hasExitSite(node->origin.semantic, ExoticObjectMode))
+ return ArrayMode(Array::Generic);
+
// Note: our profiling currently doesn't give us good information in case we have
// an unlikely control flow path that sets the base to a non-cell value. Value
// profiling and prediction propagation will probably tell us that the value is
// should just trust the array profile.
switch (type()) {
- case Array::Unprofiled:
- return ArrayMode(Array::ForceExit);
-
case Array::Undecided:
if (!value)
return withType(Array::ForceExit);
if (isInt32Speculation(value))
return withTypeAndConversion(Array::Int32, Array::Convert);
- if (isNumberSpeculation(value))
+ if (isFullNumberSpeculation(value))
return withTypeAndConversion(Array::Double, Array::Convert);
return withTypeAndConversion(Array::Contiguous, Array::Convert);
case Array::Int32:
if (!value || isInt32Speculation(value))
return *this;
- if (isNumberSpeculation(value))
+ if (isFullNumberSpeculation(value))
return withTypeAndConversion(Array::Double, Array::Convert);
return withTypeAndConversion(Array::Contiguous, Array::Convert);
case Array::Double:
- if (flags & NodeUsedAsInt)
- return withTypeAndConversion(Array::Contiguous, Array::RageConvert);
- if (!value || isNumberSpeculation(value))
+ if (!value || isFullNumberSpeculation(value))
return *this;
return withTypeAndConversion(Array::Contiguous, Array::Convert);
case Array::Contiguous:
- if (doesConversion() && (flags & NodeUsedAsInt))
- return withConversion(Array::RageConvert);
return *this;
-
- case Array::SelectUsingPredictions:
+
+ 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:
+ switch (node->op()) {
+ case PutByVal:
+ if (graph.hasExitSite(node->origin.semantic, OutOfBounds) || !isInBounds())
+ return withSpeculation(Array::OutOfBounds);
+ return withSpeculation(Array::InBounds);
+ default:
+ return withSpeculation(Array::InBounds);
+ }
+ return *this;
+ case Array::Unprofiled:
+ case Array::SelectUsingPredictions: {
base &= ~SpecOther;
if (isStringSpeculation(base))
- return ArrayMode(Array::String);
+ return withType(Array::String);
+
+ if (isDirectArgumentsSpeculation(base) || isScopedArgumentsSpeculation(base)) {
+ // Handle out-of-bounds accesses as generic accesses.
+ if (graph.hasExitSite(node->origin.semantic, OutOfBounds) || !isInBounds())
+ return ArrayMode(Array::Generic);
+
+ if (isDirectArgumentsSpeculation(base))
+ return withType(Array::DirectArguments);
+ return withType(Array::ScopedArguments);
+ }
- if (isArgumentsSpeculation(base))
- return ArrayMode(Array::Arguments);
+ ArrayMode result;
+ switch (node->op()) {
+ case PutByVal:
+ if (graph.hasExitSite(node->origin.semantic, OutOfBounds) || !isInBounds())
+ result = withSpeculation(Array::OutOfBounds);
+ else
+ result = withSpeculation(Array::InBounds);
+ break;
+
+ default:
+ result = withSpeculation(Array::InBounds);
+ break;
+ }
if (isInt8ArraySpeculation(base))
- return ArrayMode(Array::Int8Array);
+ return result.withType(Array::Int8Array);
if (isInt16ArraySpeculation(base))
- return ArrayMode(Array::Int16Array);
+ return result.withType(Array::Int16Array);
if (isInt32ArraySpeculation(base))
- return ArrayMode(Array::Int32Array);
+ return result.withType(Array::Int32Array);
if (isUint8ArraySpeculation(base))
- return ArrayMode(Array::Uint8Array);
+ return result.withType(Array::Uint8Array);
if (isUint8ClampedArraySpeculation(base))
- return ArrayMode(Array::Uint8ClampedArray);
+ return result.withType(Array::Uint8ClampedArray);
if (isUint16ArraySpeculation(base))
- return ArrayMode(Array::Uint16Array);
+ return result.withType(Array::Uint16Array);
if (isUint32ArraySpeculation(base))
- return ArrayMode(Array::Uint32Array);
+ return result.withType(Array::Uint32Array);
if (isFloat32ArraySpeculation(base))
- return ArrayMode(Array::Float32Array);
+ return result.withType(Array::Float32Array);
if (isFloat64ArraySpeculation(base))
- return ArrayMode(Array::Float64Array);
+ return result.withType(Array::Float64Array);
+ if (type() == Array::Unprofiled)
+ return ArrayMode(Array::ForceExit);
return ArrayMode(Array::Generic);
+ }
default:
return *this;
Structure* ArrayMode::originalArrayStructure(Graph& graph, const CodeOrigin& codeOrigin) const
{
- if (!isJSArrayWithOriginalStructure())
- return 0;
-
JSGlobalObject* globalObject = graph.globalObjectFor(codeOrigin);
- switch (type()) {
- case Array::Int32:
- return globalObject->originalArrayStructureForIndexingType(ArrayWithInt32);
- case Array::Double:
- return globalObject->originalArrayStructureForIndexingType(ArrayWithDouble);
- case Array::Contiguous:
- return globalObject->originalArrayStructureForIndexingType(ArrayWithContiguous);
- case Array::ArrayStorage:
- return globalObject->originalArrayStructureForIndexingType(ArrayWithArrayStorage);
+ switch (arrayClass()) {
+ case Array::OriginalArray: {
+ switch (type()) {
+ case Array::Int32:
+ return globalObject->originalArrayStructureForIndexingType(ArrayWithInt32);
+ case Array::Double:
+ return globalObject->originalArrayStructureForIndexingType(ArrayWithDouble);
+ case Array::Contiguous:
+ return globalObject->originalArrayStructureForIndexingType(ArrayWithContiguous);
+ case Array::ArrayStorage:
+ return globalObject->originalArrayStructureForIndexingType(ArrayWithArrayStorage);
+ default:
+ CRASH();
+ return 0;
+ }
+ }
+
+ case Array::OriginalNonArray: {
+ TypedArrayType type = typedArrayType();
+ if (type == NotTypedArray)
+ return 0;
+
+ return globalObject->typedArrayStructure(type);
+ }
+
default:
- CRASH();
return 0;
}
}
Structure* ArrayMode::originalArrayStructure(Graph& graph, Node* node) const
{
- return originalArrayStructure(graph, node->codeOrigin);
+ return originalArrayStructure(graph, node->origin.semantic);
}
-bool ArrayMode::alreadyChecked(Graph& graph, Node* node, AbstractValue& value, IndexingType shape) const
+bool ArrayMode::alreadyChecked(Graph& graph, Node* node, const AbstractValue& value, IndexingType shape) const
{
switch (arrayClass()) {
- case Array::OriginalArray:
- return value.m_currentKnownStructure.hasSingleton()
- && (value.m_currentKnownStructure.singleton()->indexingType() & IndexingShapeMask) == shape
- && (value.m_currentKnownStructure.singleton()->indexingType() & IsArray)
- && graph.globalObjectFor(node->codeOrigin)->isOriginalArrayStructure(value.m_currentKnownStructure.singleton());
+ case Array::OriginalArray: {
+ if (value.m_structure.isTop())
+ return false;
+ for (unsigned i = value.m_structure.size(); i--;) {
+ Structure* structure = value.m_structure[i];
+ if ((structure->indexingType() & IndexingShapeMask) != shape)
+ return false;
+ if (!(structure->indexingType() & IsArray))
+ return false;
+ if (!graph.globalObjectFor(node->origin.semantic)->isOriginalArrayStructure(structure))
+ return false;
+ }
+ return true;
+ }
- case Array::Array:
+ case Array::Array: {
if (arrayModesAlreadyChecked(value.m_arrayModes, asArrayModes(shape | IsArray)))
return true;
- return value.m_currentKnownStructure.hasSingleton()
- && (value.m_currentKnownStructure.singleton()->indexingType() & IndexingShapeMask) == shape
- && (value.m_currentKnownStructure.singleton()->indexingType() & IsArray);
+ if (value.m_structure.isTop())
+ return false;
+ for (unsigned i = value.m_structure.size(); i--;) {
+ Structure* structure = value.m_structure[i];
+ if ((structure->indexingType() & IndexingShapeMask) != shape)
+ return false;
+ if (!(structure->indexingType() & IsArray))
+ return false;
+ }
+ return true;
+ }
- default:
+ default: {
if (arrayModesAlreadyChecked(value.m_arrayModes, asArrayModes(shape) | asArrayModes(shape | IsArray)))
return true;
- return value.m_currentKnownStructure.hasSingleton()
- && (value.m_currentKnownStructure.singleton()->indexingType() & IndexingShapeMask) == shape;
- }
+ if (value.m_structure.isTop())
+ return false;
+ for (unsigned i = value.m_structure.size(); i--;) {
+ Structure* structure = value.m_structure[i];
+ if ((structure->indexingType() & IndexingShapeMask) != shape)
+ return false;
+ }
+ return true;
+ } }
}
-bool ArrayMode::alreadyChecked(Graph& graph, Node* node, AbstractValue& value) const
+bool ArrayMode::alreadyChecked(Graph& graph, Node* node, const AbstractValue& value) const
{
switch (type()) {
case Array::Generic:
case Array::SlowPutArrayStorage:
switch (arrayClass()) {
- case Array::OriginalArray:
+ case Array::OriginalArray: {
CRASH();
return false;
+ }
- case Array::Array:
+ case Array::Array: {
if (arrayModesAlreadyChecked(value.m_arrayModes, asArrayModes(ArrayWithArrayStorage) | asArrayModes(ArrayWithSlowPutArrayStorage)))
return true;
- return value.m_currentKnownStructure.hasSingleton()
- && hasArrayStorage(value.m_currentKnownStructure.singleton()->indexingType())
- && (value.m_currentKnownStructure.singleton()->indexingType() & IsArray);
+ if (value.m_structure.isTop())
+ return false;
+ for (unsigned i = value.m_structure.size(); i--;) {
+ Structure* structure = value.m_structure[i];
+ if (!hasAnyArrayStorage(structure->indexingType()))
+ return false;
+ if (!(structure->indexingType() & IsArray))
+ return false;
+ }
+ return true;
+ }
- default:
+ default: {
if (arrayModesAlreadyChecked(value.m_arrayModes, asArrayModes(NonArrayWithArrayStorage) | asArrayModes(ArrayWithArrayStorage) | asArrayModes(NonArrayWithSlowPutArrayStorage) | asArrayModes(ArrayWithSlowPutArrayStorage)))
return true;
- return value.m_currentKnownStructure.hasSingleton()
- && hasArrayStorage(value.m_currentKnownStructure.singleton()->indexingType());
- }
+ if (value.m_structure.isTop())
+ return false;
+ for (unsigned i = value.m_structure.size(); i--;) {
+ Structure* structure = value.m_structure[i];
+ if (!hasAnyArrayStorage(structure->indexingType()))
+ return false;
+ }
+ return true;
+ } }
+
+ case Array::DirectArguments:
+ return speculationChecked(value.m_type, SpecDirectArguments);
- case Array::Arguments:
- return speculationChecked(value.m_type, SpecArguments);
+ case Array::ScopedArguments:
+ return speculationChecked(value.m_type, SpecScopedArguments);
case Array::Int8Array:
return speculationChecked(value.m_type, SpecInt8Array);
return "ArrayStorage";
case Array::SlowPutArrayStorage:
return "SlowPutArrayStorage";
- case Array::Arguments:
- return "Arguments";
+ case Array::DirectArguments:
+ return "DirectArguments";
+ case Array::ScopedArguments:
+ return "ScopedArguments";
case Array::Int8Array:
return "Int8Array";
case Array::Int16Array:
return "OriginalArray";
case Array::NonArray:
return "NonArray";
+ case Array::OriginalNonArray:
+ return "OriginalNonArray";
case Array::PossiblyArray:
return "PossiblyArray";
default:
return "AsIs";
case Array::Convert:
return "Convert";
- case Array::RageConvert:
- return "RageConvert";
default:
return "Unknown!";
}
}
+IndexingType toIndexingShape(Array::Type type)
+{
+ switch (type) {
+ case Array::Int32:
+ return Int32Shape;
+ case Array::Double:
+ return DoubleShape;
+ case Array::Contiguous:
+ return ContiguousShape;
+ case Array::ArrayStorage:
+ return ArrayStorageShape;
+ case Array::SlowPutArrayStorage:
+ return SlowPutArrayStorageShape;
+ default:
+ return NoIndexingShape;
+ }
+}
+
+TypedArrayType toTypedArrayType(Array::Type type)
+{
+ switch (type) {
+ case Array::Int8Array:
+ return TypeInt8;
+ case Array::Int16Array:
+ return TypeInt16;
+ case Array::Int32Array:
+ return TypeInt32;
+ case Array::Uint8Array:
+ return TypeUint8;
+ case Array::Uint8ClampedArray:
+ return TypeUint8Clamped;
+ case Array::Uint16Array:
+ return TypeUint16;
+ case Array::Uint32Array:
+ return TypeUint32;
+ case Array::Float32Array:
+ return TypeFloat32;
+ case Array::Float64Array:
+ return TypeFloat64;
+ default:
+ return NotTypedArray;
+ }
+}
+
+Array::Type toArrayType(TypedArrayType type)
+{
+ switch (type) {
+ case TypeInt8:
+ return Array::Int8Array;
+ case TypeInt16:
+ return Array::Int16Array;
+ case TypeInt32:
+ return Array::Int32Array;
+ case TypeUint8:
+ return Array::Uint8Array;
+ case TypeUint8Clamped:
+ return Array::Uint8ClampedArray;
+ case TypeUint16:
+ return Array::Uint16Array;
+ case TypeUint32:
+ return Array::Uint32Array;
+ case TypeFloat32:
+ return Array::Float32Array;
+ case TypeFloat64:
+ return Array::Float64Array;
+ default:
+ return Array::Generic;
+ }
+}
+
+bool permitsBoundsCheckLowering(Array::Type type)
+{
+ switch (type) {
+ case Array::Int32:
+ case Array::Double:
+ case Array::Contiguous:
+ 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:
+ return true;
+ default:
+ // These don't allow for bounds check lowering either because the bounds
+ // check involves something other than GetArrayLength (like ArrayStorage),
+ // or because the bounds check isn't a speculation (like String, sort of),
+ // or because the type implies an impure access.
+ return false;
+ }
+}
+
+bool ArrayMode::permitsBoundsCheckLowering() const
+{
+ return DFG::permitsBoundsCheckLowering(type()) && isInBounds();
+}
+
void ArrayMode::dump(PrintStream& out) const
{
out.print(type(), arrayClass(), speculation(), conversion());