| OLD | NEW |
| 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file |
| 2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
| 3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
| 4 | 4 |
| 5 import '../common/codegen.dart' show CodegenWorkItem; | 5 import '../common/codegen.dart' show CodegenWorkItem; |
| 6 import '../common/tasks.dart' show CompilerTask; | 6 import '../common/tasks.dart' show CompilerTask; |
| 7 import '../compiler.dart' show Compiler; | 7 import '../compiler.dart' show Compiler; |
| 8 import '../constants/constant_system.dart'; | 8 import '../constants/constant_system.dart'; |
| 9 import '../constants/values.dart'; | 9 import '../constants/values.dart'; |
| 10 import '../core_types.dart' show CoreClasses; | 10 import '../core_types.dart' show CoreClasses; |
| (...skipping 1147 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1158 return node; | 1158 return node; |
| 1159 } | 1159 } |
| 1160 | 1160 |
| 1161 // Look for an allocation with type information and re-write type variable | 1161 // Look for an allocation with type information and re-write type variable |
| 1162 // as a function of the type parameters of the allocation. This effectively | 1162 // as a function of the type parameters of the allocation. This effectively |
| 1163 // store-forwards a type variable read through an allocation. | 1163 // store-forwards a type variable read through an allocation. |
| 1164 | 1164 |
| 1165 // Match: | 1165 // Match: |
| 1166 // | 1166 // |
| 1167 // setRuntimeTypeInfo( | 1167 // setRuntimeTypeInfo( |
| 1168 // HForeignNew(ClassElement), | 1168 // HCreate(ClassElement), |
| 1169 // HTypeInfoExpression(t_0, t_1, t_2, ...)); | 1169 // HTypeInfoExpression(t_0, t_1, t_2, ...)); |
| 1170 // | 1170 // |
| 1171 // The `t_i` are the values of the type parameters of ClassElement. | 1171 // The `t_i` are the values of the type parameters of ClassElement. |
| 1172 if (object is HInvokeStatic) { | 1172 if (object is HInvokeStatic) { |
| 1173 if (object.element == helpers.setRuntimeTypeInfo) { | 1173 if (object.element == helpers.setRuntimeTypeInfo) { |
| 1174 HInstruction allocation = object.inputs[0]; | 1174 HInstruction allocation = object.inputs[0]; |
| 1175 if (allocation is HForeignNew) { | 1175 if (allocation is HCreate) { |
| 1176 HInstruction typeInfo = object.inputs[1]; | 1176 HInstruction typeInfo = object.inputs[1]; |
| 1177 if (typeInfo is HTypeInfoExpression) { | 1177 if (typeInfo is HTypeInfoExpression) { |
| 1178 return finishSubstituted( | 1178 return finishSubstituted( |
| 1179 allocation.element, (int index) => typeInfo.inputs[index]); | 1179 allocation.element, (int index) => typeInfo.inputs[index]); |
| 1180 } | 1180 } |
| 1181 } | 1181 } |
| 1182 return node; | 1182 return node; |
| 1183 } | 1183 } |
| 1184 // TODO(sra): Factory constructors pass type arguments after the value | 1184 // TODO(sra): Factory constructors pass type arguments after the value |
| 1185 // arguments. The [select] argument indexes into these type arguments. | 1185 // arguments. The [select] argument indexes into these type arguments. |
| 1186 } | 1186 } |
| 1187 | 1187 |
| 1188 // Non-generic type (which extends or mixes in a generic type, for example | 1188 // Non-generic type (which extends or mixes in a generic type, for example |
| 1189 // CodeUnits extends UnmodifiableListBase<int>). | 1189 // CodeUnits extends UnmodifiableListBase<int>). |
| 1190 // Also used for raw-type when the type parameters are elided. | 1190 // Also used for raw-type when the type parameters are elided. |
| 1191 if (object is HForeignNew) { | 1191 if (object is HCreate) { |
| 1192 return finishSubstituted( | 1192 return finishSubstituted( |
| 1193 object.element, | 1193 object.element, |
| 1194 // If there are type arguments, all type arguments are 'dynamic'. | 1194 // If there are type arguments, all type arguments are 'dynamic'. |
| 1195 (int i) => graph.addConstantNull(compiler)); | 1195 (int i) => graph.addConstantNull(compiler)); |
| 1196 } | 1196 } |
| 1197 | 1197 |
| 1198 return node; | 1198 return node; |
| 1199 } | 1199 } |
| 1200 } | 1200 } |
| 1201 | 1201 |
| (...skipping 989 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2191 memorySet.registerFieldValue(element, receiver, instruction); | 2191 memorySet.registerFieldValue(element, receiver, instruction); |
| 2192 } | 2192 } |
| 2193 } | 2193 } |
| 2194 | 2194 |
| 2195 void visitFieldSet(HFieldSet instruction) { | 2195 void visitFieldSet(HFieldSet instruction) { |
| 2196 HInstruction receiver = instruction.getDartReceiver(compiler).nonCheck(); | 2196 HInstruction receiver = instruction.getDartReceiver(compiler).nonCheck(); |
| 2197 memorySet.registerFieldValueUpdate( | 2197 memorySet.registerFieldValueUpdate( |
| 2198 instruction.element, receiver, instruction.inputs.last); | 2198 instruction.element, receiver, instruction.inputs.last); |
| 2199 } | 2199 } |
| 2200 | 2200 |
| 2201 void visitForeignNew(HForeignNew instruction) { | 2201 void visitCreate(HCreate instruction) { |
| 2202 memorySet.registerAllocation(instruction); | 2202 memorySet.registerAllocation(instruction); |
| 2203 if (shouldTrackInitialValues(instruction)) { | 2203 if (shouldTrackInitialValues(instruction)) { |
| 2204 int argumentIndex = 0; | 2204 int argumentIndex = 0; |
| 2205 instruction.element.forEachInstanceField((_, Element member) { | 2205 instruction.element.forEachInstanceField((_, Element member) { |
| 2206 if (compiler.elementHasCompileTimeError(member)) return; | 2206 if (compiler.elementHasCompileTimeError(member)) return; |
| 2207 memorySet.registerFieldValue( | 2207 memorySet.registerFieldValue( |
| 2208 member, instruction, instruction.inputs[argumentIndex++]); | 2208 member, instruction, instruction.inputs[argumentIndex++]); |
| 2209 }, includeSuperAndInjectedMembers: true); | 2209 }, includeSuperAndInjectedMembers: true); |
| 2210 } | 2210 } |
| 2211 // In case this instruction has as input non-escaping objects, we | 2211 // In case this instruction has as input non-escaping objects, we |
| 2212 // need to mark these objects as escaping. | 2212 // need to mark these objects as escaping. |
| 2213 memorySet.killAffectedBy(instruction); | 2213 memorySet.killAffectedBy(instruction); |
| 2214 } | 2214 } |
| 2215 | 2215 |
| 2216 bool shouldTrackInitialValues(HForeignNew instruction) { | 2216 bool shouldTrackInitialValues(HCreate instruction) { |
| 2217 // Don't track initial field values of an allocation that are | 2217 // Don't track initial field values of an allocation that are |
| 2218 // unprofitable. We search the chain of single uses in allocations for a | 2218 // unprofitable. We search the chain of single uses in allocations for a |
| 2219 // limited depth. | 2219 // limited depth. |
| 2220 | 2220 |
| 2221 const MAX_HEAP_DEPTH = 5; | 2221 const MAX_HEAP_DEPTH = 5; |
| 2222 | 2222 |
| 2223 bool interestingUse(HInstruction instruction, int heapDepth) { | 2223 bool interestingUse(HInstruction instruction, int heapDepth) { |
| 2224 // Heuristic: if the allocation is too deep in heap it is unlikely we will | 2224 // Heuristic: if the allocation is too deep in heap it is unlikely we will |
| 2225 // recover a field by load-elimination. | 2225 // recover a field by load-elimination. |
| 2226 // TODO(sra): We can measure this depth by looking at load chains. | 2226 // TODO(sra): We can measure this depth by looking at load chains. |
| 2227 if (heapDepth == MAX_HEAP_DEPTH) return false; | 2227 if (heapDepth == MAX_HEAP_DEPTH) return false; |
| 2228 // There are multiple uses so do the full store analysis. | 2228 // There are multiple uses so do the full store analysis. |
| 2229 if (instruction.usedBy.length != 1) return true; | 2229 if (instruction.usedBy.length != 1) return true; |
| 2230 HInstruction use = instruction.usedBy.single; | 2230 HInstruction use = instruction.usedBy.single; |
| 2231 // When the only use is an allocation, the allocation becomes the only | 2231 // When the only use is an allocation, the allocation becomes the only |
| 2232 // heap alias for the current instruction. | 2232 // heap alias for the current instruction. |
| 2233 if (use is HForeignNew) return interestingUse(use, heapDepth + 1); | 2233 if (use is HCreate) return interestingUse(use, heapDepth + 1); |
| 2234 if (use is HLiteralList) return interestingUse(use, heapDepth + 1); | 2234 if (use is HLiteralList) return interestingUse(use, heapDepth + 1); |
| 2235 if (use is HInvokeStatic) { | 2235 if (use is HInvokeStatic) { |
| 2236 // Assume the argument escapes. All we do with our initial allocation is | 2236 // Assume the argument escapes. All we do with our initial allocation is |
| 2237 // have it escape or store it into an object that escapes. | 2237 // have it escape or store it into an object that escapes. |
| 2238 return false; | 2238 return false; |
| 2239 // TODO(sra): Handle more functions. `setRuntimeTypeInfo` does not | 2239 // TODO(sra): Handle more functions. `setRuntimeTypeInfo` does not |
| 2240 // actually kill it's input, but we don't make use of that elsewhere so | 2240 // actually kill it's input, but we don't make use of that elsewhere so |
| 2241 // there is not point in checking here. | 2241 // there is not point in checking here. |
| 2242 } | 2242 } |
| 2243 if (use is HPhi) { | 2243 if (use is HPhi) { |
| (...skipping 107 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2351 if (couldBeTypedArray(first) && couldBeTypedArray(second)) return true; | 2351 if (couldBeTypedArray(first) && couldBeTypedArray(second)) return true; |
| 2352 return !first.instructionType | 2352 return !first.instructionType |
| 2353 .isDisjoint(second.instructionType, compiler.world); | 2353 .isDisjoint(second.instructionType, compiler.world); |
| 2354 } | 2354 } |
| 2355 | 2355 |
| 2356 bool isFinal(Element element) { | 2356 bool isFinal(Element element) { |
| 2357 return compiler.world.fieldNeverChanges(element); | 2357 return compiler.world.fieldNeverChanges(element); |
| 2358 } | 2358 } |
| 2359 | 2359 |
| 2360 bool isConcrete(HInstruction instruction) { | 2360 bool isConcrete(HInstruction instruction) { |
| 2361 return instruction is HForeignNew || | 2361 return instruction is HCreate || |
| 2362 instruction is HConstant || | 2362 instruction is HConstant || |
| 2363 instruction is HLiteralList; | 2363 instruction is HLiteralList; |
| 2364 } | 2364 } |
| 2365 | 2365 |
| 2366 bool couldBeTypedArray(HInstruction receiver) { | 2366 bool couldBeTypedArray(HInstruction receiver) { |
| 2367 JavaScriptBackend backend = compiler.backend; | 2367 JavaScriptBackend backend = compiler.backend; |
| 2368 return backend.couldBeTypedArray(receiver.instructionType); | 2368 return backend.couldBeTypedArray(receiver.instructionType); |
| 2369 } | 2369 } |
| 2370 | 2370 |
| 2371 /** | 2371 /** |
| (...skipping 216 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2588 | 2588 |
| 2589 keyedValues.forEach((receiver, values) { | 2589 keyedValues.forEach((receiver, values) { |
| 2590 result.keyedValues[receiver] = | 2590 result.keyedValues[receiver] = |
| 2591 new Map<HInstruction, HInstruction>.from(values); | 2591 new Map<HInstruction, HInstruction>.from(values); |
| 2592 }); | 2592 }); |
| 2593 | 2593 |
| 2594 result.nonEscapingReceivers.addAll(nonEscapingReceivers); | 2594 result.nonEscapingReceivers.addAll(nonEscapingReceivers); |
| 2595 return result; | 2595 return result; |
| 2596 } | 2596 } |
| 2597 } | 2597 } |
| OLD | NEW |