Use SameValueZero for Map and Set
authoradamk@chromium.org <adamk@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Wed, 21 May 2014 08:47:02 +0000 (08:47 +0000)
committeradamk@chromium.org <adamk@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Wed, 21 May 2014 08:47:02 +0000 (08:47 +0000)
Instead of normalizing the keys we use SameValueZero for the actual
comparison.

BUG=v8:1622
LOG=Y
R=mstarzinger@chromium.org

Review URL: https://codereview.chromium.org/299703004

Patch from Erik Arvidsson <arv@chromium.org>.

git-svn-id: https://v8.googlecode.com/svn/branches/bleeding_edge@21400 ce2b1a6d-e550-0410-aec6-3dcde31c8c00

src/collection.js
src/objects.cc
src/objects.h
tools/generate-runtime-tests.py

index fefc7a0..94125fb 100644 (file)
 var $Set = global.Set;
 var $Map = global.Map;
 
-// Global sentinel to be used instead of undefined keys, which are not
-// supported internally but required for Harmony sets and maps.
-var undefined_sentinel = {};
-
-
-// Map and Set uses SameValueZero which means that +0 and -0 should be treated
-// as the same value.
-function NormalizeKey(key) {
-  if (IS_UNDEFINED(key)) {
-    return undefined_sentinel;
-  }
-
-  if (key === 0) {
-    return 0;
-  }
-
-  return key;
-}
-
 
 // -------------------------------------------------------------------
 // Harmony Set
@@ -48,7 +29,7 @@ function SetAddJS(key) {
     throw MakeTypeError('incompatible_method_receiver',
                         ['Set.prototype.add', this]);
   }
-  return %SetAdd(this, NormalizeKey(key));
+  return %SetAdd(this, key);
 }
 
 
@@ -57,7 +38,7 @@ function SetHasJS(key) {
     throw MakeTypeError('incompatible_method_receiver',
                         ['Set.prototype.has', this]);
   }
-  return %SetHas(this, NormalizeKey(key));
+  return %SetHas(this, key);
 }
 
 
@@ -66,7 +47,6 @@ function SetDeleteJS(key) {
     throw MakeTypeError('incompatible_method_receiver',
                         ['Set.prototype.delete', this]);
   }
-  key = NormalizeKey(key);
   if (%SetHas(this, key)) {
     %SetDelete(this, key);
     return true;
@@ -154,7 +134,7 @@ function MapGetJS(key) {
     throw MakeTypeError('incompatible_method_receiver',
                         ['Map.prototype.get', this]);
   }
-  return %MapGet(this, NormalizeKey(key));
+  return %MapGet(this, key);
 }
 
 
@@ -163,7 +143,7 @@ function MapSetJS(key, value) {
     throw MakeTypeError('incompatible_method_receiver',
                         ['Map.prototype.set', this]);
   }
-  return %MapSet(this, NormalizeKey(key), value);
+  return %MapSet(this, key, value);
 }
 
 
@@ -172,7 +152,7 @@ function MapHasJS(key) {
     throw MakeTypeError('incompatible_method_receiver',
                         ['Map.prototype.has', this]);
   }
-  return %MapHas(this, NormalizeKey(key));
+  return %MapHas(this, key);
 }
 
 
@@ -181,7 +161,7 @@ function MapDeleteJS(key) {
     throw MakeTypeError('incompatible_method_receiver',
                         ['Map.prototype.delete', this]);
   }
-  return %MapDelete(this, NormalizeKey(key));
+  return %MapDelete(this, key);
 }
 
 
index 8e8830a..a1ca34e 100644 (file)
@@ -975,6 +975,25 @@ bool Object::SameValue(Object* other) {
 }
 
 
+bool Object::SameValueZero(Object* other) {
+  if (other == this) return true;
+
+  // The object is either a number, a name, an odd-ball,
+  // a real JS object, or a Harmony proxy.
+  if (IsNumber() && other->IsNumber()) {
+    double this_value = Number();
+    double other_value = other->Number();
+    // +0 == -0 is true
+    return this_value == other_value
+        || (std::isnan(this_value) && std::isnan(other_value));
+  }
+  if (IsString() && other->IsString()) {
+    return String::cast(this)->Equals(String::cast(other));
+  }
+  return false;
+}
+
+
 void Object::ShortPrint(FILE* out) {
   HeapStringAllocator allocator;
   StringStream accumulator(&allocator);
@@ -16329,7 +16348,7 @@ int OrderedHashTable<Derived, Iterator, entrysize>::FindEntry(
        entry != kNotFound;
        entry = ChainAt(entry)) {
     Object* candidate = KeyAt(entry);
-    if (candidate->SameValue(*key))
+    if (candidate->SameValueZero(*key))
       return entry;
   }
   return kNotFound;
index 910c252..80848f8 100644 (file)
@@ -1511,6 +1511,12 @@ class Object {
   // to implement the Harmony "egal" function.
   bool SameValue(Object* other);
 
+  // Checks whether this object has the same value as the given one.
+  // +0 and -0 are treated equal. Everything else is the same as SameValue.
+  // This function is implemented according to ES6, section 7.2.4 and is used
+  // by ES6 Map and Set.
+  bool SameValueZero(Object* other);
+
   // Tries to convert an object to an array index.  Returns true and sets
   // the output parameter if it succeeds.
   inline bool ToArrayIndex(uint32_t* index);
@@ -4142,7 +4148,7 @@ class ObjectHashTable: public HashTable<ObjectHashTable,
 // insertion order. There are Map and Set interfaces (OrderedHashMap
 // and OrderedHashTable, below). It is meant to be used by JSMap/JSSet.
 //
-// Only Object* keys are supported, with Object::SameValue() used as the
+// Only Object* keys are supported, with Object::SameValueZero() used as the
 // equality operator and Object::GetHash() for the hash function.
 //
 // Based on the "Deterministic Hash Table" as described by Jason Orendorff at
index 96d4b35..66020cb 100755 (executable)
@@ -51,7 +51,7 @@ EXPECTED_FUNCTION_COUNT = 359
 EXPECTED_FUZZABLE_COUNT = 326
 EXPECTED_CCTEST_COUNT = 6
 EXPECTED_UNKNOWN_COUNT = 5
-EXPECTED_BUILTINS_COUNT = 824
+EXPECTED_BUILTINS_COUNT = 823
 
 
 # Don't call these at all.