diff options
author | Lorry Tar Creator <lorry-tar-importer@lorry> | 2017-06-27 06:07:23 +0000 |
---|---|---|
committer | Lorry Tar Creator <lorry-tar-importer@lorry> | 2017-06-27 06:07:23 +0000 |
commit | 1bf1084f2b10c3b47fd1a588d85d21ed0eb41d0c (patch) | |
tree | 46dcd36c86e7fbc6e5df36deb463b33e9967a6f7 /Source/JavaScriptCore/dfg/DFGArrayMode.cpp | |
parent | 32761a6cee1d0dee366b885b7b9c777e67885688 (diff) | |
download | WebKitGtk-tarball-master.tar.gz |
webkitgtk-2.16.5HEADwebkitgtk-2.16.5master
Diffstat (limited to 'Source/JavaScriptCore/dfg/DFGArrayMode.cpp')
-rw-r--r-- | Source/JavaScriptCore/dfg/DFGArrayMode.cpp | 297 |
1 files changed, 225 insertions, 72 deletions
diff --git a/Source/JavaScriptCore/dfg/DFGArrayMode.cpp b/Source/JavaScriptCore/dfg/DFGArrayMode.cpp index ef9b1c494..a26530ed0 100644 --- a/Source/JavaScriptCore/dfg/DFGArrayMode.cpp +++ b/Source/JavaScriptCore/dfg/DFGArrayMode.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2012, 2013 Apple Inc. All rights reserved. + * Copyright (C) 2012-2016 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -28,13 +28,14 @@ #if ENABLE(DFG_JIT) +#include "ArrayPrototype.h" #include "DFGAbstractValue.h" #include "DFGGraph.h" -#include "Operations.h" +#include "JSCInlines.h" namespace JSC { namespace DFG { -ArrayMode ArrayMode::fromObserved(const ConcurrentJITLocker& locker, ArrayProfile* profile, Array::Action action, bool makeSafe) +ArrayMode ArrayMode::fromObserved(const ConcurrentJSLocker& locker, ArrayProfile* profile, Array::Action action, bool makeSafe) { Array::Class nonArray; if (profile->usesOriginalArrayStructures(locker)) @@ -48,18 +49,18 @@ ArrayMode ArrayMode::fromObserved(const ConcurrentJITLocker& locker, ArrayProfil return ArrayMode(Array::Unprofiled); case asArrayModes(NonArray): if (action == Array::Write && !profile->mayInterceptIndexedAccesses(locker)) - return ArrayMode(Array::Undecided, nonArray, Array::OutOfBounds, Array::Convert); - return ArrayMode(Array::SelectUsingPredictions, nonArray); + return ArrayMode(Array::SelectUsingArguments, nonArray, Array::OutOfBounds, Array::Convert); + return ArrayMode(Array::SelectUsingPredictions, nonArray).withSpeculationFromProfile(locker, profile, makeSafe); case asArrayModes(ArrayWithUndecided): if (action == Array::Write) - return ArrayMode(Array::Undecided, Array::Array, Array::OutOfBounds, Array::Convert); - return ArrayMode(Array::Generic); + return ArrayMode(Array::SelectUsingArguments, Array::Array, Array::OutOfBounds, Array::Convert); + return ArrayMode(Array::Undecided, Array::Array, Array::OutOfBounds, Array::AsIs).withProfile(locker, profile, makeSafe); case asArrayModes(NonArray) | asArrayModes(ArrayWithUndecided): if (action == Array::Write && !profile->mayInterceptIndexedAccesses(locker)) - return ArrayMode(Array::Undecided, Array::PossiblyArray, Array::OutOfBounds, Array::Convert); - return ArrayMode(Array::SelectUsingPredictions); + return ArrayMode(Array::SelectUsingArguments, Array::PossiblyArray, Array::OutOfBounds, Array::Convert); + return ArrayMode(Array::SelectUsingPredictions).withSpeculationFromProfile(locker, profile, makeSafe); case asArrayModes(NonArrayWithInt32): return ArrayMode(Array::Int32, nonArray, Array::AsIs).withProfile(locker, profile, makeSafe); @@ -97,10 +98,28 @@ 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)) - return ArrayMode(Array::SelectUsingPredictions); + return ArrayMode(Array::SelectUsingPredictions).withSpeculationFromProfile(locker, profile, makeSafe); Array::Type type; Array::Class arrayClass; @@ -116,7 +135,7 @@ ArrayMode ArrayMode::fromObserved(const ConcurrentJITLocker& locker, ArrayProfil else if (shouldUseInt32(observed)) type = Array::Int32; else - type = Array::Undecided; + type = Array::SelectUsingArguments; if (hasSeenArray(observed) && hasSeenNonArray(observed)) arrayClass = Array::PossiblyArray; @@ -131,7 +150,17 @@ ArrayMode ArrayMode::fromObserved(const ConcurrentJITLocker& locker, ArrayProfil } } -ArrayMode ArrayMode::refine(SpeculatedType base, SpeculatedType index, SpeculatedType value, NodeFlags flags) const +static bool canBecomeGetArrayLength(Graph& graph, Node* node) +{ + if (node->op() != GetById) + return false; + auto uid = graph.identifiers()[node->identifierNumber()]; + return uid == graph.m_vm.propertyNames->length.impl(); +} + +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 @@ -144,6 +173,10 @@ ArrayMode ArrayMode::refine(SpeculatedType base, SpeculatedType index, Speculate 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 @@ -155,10 +188,7 @@ ArrayMode ArrayMode::refine(SpeculatedType base, SpeculatedType index, Speculate // should just trust the array profile. switch (type()) { - case Array::Unprofiled: - return ArrayMode(Array::ForceExit); - - case Array::Undecided: + case Array::SelectUsingArguments: if (!value) return withType(Array::ForceExit); if (isInt32Speculation(value)) @@ -166,7 +196,21 @@ ArrayMode ArrayMode::refine(SpeculatedType base, SpeculatedType index, Speculate if (isFullNumberSpeculation(value)) return withTypeAndConversion(Array::Double, Array::Convert); return withTypeAndConversion(Array::Contiguous, Array::Convert); - + case Array::Undecided: { + // If we have an OriginalArray and the JSArray prototype chain is sane, + // any indexed access always return undefined. We have a fast path for that. + JSGlobalObject* globalObject = graph.globalObjectFor(node->origin.semantic); + if ((node->op() == GetByVal || canBecomeGetArrayLength(graph, node)) + && arrayClass() == Array::OriginalArray + && globalObject->arrayPrototypeChainIsSane() + && !graph.hasExitSite(node->origin.semantic, OutOfBounds)) { + graph.watchpoints().addLazily(globalObject->arrayPrototype()->structure()->transitionWatchpointSet()); + graph.watchpoints().addLazily(globalObject->objectPrototype()->structure()->transitionWatchpointSet()); + if (globalObject->arrayPrototypeChainIsSane()) + return withSpeculation(Array::SaneChain); + } + return ArrayMode(Array::Generic); + } case Array::Int32: if (!value || isInt32Speculation(value)) return *this; @@ -175,54 +219,93 @@ ArrayMode ArrayMode::refine(SpeculatedType base, SpeculatedType index, Speculate 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::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 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()) { + 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 withType(Array::Int8Array); + return result.withType(Array::Int8Array); if (isInt16ArraySpeculation(base)) - return withType(Array::Int16Array); + return result.withType(Array::Int16Array); if (isInt32ArraySpeculation(base)) - return withType(Array::Int32Array); + return result.withType(Array::Int32Array); if (isUint8ArraySpeculation(base)) - return withType(Array::Uint8Array); + return result.withType(Array::Uint8Array); if (isUint8ClampedArraySpeculation(base)) - return withType(Array::Uint8ClampedArray); + return result.withType(Array::Uint8ClampedArray); if (isUint16ArraySpeculation(base)) - return withType(Array::Uint16Array); + return result.withType(Array::Uint16Array); if (isUint32ArraySpeculation(base)) - return withType(Array::Uint32Array); + return result.withType(Array::Uint32Array); if (isFloat32ArraySpeculation(base)) - return withType(Array::Float32Array); + return result.withType(Array::Float32Array); if (isFloat64ArraySpeculation(base)) - return withType(Array::Float64Array); + return result.withType(Array::Float64Array); + if (type() == Array::Unprofiled) + return ArrayMode(Array::ForceExit); return ArrayMode(Array::Generic); + } default: return *this; @@ -242,57 +325,82 @@ Structure* ArrayMode::originalArrayStructure(Graph& graph, const CodeOrigin& cod return globalObject->originalArrayStructureForIndexingType(ArrayWithDouble); case Array::Contiguous: return globalObject->originalArrayStructureForIndexingType(ArrayWithContiguous); + case Array::Undecided: + return globalObject->originalArrayStructureForIndexingType(ArrayWithUndecided); case Array::ArrayStorage: return globalObject->originalArrayStructureForIndexingType(ArrayWithArrayStorage); default: CRASH(); - return 0; + return nullptr; } } case Array::OriginalNonArray: { TypedArrayType type = typedArrayType(); if (type == NotTypedArray) - return 0; + return nullptr; - return globalObject->typedArrayStructure(type); + return globalObject->typedArrayStructureConcurrently(type); } default: - return 0; + return nullptr; } } 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--;) { + RegisteredStructure 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.get())) + 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--;) { + RegisteredStructure 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--;) { + RegisteredStructure 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: @@ -315,29 +423,50 @@ bool ArrayMode::alreadyChecked(Graph& graph, Node* node, AbstractValue& value) c case Array::ArrayStorage: return alreadyChecked(graph, node, value, ArrayStorageShape); + + case Array::Undecided: + return alreadyChecked(graph, node, value, UndecidedShape); 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--;) { + RegisteredStructure 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--;) { + RegisteredStructure 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); @@ -365,10 +494,13 @@ bool ArrayMode::alreadyChecked(Graph& graph, Node* node, AbstractValue& value) c case Array::Float64Array: return speculationChecked(value.m_type, SpecFloat64Array); - + + case Array::AnyTypedArray: + return speculationChecked(value.m_type, SpecTypedArrayView); + case Array::SelectUsingPredictions: case Array::Unprofiled: - case Array::Undecided: + case Array::SelectUsingArguments: break; } @@ -381,6 +513,8 @@ const char* arrayTypeToString(Array::Type type) switch (type) { case Array::SelectUsingPredictions: return "SelectUsingPredictions"; + case Array::SelectUsingArguments: + return "SelectUsingArguments"; case Array::Unprofiled: return "Unprofiled"; case Array::Generic: @@ -401,8 +535,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: @@ -421,6 +557,8 @@ const char* arrayTypeToString(Array::Type type) return "Float32Array"; case Array::Float64Array: return "Float64Array"; + case Array::AnyTypedArray: + return "AnyTypedArray"; 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 @@ -471,8 +609,6 @@ const char* arrayConversionToString(Array::Conversion conversion) return "AsIs"; case Array::Convert: return "Convert"; - case Array::RageConvert: - return "RageConvert"; default: return "Unknown!"; } @@ -517,6 +653,9 @@ TypedArrayType toTypedArrayType(Array::Type type) return TypeFloat32; case Array::Float64Array: return TypeFloat64; + case Array::AnyTypedArray: + RELEASE_ASSERT_NOT_REACHED(); + return NotTypedArray; default: return NotTypedArray; } @@ -548,6 +687,19 @@ Array::Type toArrayType(TypedArrayType type) } } +Array::Type refineTypedArrayType(Array::Type oldType, TypedArrayType newType) +{ + if (oldType == Array::Generic) + return oldType; + Array::Type newArrayType = toArrayType(newType); + if (newArrayType == Array::Generic) + return newArrayType; + + if (oldType != newArrayType) + return Array::AnyTypedArray; + return oldType; +} + bool permitsBoundsCheckLowering(Array::Type type) { switch (type) { @@ -563,6 +715,7 @@ bool permitsBoundsCheckLowering(Array::Type type) case Array::Uint32Array: case Array::Float32Array: case Array::Float64Array: + case Array::AnyTypedArray: return true; default: // These don't allow for bounds check lowering either because the bounds @@ -580,7 +733,7 @@ bool ArrayMode::permitsBoundsCheckLowering() const void ArrayMode::dump(PrintStream& out) const { - out.print(type(), arrayClass(), speculation(), conversion()); + out.print(type(), "+", arrayClass(), "+", speculation(), "+", conversion()); } } } // namespace JSC::DFG |