Skip to content

[VM/AOT] Smaller throw expressions #56969

@rakudrama

Description

@rakudrama

I have been investigating the code size of

    for (final item in list) {
      ...
    }

where list is the default system growable list.

The loop is the same as

    for (final iter = list.iterator; iter.moveNext();) {
      final item = iter.current;
      ...
    }

With recent improvements, AOT now generates relatively good code. The compiler fully inlines ListIterator. The local value that represents _index is monotonic and compared against the current list length, allowing the bounds check to be removed.

The part that is still lacking is the code size for throwing a ConcurrentModificationError if the list (length) changes during iteration. I copied ListIterator and tried several variations on moveNext() that differ only at the throw expression:

  bool moveNext() {
    int length = _iterable.length;
    if (_length != length) {
      throw CME(_iterable); // This line
    }
    ...

Variation 1

The default inlined loop has throw-sequence of 7 instructions and 25 bytes:

        ;; B13
        ;; v34 <- AllocateObject:24(cls=CME, <not-aliased>) T{CME}
        ;; Inlined [ListIterator2.moveNext]
0x7faa347b1986    e8fbffffff             call 0x00007faa347b1986
        ;; ParallelMove rcx <- rax, rax <- fp[-3]
        ;; Inlined [ListIterator2.moveNext]
0x7faa347b198b    4889c1                 movq rcx,rax
0x7faa347b198e    488b45e8               movq rax,[rbp-0x18]
        ;; StoreField(v34 T{CME} . modifiedObject = v2, NoStoreBarrier)
        ;; Inlined [ListIterator2.moveNext]
0x7faa347b1992    4889410f               movq [rcx+0xf],rax
        ;; ParallelMove rax <- rcx
        ;; Inlined [ListIterator2.moveNext]
0x7faa347b1996    4889c8                 movq rax,rcx
        ;; Throw:30(v34)
        ;; Inlined [ListIterator2.moveNext]
0x7faa347b1999    e8fbffffff             call 0x00007faa347b1999
0x7faa347b199e    cc                     int3

Variation 2

I tried calling a constructor (CME.new2) that is annotated with vm:never-inline.
The result is worse - 8 instruction / 30 bytes.

        ;; B13
        ;; v34 <- AllocateObject:24(cls=CME) T{CME}
        ;; Inlined [ListIterator2.moveNext2]
0x7faa347b1886    e8fbffffff             call 0x00007faa347b1886
        ;; ParallelMove rdi <- rax, rsi <- fp[-3], rax <- rax
        ;; Inlined [ListIterator2.moveNext2]
0x7faa347b188b    4889c7                 movq rdi,rax
0x7faa347b188e    488b75e8               movq rsi,[rbp-0x18]
        ;; ParallelMove fp[-3] <- rax
        ;; Inlined [ListIterator2.moveNext2]
0x7faa347b1892    488945e8               movq [rbp-0x18],rax
        ;; StaticCall:28( CME.new2<0> v34, v2)
        ;; Inlined [ListIterator2.moveNext2]
0x7faa347b1896    e8fbffffff             call 0x00007faa347b1896
        ;; ParallelMove rax <- fp[-3]
        ;; Inlined [ListIterator2.moveNext2]
0x7faa347b189b    488b45e8               movq rax,[rbp-0x18]
        ;; Throw:30(v34)
        ;; Inlined [ListIterator2.moveNext2]
0x7faa347b189f    e8fbffffff             call 0x00007faa347b189f
0x7faa347b18a4    cc                     int3

The inlining boundary is unexpected - naively I would have thought that the pragma would have caused the whole constructor sequence, including the allocation, to be out-of-line.

Variation 3

Calls a static method CME.new3 (never-inline) that calls the constructor.
Using a static method as a 'constructor' gets the code size down to 4 instructions / 15 bytes.

        ;; B13
        ;; ParallelMove rdi <- fp[-3]
        ;; Inlined [ListIterator2.moveNext3]
0x7faa347b17a6    488b7de8               movq rdi,[rbp-0x18]
        ;; v35 <- StaticCall:26( new3<0> v2) T{CME}
        ;; Inlined [ListIterator2.moveNext3]
0x7faa347b17aa    e8fbffffff             call 0x00007faa347b17aa
        ;; ParallelMove rax <- rax
        ;; Throw:28(v35)
        ;; Inlined [ListIterator2.moveNext3]
0x7faa347b17af    e8fbffffff             call 0x00007faa347b17af
0x7faa347b17b4    cc                     int3

Variation 4

Call a helper function throwCME that throws. This by far the worst.
The call itself is small (2 instructions, 8 bytes).
The problem is that the rest of the moveNext method is worse.
The loop is optimized as though (1) throwCME modifies the list and (2) then returns.
The bounds check can no longer be eliminated.
The block with the throwing call is in the middle if the loop instead of outside.

        ;; B13
        ;;   Loop 0
        ;; ParallelMove rdi <- rax
        ;; Inlined [ListIterator2.moveNext4]
0x7faa347b13d8    4889c7                 movq rdi,rax
        ;; StaticCall:26( throwCME<0> v2)
        ;; Inlined [ListIterator2.moveNext4]
0x7faa347b13db    e8fbffffff             call 0x00007faa347b13db
        ;; ParallelMove  goto:32 B15
        ;; B14
        ;; B15

Discussion

Variation 4 should have been the best for code size.

The compiler should treat functions that never return like it does Throw instructions.
With sound null-safety, it is no longer possible for a Never function to return null.
The call to the throw-helper should be block-scheduled outside the loop.

dart2js automatically achieves something close to Version 3.

In dart2js model, each generative constructor has a generative constructor factory which contains the allocation and everything else.
A new expression compiles to a call to the factory, which may or may not be inlined.
One of the inlining heuristics dart2js uses is to only allow inlining in the expression of a throw if the inlining is expected to reduce size (i.e. a location dependent reductive heuristic).

If AOT adopted a similar generative constructor factor element in its model, a similar heuristic would work. As we can see from Variation 2, that would un unadvisable without the change in the element model.

Variation 4 has the disadvantage that the throw-helper changes the call stack.

I would like to see AOT automatically compile the original code more like a slow-path stub.
This would be a combination of limited out-lining and a tail call.

It might work something like this:

During inlining we see the static call in this pattern:

v1 <- AllocateObject(cls=FooError)
v2 <- StaticCall( constructor, v1, a1, a2, a3)
Throw(v2)

A lot of information is available about the candidate.
If the inlining heuristics would want to inline constructor, or otherwise can tell there are no errors, instead, generate
a small method constructor_a1_a2_a3 with parameters a1, a2 etc.
Replace the three instructions with

StaticCall( constructor_a1_a2_a3, a1, a2, a3)
ThrowTrap() // int3

The body of the synthesized method is constructed from the inlining candidate by inserting an allocation, and ending with a new instruction

ThrowTail() // jump to a throw stub.

There will be a different stub for each combination of optional arguments.
In large programs most stubs will be used several times.
There will need to be a way to deduplicate stubs.

Appendix

dart compile exe                                         \
   --extra-gen-snapshot-options --disassemble-optimized  \
   --extra-gen-snapshot-options --code-comments          \
   --extra-gen-snapshot-options --print-flow-graph-filter=useL \
   -v bug1a3j.dart --output=z5
code.dart
import 'dart:core';
import 'dart:core' as core;

int _line = 0, _limit1 = 1, _limit2 = 10;

@pragma('vm:never-inline')
void print(Object? item) {
  _line++;
  if (_line >= 10) {
    if (_line != _limit1 * _limit2) return;
    if (_limit1 == 1) {
      _limit1 = 2;
    } else if (_limit1 == 2) {
      _limit1 = 5;
    } else if (_limit1 == 5) {
      _limit1 = 1;
      _limit2 *= 10;
    }
  }
  core.print('$_line\t$item');
}

class ListIterator2<E> implements Iterator<E> {
  final Iterable<E> _iterable;
  final int _length;
  int _index;
  E? _current;

  @pragma("wasm:prefer-inline")
  ListIterator2(Iterable<E> iterable)
      : _iterable = iterable,
        _length = iterable.length,
        _index = 0;

  E get current => _current as E;

  @pragma("vm:prefer-inline")
  bool moveNext() {
    int length = _iterable.length;
    if (_length != length) {
      throw CME(_iterable);
    }
    if (_index >= length) {
      _current = null;
      return false;
    }
    _current = _iterable.elementAt(_index);
    _index++;
    return true;
  }

  @pragma("vm:prefer-inline")
  bool moveNext2() {
    int length = _iterable.length;
    if (_length != length) {
      throw CME.new2(_iterable);
    }
    if (_index >= length) {
      _current = null;
      return false;
    }
    _current = _iterable.elementAt(_index);
    _index++;
    return true;
  }

  @pragma("vm:prefer-inline")
  bool moveNext3() {
    int length = _iterable.length;
    if (_length != length) {
      throw CME.new3(_iterable);
    }
    if (_index >= length) {
      _current = null;
      return false;
    }
    _current = _iterable.elementAt(_index);
    _index++;
    return true;
  }

  @pragma("vm:prefer-inline")
  bool moveNext4() {
    int length = _iterable.length;
    if (_length != length) {
      CME.throwCME(_iterable);
    }
    if (_index >= length) {
      _current = null;
      return false;
    }
    _current = _iterable.elementAt(_index);
    _index++;
    return true;
  }
}

class CME extends Error {
  /// The object that was modified in an incompatible way.
  final Object? modifiedObject;

  CME([this.modifiedObject]);

  @pragma('vm:never-inline')
  CME.new2([this.modifiedObject]);

  @pragma('vm:never-inline')
  static CME new3(Object? o) => CME(o);

  @pragma('vm:never-inline')
  static Never throwCME(Object? o) {
    throw CME(o);
  }

  String toString() {
    if (modifiedObject == null) {
      return "Concurrent modification during iteration.";
    }
    return "Concurrent modification during iteration: "
        "${Error.safeToString(modifiedObject)}.";
  }
}

@pragma('vm:never-inline')
@pragma('dart2js:never-inline')
void useList1(List list) {
  for (final iter = ListIterator2(list); iter.moveNext();) print(iter.current);
}

@pragma('vm:never-inline')
@pragma('dart2js:never-inline')
void useList2(List list) {
  for (final iter = ListIterator2(list); iter.moveNext2();) print(iter.current);
}

@pragma('vm:never-inline')
@pragma('dart2js:never-inline')
void useList3(List list) {
  for (final iter = ListIterator2(list); iter.moveNext3();) print(iter.current);
}

@pragma('vm:never-inline')
@pragma('dart2js:never-inline')
void useList4(List list) {
  for (final iter = ListIterator2(list); iter.moveNext4();) print(iter.current);
}

void main() {
  for (int i = 0; i < 1000000; i++) {
    useList1([]);
    useList1([1]);
    useList1([2, 3]);
    useList2([]);
    useList2([1]);
    useList2([2, 3]);
    useList3([]);
    useList3([1]);
    useList3([2, 3]);
    useList4([]);
    useList4([1]);
    useList4([2, 3]);
  }
}
Output
Specializing Platform getters for target OS linux.
Generating AOT kernel dill.
Compiling /usr/local/google/home/sra/play1/bug1a3j.dart to /usr/local/google/home/sra/Dart2/sdk/z5 using format Kind.exe:
Generating AOT snapshot. /usr/local/google/home/sra/Dart2/sdk/out/ReleaseX64/dart-sdk/bin/utils/gen_snapshot [--disassemble-optimized, --code-comments, --print-flow-graph-filter=useL]
Code for optimized function 'file:///usr/local/google/home/sra/play1/bug1a3j.dart_::_useList4' (RegularFunction) {
        ;; B0
        ;; B1
        ;; Enter frame
        ;; PrologueOffset = 0
        ;; Inlined [ListIterator2.moveNext4]
0x7faa347b1390    55                     push rbp
0x7faa347b1391    4889e5                 movq rbp,rsp
0x7faa347b1394    4883ec20               subq rsp,0x20
        ;; ParallelMove rax <- rdi, fp[-4] <- rdi
        ;; Inlined [ListIterator2.moveNext4]
0x7faa347b1398    4889f8                 movq rax,rdi
0x7faa347b139b    48897de0               movq [rbp-0x20],rdi
        ;; CheckStackOverflow:8(stack=0, loop=0)
        ;; Inlined [ListIterator2.moveNext4]
0x7faa347b139f    493b6638               cmpq rsp,[thr+0x38]
0x7faa347b13a3    0f868c000000           jna 0x00007faa347b1435
        ;; v84 <- LoadField(v2 T{_GrowableList} . GrowableObjectArray.length) [0, 576460752303423487] T{_Smi}
        ;; Inlined [ListIterator2.moveNext4]
0x7faa347b13a9    488b480f               movq rcx,[rax+0xf]
        ;; ParallelMove rcx <- rcx
        ;; v90 <- UnboxInt64([non-speculative], v84 T{_Smi}) [v84, v84] int64
        ;; Inlined [ListIterator2.moveNext4]
0x7faa347b13ad    48d1f9                 sarq rcx,1
        ;; ParallelMove fp[-3] <- rcx
        ;; Inlined [ListIterator2.moveNext4]
0x7faa347b13b0    48894de8               movq [rbp-0x18],rcx
        ;; ParallelMove rbx <- C goto:30 B5
        ;; Inlined [ListIterator2.moveNext4]
0x7faa347b13b4    33db                   xorl rbx,rbx
        ;; B5
        ;;   Loop 0
        ;;   Loop Header
        ;; ParallelMove fp[-2] <- rbx
        ;; Inlined [ListIterator2.moveNext4]
0x7faa347b13b6    48895df0               movq [rbp-0x10],rbx
        ;; CheckStackOverflow:34(stack=0, loop=1)
        ;; Inlined [ListIterator2.moveNext4]
0x7faa347b13ba    493b6638               cmpq rsp,[thr+0x38]
0x7faa347b13be    0f867d000000           jna 0x00007faa347b1441
        ;; v79 <- LoadField(v2 T{_GrowableList} . GrowableObjectArray.length) [0, 576460752303423487] T{_Smi}
        ;; Inlined [ListIterator2.moveNext4]
0x7faa347b13c4    488b500f               movq rdx,[rax+0xf]
        ;; ParallelMove rdx <- rdx
        ;; v92 <- UnboxInt64([non-speculative], v79 T{_Smi}) [v79, v79] int64
        ;; Inlined [ListIterator2.moveNext4]
0x7faa347b13c8    48d1fa                 sarq rdx,1
        ;; ParallelMove fp[-1] <- rdx
        ;; Inlined [ListIterator2.moveNext4]
0x7faa347b13cb    488955f8               movq [rbp-0x8],rdx
        ;; Branch if EqualityCompare(v90 T{_Smi} != v92 T{_Smi}) T{bool} goto (13, 14)
        ;; Inlined [ListIterator2.moveNext4]
0x7faa347b13cf    483bca                 cmpq rcx,rdx
0x7faa347b13d2    0f8408000000           jz 0x00007faa347b13e0
        ;; B13
        ;;   Loop 0
        ;; ParallelMove rdi <- rax
        ;; Inlined [ListIterator2.moveNext4]
0x7faa347b13d8    4889c7                 movq rdi,rax
        ;; StaticCall:26( throwCME<0> v2)
        ;; Inlined [ListIterator2.moveNext4]
0x7faa347b13db    e8fbffffff             call 0x00007faa347b13db
        ;; ParallelMove  goto:32 B15
        ;; B14
        ;; B15
        ;;   Loop 0
0x7faa347b13e0    488b45f8               movq rax,[rbp-0x8]
0x7faa347b13e4    488b4df0               movq rcx,[rbp-0x10]
        ;; Branch if RelationalOp(>=, [non-speculative], v97 T{int}, v92 T{_Smi}) T{bool} goto (4, 10)
0x7faa347b13e8    483bc8                 cmpq rcx,rax
0x7faa347b13eb    0f8d3b000000           jge 0x00007faa347b142c
        ;; B10
        ;;   Loop 0
        ;; ParallelMove rdx <- fp[-4]
0x7faa347b13f1    488b55e0               movq rdx,[rbp-0x20]
        ;; v54 <- LoadField(v2 T{_GrowableList} . GrowableObjectArray.length) [0, 576460752303423487] T{_Smi}
0x7faa347b13f5    488b420f               movq rax,[rdx+0xf]
        ;; ParallelMove rax <- rax
        ;; v93 <- UnboxInt64([non-speculative], v54) [v54, v54] int64
0x7faa347b13f9    48d1f8                 sarq rax,1
        ;; ParallelMove rax <- rax, rbx <- rcx
0x7faa347b13fc    4889cb                 movq rbx,rcx
        ;; GenericCheckBound:10(v93 T{_Smi}, v97 T{int}) [0, v92-1] int64
0x7faa347b13ff    483bd8                 cmpq rbx,rax
0x7faa347b1402    0f8345000000           jnc 0x00007faa347b144d
        ;; v56 <- LoadField(v2 T{_GrowableList} . GrowableObjectArray.data) T{_List}
0x7faa347b1408    488b4217               movq rax,[rdx+0x17]
        ;; v100 <- LoadIndexed:10([_List] v56, v97 T{int}) T{X0?}
0x7faa347b140c    488b7cc817             movq rdi,[rax+rcx*8+0x17]
        ;; ParallelMove rcx <- rcx
        ;; v32 <- BinaryInt64Op(+ [tr], v97 T{int}, v101 T{_Smi}) [1, v92] int64
0x7faa347b1411    4883c101               addq rcx,1
        ;; ParallelMove rdi <- rdi, fp[-1] <- rcx
0x7faa347b1415    48894df8               movq [rbp-0x8],rcx
        ;; StaticCall:26( print<0> v100 T{X0?})
0x7faa347b1419    e8fbffffff             call 0x00007faa347b1419
        ;; ParallelMove rbx <- fp[-1], rax <- fp[-4], rcx <- fp[-3] goto:32 B5
0x7faa347b141e    488b5df8               movq rbx,[rbp-0x8]
0x7faa347b1422    488b45e0               movq rax,[rbp-0x20]
0x7faa347b1426    488b4de8               movq rcx,[rbp-0x18]
0x7faa347b142a    eb8a                   jmp 0x00007faa347b13b6
        ;; B4
        ;; ParallelMove rax <- C
0x7faa347b142c    498b4670               movq rax,[thr+0x70]   null
        ;; DartReturn:36(v0)
0x7faa347b1430    4889ec                 movq rsp,rbp
0x7faa347b1433    5d                     pop rbp
0x7faa347b1434    c3                     ret
        ;; CheckStackOverflowSlowPath
0x7faa347b1435    41ff9630020000         call [thr+0x230]
0x7faa347b143c    e968ffffff             jmp 0x00007faa347b13a9
        ;; CheckStackOverflowSlowPath
0x7faa347b1441    41ff9630020000         call [thr+0x230]
0x7faa347b1448    e977ffffff             jmp 0x00007faa347b13c4
        ;; slow path check bound operation
0x7faa347b144d    e8fbffffff             call 0x00007faa347b144d
}
Source positions for function 'file:///usr/local/google/home/sra/play1/bug1a3j.dart_::_useList4' {
7faa347b1390-7faa347b13df: Function 'useList4': static.@145Function 'moveNext4':.@85
7faa347b13e0-7faa347b141d: Function 'useList4': static.@145
7faa347b141e-7faa347b143b: Function 'useList4': static.@142
7faa347b143c-7faa347b1447: Function 'useList4': static.@145
7faa347b1448-7faa347b1451: Function 'useList4': static.@NoSource
}
StackMaps for function 'file:///usr/local/google/home/sra/play1/bug1a3j.dart_::_useList4' {
0x7faa347b13e0: 000
0x7faa347b141e: 000
0x7faa347b143c: 000000000000001
0x7faa347b1448: 000000000000001
0x7faa347b1452: 000000000000100
}
Catch entry moves for function 'file:///usr/local/google/home/sra/play1/bug1a3j.dart_::_useList4' {
}
Entry points for function 'file:///usr/local/google/home/sra/play1/bug1a3j.dart_::_useList4' {
  [code+0x07] 7faa347b1390 kNormal
  [code+0x0f] 7faa347b1390 kMonomorphic
  [code+0x17] 7faa347b1390 kUnchecked
  [code+0x1f] 7faa347b1390 kMonomorphicUnchecked
}
Static call target functions {
  0x7faa347b13e0: file:///usr/local/google/home/sra/play1/bug1a3j.dart_CME_throwCME, (pc-relative-call)
  0x7faa347b141e: file:///usr/local/google/home/sra/play1/bug1a3j.dart_::_print, (pc-relative-call)
  0x7faa347b1452: [Stub] _iso_stub_RangeErrorSharedWithoutFPURegsStub, (pc-relative-call)
}
Code for optimized function 'file:///usr/local/google/home/sra/play1/bug1a3j.dart_::_useList3' (RegularFunction) {
        ;; B0
        ;; B1
        ;; Enter frame
        ;; PrologueOffset = 0
0x7faa347b1730    55                     push rbp
0x7faa347b1731    4889e5                 movq rbp,rsp
0x7faa347b1734    4883ec18               subq rsp,0x18
        ;; ParallelMove rax <- rdi, fp[-3] <- rdi
0x7faa347b1738    4889f8                 movq rax,rdi
0x7faa347b173b    48897de8               movq [rbp-0x18],rdi
        ;; CheckStackOverflow:8(stack=0, loop=0)
0x7faa347b173f    493b6638               cmpq rsp,[thr+0x38]
0x7faa347b1743    0f866c000000           jna 0x00007faa347b17b5
        ;; v85 <- LoadField(v2 T{_GrowableList} . GrowableObjectArray.length) [0, 576460752303423487] T{_Smi}
0x7faa347b1749    488b480f               movq rcx,[rax+0xf]
        ;; ParallelMove rcx <- rcx
        ;; v91 <- UnboxInt64([non-speculative], v85 T{_Smi}) [v85, v85] int64
0x7faa347b174d    48d1f9                 sarq rcx,1
        ;; ParallelMove fp[-2] <- rcx
0x7faa347b1750    48894df0               movq [rbp-0x10],rcx
        ;; ParallelMove rdx <- C goto:30 B5
0x7faa347b1754    33d2                   xorl rdx,rdx
        ;; B5
        ;;   Loop 0
        ;;   Loop Header
        ;; CheckStackOverflow:34(stack=0, loop=1)
0x7faa347b1756    493b6638               cmpq rsp,[thr+0x38]
0x7faa347b175a    0f865e000000           jna 0x00007faa347b17be
        ;; v80 <- LoadField(v2 T{_GrowableList} . GrowableObjectArray.length) [0, 576460752303423487] T{_Smi}
0x7faa347b1760    488b580f               movq rbx,[rax+0xf]
        ;; ParallelMove rbx <- rbx
        ;; v93 <- UnboxInt64([non-speculative], v80 T{_Smi}) [v80, v80] int64
0x7faa347b1764    48d1fb                 sarq rbx,1
        ;; Branch if EqualityCompare(v91 T{_Smi} != v93 T{_Smi}) T{bool} goto (13, 14)
0x7faa347b1767    483bcb                 cmpq rcx,rbx
0x7faa347b176a    0f8536000000           jnz 0x00007faa347b17a6
        ;; B14
        ;;   Loop 0
        ;; Branch if RelationalOp(>=, [non-speculative], v98 T{int}, v93 T{_Smi}) T{bool} goto (4, 10)
0x7faa347b1770    483bd3                 cmpq rdx,rbx
0x7faa347b1773    0f8d24000000           jge 0x00007faa347b179d
        ;; B10
        ;;   Loop 0
        ;; v57 <- LoadField(v2 T{_GrowableList} . GrowableObjectArray.data) T{_List}
0x7faa347b1779    488b5817               movq rbx,[rax+0x17]
        ;; v101 <- LoadIndexed:10([_List] v57, v98 T{int}) T{X0?}
0x7faa347b177d    488b7cd317             movq rdi,[rbx+rdx*8+0x17]
        ;; ParallelMove rdx <- rdx
        ;; v32 <- BinaryInt64Op(+ [tr], v98 T{int}, v102 T{_Smi}) [1, v93] int64
0x7faa347b1782    4883c201               addq rdx,1
        ;; ParallelMove rdi <- rdi, fp[-1] <- rdx
0x7faa347b1786    488955f8               movq [rbp-0x8],rdx
        ;; StaticCall:26( print<0> v101 T{X0?})
0x7faa347b178a    e8fbffffff             call 0x00007faa347b178a
        ;; ParallelMove rdx <- fp[-1], rax <- fp[-3], rcx <- fp[-2] goto:32 B5
        ;; Inlined [ListIterator2.moveNext3]
0x7faa347b178f    488b55f8               movq rdx,[rbp-0x8]
0x7faa347b1793    488b45e8               movq rax,[rbp-0x18]
0x7faa347b1797    488b4df0               movq rcx,[rbp-0x10]
0x7faa347b179b    ebb9                   jmp 0x00007faa347b1756
        ;; B4
        ;; ParallelMove rax <- C
        ;; Inlined [ListIterator2.moveNext3]
0x7faa347b179d    498b4670               movq rax,[thr+0x70]   null
        ;; DartReturn:36(v0)
        ;; Inlined [ListIterator2.moveNext3]
0x7faa347b17a1    4889ec                 movq rsp,rbp
0x7faa347b17a4    5d                     pop rbp
0x7faa347b17a5    c3                     ret
        ;; B13
        ;; ParallelMove rdi <- fp[-3]
        ;; Inlined [ListIterator2.moveNext3]
0x7faa347b17a6    488b7de8               movq rdi,[rbp-0x18]
        ;; v35 <- StaticCall:26( new3<0> v2) T{CME}
        ;; Inlined [ListIterator2.moveNext3]
0x7faa347b17aa    e8fbffffff             call 0x00007faa347b17aa
        ;; ParallelMove rax <- rax
        ;; Throw:28(v35)
        ;; Inlined [ListIterator2.moveNext3]
0x7faa347b17af    e8fbffffff             call 0x00007faa347b17af
0x7faa347b17b4    cc                     int3
        ;; CheckStackOverflowSlowPath
0x7faa347b17b5    41ff9630020000         call [thr+0x230]
0x7faa347b17bc    eb8b                   jmp 0x00007faa347b1749
        ;; CheckStackOverflowSlowPath
0x7faa347b17be    41ff9630020000         call [thr+0x230]
0x7faa347b17c5    eb99                   jmp 0x00007faa347b1760
}
Source positions for function 'file:///usr/local/google/home/sra/play1/bug1a3j.dart_::_useList3' {
7faa347b1730-7faa347b178e: Function 'useList3': static.@139
7faa347b178f-7faa347b17ae: Function 'useList3': static.@139Function 'moveNext3':.@70
7faa347b17af-7faa347b17b3: Function 'useList3': static.@139Function 'moveNext3':.@70
7faa347b17b4-7faa347b17bb: Function 'useList3': static.@136
7faa347b17bc-7faa347b17c4: Function 'useList3': static.@139
}
StackMaps for function 'file:///usr/local/google/home/sra/play1/bug1a3j.dart_::_useList3' {
0x7faa347b178f: 00
0x7faa347b17af: 000
0x7faa347b17b4: 000
0x7faa347b17bc: 00000000000001
0x7faa347b17c5: 00000000000001
}
Catch entry moves for function 'file:///usr/local/google/home/sra/play1/bug1a3j.dart_::_useList3' {
}
Entry points for function 'file:///usr/local/google/home/sra/play1/bug1a3j.dart_::_useList3' {
  [code+0x07] 7faa347b1730 kNormal
  [code+0x0f] 7faa347b1730 kMonomorphic
  [code+0x17] 7faa347b1730 kUnchecked
  [code+0x1f] 7faa347b1730 kMonomorphicUnchecked
}
Static call target functions {
  0x7faa347b178f: file:///usr/local/google/home/sra/play1/bug1a3j.dart_::_print, (pc-relative-call)
  0x7faa347b17af: file:///usr/local/google/home/sra/play1/bug1a3j.dart_CME_new3, (pc-relative-call)
  0x7faa347b17b4: [Stub] _iso_stub_ThrowStub, (pc-relative-call)
}
Code for optimized function 'file:///usr/local/google/home/sra/play1/bug1a3j.dart_::_useList2' (RegularFunction) {
        ;; B0
        ;; B1
        ;; Enter frame
        ;; PrologueOffset = 0
0x7faa347b1810    55                     push rbp
0x7faa347b1811    4889e5                 movq rbp,rsp
0x7faa347b1814    4883ec18               subq rsp,0x18
        ;; ParallelMove rsi <- rdi, fp[-3] <- rdi
0x7faa347b1818    4889fe                 movq rsi,rdi
0x7faa347b181b    48897de8               movq [rbp-0x18],rdi
        ;; CheckStackOverflow:8(stack=0, loop=0)
0x7faa347b181f    493b6638               cmpq rsp,[thr+0x38]
0x7faa347b1823    0f867c000000           jna 0x00007faa347b18a5
        ;; v85 <- LoadField(v2 T{_GrowableList} . GrowableObjectArray.length) [0, 576460752303423487] T{_Smi}
0x7faa347b1829    488b460f               movq rax,[rsi+0xf]
        ;; ParallelMove rax <- rax
        ;; v91 <- UnboxInt64([non-speculative], v85 T{_Smi}) [v85, v85] int64
0x7faa347b182d    48d1f8                 sarq rax,1
        ;; ParallelMove fp[-2] <- rax
0x7faa347b1830    488945f0               movq [rbp-0x10],rax
        ;; ParallelMove rcx <- C goto:30 B5
0x7faa347b1834    33c9                   xorl rcx,rcx
        ;; B5
        ;;   Loop 0
        ;;   Loop Header
        ;; CheckStackOverflow:34(stack=0, loop=1)
0x7faa347b1836    493b6638               cmpq rsp,[thr+0x38]
0x7faa347b183a    0f8671000000           jna 0x00007faa347b18b1
        ;; v80 <- LoadField(v2 T{_GrowableList} . GrowableObjectArray.length) [0, 576460752303423487] T{_Smi}
0x7faa347b1840    488b560f               movq rdx,[rsi+0xf]
        ;; ParallelMove rdx <- rdx
        ;; v93 <- UnboxInt64([non-speculative], v80 T{_Smi}) [v80, v80] int64
0x7faa347b1844    48d1fa                 sarq rdx,1
        ;; Branch if EqualityCompare(v91 T{_Smi} != v93 T{_Smi}) T{bool} goto (13, 14)
0x7faa347b1847    483bc2                 cmpq rax,rdx
0x7faa347b184a    0f8536000000           jnz 0x00007faa347b1886
        ;; B14
        ;;   Loop 0
        ;; Branch if RelationalOp(>=, [non-speculative], v98 T{int}, v93 T{_Smi}) T{bool} goto (4, 10)
0x7faa347b1850    483bca                 cmpq rcx,rdx
0x7faa347b1853    0f8d24000000           jge 0x00007faa347b187d
        ;; B10
        ;;   Loop 0
        ;; v57 <- LoadField(v2 T{_GrowableList} . GrowableObjectArray.data) T{_List}
0x7faa347b1859    488b5617               movq rdx,[rsi+0x17]
        ;; v101 <- LoadIndexed:10([_List] v57, v98 T{int}) T{X0?}
0x7faa347b185d    488b7cca17             movq rdi,[rdx+rcx*8+0x17]
        ;; ParallelMove rcx <- rcx
        ;; v32 <- BinaryInt64Op(+ [tr], v98 T{int}, v102 T{_Smi}) [1, v93] int64
0x7faa347b1862    4883c101               addq rcx,1
        ;; ParallelMove rdi <- rdi, fp[-1] <- rcx
0x7faa347b1866    48894df8               movq [rbp-0x8],rcx
        ;; StaticCall:26( print<0> v101 T{X0?})
0x7faa347b186a    e8fbffffff             call 0x00007faa347b186a
        ;; ParallelMove rcx <- fp[-1], rsi <- fp[-3], rax <- fp[-2] goto:32 B5
        ;; Inlined [ListIterator2.moveNext2]
0x7faa347b186f    488b4df8               movq rcx,[rbp-0x8]
0x7faa347b1873    488b75e8               movq rsi,[rbp-0x18]
0x7faa347b1877    488b45f0               movq rax,[rbp-0x10]
0x7faa347b187b    ebb9                   jmp 0x00007faa347b1836
        ;; B4
        ;; ParallelMove rax <- C
        ;; Inlined [ListIterator2.moveNext2]
0x7faa347b187d    498b4670               movq rax,[thr+0x70]   null
        ;; DartReturn:36(v0)
        ;; Inlined [ListIterator2.moveNext2]
0x7faa347b1881    4889ec                 movq rsp,rbp
0x7faa347b1884    5d                     pop rbp
0x7faa347b1885    c3                     ret
        ;; B13
        ;; v34 <- AllocateObject:24(cls=CME) T{CME}
        ;; Inlined [ListIterator2.moveNext2]
0x7faa347b1886    e8fbffffff             call 0x00007faa347b1886
        ;; ParallelMove rdi <- rax, rsi <- fp[-3], rax <- rax
        ;; Inlined [ListIterator2.moveNext2]
0x7faa347b188b    4889c7                 movq rdi,rax
0x7faa347b188e    488b75e8               movq rsi,[rbp-0x18]
        ;; ParallelMove fp[-3] <- rax
        ;; Inlined [ListIterator2.moveNext2]
0x7faa347b1892    488945e8               movq [rbp-0x18],rax
        ;; StaticCall:28( CME.new2<0> v34, v2)
        ;; Inlined [ListIterator2.moveNext2]
0x7faa347b1896    e8fbffffff             call 0x00007faa347b1896
        ;; ParallelMove rax <- fp[-3]
        ;; Inlined [ListIterator2.moveNext2]
0x7faa347b189b    488b45e8               movq rax,[rbp-0x18]
        ;; Throw:30(v34)
        ;; Inlined [ListIterator2.moveNext2]
0x7faa347b189f    e8fbffffff             call 0x00007faa347b189f
0x7faa347b18a4    cc                     int3
        ;; CheckStackOverflowSlowPath
0x7faa347b18a5    41ff9630020000         call [thr+0x230]
0x7faa347b18ac    e978ffffff             jmp 0x00007faa347b1829
        ;; CheckStackOverflowSlowPath
0x7faa347b18b1    41ff9630020000         call [thr+0x230]
0x7faa347b18b8    eb86                   jmp 0x00007faa347b1840
}
Source positions for function 'file:///usr/local/google/home/sra/play1/bug1a3j.dart_::_useList2' {
7faa347b1810-7faa347b186e: Function 'useList2': static.@133
7faa347b186f-7faa347b188a: Function 'useList2': static.@133Function 'moveNext2':.@55
7faa347b188b-7faa347b189a: Function 'useList2': static.@133Function 'moveNext2':.@55
7faa347b189b-7faa347b18a3: Function 'useList2': static.@133Function 'moveNext2':.@55
7faa347b18a4-7faa347b18ab: Function 'useList2': static.@130
7faa347b18ac-7faa347b18b7: Function 'useList2': static.@133
}
StackMaps for function 'file:///usr/local/google/home/sra/play1/bug1a3j.dart_::_useList2' {
0x7faa347b186f: 00
0x7faa347b188b: 00
0x7faa347b189b: 00
0x7faa347b18a4: 000
0x7faa347b18ac: 00000000010000
0x7faa347b18b8: 00000000010000
}
Catch entry moves for function 'file:///usr/local/google/home/sra/play1/bug1a3j.dart_::_useList2' {
}
Entry points for function 'file:///usr/local/google/home/sra/play1/bug1a3j.dart_::_useList2' {
  [code+0x07] 7faa347b1810 kNormal
  [code+0x0f] 7faa347b1810 kMonomorphic
  [code+0x17] 7faa347b1810 kUnchecked
  [code+0x1f] 7faa347b1810 kMonomorphicUnchecked
}
Static call target functions {
  0x7faa347b186f: file:///usr/local/google/home/sra/play1/bug1a3j.dart_::_print, (pc-relative-call)
  0x7faa347b188b: allocation stub for Library:'file:///usr/local/google/home/sra/play1/bug1a3j.dart' Class: CME, (pc-relative-call)
  0x7faa347b189b: file:///usr/local/google/home/sra/play1/bug1a3j.dart_CME_CME.new2, (pc-relative-call)
  0x7faa347b18a4: [Stub] _iso_stub_ThrowStub, (pc-relative-call)
}
Code for optimized function 'file:///usr/local/google/home/sra/play1/bug1a3j.dart_::_useList1' (RegularFunction) {
        ;; B0
        ;; B1
        ;; Enter frame
        ;; PrologueOffset = 0
0x7faa347b1910    55                     push rbp
0x7faa347b1911    4889e5                 movq rbp,rsp
0x7faa347b1914    4883ec18               subq rsp,0x18
        ;; ParallelMove rax <- rdi, fp[-3] <- rdi
0x7faa347b1918    4889f8                 movq rax,rdi
0x7faa347b191b    48897de8               movq [rbp-0x18],rdi
        ;; CheckStackOverflow:8(stack=0, loop=0)
0x7faa347b191f    493b6638               cmpq rsp,[thr+0x38]
0x7faa347b1923    0f8676000000           jna 0x00007faa347b199f
        ;; v91 <- LoadField(v2 T{_GrowableList} . GrowableObjectArray.length) [0, 576460752303423487] T{_Smi}
0x7faa347b1929    488b480f               movq rcx,[rax+0xf]
        ;; ParallelMove rcx <- rcx
        ;; v101 <- UnboxInt64([non-speculative], v91 T{_Smi}) [v91, v91] int64
0x7faa347b192d    48d1f9                 sarq rcx,1
        ;; ParallelMove fp[-2] <- rcx
0x7faa347b1930    48894df0               movq [rbp-0x10],rcx
        ;; ParallelMove rdx <- C goto:30 B5
0x7faa347b1934    33d2                   xorl rdx,rdx
        ;; B5
        ;;   Loop 0
        ;;   Loop Header
        ;; CheckStackOverflow:34(stack=0, loop=1)
0x7faa347b1936    493b6638               cmpq rsp,[thr+0x38]
0x7faa347b193a    0f8668000000           jna 0x00007faa347b19a8
        ;; v86 <- LoadField(v2 T{_GrowableList} . GrowableObjectArray.length) [0, 576460752303423487] T{_Smi}
0x7faa347b1940    488b580f               movq rbx,[rax+0xf]
        ;; ParallelMove rbx <- rbx
        ;; v103 <- UnboxInt64([non-speculative], v86 T{_Smi}) [v86, v86] int64
0x7faa347b1944    48d1fb                 sarq rbx,1
        ;; Branch if EqualityCompare(v101 T{_Smi} != v103 T{_Smi}) T{bool} goto (13, 14)
0x7faa347b1947    483bcb                 cmpq rcx,rbx
0x7faa347b194a    0f8536000000           jnz 0x00007faa347b1986
        ;; B14
        ;;   Loop 0
        ;; Branch if RelationalOp(>=, [non-speculative], v108 T{int}, v103 T{_Smi}) T{bool} goto (4, 10)
0x7faa347b1950    483bd3                 cmpq rdx,rbx
0x7faa347b1953    0f8d24000000           jge 0x00007faa347b197d
        ;; B10
        ;;   Loop 0
        ;; v57 <- LoadField(v2 T{_GrowableList} . GrowableObjectArray.data) T{_List}
0x7faa347b1959    488b5817               movq rbx,[rax+0x17]
        ;; v111 <- LoadIndexed:10([_List] v57, v108 T{int}) T{X0?}
0x7faa347b195d    488b7cd317             movq rdi,[rbx+rdx*8+0x17]
        ;; ParallelMove rdx <- rdx
        ;; v32 <- BinaryInt64Op(+ [tr], v108 T{int}, v112 T{_Smi}) [1, v103] int64
0x7faa347b1962    4883c201               addq rdx,1
        ;; ParallelMove rdi <- rdi, fp[-1] <- rdx
0x7faa347b1966    488955f8               movq [rbp-0x8],rdx
        ;; StaticCall:26( print<0> v111 T{X0?})
0x7faa347b196a    e8fbffffff             call 0x00007faa347b196a
        ;; ParallelMove rdx <- fp[-1], rax <- fp[-3], rcx <- fp[-2] goto:32 B5
        ;; Inlined [ListIterator2.moveNext]
0x7faa347b196f    488b55f8               movq rdx,[rbp-0x8]
0x7faa347b1973    488b45e8               movq rax,[rbp-0x18]
0x7faa347b1977    488b4df0               movq rcx,[rbp-0x10]
0x7faa347b197b    ebb9                   jmp 0x00007faa347b1936
        ;; B4
        ;; ParallelMove rax <- C
        ;; Inlined [ListIterator2.moveNext]
0x7faa347b197d    498b4670               movq rax,[thr+0x70]   null
        ;; DartReturn:36(v0)
        ;; Inlined [ListIterator2.moveNext]
0x7faa347b1981    4889ec                 movq rsp,rbp
0x7faa347b1984    5d                     pop rbp
0x7faa347b1985    c3                     ret
        ;; B13
        ;; v34 <- AllocateObject:24(cls=CME, <not-aliased>) T{CME}
        ;; Inlined [ListIterator2.moveNext]
0x7faa347b1986    e8fbffffff             call 0x00007faa347b1986
        ;; ParallelMove rcx <- rax, rax <- fp[-3]
        ;; Inlined [ListIterator2.moveNext]
0x7faa347b198b    4889c1                 movq rcx,rax
0x7faa347b198e    488b45e8               movq rax,[rbp-0x18]
        ;; StoreField(v34 T{CME} . modifiedObject = v2, NoStoreBarrier)
        ;; Inlined [ListIterator2.moveNext]
0x7faa347b1992    4889410f               movq [rcx+0xf],rax
        ;; ParallelMove rax <- rcx
        ;; Inlined [ListIterator2.moveNext]
0x7faa347b1996    4889c8                 movq rax,rcx
        ;; Throw:30(v34)
        ;; Inlined [ListIterator2.moveNext]
0x7faa347b1999    e8fbffffff             call 0x00007faa347b1999
0x7faa347b199e    cc                     int3
        ;; CheckStackOverflowSlowPath
0x7faa347b199f    41ff9630020000         call [thr+0x230]
0x7faa347b19a6    eb81                   jmp 0x00007faa347b1929
        ;; CheckStackOverflowSlowPath
0x7faa347b19a8    41ff9630020000         call [thr+0x230]
0x7faa347b19af    eb8f                   jmp 0x00007faa347b1940
}
Source positions for function 'file:///usr/local/google/home/sra/play1/bug1a3j.dart_::_useList1' {
7faa347b1910-7faa347b196e: Function 'useList1': static.@127
7faa347b196f-7faa347b198a: Function 'useList1': static.@127Function 'moveNext':.@40
7faa347b198b-7faa347b199d: Function 'useList1': static.@127Function 'moveNext':.@40
7faa347b199e-7faa347b19a5: Function 'useList1': static.@124
7faa347b19a6-7faa347b19ae: Function 'useList1': static.@127
}
StackMaps for function 'file:///usr/local/google/home/sra/play1/bug1a3j.dart_::_useList1' {
0x7faa347b196f: 00
0x7faa347b198b: 00
0x7faa347b199e: 000
0x7faa347b19a6: 00000000000001
0x7faa347b19af: 00000000000001
}
Catch entry moves for function 'file:///usr/local/google/home/sra/play1/bug1a3j.dart_::_useList1' {
}
Entry points for function 'file:///usr/local/google/home/sra/play1/bug1a3j.dart_::_useList1' {
  [code+0x07] 7faa347b1910 kNormal
  [code+0x0f] 7faa347b1910 kMonomorphic
  [code+0x17] 7faa347b1910 kUnchecked
  [code+0x1f] 7faa347b1910 kMonomorphicUnchecked
}
Static call target functions {
  0x7faa347b196f: file:///usr/local/google/home/sra/play1/bug1a3j.dart_::_print, (pc-relative-call)
  0x7faa347b198b: allocation stub for Library:'file:///usr/local/google/home/sra/play1/bug1a3j.dart' Class: CME, (pc-relative-call)
  0x7faa347b199e: [Stub] _iso_stub_ThrowStub, (pc-relative-call)
}
Generating executable.
Marking binary executable.
Generated: /usr/local/google/home/sra/Dart2/sdk/z5

Metadata

Metadata

Assignees

No one assigned

    Labels

    P3A lower priority bug or feature requestarea-vmUse area-vm for VM related issues, including code coverage, and the AOT and JIT backends.triagedIssue has been triaged by sub teamtype-performanceIssue relates to performance or code sizevm-aot-code-sizeRelated to improvements in AOT code size

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions