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 |