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 CodegenRegistry, CodegenWorkItem; | 5 import '../common/codegen.dart' show CodegenRegistry, 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 2225 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2236 if (instruction.usedBy.length != 1) return true; | 2236 if (instruction.usedBy.length != 1) return true; |
2237 HInstruction use = instruction.usedBy.single; | 2237 HInstruction use = instruction.usedBy.single; |
2238 // When the only use is an allocation, the allocation becomes the only | 2238 // When the only use is an allocation, the allocation becomes the only |
2239 // heap alias for the current instruction. | 2239 // heap alias for the current instruction. |
2240 if (use is HCreate) return interestingUse(use, heapDepth + 1); | 2240 if (use is HCreate) return interestingUse(use, heapDepth + 1); |
2241 if (use is HLiteralList) return interestingUse(use, heapDepth + 1); | 2241 if (use is HLiteralList) return interestingUse(use, heapDepth + 1); |
2242 if (use is HInvokeStatic) { | 2242 if (use is HInvokeStatic) { |
2243 // Assume the argument escapes. All we do with our initial allocation is | 2243 // Assume the argument escapes. All we do with our initial allocation is |
2244 // have it escape or store it into an object that escapes. | 2244 // have it escape or store it into an object that escapes. |
2245 return false; | 2245 return false; |
2246 // TODO(sra): Handle more functions. `setRuntimeTypeInfo` does not | 2246 // TODO(sra): Handle library functions that we know do not modify or |
2247 // actually kill it's input, but we don't make use of that elsewhere so | 2247 // leak the inputs. For example `setRuntimeTypeInfo` is used to mark |
2248 // there is not point in checking here. | 2248 // list literals with type information. |
2249 } | 2249 } |
2250 if (use is HPhi) { | 2250 if (use is HPhi) { |
2251 // The initial allocation (it's only alias) gets merged out of the model | 2251 // The initial allocation (it's only alias) gets merged out of the model |
2252 // of the heap before load. | 2252 // of the heap before load. |
2253 return false; | 2253 return false; |
2254 } | 2254 } |
2255 return true; | 2255 return true; |
2256 } | 2256 } |
2257 | 2257 |
2258 return interestingUse(instruction, 0); | 2258 return interestingUse(instruction, 0); |
(...skipping 25 matching lines...) Expand all Loading... |
2284 } | 2284 } |
2285 | 2285 |
2286 void visitStaticStore(HStaticStore instruction) { | 2286 void visitStaticStore(HStaticStore instruction) { |
2287 memorySet.registerFieldValueUpdate( | 2287 memorySet.registerFieldValueUpdate( |
2288 instruction.element, null, instruction.inputs.last); | 2288 instruction.element, null, instruction.inputs.last); |
2289 } | 2289 } |
2290 | 2290 |
2291 void visitLiteralList(HLiteralList instruction) { | 2291 void visitLiteralList(HLiteralList instruction) { |
2292 memorySet.registerAllocation(instruction); | 2292 memorySet.registerAllocation(instruction); |
2293 memorySet.killAffectedBy(instruction); | 2293 memorySet.killAffectedBy(instruction); |
| 2294 // TODO(sra): Set initial keyed values. |
| 2295 // TODO(sra): Set initial length. |
2294 } | 2296 } |
2295 | 2297 |
2296 void visitIndex(HIndex instruction) { | 2298 void visitIndex(HIndex instruction) { |
2297 HInstruction receiver = instruction.receiver.nonCheck(); | 2299 HInstruction receiver = instruction.receiver.nonCheck(); |
2298 HInstruction existing = | 2300 HInstruction existing = |
2299 memorySet.lookupKeyedValue(receiver, instruction.index); | 2301 memorySet.lookupKeyedValue(receiver, instruction.index); |
2300 if (existing != null) { | 2302 if (existing != null) { |
2301 instruction.block.rewriteWithBetterUser(instruction, existing); | 2303 instruction.block.rewriteWithBetterUser(instruction, existing); |
2302 instruction.block.remove(instruction); | 2304 instruction.block.remove(instruction); |
2303 } else { | 2305 } else { |
2304 memorySet.registerKeyedValue(receiver, instruction.index, instruction); | 2306 memorySet.registerKeyedValue(receiver, instruction.index, instruction); |
2305 } | 2307 } |
2306 } | 2308 } |
2307 | 2309 |
2308 void visitIndexAssign(HIndexAssign instruction) { | 2310 void visitIndexAssign(HIndexAssign instruction) { |
2309 HInstruction receiver = instruction.receiver.nonCheck(); | 2311 HInstruction receiver = instruction.receiver.nonCheck(); |
2310 memorySet.registerKeyedValueUpdate( | 2312 memorySet.registerKeyedValueUpdate( |
2311 receiver, instruction.index, instruction.value); | 2313 receiver, instruction.index, instruction.value); |
2312 } | 2314 } |
| 2315 |
| 2316 // Pure operations that do not escape their inputs. |
| 2317 void visitBinaryArithmetic(HBinaryArithmetic instruction) {} |
| 2318 void visitConstant(HConstant instruction) {} |
| 2319 void visitIf(HIf instruction) {} |
| 2320 void visitInterceptor(HInterceptor instruction) {} |
| 2321 void visitIs(HIs instruction) {} |
| 2322 void visitIsViaInterceptor(HIsViaInterceptor instruction) {} |
| 2323 void visitNot(HNot instruction) {} |
| 2324 void visitParameterValue(HParameterValue instruction) {} |
| 2325 void visitRelational(HRelational instruction) {} |
| 2326 void visitStringConcat(HStringConcat instruction) {} |
| 2327 void visitTypeKnown(HTypeKnown instruction) {} |
| 2328 void visitTypeInfoReadRaw(HTypeInfoReadRaw instruction) {} |
| 2329 void visitTypeInfoReadVariable(HTypeInfoReadVariable instruction) {} |
| 2330 void visitTypeInfoExpression(HTypeInfoExpression instruction) {} |
2313 } | 2331 } |
2314 | 2332 |
2315 /** | 2333 /** |
2316 * Holds values of memory places. | 2334 * Holds values of memory places. |
| 2335 * |
| 2336 * Generally, values that name a place (a receiver) have type refinements and |
| 2337 * other checks removed to ensure that checks and type refinements do not |
| 2338 * confuse aliasing. Values stored into a memory place keep the type |
| 2339 * refinements to help further optimizations. |
2317 */ | 2340 */ |
2318 class MemorySet { | 2341 class MemorySet { |
2319 final Compiler compiler; | 2342 final Compiler compiler; |
2320 | 2343 |
2321 /** | 2344 /** |
2322 * Maps a field to a map of receiver to value. | 2345 * Maps a field to a map of receiver to value. |
2323 */ | 2346 */ |
2324 final Map<Element, Map<HInstruction, HInstruction>> fieldValues = | 2347 final Map<Element, Map<HInstruction, HInstruction>> fieldValues = |
2325 <Element, Map<HInstruction, HInstruction>>{}; | 2348 <Element, Map<HInstruction, HInstruction>>{}; |
2326 | 2349 |
(...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2372 | 2395 |
2373 bool couldBeTypedArray(HInstruction receiver) { | 2396 bool couldBeTypedArray(HInstruction receiver) { |
2374 JavaScriptBackend backend = compiler.backend; | 2397 JavaScriptBackend backend = compiler.backend; |
2375 return backend.couldBeTypedArray(receiver.instructionType); | 2398 return backend.couldBeTypedArray(receiver.instructionType); |
2376 } | 2399 } |
2377 | 2400 |
2378 /** | 2401 /** |
2379 * Returns whether [receiver] escapes the current function. | 2402 * Returns whether [receiver] escapes the current function. |
2380 */ | 2403 */ |
2381 bool escapes(HInstruction receiver) { | 2404 bool escapes(HInstruction receiver) { |
| 2405 assert(receiver == null || receiver == receiver.nonCheck()); |
2382 return !nonEscapingReceivers.contains(receiver); | 2406 return !nonEscapingReceivers.contains(receiver); |
2383 } | 2407 } |
2384 | 2408 |
2385 void registerAllocation(HInstruction instruction) { | 2409 void registerAllocation(HInstruction instruction) { |
| 2410 assert(instruction == instruction.nonCheck()); |
2386 nonEscapingReceivers.add(instruction); | 2411 nonEscapingReceivers.add(instruction); |
2387 } | 2412 } |
2388 | 2413 |
2389 /** | 2414 /** |
2390 * Sets `receiver.element` to contain [value]. Kills all potential | 2415 * Sets `receiver.element` to contain [value]. Kills all potential places that |
2391 * places that may be affected by this update. | 2416 * may be affected by this update. |
2392 */ | 2417 */ |
2393 void registerFieldValueUpdate( | 2418 void registerFieldValueUpdate( |
2394 Element element, HInstruction receiver, HInstruction value) { | 2419 Element element, HInstruction receiver, HInstruction value) { |
| 2420 assert(receiver == null || receiver == receiver.nonCheck()); |
2395 if (backend.isNative(element)) { | 2421 if (backend.isNative(element)) { |
2396 return; // TODO(14955): Remove this restriction? | 2422 return; // TODO(14955): Remove this restriction? |
2397 } | 2423 } |
2398 // [value] is being set in some place in memory, we remove it from | 2424 // [value] is being set in some place in memory, we remove it from |
2399 // the non-escaping set. | 2425 // the non-escaping set. |
2400 nonEscapingReceivers.remove(value); | 2426 nonEscapingReceivers.remove(value.nonCheck()); |
2401 Map<HInstruction, HInstruction> map = | 2427 Map<HInstruction, HInstruction> map = |
2402 fieldValues.putIfAbsent(element, () => <HInstruction, HInstruction>{}); | 2428 fieldValues.putIfAbsent(element, () => <HInstruction, HInstruction>{}); |
2403 map.forEach((key, value) { | 2429 map.forEach((key, value) { |
2404 if (mayAlias(receiver, key)) map[key] = null; | 2430 if (mayAlias(receiver, key)) map[key] = null; |
2405 }); | 2431 }); |
2406 map[receiver] = value; | 2432 map[receiver] = value; |
2407 } | 2433 } |
2408 | 2434 |
2409 /** | 2435 /** |
2410 * Registers that `receiver.element` is now [value]. | 2436 * Registers that `receiver.element` is now [value]. |
2411 */ | 2437 */ |
2412 void registerFieldValue( | 2438 void registerFieldValue( |
2413 Element element, HInstruction receiver, HInstruction value) { | 2439 Element element, HInstruction receiver, HInstruction value) { |
| 2440 assert(receiver == null || receiver == receiver.nonCheck()); |
2414 if (backend.isNative(element)) { | 2441 if (backend.isNative(element)) { |
2415 return; // TODO(14955): Remove this restriction? | 2442 return; // TODO(14955): Remove this restriction? |
2416 } | 2443 } |
2417 Map<HInstruction, HInstruction> map = | 2444 Map<HInstruction, HInstruction> map = |
2418 fieldValues.putIfAbsent(element, () => <HInstruction, HInstruction>{}); | 2445 fieldValues.putIfAbsent(element, () => <HInstruction, HInstruction>{}); |
2419 map[receiver] = value; | 2446 map[receiver] = value; |
2420 } | 2447 } |
2421 | 2448 |
2422 /** | 2449 /** |
2423 * Returns the value stored in `receiver.element`. Returns null if | 2450 * Returns the value stored in `receiver.element`. Returns `null` if we don't |
2424 * we don't know. | 2451 * know. |
2425 */ | 2452 */ |
2426 HInstruction lookupFieldValue(Element element, HInstruction receiver) { | 2453 HInstruction lookupFieldValue(Element element, HInstruction receiver) { |
| 2454 assert(receiver == null || receiver == receiver.nonCheck()); |
2427 Map<HInstruction, HInstruction> map = fieldValues[element]; | 2455 Map<HInstruction, HInstruction> map = fieldValues[element]; |
2428 return (map == null) ? null : map[receiver]; | 2456 return (map == null) ? null : map[receiver]; |
2429 } | 2457 } |
2430 | 2458 |
2431 /** | 2459 /** |
2432 * Kill all places that may be affected by this [instruction]. Also | 2460 * Kill all places that may be affected by this [instruction]. Also update the |
2433 * update the set of non-escaping objects in case [instruction] has | 2461 * set of non-escaping objects in case [instruction] has non-escaping objects |
2434 * non-escaping objects in its inputs. | 2462 * in its inputs. |
2435 */ | 2463 */ |
2436 void killAffectedBy(HInstruction instruction) { | 2464 void killAffectedBy(HInstruction instruction) { |
2437 // Even if [instruction] does not have side effects, it may use | 2465 // Even if [instruction] does not have side effects, it may use non-escaping |
2438 // non-escaping objects and store them in a new object, which | 2466 // objects and store them in a new object, which make these objects |
2439 // make these objects escaping. | 2467 // escaping. |
2440 // TODO(ngeoffray): We need a new side effect flag to know whether | |
2441 // an instruction allocates an object. | |
2442 instruction.inputs.forEach((input) { | 2468 instruction.inputs.forEach((input) { |
2443 nonEscapingReceivers.remove(input); | 2469 nonEscapingReceivers.remove(input.nonCheck()); |
2444 }); | 2470 }); |
2445 | 2471 |
2446 if (instruction.sideEffects.changesInstanceProperty() || | 2472 if (instruction.sideEffects.changesInstanceProperty() || |
2447 instruction.sideEffects.changesStaticProperty()) { | 2473 instruction.sideEffects.changesStaticProperty()) { |
2448 fieldValues.forEach((element, map) { | 2474 fieldValues.forEach((element, map) { |
2449 if (isFinal(element)) return; | 2475 if (isFinal(element)) return; |
2450 map.forEach((receiver, value) { | 2476 map.forEach((receiver, value) { |
2451 if (escapes(receiver)) { | 2477 if (escapes(receiver)) { |
2452 map[receiver] = null; | 2478 map[receiver] = null; |
2453 } | 2479 } |
(...skipping 30 matching lines...) Expand all Loading... |
2484 keyedValues.putIfAbsent(receiver, () => <HInstruction, HInstruction>{}); | 2510 keyedValues.putIfAbsent(receiver, () => <HInstruction, HInstruction>{}); |
2485 map[index] = value; | 2511 map[index] = value; |
2486 } | 2512 } |
2487 | 2513 |
2488 /** | 2514 /** |
2489 * Sets `receiver[index]` to contain [value]. Kills all potential | 2515 * Sets `receiver[index]` to contain [value]. Kills all potential |
2490 * places that may be affected by this update. | 2516 * places that may be affected by this update. |
2491 */ | 2517 */ |
2492 void registerKeyedValueUpdate( | 2518 void registerKeyedValueUpdate( |
2493 HInstruction receiver, HInstruction index, HInstruction value) { | 2519 HInstruction receiver, HInstruction index, HInstruction value) { |
2494 nonEscapingReceivers.remove(value); | 2520 nonEscapingReceivers.remove(value.nonCheck()); |
2495 keyedValues.forEach((key, values) { | 2521 keyedValues.forEach((key, values) { |
2496 if (mayAlias(receiver, key)) { | 2522 if (mayAlias(receiver, key)) { |
2497 // Typed arrays that are views of the same buffer may have different | 2523 // Typed arrays that are views of the same buffer may have different |
2498 // offsets or element sizes, unless they are the same typed array. | 2524 // offsets or element sizes, unless they are the same typed array. |
2499 bool weakIndex = couldBeTypedArray(key) && !mustAlias(receiver, key); | 2525 bool weakIndex = couldBeTypedArray(key) && !mustAlias(receiver, key); |
2500 values.forEach((otherIndex, otherValue) { | 2526 values.forEach((otherIndex, otherValue) { |
2501 if (weakIndex || mayAlias(index, otherIndex)) { | 2527 if (weakIndex || mayAlias(index, otherIndex)) { |
2502 values[otherIndex] = null; | 2528 values[otherIndex] = null; |
2503 } | 2529 } |
2504 }); | 2530 }); |
(...skipping 90 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2595 | 2621 |
2596 keyedValues.forEach((receiver, values) { | 2622 keyedValues.forEach((receiver, values) { |
2597 result.keyedValues[receiver] = | 2623 result.keyedValues[receiver] = |
2598 new Map<HInstruction, HInstruction>.from(values); | 2624 new Map<HInstruction, HInstruction>.from(values); |
2599 }); | 2625 }); |
2600 | 2626 |
2601 result.nonEscapingReceivers.addAll(nonEscapingReceivers); | 2627 result.nonEscapingReceivers.addAll(nonEscapingReceivers); |
2602 return result; | 2628 return result; |
2603 } | 2629 } |
2604 } | 2630 } |
OLD | NEW |