[kernel] Change dill representation of doubles

This is the second try. First commit failed because another reading of
the binary was added after the change was originally made and before
actually landing it (and wasn't noticed when rebasing).
This reverts commit b298fc6d8f6a0e1aa841dbbdda26663d6012a79a.

See 6e2536f5859b4838fee9af4ef89372921cc9beb7 for more information.

Change-Id: Ia0e7f8921de2cec8088654fa24950df13d846237
Reviewed-on: https://dart-review.googlesource.com/53560
Commit-Queue: Jens Johansen <jensj@google.com>
Reviewed-by: Alexander Aprelev <aam@google.com>
diff --git a/pkg/kernel/binary.md b/pkg/kernel/binary.md
index ba13f5c..0af9f95 100644
--- a/pkg/kernel/binary.md
+++ b/pkg/kernel/binary.md
@@ -42,6 +42,8 @@
 
 type UInt32 = big endian 32-bit unsigned integer
 
+type Double = Double-precision floating-point number.
+
 type List<T> {
   UInt length;
   T[length] items;
@@ -711,7 +713,7 @@
 
 type DoubleLiteral extends Expression {
   Byte tag = 40;
-  StringReference valueString;
+  Double value;
 }
 
 type TrueLiteral extends Expression {
@@ -874,7 +876,7 @@
 
 type DoubleConstant extends Constant {
   Byte tag = 3;
-  StringReference value;
+  Double value;
 }
 
 type StringConstant extends Constant {
diff --git a/pkg/kernel/lib/binary/ast_from_binary.dart b/pkg/kernel/lib/binary/ast_from_binary.dart
index d9e61cc..4ff4a37 100644
--- a/pkg/kernel/lib/binary/ast_from_binary.dart
+++ b/pkg/kernel/lib/binary/ast_from_binary.dart
@@ -97,6 +97,22 @@
         readByte();
   }
 
+  final Float64List _doubleBuffer = new Float64List(1);
+  Uint8List _doubleBufferUint8;
+
+  double readDouble() {
+    _doubleBufferUint8 ??= _doubleBuffer.buffer.asUint8List();
+    _doubleBufferUint8[0] = readByte();
+    _doubleBufferUint8[1] = readByte();
+    _doubleBufferUint8[2] = readByte();
+    _doubleBufferUint8[3] = readByte();
+    _doubleBufferUint8[4] = readByte();
+    _doubleBufferUint8[5] = readByte();
+    _doubleBufferUint8[6] = readByte();
+    _doubleBufferUint8[7] = readByte();
+    return _doubleBuffer[0];
+  }
+
   List<int> readByteList() {
     List<int> bytes = new Uint8List(readUInt());
     bytes.setRange(0, bytes.length, _bytes, _byteOffset);
@@ -174,7 +190,7 @@
       case ConstantTag.IntConstant:
         return new IntConstant((readExpression() as IntLiteral).value);
       case ConstantTag.DoubleConstant:
-        return new DoubleConstant(double.parse(readStringReference()));
+        return new DoubleConstant(readDouble());
       case ConstantTag.StringConstant:
         return new StringConstant(readStringReference());
       case ConstantTag.MapConstant:
@@ -1333,7 +1349,7 @@
       case Tag.BigIntLiteral:
         return new IntLiteral(int.parse(readStringReference()));
       case Tag.DoubleLiteral:
-        return new DoubleLiteral(double.parse(readStringReference()));
+        return new DoubleLiteral(readDouble());
       case Tag.TrueLiteral:
         return new BoolLiteral(true);
       case Tag.FalseLiteral:
diff --git a/pkg/kernel/lib/binary/ast_to_binary.dart b/pkg/kernel/lib/binary/ast_to_binary.dart
index adb16a0..a65dd03 100644
--- a/pkg/kernel/lib/binary/ast_to_binary.dart
+++ b/pkg/kernel/lib/binary/ast_to_binary.dart
@@ -147,7 +147,7 @@
       writeInteger(constant.value);
     } else if (constant is DoubleConstant) {
       writeByte(ConstantTag.DoubleConstant);
-      writeStringReference('${constant.value}');
+      writeDouble(constant.value);
     } else if (constant is StringConstant) {
       writeByte(ConstantTag.StringConstant);
       writeStringReference(constant.value);
@@ -1238,13 +1238,12 @@
 
   @override
   void visitDoubleLiteral(DoubleLiteral node) {
+    writeByte(Tag.DoubleLiteral);
     writeDouble(node.value);
   }
 
   writeDouble(double value) {
-    // TODO: Pick a better format for double literals.
-    writeByte(Tag.DoubleLiteral);
-    writeStringReference('$value');
+    _sink.addDouble(value);
   }
 
   @override
@@ -2190,8 +2189,20 @@
   int length = 0;
   int flushedLength = 0;
 
+  Float64List _doubleBuffer = new Float64List(1);
+  Uint8List _doubleBufferUint8;
+
   BufferedSink(this._sink);
 
+  void addDouble(double d) {
+    _doubleBufferUint8 ??= _doubleBuffer.buffer.asUint8List();
+    _doubleBuffer[0] = d;
+    addByte4(_doubleBufferUint8[0], _doubleBufferUint8[1],
+        _doubleBufferUint8[2], _doubleBufferUint8[3]);
+    addByte4(_doubleBufferUint8[4], _doubleBufferUint8[5],
+        _doubleBufferUint8[6], _doubleBufferUint8[7]);
+  }
+
   void addByte(int byte) {
     _buffer[length++] = byte;
     if (length == SIZE) {
diff --git a/runtime/vm/compiler/frontend/kernel_binary_flowgraph.cc b/runtime/vm/compiler/frontend/kernel_binary_flowgraph.cc
index 77cdb04..5d5b373 100644
--- a/runtime/vm/compiler/frontend/kernel_binary_flowgraph.cc
+++ b/runtime/vm/compiler/frontend/kernel_binary_flowgraph.cc
@@ -1633,7 +1633,7 @@
       builder_->ReadUInt();  // read value.
       return;
     case kDoubleLiteral:
-      builder_->SkipStringReference();  // read index into string table.
+      builder_->ReadDouble();  // read value.
       return;
     case kTrueLiteral:
       return;
@@ -3602,8 +3602,7 @@
 }
 
 void StreamingConstantEvaluator::EvaluateDoubleLiteral() {
-  result_ = Double::New(H.DartString(builder_->ReadStringReference()),
-                        Heap::kOld);  // read string reference.
+  result_ = Double::New(builder_->ReadDouble(), Heap::kOld);  // read value.
   result_ = H.Canonicalize(result_);
 }
 
@@ -4276,9 +4275,13 @@
     case kPositiveIntLiteral:
       BuildHash(ReadUInt());  // read value.
       return;
-    case kDoubleLiteral:
-      CalculateStringReferenceFingerprint();  // read index into string table.
+    case kDoubleLiteral: {
+      double value = ReadDouble();  // read value.
+      uint64_t data = bit_cast<uint64_t>(value);
+      BuildHash(static_cast<uint32_t>(data >> 32));
+      BuildHash(static_cast<uint32_t>(data));
       return;
+    }
     case kTrueLiteral:
       return;
     case kFalseLiteral:
@@ -6047,6 +6050,10 @@
   return reader_.ReadUInt();
 }
 
+double KernelReaderHelper::ReadDouble() {
+  return reader_.ReadDouble();
+}
+
 uint32_t KernelReaderHelper::PeekListLength() {
   AlternativeReadingScope alt(&reader_);
   return reader_.ReadListLength();
@@ -6492,7 +6499,7 @@
       ReadUInt();  // read value.
       return;
     case kDoubleLiteral:
-      SkipStringReference();  // read index into string table.
+      ReadDouble();  // read value.
       return;
     case kTrueLiteral:
       return;
@@ -8986,8 +8993,7 @@
   if (position != NULL) *position = TokenPosition::kNoSource;
 
   Double& constant = Double::ZoneHandle(
-      Z, Double::NewCanonical(
-             H.DartString(ReadStringReference())));  // read string reference.
+      Z, Double::NewCanonical(ReadDouble()));  // read double.
   return Constant(constant);
 }
 
@@ -10718,8 +10724,7 @@
         break;
       }
       case kDoubleConstant: {
-        temp_instance_ = Double::New(
-            H.DartString(builder_.ReadStringReference()), Heap::kOld);
+        temp_instance_ = Double::New(builder_.ReadDouble(), Heap::kOld);
         temp_instance_ = H.Canonicalize(temp_instance_);
         break;
       }
diff --git a/runtime/vm/compiler/frontend/kernel_binary_flowgraph.h b/runtime/vm/compiler/frontend/kernel_binary_flowgraph.h
index f32e38f..87ef12b 100644
--- a/runtime/vm/compiler/frontend/kernel_binary_flowgraph.h
+++ b/runtime/vm/compiler/frontend/kernel_binary_flowgraph.h
@@ -1042,6 +1042,7 @@
   uint32_t ReadUInt();
   uint32_t ReadUInt32();
   uint32_t PeekUInt();
+  double ReadDouble();
   uint32_t PeekListLength();
   StringIndex ReadStringReference();
   NameIndex ReadCanonicalNameReference();
diff --git a/runtime/vm/kernel_binary.h b/runtime/vm/kernel_binary.h
index 1106d45..daee540 100644
--- a/runtime/vm/kernel_binary.h
+++ b/runtime/vm/kernel_binary.h
@@ -213,6 +213,14 @@
     return value;
   }
 
+  double ReadDouble() {
+    ASSERT((size_ >= 8) && (offset_ >= 0) && (offset_ <= size_ - 8));
+    double value = ReadUnaligned(
+        reinterpret_cast<const double*>(&this->buffer()[offset_]));
+    offset_ += 8;
+    return value;
+  }
+
   uint32_t ReadUInt() {
     ASSERT((size_ >= 1) && (offset_ >= 0) && (offset_ <= size_ - 1));
 
diff --git a/runtime/vm/kernel_loader.cc b/runtime/vm/kernel_loader.cc
index 4b83212..6a3358c 100644
--- a/runtime/vm/kernel_loader.cc
+++ b/runtime/vm/kernel_loader.cc
@@ -82,8 +82,7 @@
         return true;
       case kDoubleLiteral:
         simple_value_ = &Double::ZoneHandle(
-            Z, Double::New(H.DartString(builder_->ReadStringReference()),
-                           Heap::kOld));  // read string reference.
+            Z, Double::New(builder_->ReadDouble(), Heap::kOld));  // read value.
         *simple_value_ = H.Canonicalize(*simple_value_);
         return true;
       case kTrueLiteral: