| Index: pkg/compiler/lib/src/ssa/optimize.dart
|
| diff --git a/pkg/compiler/lib/src/ssa/optimize.dart b/pkg/compiler/lib/src/ssa/optimize.dart
|
| index 3ac8e272e90908d5812798de127ec87d154297d9..276631c1bfcf2b9474e1fd354f8efc1cc2c2d2ad 100644
|
| --- a/pkg/compiler/lib/src/ssa/optimize.dart
|
| +++ b/pkg/compiler/lib/src/ssa/optimize.dart
|
| @@ -2243,9 +2243,9 @@ class SsaLoadElimination extends HBaseVisitor implements OptimizationPhase {
|
| // Assume the argument escapes. All we do with our initial allocation is
|
| // have it escape or store it into an object that escapes.
|
| return false;
|
| - // TODO(sra): Handle more functions. `setRuntimeTypeInfo` does not
|
| - // actually kill it's input, but we don't make use of that elsewhere so
|
| - // there is not point in checking here.
|
| + // TODO(sra): Handle library functions that we know do not modify or
|
| + // leak the inputs. For example `setRuntimeTypeInfo` is used to mark
|
| + // list literals with type information.
|
| }
|
| if (use is HPhi) {
|
| // The initial allocation (it's only alias) gets merged out of the model
|
| @@ -2291,6 +2291,8 @@ class SsaLoadElimination extends HBaseVisitor implements OptimizationPhase {
|
| void visitLiteralList(HLiteralList instruction) {
|
| memorySet.registerAllocation(instruction);
|
| memorySet.killAffectedBy(instruction);
|
| + // TODO(sra): Set initial keyed values.
|
| + // TODO(sra): Set initial length.
|
| }
|
|
|
| void visitIndex(HIndex instruction) {
|
| @@ -2310,10 +2312,31 @@ class SsaLoadElimination extends HBaseVisitor implements OptimizationPhase {
|
| memorySet.registerKeyedValueUpdate(
|
| receiver, instruction.index, instruction.value);
|
| }
|
| +
|
| + // Pure operations that do not escape their inputs.
|
| + void visitBinaryArithmetic(HBinaryArithmetic instruction) {}
|
| + void visitConstant(HConstant instruction) {}
|
| + void visitIf(HIf instruction) {}
|
| + void visitInterceptor(HInterceptor instruction) {}
|
| + void visitIs(HIs instruction) {}
|
| + void visitIsViaInterceptor(HIsViaInterceptor instruction) {}
|
| + void visitNot(HNot instruction) {}
|
| + void visitParameterValue(HParameterValue instruction) {}
|
| + void visitRelational(HRelational instruction) {}
|
| + void visitStringConcat(HStringConcat instruction) {}
|
| + void visitTypeKnown(HTypeKnown instruction) {}
|
| + void visitTypeInfoReadRaw(HTypeInfoReadRaw instruction) {}
|
| + void visitTypeInfoReadVariable(HTypeInfoReadVariable instruction) {}
|
| + void visitTypeInfoExpression(HTypeInfoExpression instruction) {}
|
| }
|
|
|
| /**
|
| * Holds values of memory places.
|
| + *
|
| + * Generally, values that name a place (a receiver) have type refinements and
|
| + * other checks removed to ensure that checks and type refinements do not
|
| + * confuse aliasing. Values stored into a memory place keep the type
|
| + * refinements to help further optimizations.
|
| */
|
| class MemorySet {
|
| final Compiler compiler;
|
| @@ -2379,25 +2402,28 @@ class MemorySet {
|
| * Returns whether [receiver] escapes the current function.
|
| */
|
| bool escapes(HInstruction receiver) {
|
| + assert(receiver == null || receiver == receiver.nonCheck());
|
| return !nonEscapingReceivers.contains(receiver);
|
| }
|
|
|
| void registerAllocation(HInstruction instruction) {
|
| + assert(instruction == instruction.nonCheck());
|
| nonEscapingReceivers.add(instruction);
|
| }
|
|
|
| /**
|
| - * Sets `receiver.element` to contain [value]. Kills all potential
|
| - * places that may be affected by this update.
|
| + * Sets `receiver.element` to contain [value]. Kills all potential places that
|
| + * may be affected by this update.
|
| */
|
| void registerFieldValueUpdate(
|
| Element element, HInstruction receiver, HInstruction value) {
|
| + assert(receiver == null || receiver == receiver.nonCheck());
|
| if (backend.isNative(element)) {
|
| return; // TODO(14955): Remove this restriction?
|
| }
|
| // [value] is being set in some place in memory, we remove it from
|
| // the non-escaping set.
|
| - nonEscapingReceivers.remove(value);
|
| + nonEscapingReceivers.remove(value.nonCheck());
|
| Map<HInstruction, HInstruction> map =
|
| fieldValues.putIfAbsent(element, () => <HInstruction, HInstruction>{});
|
| map.forEach((key, value) {
|
| @@ -2411,6 +2437,7 @@ class MemorySet {
|
| */
|
| void registerFieldValue(
|
| Element element, HInstruction receiver, HInstruction value) {
|
| + assert(receiver == null || receiver == receiver.nonCheck());
|
| if (backend.isNative(element)) {
|
| return; // TODO(14955): Remove this restriction?
|
| }
|
| @@ -2420,27 +2447,26 @@ class MemorySet {
|
| }
|
|
|
| /**
|
| - * Returns the value stored in `receiver.element`. Returns null if
|
| - * we don't know.
|
| + * Returns the value stored in `receiver.element`. Returns `null` if we don't
|
| + * know.
|
| */
|
| HInstruction lookupFieldValue(Element element, HInstruction receiver) {
|
| + assert(receiver == null || receiver == receiver.nonCheck());
|
| Map<HInstruction, HInstruction> map = fieldValues[element];
|
| return (map == null) ? null : map[receiver];
|
| }
|
|
|
| /**
|
| - * Kill all places that may be affected by this [instruction]. Also
|
| - * update the set of non-escaping objects in case [instruction] has
|
| - * non-escaping objects in its inputs.
|
| + * Kill all places that may be affected by this [instruction]. Also update the
|
| + * set of non-escaping objects in case [instruction] has non-escaping objects
|
| + * in its inputs.
|
| */
|
| void killAffectedBy(HInstruction instruction) {
|
| - // Even if [instruction] does not have side effects, it may use
|
| - // non-escaping objects and store them in a new object, which
|
| - // make these objects escaping.
|
| - // TODO(ngeoffray): We need a new side effect flag to know whether
|
| - // an instruction allocates an object.
|
| + // Even if [instruction] does not have side effects, it may use non-escaping
|
| + // objects and store them in a new object, which make these objects
|
| + // escaping.
|
| instruction.inputs.forEach((input) {
|
| - nonEscapingReceivers.remove(input);
|
| + nonEscapingReceivers.remove(input.nonCheck());
|
| });
|
|
|
| if (instruction.sideEffects.changesInstanceProperty() ||
|
| @@ -2491,7 +2517,7 @@ class MemorySet {
|
| */
|
| void registerKeyedValueUpdate(
|
| HInstruction receiver, HInstruction index, HInstruction value) {
|
| - nonEscapingReceivers.remove(value);
|
| + nonEscapingReceivers.remove(value.nonCheck());
|
| keyedValues.forEach((key, values) {
|
| if (mayAlias(receiver, key)) {
|
| // Typed arrays that are views of the same buffer may have different
|
|
|