| OLD | NEW |
| 1 // Copyright 2014 the V8 project authors. All rights reserved. | 1 // Copyright 2014 the V8 project authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "src/compiler/js-typed-lowering.h" | 5 #include "src/compiler/js-typed-lowering.h" |
| 6 | 6 |
| 7 #include "src/builtins/builtins-utils.h" | 7 #include "src/builtins/builtins-utils.h" |
| 8 #include "src/code-factory.h" | 8 #include "src/code-factory.h" |
| 9 #include "src/compilation-dependencies.h" | 9 #include "src/compilation-dependencies.h" |
| 10 #include "src/compiler/access-builder.h" | 10 #include "src/compiler/access-builder.h" |
| (...skipping 412 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 423 // - relax effects from generic but not-side-effecting operations | 423 // - relax effects from generic but not-side-effecting operations |
| 424 | 424 |
| 425 | 425 |
| 426 JSTypedLowering::JSTypedLowering(Editor* editor, | 426 JSTypedLowering::JSTypedLowering(Editor* editor, |
| 427 CompilationDependencies* dependencies, | 427 CompilationDependencies* dependencies, |
| 428 Flags flags, JSGraph* jsgraph, Zone* zone) | 428 Flags flags, JSGraph* jsgraph, Zone* zone) |
| 429 : AdvancedReducer(editor), | 429 : AdvancedReducer(editor), |
| 430 dependencies_(dependencies), | 430 dependencies_(dependencies), |
| 431 flags_(flags), | 431 flags_(flags), |
| 432 jsgraph_(jsgraph), | 432 jsgraph_(jsgraph), |
| 433 true_type_(Type::Constant(factory()->true_value(), graph()->zone())), | |
| 434 false_type_(Type::Constant(factory()->false_value(), graph()->zone())), | |
| 435 the_hole_type_( | 433 the_hole_type_( |
| 436 Type::Constant(factory()->the_hole_value(), graph()->zone())), | 434 Type::Constant(factory()->the_hole_value(), graph()->zone())), |
| 437 type_cache_(TypeCache::Get()) { | 435 type_cache_(TypeCache::Get()) { |
| 438 for (size_t k = 0; k < arraysize(shifted_int32_ranges_); ++k) { | 436 for (size_t k = 0; k < arraysize(shifted_int32_ranges_); ++k) { |
| 439 double min = kMinInt / (1 << k); | 437 double min = kMinInt / (1 << k); |
| 440 double max = kMaxInt / (1 << k); | 438 double max = kMaxInt / (1 << k); |
| 441 shifted_int32_ranges_[k] = Type::Range(min, max, graph()->zone()); | 439 shifted_int32_ranges_[k] = Type::Range(min, max, graph()->zone()); |
| 442 } | 440 } |
| 443 } | 441 } |
| 444 | 442 |
| (...skipping 1475 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1920 Node* element = effect = graph()->NewNode( | 1918 Node* element = effect = graph()->NewNode( |
| 1921 simplified()->LoadField(element_field), array, effect, control); | 1919 simplified()->LoadField(element_field), array, effect, control); |
| 1922 Node* stale = jsgraph()->StaleRegisterConstant(); | 1920 Node* stale = jsgraph()->StaleRegisterConstant(); |
| 1923 effect = graph()->NewNode(simplified()->StoreField(element_field), array, | 1921 effect = graph()->NewNode(simplified()->StoreField(element_field), array, |
| 1924 stale, effect, control); | 1922 stale, effect, control); |
| 1925 | 1923 |
| 1926 ReplaceWithValue(node, element, effect, control); | 1924 ReplaceWithValue(node, element, effect, control); |
| 1927 return Changed(element); | 1925 return Changed(element); |
| 1928 } | 1926 } |
| 1929 | 1927 |
| 1930 Reduction JSTypedLowering::ReducePhi(Node* node) { | |
| 1931 // Try to narrow the type of the Phi {node}, which might be more precise now | |
| 1932 // after lowering based on types, i.e. a SpeculativeNumberAdd has a more | |
| 1933 // precise type than the JSAdd that was in the graph when the Typer was run. | |
| 1934 DCHECK_EQ(IrOpcode::kPhi, node->opcode()); | |
| 1935 int arity = node->op()->ValueInputCount(); | |
| 1936 Type* type = NodeProperties::GetType(node->InputAt(0)); | |
| 1937 for (int i = 1; i < arity; ++i) { | |
| 1938 type = Type::Union(type, NodeProperties::GetType(node->InputAt(i)), | |
| 1939 graph()->zone()); | |
| 1940 } | |
| 1941 Type* const node_type = NodeProperties::GetType(node); | |
| 1942 if (!node_type->Is(type)) { | |
| 1943 type = Type::Intersect(node_type, type, graph()->zone()); | |
| 1944 NodeProperties::SetType(node, type); | |
| 1945 return Changed(node); | |
| 1946 } | |
| 1947 return NoChange(); | |
| 1948 } | |
| 1949 | |
| 1950 Reduction JSTypedLowering::ReduceSelect(Node* node) { | |
| 1951 DCHECK_EQ(IrOpcode::kSelect, node->opcode()); | |
| 1952 Node* const condition = NodeProperties::GetValueInput(node, 0); | |
| 1953 Type* const condition_type = NodeProperties::GetType(condition); | |
| 1954 Node* const vtrue = NodeProperties::GetValueInput(node, 1); | |
| 1955 Type* const vtrue_type = NodeProperties::GetType(vtrue); | |
| 1956 Node* const vfalse = NodeProperties::GetValueInput(node, 2); | |
| 1957 Type* const vfalse_type = NodeProperties::GetType(vfalse); | |
| 1958 if (condition_type->Is(true_type_)) { | |
| 1959 // Select(condition:true, vtrue, vfalse) => vtrue | |
| 1960 return Replace(vtrue); | |
| 1961 } | |
| 1962 if (condition_type->Is(false_type_)) { | |
| 1963 // Select(condition:false, vtrue, vfalse) => vfalse | |
| 1964 return Replace(vfalse); | |
| 1965 } | |
| 1966 if (vtrue_type->Is(true_type_) && vfalse_type->Is(false_type_)) { | |
| 1967 // Select(condition, vtrue:true, vfalse:false) => condition | |
| 1968 return Replace(condition); | |
| 1969 } | |
| 1970 if (vtrue_type->Is(false_type_) && vfalse_type->Is(true_type_)) { | |
| 1971 // Select(condition, vtrue:false, vfalse:true) => BooleanNot(condition) | |
| 1972 node->TrimInputCount(1); | |
| 1973 NodeProperties::ChangeOp(node, simplified()->BooleanNot()); | |
| 1974 return Changed(node); | |
| 1975 } | |
| 1976 return NoChange(); | |
| 1977 } | |
| 1978 | |
| 1979 namespace { | |
| 1980 | |
| 1981 MaybeHandle<Map> GetStableMapFromObjectType(Type* object_type) { | |
| 1982 if (object_type->IsConstant() && | |
| 1983 object_type->AsConstant()->Value()->IsHeapObject()) { | |
| 1984 Handle<Map> object_map( | |
| 1985 Handle<HeapObject>::cast(object_type->AsConstant()->Value())->map()); | |
| 1986 if (object_map->is_stable()) return object_map; | |
| 1987 } else if (object_type->IsClass()) { | |
| 1988 Handle<Map> object_map = object_type->AsClass()->Map(); | |
| 1989 if (object_map->is_stable()) return object_map; | |
| 1990 } | |
| 1991 return MaybeHandle<Map>(); | |
| 1992 } | |
| 1993 | |
| 1994 } // namespace | |
| 1995 | |
| 1996 Reduction JSTypedLowering::ReduceCheckMaps(Node* node) { | |
| 1997 // TODO(bmeurer): Find a better home for this thing! | |
| 1998 // The CheckMaps(o, ...map...) can be eliminated if map is stable and | |
| 1999 // either | |
| 2000 // (a) o has type Constant(object) and map == object->map, or | |
| 2001 // (b) o has type Class(map), | |
| 2002 // and either | |
| 2003 // (1) map cannot transition further, or | |
| 2004 // (2) we can add a code dependency on the stability of map | |
| 2005 // (to guard the Constant type information). | |
| 2006 Node* const object = NodeProperties::GetValueInput(node, 0); | |
| 2007 Type* const object_type = NodeProperties::GetType(object); | |
| 2008 Node* const effect = NodeProperties::GetEffectInput(node); | |
| 2009 Handle<Map> object_map; | |
| 2010 if (GetStableMapFromObjectType(object_type).ToHandle(&object_map)) { | |
| 2011 for (int i = 1; i < node->op()->ValueInputCount(); ++i) { | |
| 2012 Node* const map = NodeProperties::GetValueInput(node, i); | |
| 2013 Type* const map_type = NodeProperties::GetType(map); | |
| 2014 if (map_type->IsConstant() && | |
| 2015 map_type->AsConstant()->Value().is_identical_to(object_map)) { | |
| 2016 if (object_map->CanTransition()) { | |
| 2017 DCHECK(flags() & kDeoptimizationEnabled); | |
| 2018 dependencies()->AssumeMapStable(object_map); | |
| 2019 } | |
| 2020 return Replace(effect); | |
| 2021 } | |
| 2022 } | |
| 2023 } | |
| 2024 return NoChange(); | |
| 2025 } | |
| 2026 | |
| 2027 Reduction JSTypedLowering::ReduceCheckString(Node* node) { | |
| 2028 // TODO(bmeurer): Find a better home for this thing! | |
| 2029 Node* const input = NodeProperties::GetValueInput(node, 0); | |
| 2030 Type* const input_type = NodeProperties::GetType(input); | |
| 2031 if (input_type->Is(Type::String())) { | |
| 2032 ReplaceWithValue(node, input); | |
| 2033 return Replace(input); | |
| 2034 } | |
| 2035 return NoChange(); | |
| 2036 } | |
| 2037 | |
| 2038 Reduction JSTypedLowering::ReduceLoadField(Node* node) { | |
| 2039 // TODO(bmeurer): Find a better home for this thing! | |
| 2040 Node* const object = NodeProperties::GetValueInput(node, 0); | |
| 2041 Type* const object_type = NodeProperties::GetType(object); | |
| 2042 FieldAccess const& access = FieldAccessOf(node->op()); | |
| 2043 if (access.base_is_tagged == kTaggedBase && | |
| 2044 access.offset == HeapObject::kMapOffset) { | |
| 2045 // We can replace LoadField[Map](o) with map if is stable and either | |
| 2046 // (a) o has type Constant(object) and map == object->map, or | |
| 2047 // (b) o has type Class(map), | |
| 2048 // and either | |
| 2049 // (1) map cannot transition further, or | |
| 2050 // (2) deoptimization is enabled and we can add a code dependency on the | |
| 2051 // stability of map (to guard the Constant type information). | |
| 2052 Handle<Map> object_map; | |
| 2053 if (GetStableMapFromObjectType(object_type).ToHandle(&object_map)) { | |
| 2054 if (object_map->CanTransition()) { | |
| 2055 if (flags() & kDeoptimizationEnabled) { | |
| 2056 dependencies()->AssumeMapStable(object_map); | |
| 2057 } else { | |
| 2058 return NoChange(); | |
| 2059 } | |
| 2060 } | |
| 2061 Node* const value = jsgraph()->HeapConstant(object_map); | |
| 2062 ReplaceWithValue(node, value); | |
| 2063 return Replace(value); | |
| 2064 } | |
| 2065 } | |
| 2066 return NoChange(); | |
| 2067 } | |
| 2068 | |
| 2069 Reduction JSTypedLowering::ReduceNumberRoundop(Node* node) { | |
| 2070 // TODO(bmeurer): Find a better home for this thing! | |
| 2071 Node* const input = NodeProperties::GetValueInput(node, 0); | |
| 2072 Type* const input_type = NodeProperties::GetType(input); | |
| 2073 if (input_type->Is(type_cache_.kIntegerOrMinusZeroOrNaN)) { | |
| 2074 return Replace(input); | |
| 2075 } | |
| 2076 return NoChange(); | |
| 2077 } | |
| 2078 | |
| 2079 Reduction JSTypedLowering::Reduce(Node* node) { | 1928 Reduction JSTypedLowering::Reduce(Node* node) { |
| 2080 // Check if the output type is a singleton. In that case we already know the | |
| 2081 // result value and can simply replace the node if it's eliminable. | |
| 2082 if (!NodeProperties::IsConstant(node) && NodeProperties::IsTyped(node) && | |
| 2083 node->op()->HasProperty(Operator::kEliminatable)) { | |
| 2084 // We can only constant-fold nodes here, that are known to not cause any | |
| 2085 // side-effect, may it be a JavaScript observable side-effect or a possible | |
| 2086 // eager deoptimization exit (i.e. {node} has an operator that doesn't have | |
| 2087 // the Operator::kNoDeopt property). | |
| 2088 Type* upper = NodeProperties::GetType(node); | |
| 2089 if (upper->IsInhabited()) { | |
| 2090 if (upper->IsConstant()) { | |
| 2091 Node* replacement = jsgraph()->Constant(upper->AsConstant()->Value()); | |
| 2092 ReplaceWithValue(node, replacement); | |
| 2093 return Changed(replacement); | |
| 2094 } else if (upper->Is(Type::MinusZero())) { | |
| 2095 Node* replacement = jsgraph()->Constant(factory()->minus_zero_value()); | |
| 2096 ReplaceWithValue(node, replacement); | |
| 2097 return Changed(replacement); | |
| 2098 } else if (upper->Is(Type::NaN())) { | |
| 2099 Node* replacement = jsgraph()->NaNConstant(); | |
| 2100 ReplaceWithValue(node, replacement); | |
| 2101 return Changed(replacement); | |
| 2102 } else if (upper->Is(Type::Null())) { | |
| 2103 Node* replacement = jsgraph()->NullConstant(); | |
| 2104 ReplaceWithValue(node, replacement); | |
| 2105 return Changed(replacement); | |
| 2106 } else if (upper->Is(Type::PlainNumber()) && | |
| 2107 upper->Min() == upper->Max()) { | |
| 2108 Node* replacement = jsgraph()->Constant(upper->Min()); | |
| 2109 ReplaceWithValue(node, replacement); | |
| 2110 return Changed(replacement); | |
| 2111 } else if (upper->Is(Type::Undefined())) { | |
| 2112 Node* replacement = jsgraph()->UndefinedConstant(); | |
| 2113 ReplaceWithValue(node, replacement); | |
| 2114 return Changed(replacement); | |
| 2115 } | |
| 2116 } | |
| 2117 } | |
| 2118 switch (node->opcode()) { | 1929 switch (node->opcode()) { |
| 2119 case IrOpcode::kJSEqual: | 1930 case IrOpcode::kJSEqual: |
| 2120 return ReduceJSEqual(node, false); | 1931 return ReduceJSEqual(node, false); |
| 2121 case IrOpcode::kJSNotEqual: | 1932 case IrOpcode::kJSNotEqual: |
| 2122 return ReduceJSEqual(node, true); | 1933 return ReduceJSEqual(node, true); |
| 2123 case IrOpcode::kJSStrictEqual: | 1934 case IrOpcode::kJSStrictEqual: |
| 2124 return ReduceJSStrictEqual(node, false); | 1935 return ReduceJSStrictEqual(node, false); |
| 2125 case IrOpcode::kJSStrictNotEqual: | 1936 case IrOpcode::kJSStrictNotEqual: |
| 2126 return ReduceJSStrictEqual(node, true); | 1937 return ReduceJSStrictEqual(node, true); |
| 2127 case IrOpcode::kJSLessThan: // fall through | 1938 case IrOpcode::kJSLessThan: // fall through |
| (...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2180 case IrOpcode::kJSForInNext: | 1991 case IrOpcode::kJSForInNext: |
| 2181 return ReduceJSForInNext(node); | 1992 return ReduceJSForInNext(node); |
| 2182 case IrOpcode::kJSForInStep: | 1993 case IrOpcode::kJSForInStep: |
| 2183 return ReduceJSForInStep(node); | 1994 return ReduceJSForInStep(node); |
| 2184 case IrOpcode::kJSGeneratorStore: | 1995 case IrOpcode::kJSGeneratorStore: |
| 2185 return ReduceJSGeneratorStore(node); | 1996 return ReduceJSGeneratorStore(node); |
| 2186 case IrOpcode::kJSGeneratorRestoreContinuation: | 1997 case IrOpcode::kJSGeneratorRestoreContinuation: |
| 2187 return ReduceJSGeneratorRestoreContinuation(node); | 1998 return ReduceJSGeneratorRestoreContinuation(node); |
| 2188 case IrOpcode::kJSGeneratorRestoreRegister: | 1999 case IrOpcode::kJSGeneratorRestoreRegister: |
| 2189 return ReduceJSGeneratorRestoreRegister(node); | 2000 return ReduceJSGeneratorRestoreRegister(node); |
| 2190 case IrOpcode::kPhi: | |
| 2191 return ReducePhi(node); | |
| 2192 case IrOpcode::kSelect: | |
| 2193 return ReduceSelect(node); | |
| 2194 case IrOpcode::kCheckMaps: | |
| 2195 return ReduceCheckMaps(node); | |
| 2196 case IrOpcode::kCheckString: | |
| 2197 return ReduceCheckString(node); | |
| 2198 case IrOpcode::kNumberCeil: | |
| 2199 case IrOpcode::kNumberFloor: | |
| 2200 case IrOpcode::kNumberRound: | |
| 2201 case IrOpcode::kNumberTrunc: | |
| 2202 return ReduceNumberRoundop(node); | |
| 2203 case IrOpcode::kLoadField: | |
| 2204 return ReduceLoadField(node); | |
| 2205 default: | 2001 default: |
| 2206 break; | 2002 break; |
| 2207 } | 2003 } |
| 2208 return NoChange(); | 2004 return NoChange(); |
| 2209 } | 2005 } |
| 2210 | 2006 |
| 2211 | 2007 |
| 2212 Factory* JSTypedLowering::factory() const { return jsgraph()->factory(); } | 2008 Factory* JSTypedLowering::factory() const { return jsgraph()->factory(); } |
| 2213 | 2009 |
| 2214 | 2010 |
| (...skipping 21 matching lines...) Expand all Loading... |
| 2236 } | 2032 } |
| 2237 | 2033 |
| 2238 | 2034 |
| 2239 CompilationDependencies* JSTypedLowering::dependencies() const { | 2035 CompilationDependencies* JSTypedLowering::dependencies() const { |
| 2240 return dependencies_; | 2036 return dependencies_; |
| 2241 } | 2037 } |
| 2242 | 2038 |
| 2243 } // namespace compiler | 2039 } // namespace compiler |
| 2244 } // namespace internal | 2040 } // namespace internal |
| 2245 } // namespace v8 | 2041 } // namespace v8 |
| OLD | NEW |