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-builtin-reducer.h" | 5 #include "src/compiler/js-builtin-reducer.h" |
6 | 6 |
| 7 #include "src/compilation-dependencies.h" |
7 #include "src/compiler/access-builder.h" | 8 #include "src/compiler/access-builder.h" |
8 #include "src/compiler/js-graph.h" | 9 #include "src/compiler/js-graph.h" |
9 #include "src/compiler/node-matchers.h" | 10 #include "src/compiler/node-matchers.h" |
10 #include "src/compiler/node-properties.h" | 11 #include "src/compiler/node-properties.h" |
11 #include "src/compiler/simplified-operator.h" | 12 #include "src/compiler/simplified-operator.h" |
12 #include "src/objects-inl.h" | 13 #include "src/objects-inl.h" |
13 #include "src/type-cache.h" | 14 #include "src/type-cache.h" |
14 #include "src/types.h" | 15 #include "src/types.h" |
15 | 16 |
16 namespace v8 { | 17 namespace v8 { |
(...skipping 69 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
86 DCHECK_EQ(IrOpcode::kJSCallFunction, node_->opcode()); | 87 DCHECK_EQ(IrOpcode::kJSCallFunction, node_->opcode()); |
87 DCHECK_LT(index, GetJSCallArity()); | 88 DCHECK_LT(index, GetJSCallArity()); |
88 // Skip first (i.e. callee) and second (i.e. receiver) operand. | 89 // Skip first (i.e. callee) and second (i.e. receiver) operand. |
89 return NodeProperties::GetValueInput(node_, index + 2); | 90 return NodeProperties::GetValueInput(node_, index + 2); |
90 } | 91 } |
91 | 92 |
92 private: | 93 private: |
93 Node* node_; | 94 Node* node_; |
94 }; | 95 }; |
95 | 96 |
96 JSBuiltinReducer::JSBuiltinReducer(Editor* editor, JSGraph* jsgraph) | 97 JSBuiltinReducer::JSBuiltinReducer(Editor* editor, JSGraph* jsgraph, |
| 98 Flags flags, |
| 99 CompilationDependencies* dependencies) |
97 : AdvancedReducer(editor), | 100 : AdvancedReducer(editor), |
| 101 dependencies_(dependencies), |
| 102 flags_(flags), |
98 jsgraph_(jsgraph), | 103 jsgraph_(jsgraph), |
99 type_cache_(TypeCache::Get()) {} | 104 type_cache_(TypeCache::Get()) {} |
100 | 105 |
| 106 namespace { |
| 107 |
| 108 MaybeHandle<Map> GetMapWitness(Node* node) { |
| 109 Node* receiver = NodeProperties::GetValueInput(node, 1); |
| 110 Node* effect = NodeProperties::GetEffectInput(node); |
| 111 // Check if the {node} is dominated by a CheckMaps with a single map |
| 112 // for the {receiver}, and if so use that map for the lowering below. |
| 113 for (Node* dominator = effect;;) { |
| 114 if (dominator->opcode() == IrOpcode::kCheckMaps && |
| 115 dominator->InputAt(0) == receiver) { |
| 116 if (dominator->op()->ValueInputCount() == 2) { |
| 117 HeapObjectMatcher m(dominator->InputAt(1)); |
| 118 if (m.HasValue()) return Handle<Map>::cast(m.Value()); |
| 119 } |
| 120 return MaybeHandle<Map>(); |
| 121 } |
| 122 if (dominator->op()->EffectInputCount() != 1) { |
| 123 // Didn't find any appropriate CheckMaps node. |
| 124 return MaybeHandle<Map>(); |
| 125 } |
| 126 dominator = NodeProperties::GetEffectInput(dominator); |
| 127 } |
| 128 } |
| 129 |
| 130 // TODO(turbofan): This was copied from Crankshaft, might be too restrictive. |
| 131 bool IsReadOnlyLengthDescriptor(Handle<Map> jsarray_map) { |
| 132 DCHECK(!jsarray_map->is_dictionary_map()); |
| 133 Isolate* isolate = jsarray_map->GetIsolate(); |
| 134 Handle<Name> length_string = isolate->factory()->length_string(); |
| 135 DescriptorArray* descriptors = jsarray_map->instance_descriptors(); |
| 136 int number = |
| 137 descriptors->SearchWithCache(isolate, *length_string, *jsarray_map); |
| 138 DCHECK_NE(DescriptorArray::kNotFound, number); |
| 139 return descriptors->GetDetails(number).IsReadOnly(); |
| 140 } |
| 141 |
| 142 // TODO(turbofan): This was copied from Crankshaft, might be too restrictive. |
| 143 bool CanInlineArrayResizeOperation(Handle<Map> receiver_map) { |
| 144 Isolate* const isolate = receiver_map->GetIsolate(); |
| 145 if (!receiver_map->prototype()->IsJSArray()) return false; |
| 146 Handle<JSArray> receiver_prototype(JSArray::cast(receiver_map->prototype()), |
| 147 isolate); |
| 148 return receiver_map->instance_type() == JS_ARRAY_TYPE && |
| 149 IsFastElementsKind(receiver_map->elements_kind()) && |
| 150 !receiver_map->is_dictionary_map() && receiver_map->is_extensible() && |
| 151 (!receiver_map->is_prototype_map() || receiver_map->is_stable()) && |
| 152 receiver_prototype->map()->is_stable() && |
| 153 isolate->IsFastArrayConstructorPrototypeChainIntact() && |
| 154 isolate->IsAnyInitialArrayPrototype(receiver_prototype) && |
| 155 !IsReadOnlyLengthDescriptor(receiver_map); |
| 156 } |
| 157 |
| 158 } // namespace |
| 159 |
| 160 // ES6 section 22.1.3.17 Array.prototype.pop ( ) |
| 161 Reduction JSBuiltinReducer::ReduceArrayPop(Node* node) { |
| 162 Handle<Map> receiver_map; |
| 163 Node* receiver = NodeProperties::GetValueInput(node, 1); |
| 164 Node* effect = NodeProperties::GetEffectInput(node); |
| 165 Node* control = NodeProperties::GetControlInput(node); |
| 166 // TODO(turbofan): Extend this to also handle fast (holey) double elements |
| 167 // once we got the hole NaN mess sorted out in TurboFan/V8. |
| 168 if (GetMapWitness(node).ToHandle(&receiver_map) && |
| 169 CanInlineArrayResizeOperation(receiver_map) && |
| 170 IsFastSmiOrObjectElementsKind(receiver_map->elements_kind())) { |
| 171 // Install code dependencies on the {receiver} prototype maps and the |
| 172 // global array protector cell. |
| 173 dependencies()->AssumePropertyCell(factory()->array_protector()); |
| 174 dependencies()->AssumePrototypeMapsStable(receiver_map); |
| 175 |
| 176 // Load the "length" property of the {receiver}. |
| 177 Node* length = effect = graph()->NewNode( |
| 178 simplified()->LoadField( |
| 179 AccessBuilder::ForJSArrayLength(receiver_map->elements_kind())), |
| 180 receiver, effect, control); |
| 181 |
| 182 // Check if the {receiver} has any elements. |
| 183 Node* check = graph()->NewNode(simplified()->NumberEqual(), length, |
| 184 jsgraph()->ZeroConstant()); |
| 185 Node* branch = |
| 186 graph()->NewNode(common()->Branch(BranchHint::kFalse), check, control); |
| 187 |
| 188 Node* if_true = graph()->NewNode(common()->IfTrue(), branch); |
| 189 Node* etrue = effect; |
| 190 Node* vtrue = jsgraph()->UndefinedConstant(); |
| 191 |
| 192 Node* if_false = graph()->NewNode(common()->IfFalse(), branch); |
| 193 Node* efalse = effect; |
| 194 Node* vfalse; |
| 195 { |
| 196 // Load the elements backing store from the {receiver}. |
| 197 Node* elements = efalse = graph()->NewNode( |
| 198 simplified()->LoadField(AccessBuilder::ForJSObjectElements()), |
| 199 receiver, efalse, if_false); |
| 200 |
| 201 // Ensure that we aren't popping from a copy-on-write backing store. |
| 202 elements = efalse = |
| 203 graph()->NewNode(simplified()->EnsureWritableFastElements(), receiver, |
| 204 elements, efalse, if_false); |
| 205 |
| 206 // Compute the new {length}. |
| 207 length = graph()->NewNode(simplified()->NumberSubtract(), length, |
| 208 jsgraph()->OneConstant()); |
| 209 |
| 210 // Store the new {length} to the {receiver}. |
| 211 efalse = graph()->NewNode( |
| 212 simplified()->StoreField( |
| 213 AccessBuilder::ForJSArrayLength(receiver_map->elements_kind())), |
| 214 receiver, length, efalse, if_false); |
| 215 |
| 216 // Load the last entry from the {elements}. |
| 217 vfalse = efalse = graph()->NewNode( |
| 218 simplified()->LoadElement(AccessBuilder::ForFixedArrayElement( |
| 219 receiver_map->elements_kind())), |
| 220 elements, length, efalse, if_false); |
| 221 |
| 222 // Store a hole to the element we just removed from the {receiver}. |
| 223 efalse = graph()->NewNode( |
| 224 simplified()->StoreElement(AccessBuilder::ForFixedArrayElement( |
| 225 GetHoleyElementsKind(receiver_map->elements_kind()))), |
| 226 elements, length, jsgraph()->TheHoleConstant(), efalse, if_false); |
| 227 } |
| 228 |
| 229 control = graph()->NewNode(common()->Merge(2), if_true, if_false); |
| 230 effect = graph()->NewNode(common()->EffectPhi(2), etrue, efalse, control); |
| 231 Node* value = |
| 232 graph()->NewNode(common()->Phi(MachineRepresentation::kTagged, 2), |
| 233 vtrue, vfalse, control); |
| 234 |
| 235 // Convert the hole to undefined. Do this last, so that we can optimize |
| 236 // conversion operator via some smart strength reduction in many cases. |
| 237 if (IsFastHoleyElementsKind(receiver_map->elements_kind())) { |
| 238 value = |
| 239 graph()->NewNode(simplified()->ConvertTaggedHoleToUndefined(), value); |
| 240 } |
| 241 |
| 242 ReplaceWithValue(node, value, effect, control); |
| 243 return Replace(value); |
| 244 } |
| 245 return NoChange(); |
| 246 } |
| 247 |
101 // ES6 section 20.2.2.1 Math.abs ( x ) | 248 // ES6 section 20.2.2.1 Math.abs ( x ) |
102 Reduction JSBuiltinReducer::ReduceMathAbs(Node* node) { | 249 Reduction JSBuiltinReducer::ReduceMathAbs(Node* node) { |
103 JSCallReduction r(node); | 250 JSCallReduction r(node); |
104 if (r.InputsMatchOne(Type::PlainPrimitive())) { | 251 if (r.InputsMatchOne(Type::PlainPrimitive())) { |
105 // Math.abs(a:plain-primitive) -> NumberAbs(ToNumber(a)) | 252 // Math.abs(a:plain-primitive) -> NumberAbs(ToNumber(a)) |
106 Node* input = ToNumber(r.GetJSCallInput(0)); | 253 Node* input = ToNumber(r.GetJSCallInput(0)); |
107 Node* value = graph()->NewNode(simplified()->NumberAbs(), input); | 254 Node* value = graph()->NewNode(simplified()->NumberAbs(), input); |
108 return Replace(value); | 255 return Replace(value); |
109 } | 256 } |
110 return NoChange(); | 257 return NoChange(); |
(...skipping 631 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
742 return NoChange(); | 889 return NoChange(); |
743 } | 890 } |
744 | 891 |
745 Reduction JSBuiltinReducer::Reduce(Node* node) { | 892 Reduction JSBuiltinReducer::Reduce(Node* node) { |
746 Reduction reduction = NoChange(); | 893 Reduction reduction = NoChange(); |
747 JSCallReduction r(node); | 894 JSCallReduction r(node); |
748 | 895 |
749 // Dispatch according to the BuiltinFunctionId if present. | 896 // Dispatch according to the BuiltinFunctionId if present. |
750 if (!r.HasBuiltinFunctionId()) return NoChange(); | 897 if (!r.HasBuiltinFunctionId()) return NoChange(); |
751 switch (r.GetBuiltinFunctionId()) { | 898 switch (r.GetBuiltinFunctionId()) { |
| 899 case kArrayPop: |
| 900 return ReduceArrayPop(node); |
752 case kMathAbs: | 901 case kMathAbs: |
753 reduction = ReduceMathAbs(node); | 902 reduction = ReduceMathAbs(node); |
754 break; | 903 break; |
755 case kMathAcos: | 904 case kMathAcos: |
756 reduction = ReduceMathAcos(node); | 905 reduction = ReduceMathAcos(node); |
757 break; | 906 break; |
758 case kMathAcosh: | 907 case kMathAcosh: |
759 reduction = ReduceMathAcosh(node); | 908 reduction = ReduceMathAcosh(node); |
760 break; | 909 break; |
761 case kMathAsin: | 910 case kMathAsin: |
(...skipping 134 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
896 | 1045 |
897 Node* JSBuiltinReducer::ToUint32(Node* input) { | 1046 Node* JSBuiltinReducer::ToUint32(Node* input) { |
898 input = ToNumber(input); | 1047 input = ToNumber(input); |
899 Type* input_type = NodeProperties::GetType(input); | 1048 Type* input_type = NodeProperties::GetType(input); |
900 if (input_type->Is(Type::Unsigned32())) return input; | 1049 if (input_type->Is(Type::Unsigned32())) return input; |
901 return graph()->NewNode(simplified()->NumberToUint32(), input); | 1050 return graph()->NewNode(simplified()->NumberToUint32(), input); |
902 } | 1051 } |
903 | 1052 |
904 Graph* JSBuiltinReducer::graph() const { return jsgraph()->graph(); } | 1053 Graph* JSBuiltinReducer::graph() const { return jsgraph()->graph(); } |
905 | 1054 |
| 1055 Factory* JSBuiltinReducer::factory() const { return isolate()->factory(); } |
906 | 1056 |
907 Isolate* JSBuiltinReducer::isolate() const { return jsgraph()->isolate(); } | 1057 Isolate* JSBuiltinReducer::isolate() const { return jsgraph()->isolate(); } |
908 | 1058 |
909 | 1059 |
910 CommonOperatorBuilder* JSBuiltinReducer::common() const { | 1060 CommonOperatorBuilder* JSBuiltinReducer::common() const { |
911 return jsgraph()->common(); | 1061 return jsgraph()->common(); |
912 } | 1062 } |
913 | 1063 |
914 | 1064 |
915 SimplifiedOperatorBuilder* JSBuiltinReducer::simplified() const { | 1065 SimplifiedOperatorBuilder* JSBuiltinReducer::simplified() const { |
916 return jsgraph()->simplified(); | 1066 return jsgraph()->simplified(); |
917 } | 1067 } |
918 | 1068 |
919 } // namespace compiler | 1069 } // namespace compiler |
920 } // namespace internal | 1070 } // namespace internal |
921 } // namespace v8 | 1071 } // namespace v8 |
OLD | NEW |