| 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 |