Revision: 22129
Author:   [email protected]
Date:     Tue Jul  1 15:02:31 2014 UTC
Log: Reland r22082 "Replace HeapNumber as doublebox with an explicit MutableHeapNumber."

[email protected]

Review URL: https://codereview.chromium.org/334323003
http://code.google.com/p/v8/source/detail?r=22129

Added:
 /branches/bleeding_edge/test/mjsunit/migrations.js
Modified:
 /branches/bleeding_edge/include/v8.h
 /branches/bleeding_edge/src/arm/macro-assembler-arm.cc
 /branches/bleeding_edge/src/arm/macro-assembler-arm.h
 /branches/bleeding_edge/src/arm/stub-cache-arm.cc
 /branches/bleeding_edge/src/arm64/macro-assembler-arm64.cc
 /branches/bleeding_edge/src/arm64/macro-assembler-arm64.h
 /branches/bleeding_edge/src/arm64/stub-cache-arm64.cc
 /branches/bleeding_edge/src/deoptimizer.cc
 /branches/bleeding_edge/src/factory.cc
 /branches/bleeding_edge/src/factory.h
 /branches/bleeding_edge/src/heap-snapshot-generator.cc
 /branches/bleeding_edge/src/heap.cc
 /branches/bleeding_edge/src/heap.h
 /branches/bleeding_edge/src/hydrogen.cc
 /branches/bleeding_edge/src/ia32/macro-assembler-ia32.cc
 /branches/bleeding_edge/src/ia32/macro-assembler-ia32.h
 /branches/bleeding_edge/src/ia32/stub-cache-ia32.cc
 /branches/bleeding_edge/src/json-parser.h
 /branches/bleeding_edge/src/json-stringifier.h
 /branches/bleeding_edge/src/mark-compact.cc
 /branches/bleeding_edge/src/mips/macro-assembler-mips.cc
 /branches/bleeding_edge/src/mips/macro-assembler-mips.h
 /branches/bleeding_edge/src/mips/stub-cache-mips.cc
 /branches/bleeding_edge/src/objects-debug.cc
 /branches/bleeding_edge/src/objects-inl.h
 /branches/bleeding_edge/src/objects-printer.cc
 /branches/bleeding_edge/src/objects-visiting.cc
 /branches/bleeding_edge/src/objects.cc
 /branches/bleeding_edge/src/objects.h
 /branches/bleeding_edge/src/runtime.cc
 /branches/bleeding_edge/src/x64/macro-assembler-x64.cc
 /branches/bleeding_edge/src/x64/macro-assembler-x64.h
 /branches/bleeding_edge/src/x64/stub-cache-x64.cc
 /branches/bleeding_edge/src/x87/macro-assembler-x87.cc
 /branches/bleeding_edge/src/x87/macro-assembler-x87.h
 /branches/bleeding_edge/src/x87/stub-cache-x87.cc
 /branches/bleeding_edge/test/cctest/test-heap-profiler.cc
 /branches/bleeding_edge/test/mjsunit/mjsunit.status

=======================================
--- /dev/null
+++ /branches/bleeding_edge/test/mjsunit/migrations.js Tue Jul 1 15:02:31 2014 UTC
@@ -0,0 +1,311 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-ayle license that can be
+// found in the LICENSE file.
+
+// Flags: --allow-natives-syntax --track-fields --expose-gc
+
+var global = Function('return this')();
+var verbose = 0;
+
+function test(ctor_desc, use_desc, migr_desc) {
+  var n = 5;
+  var objects = [];
+  var results = [];
+
+  if (verbose) {
+    print();
+    print("===========================================================");
+    print("=== " + ctor_desc.name +
+          " | " + use_desc.name + " |--> " + migr_desc.name);
+    print("===========================================================");
+  }
+
+  // Clean ICs and transitions.
+  %NotifyContextDisposed();
+  gc(); gc(); gc();
+
+
+  // create objects
+  if (verbose) {
+    print("-----------------------------");
+    print("--- construct");
+    print();
+  }
+  for (var i = 0; i < n; i++) {
+    objects[i] = ctor_desc.ctor.apply(ctor_desc, ctor_desc.args(i));
+  }
+
+  try {
+    // use them
+    if (verbose) {
+      print("-----------------------------");
+      print("--- use 1");
+      print();
+    }
+    var use = use_desc.use1;
+    for (var i = 0; i < n; i++) {
+      if (i == 3) %OptimizeFunctionOnNextCall(use);
+      results[i] = use(objects[i], i);
+    }
+
+    // trigger migrations
+    if (verbose) {
+      print("-----------------------------");
+      print("--- trigger migration");
+      print();
+    }
+    var migr = migr_desc.migr;
+    for (var i = 0; i < n; i++) {
+      if (i == 3) %OptimizeFunctionOnNextCall(migr);
+      migr(objects[i], i);
+    }
+
+    // use again
+    if (verbose) {
+      print("-----------------------------");
+      print("--- use 2");
+      print();
+    }
+    var use = use_desc.use2 !== undefined ? use_desc.use2 : use_desc.use1;
+    for (var i = 0; i < n; i++) {
+      if (i == 3) %OptimizeFunctionOnNextCall(use);
+      results[i] = use(objects[i], i);
+      if (verbose >= 2) print(results[i]);
+    }
+
+  } catch (e) {
+    if (verbose) print("--- incompatible use: " + e);
+  }
+  return results;
+}
+
+
+var ctors = [
+  {
+    name: "none-to-double",
+    ctor: function(v) { return {a: v}; },
+    args: function(i) { return [1.5 + i]; },
+  },
+  {
+    name: "double",
+    ctor: function(v) { var o = {}; o.a = v; return o; },
+    args: function(i) { return [1.5 + i]; },
+  },
+  {
+    name: "none-to-smi",
+    ctor: function(v) { return {a: v}; },
+    args: function(i) { return [i]; },
+  },
+  {
+    name: "smi",
+    ctor: function(v) { var o = {}; o.a = v; return o; },
+    args: function(i) { return [i]; },
+  },
+  {
+    name: "none-to-object",
+    ctor: function(v) { return {a: v}; },
+    args: function(i) { return ["s"]; },
+  },
+  {
+    name: "object",
+    ctor: function(v) { var o = {}; o.a = v; return o; },
+    args: function(i) { return ["s"]; },
+  },
+  {
+    name: "{a:, b:, c:}",
+    ctor: function(v1, v2, v3) { return {a: v1, b: v2, c: v3}; },
+    args: function(i)    { return [1.5 + i, 1.6, 1.7]; },
+  },
+  {
+    name: "{a..h:}",
+ ctor: function(v) { var o = {}; o.h=o.g=o.f=o.e=o.d=o.c=o.b=o.a=v; return o; },
+    args: function(i) { return [1.5 + i]; },
+  },
+  {
+    name: "1",
+    ctor: function(v) { var o = 1; o.a = v; return o; },
+    args: function(i) { return [1.5 + i]; },
+  },
+  {
+    name: "f()",
+ ctor: function(v) { var o = function() { return v;}; o.a = v; return o; },
+    args: function(i) { return [1.5 + i]; },
+  },
+  {
+    name: "f().bind",
+ ctor: function(v) { var o = function(a,b,c) { return a+b+c; }; o = o.bind(o, v, v+1, v+2.2); return o; },
+    args: function(i) { return [1.5 + i]; },
+  },
+  {
+    name: "dictionary elements",
+    ctor: function(v) { var o = []; o[1] = v; o[200000] = v; return o; },
+    args: function(i) { return [1.5 + i]; },
+  },
+  {
+    name: "json",
+ ctor: function(v) { var json = '{"a":' + v + ',"b":' + v + '}'; return JSON.parse(json); },
+    args: function(i) { return [1.5 + i]; },
+  },
+  {
+    name: "fast accessors",
+    accessor: {
+        get: function() { return this.a_; },
+        set: function(value) {this.a_ = value; },
+        configurable: true,
+    },
+    ctor: function(v) {
+      var o = {a_:v};
+      Object.defineProperty(o, "a", this.accessor);
+      return o;
+    },
+    args: function(i) { return [1.5 + i]; },
+  },
+  {
+    name: "slow accessor",
+    accessor1: { value: this.a_, configurable: true },
+    accessor2: {
+        get: function() { return this.a_; },
+        set: function(value) {this.a_ = value; },
+        configurable: true,
+    },
+    ctor: function(v) {
+      var o = {a_:v};
+      Object.defineProperty(o, "a", this.accessor1);
+      Object.defineProperty(o, "a", this.accessor2);
+      return o;
+    },
+    args: function(i) { return [1.5 + i]; },
+  },
+  {
+    name: "slow",
+    proto: {},
+    ctor: function(v) {
+      var o = {__proto__: this.proto};
+      o.a = v;
+      for (var i = 0; %HasFastProperties(o); i++) o["f"+i] = v;
+      return o;
+    },
+    args: function(i) { return [1.5 + i]; },
+  },
+  {
+    name: "global",
+    ctor: function(v) { return global; },
+    args: function(i) { return [i]; },
+  },
+];
+
+
+
+var uses = [
+  {
+    name: "o.a+1.0",
+    use1: function(o, i) { return o.a + 1.0; },
+    use2: function(o, i) { return o.a + 1.1; },
+  },
+  {
+    name: "o.b+1.0",
+    use1: function(o, i) { return o.b + 1.0; },
+    use2: function(o, i) { return o.b + 1.1; },
+  },
+  {
+    name: "o[1]+1.0",
+    use1: function(o, i) { return o[1] + 1.0; },
+    use2: function(o, i) { return o[1] + 1.1; },
+  },
+  {
+    name: "o[-1]+1.0",
+    use1: function(o, i) { return o[-1] + 1.0; },
+    use2: function(o, i) { return o[-1] + 1.1; },
+  },
+  {
+    name: "()",
+    use1: function(o, i) { return o() + 1.0; },
+    use2: function(o, i) { return o() + 1.1; },
+  },
+];
+
+
+
+var migrations = [
+  {
+    name: "to smi",
+    migr: function(o, i) { if (i == 0) o.a = 1; },
+  },
+  {
+    name: "to double",
+    migr: function(o, i) { if (i == 0) o.a = 1.1; },
+  },
+  {
+    name: "to object",
+    migr: function(o, i) { if (i == 0) o.a = {}; },
+  },
+  {
+    name: "set prototype {}",
+    migr: function(o, i) { o.__proto__ = {}; },
+  },
+  {
+    name: "%FunctionSetPrototype",
+    migr: function(o, i) { %FunctionSetPrototype(o, null); },
+  },
+  {
+    name: "modify prototype",
+ migr: function(o, i) { if (i == 0) o.__proto__.__proto1__ = [,,,5,,,]; },
+  },
+  {
+    name: "freeze prototype",
+    migr: function(o, i) { if (i == 0) Object.freeze(o.__proto__); },
+  },
+  {
+    name: "delete and re-add property",
+    migr: function(o, i) { var v = o.a; delete o.a; o.a = v; },
+  },
+  {
+    name: "modify prototype",
+    migr: function(o, i) { if (i >= 0) o.__proto__ = {}; },
+  },
+  {
+    name: "set property callback",
+    migr: function(o, i) {
+      Object.defineProperty(o, "a", {
+        get: function() { return 1.5 + i; },
+        set: function(value) {},
+        configurable: true,
+      });
+    },
+  },
+  {
+    name: "observe",
+    migr: function(o, i) { Object.observe(o, function(){}); },
+  },
+  {
+    name: "%EnableAccessChecks",
+    migr: function(o, i) {
+      if (typeof (o) !== 'function') %EnableAccessChecks(o);
+    },
+  },
+  {
+    name: "%DisableAccessChecks",
+    migr: function(o, i) {
+ if ((typeof (o) !== 'function') && (o !== global)) %DisableAccessChecks(o);
+    },
+  },
+  {
+    name: "seal",
+    migr: function(o, i) { Object.seal(o); },
+  },
+ { // Must be the last in the sequence, because after the global object freeze
+    // the other modifications does not make sence.
+    name: "freeze",
+    migr: function(o, i) { Object.freeze(o); },
+  },
+];
+
+
+
+migrations.forEach(function(migr) {
+  uses.forEach(function(use) {
+    ctors.forEach(function(ctor) {
+      test(ctor, use, migr);
+    });
+  });
+});
=======================================
--- /branches/bleeding_edge/include/v8.h        Mon Jun 30 13:35:16 2014 UTC
+++ /branches/bleeding_edge/include/v8.h        Tue Jul  1 15:02:31 2014 UTC
@@ -5587,7 +5587,7 @@
   static const int kNullValueRootIndex = 7;
   static const int kTrueValueRootIndex = 8;
   static const int kFalseValueRootIndex = 9;
-  static const int kEmptyStringRootIndex = 160;
+  static const int kEmptyStringRootIndex = 161;

// The external allocation limit should be below 256 MB on all architectures
   // to avoid that resource-constrained embedders run low on memory.
@@ -5602,10 +5602,10 @@
   static const int kNodeIsIndependentShift = 4;
   static const int kNodeIsPartiallyDependentShift = 5;

-  static const int kJSObjectType = 0xbb;
+  static const int kJSObjectType = 0xbc;
   static const int kFirstNonstringType = 0x80;
   static const int kOddballType = 0x83;
-  static const int kForeignType = 0x87;
+  static const int kForeignType = 0x88;

   static const int kUndefinedOddballKind = 5;
   static const int kNullOddballKind = 3;
=======================================
--- /branches/bleeding_edge/src/arm/macro-assembler-arm.cc Mon Jun 30 13:25:46 2014 UTC +++ /branches/bleeding_edge/src/arm/macro-assembler-arm.cc Tue Jul 1 15:02:31 2014 UTC
@@ -3274,14 +3274,19 @@
                                         Register scratch2,
                                         Register heap_number_map,
                                         Label* gc_required,
-                                        TaggingMode tagging_mode) {
+                                        TaggingMode tagging_mode,
+                                        MutableMode mode) {
// Allocate an object in the heap for the heap number and tag it as a heap
   // object.
   Allocate(HeapNumber::kSize, result, scratch1, scratch2, gc_required,
            tagging_mode == TAG_RESULT ? TAG_OBJECT : NO_ALLOCATION_FLAGS);

+  Heap::RootListIndex map_index = mode == MUTABLE
+      ? Heap::kMutableHeapNumberMapRootIndex
+      : Heap::kHeapNumberMapRootIndex;
+  AssertIsRoot(heap_number_map, map_index);
+
   // Store heap number map in the allocated object.
-  AssertIsRoot(heap_number_map, Heap::kHeapNumberMapRootIndex);
   if (tagging_mode == TAG_RESULT) {
     str(heap_number_map, FieldMemOperand(result, HeapObject::kMapOffset));
   } else {
=======================================
--- /branches/bleeding_edge/src/arm/macro-assembler-arm.h Mon Jun 30 13:25:46 2014 UTC +++ /branches/bleeding_edge/src/arm/macro-assembler-arm.h Tue Jul 1 15:02:31 2014 UTC
@@ -778,7 +778,8 @@
                           Register scratch2,
                           Register heap_number_map,
                           Label* gc_required,
-                          TaggingMode tagging_mode = TAG_RESULT);
+                          TaggingMode tagging_mode = TAG_RESULT,
+                          MutableMode mode = IMMUTABLE);
   void AllocateHeapNumberWithValue(Register result,
                                    DwVfpRegister value,
                                    Register scratch1,
=======================================
--- /branches/bleeding_edge/src/arm/stub-cache-arm.cc Tue Jul 1 12:12:34 2014 UTC +++ /branches/bleeding_edge/src/arm/stub-cache-arm.cc Tue Jul 1 15:02:31 2014 UTC
@@ -426,8 +426,9 @@
     }
   } else if (representation.IsDouble()) {
     Label do_store, heap_number;
-    __ LoadRoot(scratch3, Heap::kHeapNumberMapRootIndex);
-    __ AllocateHeapNumber(storage_reg, scratch1, scratch2, scratch3, slow);
+    __ LoadRoot(scratch3, Heap::kMutableHeapNumberMapRootIndex);
+    __ AllocateHeapNumber(storage_reg, scratch1, scratch2, scratch3, slow,
+                          TAG_RESULT, MUTABLE);

     __ JumpIfNotSmi(value_reg, &heap_number);
     __ SmiUntag(scratch1, value_reg);
=======================================
--- /branches/bleeding_edge/src/arm64/macro-assembler-arm64.cc Tue Jul 1 13:50:46 2014 UTC +++ /branches/bleeding_edge/src/arm64/macro-assembler-arm64.cc Tue Jul 1 15:02:31 2014 UTC
@@ -3570,7 +3570,8 @@
                                         Register scratch1,
                                         Register scratch2,
                                         CPURegister value,
-                                        CPURegister heap_number_map) {
+                                        CPURegister heap_number_map,
+                                        MutableMode mode) {
   ASSERT(!value.IsValid() || value.Is64Bits());
   UseScratchRegisterScope temps(this);

@@ -3579,6 +3580,10 @@
   Allocate(HeapNumber::kSize, result, scratch1, scratch2, gc_required,
            NO_ALLOCATION_FLAGS);

+  Heap::RootListIndex map_index = mode == MUTABLE
+      ? Heap::kMutableHeapNumberMapRootIndex
+      : Heap::kHeapNumberMapRootIndex;
+
   // Prepare the heap number map.
   if (!heap_number_map.IsValid()) {
// If we have a valid value register, use the same type of register to store
@@ -3588,7 +3593,7 @@
     } else {
       heap_number_map = scratch1;
     }
-    LoadRoot(heap_number_map, Heap::kHeapNumberMapRootIndex);
+    LoadRoot(heap_number_map, map_index);
   }
   if (emit_debug_code()) {
     Register map;
@@ -3598,7 +3603,7 @@
     } else {
       map = Register(heap_number_map);
     }
-    AssertRegisterIsRoot(map, Heap::kHeapNumberMapRootIndex);
+    AssertRegisterIsRoot(map, map_index);
   }

   // Store the heap number map and the value in the allocated object.
=======================================
--- /branches/bleeding_edge/src/arm64/macro-assembler-arm64.h Tue Jul 1 13:33:22 2014 UTC +++ /branches/bleeding_edge/src/arm64/macro-assembler-arm64.h Tue Jul 1 15:02:31 2014 UTC
@@ -1372,7 +1372,8 @@
                           Register scratch1,
                           Register scratch2,
                           CPURegister value = NoFPReg,
-                          CPURegister heap_number_map = NoReg);
+                          CPURegister heap_number_map = NoReg,
+                          MutableMode mode = IMMUTABLE);

// ---------------------------------------------------------------------------
   // Support functions.
=======================================
--- /branches/bleeding_edge/src/arm64/stub-cache-arm64.cc Tue Jul 1 12:12:34 2014 UTC +++ /branches/bleeding_edge/src/arm64/stub-cache-arm64.cc Tue Jul 1 15:02:31 2014 UTC
@@ -399,7 +399,8 @@
__ Ldr(temp_double, FieldMemOperand(value_reg, HeapNumber::kValueOffset));

     __ Bind(&do_store);
- __ AllocateHeapNumber(storage_reg, slow, scratch1, scratch2, temp_double); + __ AllocateHeapNumber(storage_reg, slow, scratch1, scratch2, temp_double,
+                          NoReg, MUTABLE);
   }

// Stub never generated for non-global objects that require access checks.
=======================================
--- /branches/bleeding_edge/src/deoptimizer.cc  Mon Jun 30 13:25:46 2014 UTC
+++ /branches/bleeding_edge/src/deoptimizer.cc  Tue Jul  1 15:02:31 2014 UTC
@@ -1813,9 +1813,11 @@
     Handle<Map> map = Map::GeneralizeAllFieldRepresentations(
         Handle<Map>::cast(MaterializeNextValue()));
     switch (map->instance_type()) {
+      case MUTABLE_HEAP_NUMBER_TYPE:
       case HEAP_NUMBER_TYPE: {
         // Reuse the HeapNumber value directly as it is already properly
-        // tagged and skip materializing the HeapNumber explicitly.
+ // tagged and skip materializing the HeapNumber explicitly. Turn mutable
+        // heap numbers immutable.
         Handle<Object> object = MaterializeNextValue();
         if (object_index < prev_materialized_count_) {
           materialized_objects_->Add(Handle<Object>(
@@ -1877,6 +1879,9 @@
 Handle<Object> Deoptimizer::MaterializeNextValue() {
   int value_index = materialization_value_index_++;
   Handle<Object> value = materialized_values_->at(value_index);
+  if (value->IsMutableHeapNumber()) {
+    HeapNumber::cast(*value)->set_map(isolate_->heap()->heap_number_map());
+  }
   if (*value == isolate_->heap()->arguments_marker()) {
     value = MaterializeNextHeapObject();
   }
@@ -3383,6 +3388,7 @@
       // TODO(jarin) this should be unified with the code in
       // Deoptimizer::MaterializeNextHeapObject()
       switch (map->instance_type()) {
+        case MUTABLE_HEAP_NUMBER_TYPE:
         case HEAP_NUMBER_TYPE: {
           // Reuse the HeapNumber value directly as it is already properly
           // tagged and skip materializing the HeapNumber explicitly.
=======================================
--- /branches/bleeding_edge/src/factory.cc      Tue Jul  1 12:12:34 2014 UTC
+++ /branches/bleeding_edge/src/factory.cc      Tue Jul  1 15:02:31 2014 UTC
@@ -1008,7 +1008,7 @@
   // We need to distinguish the minus zero value and this cannot be
   // done after conversion to int. Doing this by comparing bit
   // patterns is faster than using fpclassify() et al.
-  if (IsMinusZero(value)) return NewHeapNumber(-0.0, pretenure);
+  if (IsMinusZero(value)) return NewHeapNumber(-0.0, IMMUTABLE, pretenure);

   int int_value = FastD2I(value);
   if (value == int_value && Smi::IsValid(int_value)) {
@@ -1016,15 +1016,15 @@
   }

   // Materialize the value in the heap.
-  return NewHeapNumber(value, pretenure);
+  return NewHeapNumber(value, IMMUTABLE, pretenure);
 }


 Handle<Object> Factory::NewNumberFromInt(int32_t value,
                                          PretenureFlag pretenure) {
   if (Smi::IsValid(value)) return handle(Smi::FromInt(value), isolate());
-  // Bypass NumberFromDouble to avoid various redundant checks.
-  return NewHeapNumber(FastI2D(value), pretenure);
+  // Bypass NewNumber to avoid various redundant checks.
+  return NewHeapNumber(FastI2D(value), IMMUTABLE, pretenure);
 }


@@ -1034,15 +1034,17 @@
   if (int32v >= 0 && Smi::IsValid(int32v)) {
     return handle(Smi::FromInt(int32v), isolate());
   }
-  return NewHeapNumber(FastUI2D(value), pretenure);
+  return NewHeapNumber(FastUI2D(value), IMMUTABLE, pretenure);
 }


 Handle<HeapNumber> Factory::NewHeapNumber(double value,
+                                          MutableMode mode,
                                           PretenureFlag pretenure) {
   CALL_HEAP_FUNCTION(
       isolate(),
-      isolate()->heap()->AllocateHeapNumber(value, pretenure), HeapNumber);
+      isolate()->heap()->AllocateHeapNumber(value, mode, pretenure),
+      HeapNumber);
 }


=======================================
--- /branches/bleeding_edge/src/factory.h       Tue Jul  1 12:12:34 2014 UTC
+++ /branches/bleeding_edge/src/factory.h       Tue Jul  1 15:02:31 2014 UTC
@@ -352,9 +352,9 @@
     return NewNumber(static_cast<double>(value), pretenure);
   }
   Handle<HeapNumber> NewHeapNumber(double value,
+                                   MutableMode mode = IMMUTABLE,
                                    PretenureFlag pretenure = NOT_TENURED);

-
   // These objects are used by the api to create env-independent data
   // structures in the heap.
   inline Handle<JSObject> NewNeanderObject() {
=======================================
--- /branches/bleeding_edge/src/heap-snapshot-generator.cc Tue Jul 1 12:12:34 2014 UTC +++ /branches/bleeding_edge/src/heap-snapshot-generator.cc Tue Jul 1 15:02:31 2014 UTC
@@ -1641,6 +1641,8 @@
     for (int i = 0; i < real_size; i++) {
       switch (descs->GetType(i)) {
         case FIELD: {
+          Representation r = descs->GetDetails(i).representation();
+          if (r.IsSmi() || r.IsDouble()) break;
           int index = descs->GetFieldIndex(i);

           Name* k = descs->GetKey(i);
=======================================
--- /branches/bleeding_edge/src/heap.cc Mon Jun 30 13:25:46 2014 UTC
+++ /branches/bleeding_edge/src/heap.cc Tue Jul  1 15:02:31 2014 UTC
@@ -2528,6 +2528,8 @@

     ALLOCATE_VARSIZE_MAP(FIXED_ARRAY_TYPE, scope_info)
     ALLOCATE_MAP(HEAP_NUMBER_TYPE, HeapNumber::kSize, heap_number)
+    ALLOCATE_MAP(
+        MUTABLE_HEAP_NUMBER_TYPE, HeapNumber::kSize, mutable_heap_number)
     ALLOCATE_MAP(SYMBOL_TYPE, Symbol::kSize, symbol)
     ALLOCATE_MAP(FOREIGN_TYPE, Foreign::kSize, foreign)

@@ -2652,6 +2654,7 @@


 AllocationResult Heap::AllocateHeapNumber(double value,
+                                          MutableMode mode,
                                           PretenureFlag pretenure) {
   // Statically ensure that it is safe to allocate heap numbers in paged
   // spaces.
@@ -2665,7 +2668,8 @@
     if (!allocation.To(&result)) return allocation;
   }

-  result->set_map_no_write_barrier(heap_number_map());
+ Map* map = mode == MUTABLE ? mutable_heap_number_map() : heap_number_map();
+  HeapObject::cast(result)->set_map_no_write_barrier(map);
   HeapNumber::cast(result)->set_value(value);
   return result;
 }
@@ -2771,12 +2775,13 @@
   HandleScope scope(isolate());
   Factory* factory = isolate()->factory();

-  // The -0 value must be set before NumberFromDouble works.
-  set_minus_zero_value(*factory->NewHeapNumber(-0.0, TENURED));
+  // The -0 value must be set before NewNumber works.
+  set_minus_zero_value(*factory->NewHeapNumber(-0.0, IMMUTABLE, TENURED));
   ASSERT(std::signbit(minus_zero_value()->Number()) != 0);

-  set_nan_value(*factory->NewHeapNumber(base::OS::nan_value(), TENURED));
-  set_infinity_value(*factory->NewHeapNumber(V8_INFINITY, TENURED));
+  set_nan_value(
+      *factory->NewHeapNumber(base::OS::nan_value(), IMMUTABLE, TENURED));
+ set_infinity_value(*factory->NewHeapNumber(V8_INFINITY, IMMUTABLE, TENURED));

   // The hole has not been created yet, but we want to put something
// predictable in the gaps in the string table, so lets make that Smi zero.
=======================================
--- /branches/bleeding_edge/src/heap.h  Mon Jun 30 13:25:46 2014 UTC
+++ /branches/bleeding_edge/src/heap.h  Tue Jul  1 15:02:31 2014 UTC
@@ -42,6 +42,7 @@
V(Map, shared_function_info_map, SharedFunctionInfoMap) \ V(Map, meta_map, MetaMap) \ V(Map, heap_number_map, HeapNumberMap) \ + V(Map, mutable_heap_number_map, MutableHeapNumberMap) \ V(Map, native_context_map, NativeContextMap) \ V(Map, fixed_array_map, FixedArrayMap) \ V(Map, code_map, CodeMap) \
@@ -230,6 +231,7 @@
   V(shared_function_info_map)             \
   V(meta_map)                             \
   V(heap_number_map)                      \
+  V(mutable_heap_number_map)              \
   V(native_context_map)                   \
   V(fixed_array_map)                      \
   V(code_map)                             \
@@ -1460,7 +1462,9 @@

   // Allocated a HeapNumber from value.
   MUST_USE_RESULT AllocationResult AllocateHeapNumber(
-      double value, PretenureFlag pretenure = NOT_TENURED);
+      double value,
+      MutableMode mode = IMMUTABLE,
+      PretenureFlag pretenure = NOT_TENURED);

   // Allocate a byte array of the specified length
   MUST_USE_RESULT AllocationResult AllocateByteArray(
=======================================
--- /branches/bleeding_edge/src/hydrogen.cc     Tue Jul  1 14:52:14 2014 UTC
+++ /branches/bleeding_edge/src/hydrogen.cc     Tue Jul  1 15:02:31 2014 UTC
@@ -5781,8 +5781,9 @@
       HInstruction* heap_number = Add<HAllocate>(heap_number_size,
           HType::HeapObject(),
           NOT_TENURED,
-          HEAP_NUMBER_TYPE);
- AddStoreMapConstant(heap_number, isolate()->factory()->heap_number_map());
+          MUTABLE_HEAP_NUMBER_TYPE);
+      AddStoreMapConstant(
+          heap_number, isolate()->factory()->mutable_heap_number_map());
Add<HStoreNamedField>(heap_number, HObjectAccess::ForHeapNumberValue(),
                             value);
       instr = New<HStoreNamedField>(checked_object->ActualValue(),
@@ -10950,11 +10951,14 @@
         // 2) we can just use the mode of the parent object for pretenuring
         HInstruction* double_box =
             Add<HAllocate>(heap_number_constant, HType::HeapObject(),
-                pretenure_flag, HEAP_NUMBER_TYPE);
+                pretenure_flag, MUTABLE_HEAP_NUMBER_TYPE);
         AddStoreMapConstant(double_box,
-            isolate()->factory()->heap_number_map());
- Add<HStoreNamedField>(double_box, HObjectAccess::ForHeapNumberValue(),
-                              Add<HConstant>(value));
+            isolate()->factory()->mutable_heap_number_map());
+        // Unwrap the mutable heap number from the boilerplate.
+        HValue* double_value =
+            Add<HConstant>(Handle<HeapNumber>::cast(value)->value());
+        Add<HStoreNamedField>(
+            double_box, HObjectAccess::ForHeapNumberValue(), double_value);
         value_instruction = double_box;
       } else if (representation.IsSmi()) {
         value_instruction = value->IsUninitialized()
=======================================
--- /branches/bleeding_edge/src/ia32/macro-assembler-ia32.cc Mon Jun 30 13:25:46 2014 UTC +++ /branches/bleeding_edge/src/ia32/macro-assembler-ia32.cc Tue Jul 1 15:02:31 2014 UTC
@@ -1683,14 +1683,18 @@
 void MacroAssembler::AllocateHeapNumber(Register result,
                                         Register scratch1,
                                         Register scratch2,
-                                        Label* gc_required) {
+                                        Label* gc_required,
+                                        MutableMode mode) {
   // Allocate heap number in new space.
   Allocate(HeapNumber::kSize, result, scratch1, scratch2, gc_required,
            TAG_OBJECT);

+  Handle<Map> map = mode == MUTABLE
+      ? isolate()->factory()->mutable_heap_number_map()
+      : isolate()->factory()->heap_number_map();
+
   // Set the map.
-  mov(FieldOperand(result, HeapObject::kMapOffset),
-      Immediate(isolate()->factory()->heap_number_map()));
+  mov(FieldOperand(result, HeapObject::kMapOffset), Immediate(map));
 }


=======================================
--- /branches/bleeding_edge/src/ia32/macro-assembler-ia32.h Mon Jun 30 10:19:31 2014 UTC +++ /branches/bleeding_edge/src/ia32/macro-assembler-ia32.h Tue Jul 1 15:02:31 2014 UTC
@@ -638,7 +638,8 @@
   void AllocateHeapNumber(Register result,
                           Register scratch1,
                           Register scratch2,
-                          Label* gc_required);
+                          Label* gc_required,
+                          MutableMode mode = IMMUTABLE);

// Allocate a sequential string. All the header fields of the string object
   // are initialized.
=======================================
--- /branches/bleeding_edge/src/ia32/stub-cache-ia32.cc Tue Jul 1 12:12:34 2014 UTC +++ /branches/bleeding_edge/src/ia32/stub-cache-ia32.cc Tue Jul 1 15:02:31 2014 UTC
@@ -523,7 +523,7 @@
     }
   } else if (representation.IsDouble()) {
     Label do_store, heap_number;
-    __ AllocateHeapNumber(storage_reg, scratch1, scratch2, slow);
+    __ AllocateHeapNumber(storage_reg, scratch1, scratch2, slow, MUTABLE);

     __ JumpIfNotSmi(value_reg, &heap_number);
     __ SmiUntag(value_reg);
=======================================
--- /branches/bleeding_edge/src/json-parser.h   Mon Jun 30 13:25:46 2014 UTC
+++ /branches/bleeding_edge/src/json-parser.h   Tue Jul  1 15:02:31 2014 UTC
@@ -387,11 +387,9 @@
Representation expected_representation = details.representation();

           if (value->FitsRepresentation(expected_representation)) {
- // If the target representation is double and the value is already
-            // double, use the existing box.
-            if (value->IsSmi() && expected_representation.IsDouble()) {
-              value = factory()->NewHeapNumber(
-                  Handle<Smi>::cast(value)->value());
+            if (expected_representation.IsDouble()) {
+              value = Object::NewStorageFor(isolate(), value,
+                                            expected_representation);
             } else if (expected_representation.IsHeapObject() &&
                        !target->instance_descriptors()->GetFieldType(
                            descriptor)->NowContains(value)) {
=======================================
--- /branches/bleeding_edge/src/json-stringifier.h Mon Jun 30 10:19:31 2014 UTC +++ /branches/bleeding_edge/src/json-stringifier.h Tue Jul 1 15:02:31 2014 UTC
@@ -407,6 +407,7 @@

   switch (HeapObject::cast(*object)->map()->instance_type()) {
     case HEAP_NUMBER_TYPE:
+    case MUTABLE_HEAP_NUMBER_TYPE:
       if (deferred_string_key) SerializeDeferredKey(comma, key);
       return SerializeHeapNumber(Handle<HeapNumber>::cast(object));
     case ODDBALL_TYPE:
=======================================
--- /branches/bleeding_edge/src/mark-compact.cc Mon Jun 30 13:25:46 2014 UTC
+++ /branches/bleeding_edge/src/mark-compact.cc Tue Jul  1 15:02:31 2014 UTC
@@ -292,6 +292,7 @@
           case CODE_TYPE:
           case FIXED_DOUBLE_ARRAY_TYPE:
           case HEAP_NUMBER_TYPE:
+          case MUTABLE_HEAP_NUMBER_TYPE:
           case INTERCEPTOR_INFO_TYPE:
           case ODDBALL_TYPE:
           case SCRIPT_TYPE:
=======================================
--- /branches/bleeding_edge/src/mips/macro-assembler-mips.cc Mon Jun 30 13:25:46 2014 UTC +++ /branches/bleeding_edge/src/mips/macro-assembler-mips.cc Tue Jul 1 15:02:31 2014 UTC
@@ -3274,14 +3274,19 @@
                                         Register scratch2,
                                         Register heap_number_map,
                                         Label* need_gc,
-                                        TaggingMode tagging_mode) {
+                                        TaggingMode tagging_mode,
+                                        MutableMode mode) {
// Allocate an object in the heap for the heap number and tag it as a heap
   // object.
   Allocate(HeapNumber::kSize, result, scratch1, scratch2, need_gc,
            tagging_mode == TAG_RESULT ? TAG_OBJECT : NO_ALLOCATION_FLAGS);

+  Heap::RootListIndex map_index = mode == MUTABLE
+      ? Heap::kMutableHeapNumberMapRootIndex
+      : Heap::kHeapNumberMapRootIndex;
+  AssertIsRoot(heap_number_map, map_index);
+
   // Store heap number map in the allocated object.
-  AssertIsRoot(heap_number_map, Heap::kHeapNumberMapRootIndex);
   if (tagging_mode == TAG_RESULT) {
     sw(heap_number_map, FieldMemOperand(result, HeapObject::kMapOffset));
   } else {
=======================================
--- /branches/bleeding_edge/src/mips/macro-assembler-mips.h Mon Jun 30 13:25:46 2014 UTC +++ /branches/bleeding_edge/src/mips/macro-assembler-mips.h Tue Jul 1 15:02:31 2014 UTC
@@ -546,7 +546,8 @@
                           Register scratch2,
                           Register heap_number_map,
                           Label* gc_required,
-                          TaggingMode tagging_mode = TAG_RESULT);
+                          TaggingMode tagging_mode = TAG_RESULT,
+                          MutableMode mode = IMMUTABLE);
   void AllocateHeapNumberWithValue(Register result,
                                    FPURegister value,
                                    Register scratch1,
=======================================
--- /branches/bleeding_edge/src/mips/stub-cache-mips.cc Mon Jun 30 10:19:31 2014 UTC +++ /branches/bleeding_edge/src/mips/stub-cache-mips.cc Tue Jul 1 15:02:31 2014 UTC
@@ -413,8 +413,9 @@
     }
   } else if (representation.IsDouble()) {
     Label do_store, heap_number;
-    __ LoadRoot(scratch3, Heap::kHeapNumberMapRootIndex);
-    __ AllocateHeapNumber(storage_reg, scratch1, scratch2, scratch3, slow);
+    __ LoadRoot(scratch3, Heap::kMutableHeapNumberMapRootIndex);
+    __ AllocateHeapNumber(storage_reg, scratch1, scratch2, scratch3, slow,
+                          TAG_RESULT, MUTABLE);

     __ JumpIfNotSmi(value_reg, &heap_number);
     __ SmiUntag(scratch1, value_reg);
=======================================
--- /branches/bleeding_edge/src/objects-debug.cc Mon Jun 30 10:19:31 2014 UTC +++ /branches/bleeding_edge/src/objects-debug.cc Tue Jul 1 15:02:31 2014 UTC
@@ -54,6 +54,7 @@
       Map::cast(this)->MapVerify();
       break;
     case HEAP_NUMBER_TYPE:
+    case MUTABLE_HEAP_NUMBER_TYPE:
       HeapNumber::cast(this)->HeapNumberVerify();
       break;
     case FIXED_ARRAY_TYPE:
@@ -205,7 +206,7 @@


 void HeapNumber::HeapNumberVerify() {
-  CHECK(IsHeapNumber());
+  CHECK(IsHeapNumber() || IsMutableHeapNumber());
 }


@@ -263,7 +264,7 @@
         Representation r = descriptors->GetDetails(i).representation();
         FieldIndex index = FieldIndex::ForDescriptor(map(), i);
         Object* value = RawFastPropertyAt(index);
-        if (r.IsDouble()) ASSERT(value->IsHeapNumber());
+        if (r.IsDouble()) ASSERT(value->IsMutableHeapNumber());
         if (value->IsUninitialized()) continue;
         if (r.IsSmi()) ASSERT(value->IsSmi());
         if (r.IsHeapObject()) ASSERT(value->IsHeapObject());
=======================================
--- /branches/bleeding_edge/src/objects-inl.h   Tue Jul  1 12:12:34 2014 UTC
+++ /branches/bleeding_edge/src/objects-inl.h   Tue Jul  1 15:02:31 2014 UTC
@@ -165,6 +165,7 @@


 TYPE_CHECKER(HeapNumber, HEAP_NUMBER_TYPE)
+TYPE_CHECKER(MutableHeapNumber, MUTABLE_HEAP_NUMBER_TYPE)
 TYPE_CHECKER(Symbol, SYMBOL_TYPE)


@@ -277,10 +278,27 @@
     return handle(Smi::FromInt(0), isolate);
   }
   if (!representation.IsDouble()) return object;
+  double value;
   if (object->IsUninitialized()) {
-    return isolate->factory()->NewHeapNumber(0);
+    value = 0;
+  } else if (object->IsMutableHeapNumber()) {
+    value = HeapNumber::cast(*object)->value();
+  } else {
+    value = object->Number();
+  }
+  return isolate->factory()->NewHeapNumber(value, MUTABLE);
+}
+
+
+Handle<Object> Object::WrapForRead(Isolate* isolate,
+                                   Handle<Object> object,
+                                   Representation representation) {
+  ASSERT(!object->IsUninitialized());
+  if (!representation.IsDouble()) {
+    ASSERT(object->FitsRepresentation(representation));
+    return object;
   }
-  return isolate->factory()->NewHeapNumber(object->Number());
+ return isolate->factory()->NewHeapNumber(HeapNumber::cast(*object)->value());
 }


@@ -3079,7 +3097,6 @@
 CAST_ACCESSOR(Foreign)
 CAST_ACCESSOR(FreeSpace)
 CAST_ACCESSOR(GlobalObject)
-CAST_ACCESSOR(HeapNumber)
 CAST_ACCESSOR(HeapObject)
 CAST_ACCESSOR(JSArray)
 CAST_ACCESSOR(JSArrayBuffer)
@@ -5949,6 +5966,18 @@
 ACCESSORS(JSValue, value, Object, kValueOffset)


+HeapNumber* HeapNumber::cast(Object* object) {
+  SLOW_ASSERT(object->IsHeapNumber() || object->IsMutableHeapNumber());
+  return reinterpret_cast<HeapNumber*>(object);
+}
+
+
+const HeapNumber* HeapNumber::cast(const Object* object) {
+  SLOW_ASSERT(object->IsHeapNumber() || object->IsMutableHeapNumber());
+  return reinterpret_cast<const HeapNumber*>(object);
+}
+
+
 ACCESSORS(JSDate, value, Object, kValueOffset)
 ACCESSORS(JSDate, cache_stamp, Object, kCacheStampOffset)
 ACCESSORS(JSDate, year, Object, kYearOffset)
=======================================
--- /branches/bleeding_edge/src/objects-printer.cc Mon Jun 30 10:19:31 2014 UTC +++ /branches/bleeding_edge/src/objects-printer.cc Tue Jul 1 15:02:31 2014 UTC
@@ -64,6 +64,11 @@
     case HEAP_NUMBER_TYPE:
       HeapNumber::cast(this)->HeapNumberPrint(out);
       break;
+    case MUTABLE_HEAP_NUMBER_TYPE:
+      PrintF(out, "<mutable ");
+      HeapNumber::cast(this)->HeapNumberPrint(out);
+      PrintF(out, ">");
+      break;
     case FIXED_DOUBLE_ARRAY_TYPE:
       FixedDoubleArray::cast(this)->FixedDoubleArrayPrint(out);
       break;
=======================================
--- /branches/bleeding_edge/src/objects-visiting.cc Mon Jun 30 10:19:31 2014 UTC +++ /branches/bleeding_edge/src/objects-visiting.cc Tue Jul 1 15:02:31 2014 UTC
@@ -148,6 +148,7 @@
       return kVisitJSFunction;

     case HEAP_NUMBER_TYPE:
+    case MUTABLE_HEAP_NUMBER_TYPE:
#define EXTERNAL_ARRAY_CASE(Type, type, TYPE, ctype, size) \
     case EXTERNAL_##TYPE##_ARRAY_TYPE:

=======================================
--- /branches/bleeding_edge/src/objects.cc      Mon Jun 30 13:48:57 2014 UTC
+++ /branches/bleeding_edge/src/objects.cc      Tue Jul  1 15:02:31 2014 UTC
@@ -1540,6 +1540,11 @@
       HeapNumber::cast(this)->HeapNumberPrint(accumulator);
       accumulator->Put('>');
       break;
+    case MUTABLE_HEAP_NUMBER_TYPE:
+      accumulator->Add("<MutableNumber: ");
+      HeapNumber::cast(this)->HeapNumberPrint(accumulator);
+      accumulator->Put('>');
+      break;
     case JS_PROXY_TYPE:
       accumulator->Add("<JSProxy>");
       break;
@@ -1665,6 +1670,7 @@
       break;

     case HEAP_NUMBER_TYPE:
+    case MUTABLE_HEAP_NUMBER_TYPE:
     case FILLER_TYPE:
     case BYTE_ARRAY_TYPE:
     case FREE_SPACE_TYPE:
@@ -1706,7 +1712,7 @@


 void HeapNumber::HeapNumberPrint(FILE* out) {
-  PrintF(out, "%.16g", Number());
+  PrintF(out, "%.16g", value());
 }


@@ -1718,7 +1724,7 @@
   // print that using vsnprintf (which may truncate but never allocate if
   // there is no more space in the buffer).
   EmbeddedVector<char, 100> buffer;
-  SNPrintF(buffer, "%.16g", Number());
+  SNPrintF(buffer, "%.16g", value());
   accumulator->Add("%s", buffer.start());
 }

@@ -2070,8 +2076,8 @@
   DescriptorArray* new_desc = target->instance_descriptors();
   int limit = NumberOfOwnDescriptors();
   for (int i = 0; i < limit; i++) {
-    if (new_desc->GetDetails(i).representation().IsDouble() &&
-        !old_desc->GetDetails(i).representation().IsDouble()) {
+    if (new_desc->GetDetails(i).representation().IsDouble() !=
+        old_desc->GetDetails(i).representation().IsDouble()) {
       return true;
     }
   }
@@ -2168,7 +2174,7 @@
     PropertyDetails details = new_map->GetLastDescriptorDetails();
     Handle<Object> value;
     if (details.representation().IsDouble()) {
-      value = isolate->factory()->NewHeapNumber(0);
+      value = isolate->factory()->NewHeapNumber(0, MUTABLE);
     } else {
       value = isolate->factory()->uninitialized_value();
     }
@@ -2216,6 +2222,9 @@
         value = handle(Smi::FromInt(0), isolate);
       }
value = Object::NewStorageFor(isolate, value, details.representation());
+    } else if (old_details.representation().IsDouble() &&
+               !details.representation().IsDouble()) {
+ value = Object::WrapForRead(isolate, value, old_details.representation());
     }
     ASSERT(!(details.representation().IsDouble() && value->IsSmi()));
     int target_index = new_descriptors->GetFieldIndex(i) - inobject;
@@ -2228,7 +2237,7 @@
     if (details.type() != FIELD) continue;
     Handle<Object> value;
     if (details.representation().IsDouble()) {
-      value = isolate->factory()->NewHeapNumber(0);
+      value = isolate->factory()->NewHeapNumber(0, MUTABLE);
     } else {
       value = isolate->factory()->uninitialized_value();
     }
@@ -3975,6 +3984,7 @@
     // Nothing more to be done.
     if (value->IsUninitialized()) return;
     HeapNumber* box = HeapNumber::cast(RawFastPropertyAt(index));
+    ASSERT(box->IsMutableHeapNumber());
     box->set_value(value->Number());
   } else {
     FastPropertyAtPut(index, value);
@@ -4644,6 +4654,11 @@
         FieldIndex index = FieldIndex::ForDescriptor(*map, i);
         Handle<Object> value(
             object->RawFastPropertyAt(index), isolate);
+        if (details.representation().IsDouble()) {
+          ASSERT(value->IsMutableHeapNumber());
+          Handle<HeapNumber> old = Handle<HeapNumber>::cast(value);
+          value = isolate->factory()->NewHeapNumber(old->value());
+        }
         PropertyDetails d =
             PropertyDetails(details.attributes(), NORMAL, i + 1);
         dictionary = NameDictionary::Add(dictionary, key, value, d);
@@ -5811,7 +5826,7 @@
                                         FieldIndex index) {
   Isolate* isolate = object->GetIsolate();
   Handle<Object> raw_value(object->RawFastPropertyAt(index), isolate);
-  return Object::NewStorageFor(isolate, raw_value, representation);
+  return Object::WrapForRead(isolate, raw_value, representation);
 }


@@ -7002,7 +7017,7 @@
         Object* property =
             RawFastPropertyAt(FieldIndex::ForDescriptor(map(), i));
         if (descs->GetDetails(i).representation().IsDouble()) {
-          ASSERT(property->IsHeapNumber());
+          ASSERT(property->IsMutableHeapNumber());
           if (value->IsNumber() && property->Number() == value->Number()) {
             return descs->GetKey(i);
           }
=======================================
--- /branches/bleeding_edge/src/objects.h       Tue Jul  1 12:12:34 2014 UTC
+++ /branches/bleeding_edge/src/objects.h       Tue Jul  1 15:02:31 2014 UTC
@@ -168,6 +168,12 @@
 };


+enum MutableMode {
+  MUTABLE,
+  IMMUTABLE
+};
+
+
 static const int kGrowICDelta = STORE_AND_GROW_NO_TRANSITION -
     STANDARD_STORE;
 STATIC_ASSERT(STANDARD_STORE == 0);
@@ -352,6 +358,7 @@
V(PROPERTY_CELL_TYPE) \ \ V(HEAP_NUMBER_TYPE) \ + V(MUTABLE_HEAP_NUMBER_TYPE) \ V(FOREIGN_TYPE) \ V(BYTE_ARRAY_TYPE) \ V(FREE_SPACE_TYPE) \
@@ -680,6 +687,7 @@
   // "Data", objects that cannot contain non-map-word pointers to heap
   // objects.
   HEAP_NUMBER_TYPE,
+  MUTABLE_HEAP_NUMBER_TYPE,
   FOREIGN_TYPE,
   BYTE_ARRAY_TYPE,
   FREE_SPACE_TYPE,
@@ -900,6 +908,7 @@

 #define HEAP_OBJECT_TYPE_LIST(V)               \
   V(HeapNumber)                                \
+  V(MutableHeapNumber)                         \
   V(Name)                                      \
   V(UniqueName)                                \
   V(String)                                    \
@@ -1427,7 +1436,7 @@
     } else if (FLAG_track_fields && representation.IsSmi()) {
       return IsSmi();
     } else if (FLAG_track_double_fields && representation.IsDouble()) {
-      return IsNumber();
+      return IsMutableHeapNumber() || IsNumber();
} else if (FLAG_track_heap_object_fields && representation.IsHeapObject()) {
       return IsHeapObject();
     }
@@ -1440,6 +1449,10 @@
                                              Handle<Object> object,
Representation representation);

+  inline static Handle<Object> WrapForRead(Isolate* isolate,
+                                           Handle<Object> object,
+                                           Representation representation);
+
   // Returns true if the object is of the correct type to be used as a
   // implementation of a JSObject's elements.
   inline bool HasValidElements();
=======================================
--- /branches/bleeding_edge/src/runtime.cc      Tue Jul  1 12:12:34 2014 UTC
+++ /branches/bleeding_edge/src/runtime.cc      Tue Jul  1 15:02:31 2014 UTC
@@ -14542,8 +14542,8 @@
                    object->properties()->length());
   }
Handle<Object> raw_value(object->RawFastPropertyAt(field_index), isolate);
-  RUNTIME_ASSERT(raw_value->IsNumber() || raw_value->IsUninitialized());
- return *Object::NewStorageFor(isolate, raw_value, Representation::Double());
+  RUNTIME_ASSERT(raw_value->IsMutableHeapNumber());
+ return *Object::WrapForRead(isolate, raw_value, Representation::Double());
 }


=======================================
--- /branches/bleeding_edge/src/x64/macro-assembler-x64.cc Mon Jun 30 13:25:46 2014 UTC +++ /branches/bleeding_edge/src/x64/macro-assembler-x64.cc Tue Jul 1 15:02:31 2014 UTC
@@ -4593,12 +4593,17 @@

 void MacroAssembler::AllocateHeapNumber(Register result,
                                         Register scratch,
-                                        Label* gc_required) {
+                                        Label* gc_required,
+                                        MutableMode mode) {
   // Allocate heap number in new space.
Allocate(HeapNumber::kSize, result, scratch, no_reg, gc_required, TAG_OBJECT);

+  Heap::RootListIndex map_index = mode == MUTABLE
+      ? Heap::kMutableHeapNumberMapRootIndex
+      : Heap::kHeapNumberMapRootIndex;
+
   // Set the map.
-  LoadRoot(kScratchRegister, Heap::kHeapNumberMapRootIndex);
+  LoadRoot(kScratchRegister, map_index);
   movp(FieldOperand(result, HeapObject::kMapOffset), kScratchRegister);
 }

=======================================
--- /branches/bleeding_edge/src/x64/macro-assembler-x64.h Mon Jun 30 10:19:31 2014 UTC +++ /branches/bleeding_edge/src/x64/macro-assembler-x64.h Tue Jul 1 15:02:31 2014 UTC
@@ -1186,7 +1186,8 @@
   // space is full.
   void AllocateHeapNumber(Register result,
                           Register scratch,
-                          Label* gc_required);
+                          Label* gc_required,
+                          MutableMode mode = IMMUTABLE);

// Allocate a sequential string. All the header fields of the string object
   // are initialized.
=======================================
--- /branches/bleeding_edge/src/x64/stub-cache-x64.cc Tue Jul 1 12:12:34 2014 UTC +++ /branches/bleeding_edge/src/x64/stub-cache-x64.cc Tue Jul 1 15:02:31 2014 UTC
@@ -489,7 +489,7 @@
     }
   } else if (representation.IsDouble()) {
     Label do_store, heap_number;
-    __ AllocateHeapNumber(storage_reg, scratch1, slow);
+    __ AllocateHeapNumber(storage_reg, scratch1, slow, MUTABLE);

     __ JumpIfNotSmi(value_reg, &heap_number);
     __ SmiToInteger32(scratch1, value_reg);
=======================================
--- /branches/bleeding_edge/src/x87/macro-assembler-x87.cc Mon Jun 30 13:25:46 2014 UTC +++ /branches/bleeding_edge/src/x87/macro-assembler-x87.cc Tue Jul 1 15:02:31 2014 UTC
@@ -1576,14 +1576,18 @@
 void MacroAssembler::AllocateHeapNumber(Register result,
                                         Register scratch1,
                                         Register scratch2,
-                                        Label* gc_required) {
+                                        Label* gc_required,
+                                        MutableMode mode) {
   // Allocate heap number in new space.
   Allocate(HeapNumber::kSize, result, scratch1, scratch2, gc_required,
            TAG_OBJECT);

+  Handle<Map> map = mode == MUTABLE
+      ? isolate()->factory()->mutable_heap_number_map()
+      : isolate()->factory()->heap_number_map();
+
   // Set the map.
-  mov(FieldOperand(result, HeapObject::kMapOffset),
-      Immediate(isolate()->factory()->heap_number_map()));
+  mov(FieldOperand(result, HeapObject::kMapOffset), Immediate(map));
 }


=======================================
--- /branches/bleeding_edge/src/x87/macro-assembler-x87.h Mon Jun 30 10:19:31 2014 UTC +++ /branches/bleeding_edge/src/x87/macro-assembler-x87.h Tue Jul 1 15:02:31 2014 UTC
@@ -617,7 +617,8 @@
   void AllocateHeapNumber(Register result,
                           Register scratch1,
                           Register scratch2,
-                          Label* gc_required);
+                          Label* gc_required,
+                          MutableMode mode = IMMUTABLE);

// Allocate a sequential string. All the header fields of the string object
   // are initialized.
=======================================
--- /branches/bleeding_edge/src/x87/stub-cache-x87.cc Tue Jul 1 13:34:18 2014 UTC +++ /branches/bleeding_edge/src/x87/stub-cache-x87.cc Tue Jul 1 15:02:31 2014 UTC
@@ -523,7 +523,7 @@
     }
   } else if (representation.IsDouble()) {
     Label do_store, heap_number;
-    __ AllocateHeapNumber(storage_reg, scratch1, scratch2, slow);
+    __ AllocateHeapNumber(storage_reg, scratch1, scratch2, slow, MUTABLE);

     __ JumpIfNotSmi(value_reg, &heap_number);
     __ SmiUntag(value_reg);
=======================================
--- /branches/bleeding_edge/test/cctest/test-heap-profiler.cc Tue Jul 1 12:12:34 2014 UTC +++ /branches/bleeding_edge/test/cctest/test-heap-profiler.cc Tue Jul 1 15:02:31 2014 UTC
@@ -1688,7 +1688,7 @@
   v8::HandleScope scope(env->GetIsolate());
   v8::HeapProfiler* heap_profiler = env->GetIsolate()->GetHeapProfiler();

-  CompileRun("a = { s_prop: \'value\', n_prop: 0.1 };");
+  CompileRun("a = { s_prop: \'value\', n_prop: \'value2\' };");
   const v8::HeapSnapshot* snapshot =
       heap_profiler->TakeHeapSnapshot(v8_str("value"));
   CHECK(ValidateSnapshot(snapshot));
@@ -1709,10 +1709,9 @@
   CHECK(js_s_prop == heap_profiler->FindObjectById(s_prop->GetId()));
   const v8::HeapGraphNode* n_prop =
       GetProperty(obj, v8::HeapGraphEdge::kProperty, "n_prop");
-  v8::Local<v8::Number> js_n_prop =
-      js_obj->Get(v8_str("n_prop")).As<v8::Number>();
-  CHECK(js_n_prop->NumberValue() ==
-        heap_profiler->FindObjectById(n_prop->GetId())->NumberValue());
+  v8::Local<v8::String> js_n_prop =
+      js_obj->Get(v8_str("n_prop")).As<v8::String>();
+  CHECK(js_n_prop == heap_profiler->FindObjectById(n_prop->GetId()));
 }


=======================================
--- /branches/bleeding_edge/test/mjsunit/mjsunit.status Tue Jul 1 08:32:47 2014 UTC +++ /branches/bleeding_edge/test/mjsunit/mjsunit.status Tue Jul 1 15:02:31 2014 UTC
@@ -87,6 +87,7 @@
##############################################################################
   # Skip long running tests that time out in debug mode.
   'generated-transition-stub': [PASS, ['mode == debug', SKIP]],
+  'migrations': [PASS, ['mode == debug', SLOW]],

##############################################################################
   # This test sets the umask on a per-process basis and hence cannot be

--
--
v8-dev mailing list
[email protected]
http://groups.google.com/group/v8-dev
--- You received this message because you are subscribed to the Google Groups "v8-dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
For more options, visit https://groups.google.com/d/optout.

Reply via email to