]> git.saurik.com Git - apple/javascriptcore.git/blobdiff - dfg/DFGArrayMode.cpp
JavaScriptCore-7601.1.46.3.tar.gz
[apple/javascriptcore.git] / dfg / DFGArrayMode.cpp
index 0cbdc7c433c0c80fd28858c6ae945d29d753a318..b0a4b049d3e57aab708edfcebc4f068c803b8ad7 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2012, 2013, 2014 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
@@ -97,6 +97,24 @@ ArrayMode ArrayMode::fromObserved(const ConcurrentJITLocker& locker, ArrayProfil
     case asArrayModes(NonArrayWithSlowPutArrayStorage) | asArrayModes(ArrayWithSlowPutArrayStorage):
     case asArrayModes(NonArrayWithArrayStorage) | asArrayModes(ArrayWithArrayStorage) | asArrayModes(NonArrayWithSlowPutArrayStorage) | asArrayModes(ArrayWithSlowPutArrayStorage):
         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(locker))
@@ -133,8 +151,7 @@ ArrayMode ArrayMode::fromObserved(const ConcurrentJITLocker& locker, ArrayProfil
 
 ArrayMode ArrayMode::refine(
     Graph& graph, Node* node,
-    SpeculatedType base, SpeculatedType index, SpeculatedType value,
-    NodeFlags flags) const
+    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
@@ -147,6 +164,10 @@ ArrayMode ArrayMode::refine(
     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
@@ -158,9 +179,6 @@ ArrayMode ArrayMode::refine(
     // should just trust the array profile.
     
     switch (type()) {
-    case Array::Unprofiled:
-        return ArrayMode(Array::ForceExit);
-        
     case Array::Undecided:
         if (!value)
             return withType(Array::ForceExit);
@@ -178,25 +196,47 @@ ArrayMode ArrayMode::refine(
         return withTypeAndConversion(Array::Contiguous, Array::Convert);
         
     case Array::Double:
-        if (flags & NodeBytecodeUsesAsInt)
-            return withTypeAndConversion(Array::Contiguous, Array::RageConvert);
         if (!value || isFullNumberSpeculation(value))
             return *this;
         return withTypeAndConversion(Array::Contiguous, Array::Convert);
         
     case Array::Contiguous:
-        if (doesConversion() && (flags & NodeBytecodeUsesAsInt))
-            return withConversion(Array::RageConvert);
         return *this;
-        
+
+    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 withType(Array::String);
         
-        if (isArgumentsSpeculation(base))
-            return withType(Array::Arguments);
+        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);
+        }
         
         ArrayMode result;
         switch (node->op()) {
@@ -239,6 +279,8 @@ ArrayMode ArrayMode::refine(
         if (isFloat64ArraySpeculation(base))
             return result.withType(Array::Float64Array);
 
+        if (type() == Array::Unprofiled)
+            return ArrayMode(Array::ForceExit);
         return ArrayMode(Array::Generic);
     }
 
@@ -286,31 +328,54 @@ Structure* ArrayMode::originalArrayStructure(Graph& graph, Node* node) const
     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->origin.semantic)->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:
@@ -336,26 +401,44 @@ bool ArrayMode::alreadyChecked(Graph& graph, Node* node, AbstractValue& value) c
         
     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()
-                && hasAnyArrayStorage(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()
-                && hasAnyArrayStorage(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);
@@ -419,8 +502,10 @@ const char* arrayTypeToString(Array::Type type)
         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:
@@ -489,8 +574,6 @@ const char* arrayConversionToString(Array::Conversion conversion)
         return "AsIs";
     case Array::Convert:
         return "Convert";
-    case Array::RageConvert:
-        return "RageConvert";
     default:
         return "Unknown!";
     }