[vm/bytecode] Add starting and ending source positions for closures

Issue: https://github.com/dart-lang/sdk/issues/36427
Change-Id: Ib2f55504f9238036a9700f1e2672b4641536ab7c
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/103480
Reviewed-by: RĂ©gis Crelier <regis@google.com>
Commit-Queue: Alexander Markov <alexmarkov@google.com>
diff --git a/pkg/vm/lib/bytecode/dbc.dart b/pkg/vm/lib/bytecode/dbc.dart
index 2ee6f20..974c842 100644
--- a/pkg/vm/lib/bytecode/dbc.dart
+++ b/pkg/vm/lib/bytecode/dbc.dart
@@ -10,7 +10,7 @@
 /// Before bumping current bytecode version format, make sure that
 /// all users have switched to a VM which is able to consume new
 /// version of bytecode.
-const int currentBytecodeFormatVersion = 7;
+const int currentBytecodeFormatVersion = 8;
 
 /// Version of experimental / bleeding edge bytecode format.
 /// Produced by bytecode generator when --use-future-bytecode-format
diff --git a/pkg/vm/lib/bytecode/declarations.dart b/pkg/vm/lib/bytecode/declarations.dart
index 5fde12c..5baf7d6 100644
--- a/pkg/vm/lib/bytecode/declarations.dart
+++ b/pkg/vm/lib/bytecode/declarations.dart
@@ -140,10 +140,10 @@
         ((flags & hasCustomScriptFlag) != 0) ? reader.readPackedObject() : null;
     final position = ((flags & hasSourcePositionsFlag) != 0)
         ? reader.readPackedUInt30() - 1
-        : 0;
+        : TreeNode.noOffset;
     final endPosition = ((flags & hasSourcePositionsFlag) != 0)
         ? reader.readPackedUInt30() - 1
-        : 0;
+        : TreeNode.noOffset;
     final initializerCode =
         ((flags & hasInitializerFlag) != 0 && (flags & isStaticFlag) != 0)
             ? reader.readLinkOffset<Code>()
@@ -298,10 +298,10 @@
         ((flags & hasCustomScriptFlag) != 0) ? reader.readPackedObject() : null;
     final position = ((flags & hasSourcePositionsFlag) != 0)
         ? reader.readPackedUInt30() - 1
-        : 0;
+        : TreeNode.noOffset;
     final endPosition = ((flags & hasSourcePositionsFlag) != 0)
         ? reader.readPackedUInt30() - 1
-        : 0;
+        : TreeNode.noOffset;
     final typeParameters = ((flags & hasTypeParamsFlag) != 0)
         ? new TypeParametersDeclaration.read(reader)
         : null;
@@ -628,12 +628,15 @@
 }
 
 class ClosureDeclaration {
-  static const int flagHasOptionalPositionalParams = 1 << 0;
-  static const int flagHasOptionalNamedParams = 1 << 1;
-  static const int flagHasTypeParams = 1 << 2;
+  static const int hasOptionalPositionalParamsFlag = 1 << 0;
+  static const int hasOptionalNamedParamsFlag = 1 << 1;
+  static const int hasTypeParamsFlag = 1 << 2;
+  static const int hasSourcePositionsFlag = 1 << 3;
 
   final ObjectHandle parent;
   final ObjectHandle name;
+  final int position;
+  final int endPosition;
   final List<NameAndType> typeParams;
   final int numRequiredParams;
   final int numNamedParams;
@@ -644,6 +647,8 @@
   ClosureDeclaration(
       this.parent,
       this.name,
+      this.position,
+      this.endPosition,
       this.typeParams,
       this.numRequiredParams,
       this.numNamedParams,
@@ -654,19 +659,27 @@
     int flags = 0;
     if (numRequiredParams != parameters.length) {
       if (numNamedParams > 0) {
-        flags |= flagHasOptionalNamedParams;
+        flags |= hasOptionalNamedParamsFlag;
       } else {
-        flags |= flagHasOptionalPositionalParams;
+        flags |= hasOptionalPositionalParamsFlag;
       }
     }
     if (typeParams.isNotEmpty) {
-      flags |= flagHasTypeParams;
+      flags |= hasTypeParamsFlag;
+    }
+    if (position != TreeNode.noOffset) {
+      flags |= hasSourcePositionsFlag;
     }
     writer.writePackedUInt30(flags);
     writer.writePackedObject(parent);
     writer.writePackedObject(name);
 
-    if (flags & flagHasTypeParams != 0) {
+    if (flags & hasSourcePositionsFlag != 0) {
+      writer.writePackedUInt30(position + 1);
+      writer.writePackedUInt30(endPosition + 1);
+    }
+
+    if (flags & hasTypeParamsFlag != 0) {
       writer.writePackedUInt30(typeParams.length);
       for (var tp in typeParams) {
         writer.writePackedObject(tp.name);
@@ -677,7 +690,7 @@
     }
     writer.writePackedUInt30(parameters.length);
     if (flags &
-            (flagHasOptionalPositionalParams | flagHasOptionalNamedParams) !=
+            (hasOptionalPositionalParamsFlag | hasOptionalNamedParamsFlag) !=
         0) {
       writer.writePackedUInt30(numRequiredParams);
     }
@@ -692,8 +705,14 @@
     final int flags = reader.readPackedUInt30();
     final parent = reader.readPackedObject();
     final name = reader.readPackedObject();
+    final position = ((flags & hasSourcePositionsFlag) != 0)
+        ? reader.readPackedUInt30() - 1
+        : TreeNode.noOffset;
+    final endPosition = ((flags & hasSourcePositionsFlag) != 0)
+        ? reader.readPackedUInt30() - 1
+        : TreeNode.noOffset;
     List<NameAndType> typeParams;
-    if ((flags & flagHasTypeParams) != 0) {
+    if ((flags & hasTypeParamsFlag) != 0) {
       final int numTypeParams = reader.readPackedUInt30();
       List<ObjectHandle> names = new List<ObjectHandle>.generate(
           numTypeParams, (_) => reader.readPackedObject());
@@ -706,12 +725,12 @@
     }
     final numParams = reader.readPackedUInt30();
     final numRequiredParams = (flags &
-                (flagHasOptionalPositionalParams |
-                    flagHasOptionalNamedParams) !=
+                (hasOptionalPositionalParamsFlag |
+                    hasOptionalNamedParamsFlag) !=
             0)
         ? reader.readPackedUInt30()
         : numParams;
-    final numNamedParams = (flags & flagHasOptionalNamedParams != 0)
+    final numNamedParams = (flags & hasOptionalNamedParamsFlag != 0)
         ? (numParams - numRequiredParams)
         : 0;
     final List<NameAndType> parameters = new List<NameAndType>.generate(
@@ -719,14 +738,17 @@
         (_) => new NameAndType(
             reader.readPackedObject(), reader.readPackedObject()));
     final returnType = reader.readPackedObject();
-    return new ClosureDeclaration(parent, name, typeParams, numRequiredParams,
-        numNamedParams, parameters, returnType);
+    return new ClosureDeclaration(parent, name, position, endPosition,
+        typeParams, numRequiredParams, numNamedParams, parameters, returnType);
   }
 
   @override
   String toString() {
     StringBuffer sb = new StringBuffer();
     sb.write('Closure $parent::$name');
+    if (position != TreeNode.noOffset) {
+      sb.write(' pos = $position, end-pos = $endPosition');
+    }
     if (typeParams.isNotEmpty) {
       sb.write(' <${typeParams.join(', ')}>');
     }
diff --git a/pkg/vm/lib/bytecode/gen_bytecode.dart b/pkg/vm/lib/bytecode/gen_bytecode.dart
index 216ac55..e100111 100644
--- a/pkg/vm/lib/bytecode/gen_bytecode.dart
+++ b/pkg/vm/lib/bytecode/gen_bytecode.dart
@@ -1618,6 +1618,15 @@
     final savedLoopDepth = currentLoopDepth;
     currentLoopDepth = 0;
 
+    int position = TreeNode.noOffset;
+    int endPosition = TreeNode.noOffset;
+    if (emitSourcePositions) {
+      position = (node is ast.FunctionDeclaration)
+          ? node.fileOffset
+          : function.fileOffset;
+      endPosition = function.fileEndOffset;
+    }
+
     if (function.typeParameters.isNotEmpty) {
       functionTypeParameters ??= new List<TypeParameter>();
       functionTypeParameters.addAll(function.typeParameters);
@@ -1644,6 +1653,8 @@
         objectTable
             .getHandle(savedIsClosure ? parentFunction : enclosingMember),
         objectTable.getNameHandle(null, name),
+        position,
+        endPosition,
         function.typeParameters
             .map((tp) => new NameAndType(
                 objectTable.getNameHandle(null, tp.name),
diff --git a/runtime/vm/compiler/frontend/bytecode_reader.cc b/runtime/vm/compiler/frontend/bytecode_reader.cc
index 602d55b..7ca1f85 100644
--- a/runtime/vm/compiler/frontend/bytecode_reader.cc
+++ b/runtime/vm/compiler/frontend/bytecode_reader.cc
@@ -352,9 +352,12 @@
 
 void BytecodeReaderHelper::ReadClosureDeclaration(const Function& function,
                                                   intptr_t closureIndex) {
-  const int kHasOptionalPositionalParams = 1 << 0;
-  const int kHasOptionalNamedParams = 1 << 1;
-  const int kHasTypeParams = 1 << 2;
+  // Closure flags, must be in sync with ClosureDeclaration constants in
+  // pkg/vm/lib/bytecode/declarations.dart.
+  const int kHasOptionalPositionalParamsFlag = 1 << 0;
+  const int kHasOptionalNamedParamsFlag = 1 << 1;
+  const int kHasTypeParamsFlag = 1 << 2;
+  const int kHasSourcePositionsFlag = 1 << 3;
 
   const intptr_t flags = helper_->reader_.ReadUInt();
 
@@ -369,20 +372,27 @@
   String& name = String::CheckedHandle(Z, ReadObject());
   ASSERT(name.IsSymbol());
 
+  TokenPosition position = TokenPosition::kNoSource;
+  TokenPosition end_position = TokenPosition::kNoSource;
+  if ((flags & kHasSourcePositionsFlag) != 0) {
+    position = helper_->ReadPosition();
+    end_position = helper_->ReadPosition();
+  }
+
   const Function& closure = Function::Handle(
-      Z, Function::NewClosureFunction(name, Function::Cast(parent),
-                                      TokenPosition::kNoSource));
+      Z, Function::NewClosureFunction(name, Function::Cast(parent), position));
 
   closure.set_is_declared_in_bytecode(true);
+  closure.set_end_token_pos(end_position);
 
   closures_->SetAt(closureIndex, closure);
 
-  Type& signature_type =
-      Type::Handle(Z, ReadFunctionSignature(
-                          closure, (flags & kHasOptionalPositionalParams) != 0,
-                          (flags & kHasOptionalNamedParams) != 0,
-                          (flags & kHasTypeParams) != 0,
-                          /* has_positional_param_names = */ true));
+  Type& signature_type = Type::Handle(
+      Z, ReadFunctionSignature(closure,
+                               (flags & kHasOptionalPositionalParamsFlag) != 0,
+                               (flags & kHasOptionalNamedParamsFlag) != 0,
+                               (flags & kHasTypeParamsFlag) != 0,
+                               /* has_positional_param_names = */ true));
 
   closure.SetSignatureType(signature_type);
 }
diff --git a/runtime/vm/constants_kbc.h b/runtime/vm/constants_kbc.h
index 8a26be6..a9aa1c7 100644
--- a/runtime/vm/constants_kbc.h
+++ b/runtime/vm/constants_kbc.h
@@ -749,7 +749,7 @@
   // Maximum bytecode format version supported by VM.
   // The range of supported versions should include version produced by bytecode
   // generator (currentBytecodeFormatVersion in pkg/vm/lib/bytecode/dbc.dart).
-  static const intptr_t kMaxSupportedBytecodeFormatVersion = 7;
+  static const intptr_t kMaxSupportedBytecodeFormatVersion = 8;
 
   enum Opcode {
 #define DECLARE_BYTECODE(name, encoding, kind, op1, op2, op3) k##name,