Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2015 the V8 project authors. All rights reserved. | 1 // Copyright 2015 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-type-feedback.h" | 5 #include "src/compiler/js-type-feedback.h" |
| 6 | 6 |
| 7 #include "src/property-details.h" | 7 #include "src/property-details.h" |
| 8 | 8 |
| 9 #include "src/accessors.h" | 9 #include "src/accessors.h" |
| 10 #include "src/ast.h" | 10 #include "src/ast.h" |
| 11 #include "src/compiler.h" | |
| 11 #include "src/type-info.h" | 12 #include "src/type-info.h" |
| 12 | 13 |
| 13 #include "src/compiler/access-builder.h" | 14 #include "src/compiler/access-builder.h" |
| 14 #include "src/compiler/common-operator.h" | 15 #include "src/compiler/common-operator.h" |
| 15 #include "src/compiler/node-aux-data.h" | 16 #include "src/compiler/node-aux-data.h" |
| 16 #include "src/compiler/node-matchers.h" | 17 #include "src/compiler/node-matchers.h" |
| 17 #include "src/compiler/simplified-operator.h" | 18 #include "src/compiler/simplified-operator.h" |
| 18 | 19 |
| 19 namespace v8 { | 20 namespace v8 { |
| 20 namespace internal { | 21 namespace internal { |
| (...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 63 } | 64 } |
| 64 return ReduceJSStoreProperty(node); | 65 return ReduceJSStoreProperty(node); |
| 65 } | 66 } |
| 66 default: | 67 default: |
| 67 break; | 68 break; |
| 68 } | 69 } |
| 69 return NoChange(); | 70 return NoChange(); |
| 70 } | 71 } |
| 71 | 72 |
| 72 | 73 |
| 74 static void AddFieldAccessTypes(FieldAccess* access, | |
| 75 PropertyDetails property_details) { | |
| 76 if (property_details.representation().IsSmi()) { | |
| 77 access->type = Type::SignedSmall(); | |
| 78 access->machine_type = static_cast<MachineType>(kTypeInt32 | kRepTagged); | |
| 79 } else if (property_details.representation().IsDouble()) { | |
| 80 access->type = Type::Number(); | |
| 81 access->machine_type = kMachFloat64; | |
| 82 } | |
| 83 } | |
| 84 | |
| 85 | |
| 73 static bool GetInObjectFieldAccess(LoadOrStore mode, Handle<Map> map, | 86 static bool GetInObjectFieldAccess(LoadOrStore mode, Handle<Map> map, |
| 74 Handle<Name> name, FieldAccess* access) { | 87 Handle<Name> name, FieldAccess* access) { |
| 75 access->base_is_tagged = kTaggedBase; | 88 access->base_is_tagged = kTaggedBase; |
| 76 access->offset = -1; | 89 access->offset = -1; |
| 77 access->name = name; | 90 access->name = name; |
| 78 access->type = Type::Any(); | 91 access->type = Type::Any(); |
| 79 access->machine_type = kMachAnyTagged; | 92 access->machine_type = kMachAnyTagged; |
| 80 | 93 |
| 81 // Check for properties that have accessors but are JSObject fields. | 94 // Check for properties that have accessors but are JSObject fields. |
| 82 if (Accessors::IsJSObjectFieldAccessor(map, name, &access->offset)) { | 95 if (Accessors::IsJSObjectFieldAccessor(map, name, &access->offset)) { |
| (...skipping 11 matching lines...) Expand all Loading... | |
| 94 PropertyDetails property_details = descriptors->GetDetails(number); | 107 PropertyDetails property_details = descriptors->GetDetails(number); |
| 95 | 108 |
| 96 bool is_smi = property_details.representation().IsSmi(); | 109 bool is_smi = property_details.representation().IsSmi(); |
| 97 bool is_double = property_details.representation().IsDouble(); | 110 bool is_double = property_details.representation().IsDouble(); |
| 98 | 111 |
| 99 if (property_details.type() != DATA) { | 112 if (property_details.type() != DATA) { |
| 100 // TODO(turbofan): constant loads and stores. | 113 // TODO(turbofan): constant loads and stores. |
| 101 return false; | 114 return false; |
| 102 } | 115 } |
| 103 | 116 |
| 117 // Transfer known types from property details. | |
| 118 AddFieldAccessTypes(access, property_details); | |
| 119 | |
| 104 if (mode == STORE) { | 120 if (mode == STORE) { |
| 105 if (property_details.IsReadOnly()) return false; | 121 if (property_details.IsReadOnly()) { |
| 106 if (is_smi) { | 122 // TODO(turbofan): deopt, ignore or throw on readonly stores. |
| 107 // TODO(turbofan): SMI stores. | |
| 108 return false; | 123 return false; |
| 109 } | 124 } |
| 110 if (is_double) { | 125 if (is_smi || is_double) { |
| 111 // TODO(turbofan): double stores. | 126 // TODO(turbofan): check type and deopt for SMI/double stores. |
| 112 return false; | 127 return false; |
| 113 } | 128 } |
| 114 } else { | |
| 115 // Check property details for loads. | |
| 116 if (is_smi) { | |
| 117 access->type = Type::SignedSmall(); | |
| 118 access->machine_type = static_cast<MachineType>(kTypeInt32 | kRepTagged); | |
| 119 } | |
| 120 if (is_double) { | |
| 121 access->type = Type::Number(); | |
| 122 access->machine_type = kMachFloat64; | |
| 123 } | |
| 124 } | 129 } |
| 125 | 130 |
| 126 int index = map->instance_descriptors()->GetFieldIndex(number); | 131 int index = map->instance_descriptors()->GetFieldIndex(number); |
| 127 FieldIndex field_index = FieldIndex::ForPropertyIndex(*map, index, is_double); | 132 FieldIndex field_index = FieldIndex::ForPropertyIndex(*map, index, is_double); |
| 128 | 133 |
| 129 if (field_index.is_inobject()) { | 134 if (field_index.is_inobject()) { |
| 130 access->offset = field_index.offset(); | 135 access->offset = field_index.offset(); |
| 131 return true; | 136 return true; |
| 132 } | 137 } |
| 133 | 138 |
| 134 // TODO(turbofan): handle out of object properties. | 139 // TODO(turbofan): handle out of object properties. |
| 135 return false; | 140 return false; |
| 136 } | 141 } |
| 137 | 142 |
| 138 | 143 |
| 144 static bool IsGlobalObject(Node* node) { | |
| 145 return NodeProperties::IsTyped(node) && | |
| 146 NodeProperties::GetBounds(node).upper->Is(Type::GlobalObject()); | |
| 147 } | |
| 148 | |
| 149 | |
| 139 Reduction JSTypeFeedbackSpecializer::ReduceJSLoadNamed(Node* node) { | 150 Reduction JSTypeFeedbackSpecializer::ReduceJSLoadNamed(Node* node) { |
| 140 DCHECK(node->opcode() == IrOpcode::kJSLoadNamed); | 151 DCHECK(node->opcode() == IrOpcode::kJSLoadNamed); |
| 152 Node* receiver = node->InputAt(0); | |
| 153 if (IsGlobalObject(receiver)) { | |
| 154 return ReduceJSLoadNamedFromGlobalObject(node); | |
| 155 } | |
| 156 | |
| 141 // TODO(turbofan): type feedback currently requires deoptimization. | 157 // TODO(turbofan): type feedback currently requires deoptimization. |
| 142 if (!FLAG_turbo_deoptimization) return NoChange(); | 158 if (!FLAG_turbo_deoptimization) return NoChange(); |
| 143 | 159 |
| 144 // TODO(turbofan): handle vector-based type feedback. | 160 // TODO(turbofan): handle vector-based type feedback. |
| 145 TypeFeedbackId id = js_type_feedback_->find(node); | 161 TypeFeedbackId id = js_type_feedback_->find(node); |
| 146 if (id.IsNone() || oracle()->LoadInlineCacheState(id) == UNINITIALIZED) { | 162 if (id.IsNone() || oracle()->LoadInlineCacheState(id) == UNINITIALIZED) { |
| 147 return NoChange(); | 163 return NoChange(); |
| 148 } | 164 } |
| 149 | 165 |
| 150 const LoadNamedParameters& p = LoadNamedParametersOf(node->op()); | 166 const LoadNamedParameters& p = LoadNamedParametersOf(node->op()); |
| 151 SmallMapList maps; | 167 SmallMapList maps; |
| 152 Handle<Name> name = p.name().handle(); | 168 Handle<Name> name = p.name().handle(); |
| 153 Node* receiver = node->InputAt(0); | |
| 154 Node* effect = NodeProperties::GetEffectInput(node); | 169 Node* effect = NodeProperties::GetEffectInput(node); |
| 155 GatherReceiverTypes(receiver, effect, id, name, &maps); | 170 GatherReceiverTypes(receiver, effect, id, name, &maps); |
| 156 | 171 |
| 157 if (maps.length() != 1) return NoChange(); // TODO(turbofan): polymorphism | 172 if (maps.length() != 1) return NoChange(); // TODO(turbofan): polymorphism |
| 158 | 173 |
| 159 Handle<Map> map = maps.first(); | 174 Handle<Map> map = maps.first(); |
| 160 FieldAccess field_access; | 175 FieldAccess field_access; |
| 161 if (!GetInObjectFieldAccess(LOAD, map, name, &field_access)) { | 176 if (!GetInObjectFieldAccess(LOAD, map, name, &field_access)) { |
| 162 return NoChange(); | 177 return NoChange(); |
| 163 } | 178 } |
| (...skipping 12 matching lines...) Expand all Loading... | |
| 176 // TODO(titzer): frame state should be from before the load. | 191 // TODO(titzer): frame state should be from before the load. |
| 177 Node* frame_state = NodeProperties::GetFrameStateInput(node, 0); | 192 Node* frame_state = NodeProperties::GetFrameStateInput(node, 0); |
| 178 Node* deopt = graph()->NewNode(common()->Deoptimize(), frame_state, effect, | 193 Node* deopt = graph()->NewNode(common()->Deoptimize(), frame_state, effect, |
| 179 check_failed); | 194 check_failed); |
| 180 NodeProperties::MergeControlToEnd(graph(), common(), deopt); | 195 NodeProperties::MergeControlToEnd(graph(), common(), deopt); |
| 181 NodeProperties::ReplaceWithValue(node, load, load, check_success); | 196 NodeProperties::ReplaceWithValue(node, load, load, check_success); |
| 182 return Replace(load); | 197 return Replace(load); |
| 183 } | 198 } |
| 184 | 199 |
| 185 | 200 |
| 201 Reduction JSTypeFeedbackSpecializer::ReduceJSLoadNamedFromGlobalObject( | |
| 202 Node* node) { | |
| 203 Handle<Name> name = LoadNamedParametersOf(node->op()).name().handle(); | |
| 204 // Try to optimize loads from the global object. | |
| 205 Handle<Object> constant_value = | |
| 206 jsgraph()->isolate()->factory()->GlobalConstantFor(name); | |
| 207 if (!constant_value.is_null()) { | |
| 208 // Always optimize global constants. | |
| 209 Node* constant = jsgraph()->Constant(constant_value); | |
| 210 NodeProperties::ReplaceWithValue(node, constant); | |
| 211 return Replace(constant); | |
| 212 } | |
| 213 | |
| 214 if (global_object_.is_null()) { | |
| 215 // Nothing else can be done if we don't have a global object. | |
| 216 return NoChange(); | |
| 217 } | |
| 218 | |
| 219 if (FLAG_turbo_deoptimization) { | |
| 220 // Constant promotion or cell access requires lazy deoptimization support. | |
| 221 LookupIterator it(global_object_, name, LookupIterator::OWN); | |
| 222 | |
| 223 if (it.state() == LookupIterator::DATA) { | |
| 224 Handle<PropertyCell> cell = it.GetPropertyCell(); | |
| 225 dependencies_->AssumePropertyCell(cell); | |
| 226 | |
| 227 if (it.property_details().cell_type() == PropertyCellType::kConstant) { | |
| 228 // Constant promote the global's current value. | |
| 229 Handle<Object> constant_value(cell->value(), jsgraph()->isolate()); | |
| 230 if (constant_value->IsConsString()) { | |
| 231 constant_value = | |
| 232 String::Flatten(Handle<String>::cast(constant_value)); | |
|
Michael Starzinger
2015/04/21 12:34:01
rant: We need to flatten strings here? SRSLY? OMG!
titzer
2015/04/21 12:56:52
Agreed, cribbed this one from Crankyshaft.
| |
| 233 } | |
| 234 Node* constant = jsgraph()->Constant(constant_value); | |
| 235 NodeProperties::ReplaceWithValue(node, constant); | |
| 236 return Replace(constant); | |
| 237 } else { | |
| 238 // Load directly from the property cell. | |
| 239 FieldAccess access = AccessBuilder::ForPropertyCellValue(); | |
| 240 Node* control = NodeProperties::GetControlInput(node); | |
| 241 Node* load_field = graph()->NewNode( | |
| 242 simplified()->LoadField(access), jsgraph()->Constant(cell), | |
| 243 NodeProperties::GetEffectInput(node), control); | |
| 244 NodeProperties::ReplaceWithValue(node, load_field, load_field, control); | |
| 245 return Replace(load_field); | |
| 246 } | |
| 247 } | |
| 248 } else { | |
| 249 // TODO(turbofan): non-configurable properties on the global object | |
| 250 // should be loadable through a cell without deoptimization support. | |
| 251 } | |
| 252 | |
| 253 return NoChange(); | |
| 254 } | |
| 255 | |
| 256 | |
| 186 Reduction JSTypeFeedbackSpecializer::ReduceJSLoadProperty(Node* node) { | 257 Reduction JSTypeFeedbackSpecializer::ReduceJSLoadProperty(Node* node) { |
| 187 return NoChange(); | 258 return NoChange(); |
| 188 } | 259 } |
| 189 | 260 |
| 190 | 261 |
| 191 Reduction JSTypeFeedbackSpecializer::ReduceJSStoreNamed(Node* node) { | 262 Reduction JSTypeFeedbackSpecializer::ReduceJSStoreNamed(Node* node) { |
| 192 DCHECK(node->opcode() == IrOpcode::kJSStoreNamed); | 263 DCHECK(node->opcode() == IrOpcode::kJSStoreNamed); |
| 193 // TODO(turbofan): type feedback currently requires deoptimization. | 264 // TODO(turbofan): type feedback currently requires deoptimization. |
| 194 if (!FLAG_turbo_deoptimization) return NoChange(); | 265 if (!FLAG_turbo_deoptimization) return NoChange(); |
| 195 | 266 |
| (...skipping 80 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 276 // TODO(turbofan): filter maps by initial receiver map if known | 347 // TODO(turbofan): filter maps by initial receiver map if known |
| 277 // TODO(turbofan): filter maps by native context (if specializing) | 348 // TODO(turbofan): filter maps by native context (if specializing) |
| 278 // TODO(turbofan): filter maps by effect chain | 349 // TODO(turbofan): filter maps by effect chain |
| 279 oracle()->PropertyReceiverTypes(id, name, maps); | 350 oracle()->PropertyReceiverTypes(id, name, maps); |
| 280 } | 351 } |
| 281 | 352 |
| 282 | 353 |
| 283 } // namespace compiler | 354 } // namespace compiler |
| 284 } // namespace internal | 355 } // namespace internal |
| 285 } // namespace v8 | 356 } // namespace v8 |
| OLD | NEW |