Correct semantics for numerically indexed stores to typed arrays.
authordslomov@chromium.org <dslomov@chromium.org>
Fri, 17 Oct 2014 16:33:38 +0000 (16:33 +0000)
committerdslomov@chromium.org <dslomov@chromium.org>
Fri, 17 Oct 2014 16:33:38 +0000 (16:33 +0000)
R=verwaest@chromium.org, ishell@chromium.org

Committed: https://code.google.com/p/v8/source/detail?r=24691

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

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

src/lookup.cc
src/lookup.h
src/objects.cc
test/mjsunit/harmony/typedarrays.js

index b855abe97fdb47fba3821215e36310c1e2365553..bca0ab5d5f4379888605026c65528a1f7d5eb40c 100644 (file)
@@ -309,6 +309,24 @@ void LookupIterator::WriteDataValue(Handle<Object> value) {
 }
 
 
+bool LookupIterator::IsSpecialNumericIndex() const {
+  if (GetStoreTarget()->IsJSTypedArray() && name()->IsString()) {
+    Handle<String> name_string = Handle<String>::cast(name());
+    if (name_string->length() > 0) {
+      double d =
+          StringToDouble(isolate()->unicode_cache(), *name_string, NO_FLAGS);
+      if (!std::isnan(d)) {
+        Factory* factory = isolate()->factory();
+        Handle<Object> num = factory->NewNumber(d);
+        Handle<String> roundtrip_string = factory->NumberToString(num);
+        if (String::Equals(name_string, roundtrip_string)) return true;
+      }
+    }
+  }
+  return false;
+}
+
+
 void LookupIterator::InternalizeName() {
   if (name_->IsUniqueName()) return;
   name_ = factory()->InternalizeString(Handle<String>::cast(name_));
index 14ca010d31d8477d531b0215aef03dd4073f1d61..52231e5d908ce4b657f14b327d6f5861e2267def 100644 (file)
@@ -138,6 +138,10 @@ class LookupIterator FINAL BASE_EMBEDDED {
   Handle<Object> GetDataValue() const;
   void WriteDataValue(Handle<Object> value);
 
+  // Checks whether the receiver is an indexed exotic object
+  // and name is a special numeric index.
+  bool IsSpecialNumericIndex() const;
+
   void InternalizeName();
 
  private:
index 930342d20b25fffe5e28376bf39f34822bc683d0..1dff71eca2e57b89c792365842c4dea87b3b3a76 100644 (file)
@@ -3077,6 +3077,10 @@ MaybeHandle<Object> Object::AddDataProperty(LookupIterator* it,
   // instead. If the prototype is Null, the proxy is detached.
   if (receiver->IsJSGlobalProxy()) return value;
 
+  // If the receiver is Indexed Exotic object (currently only typed arrays),
+  // disallow adding properties with numeric names.
+  if (it->IsSpecialNumericIndex()) return value;
+
   // Possibly migrate to the most up-to-date map that will be able to store
   // |value| under it->name() with |attributes|.
   it->PrepareTransitionToDataProperty(value, attributes, store_mode);
index 5b75874cd40685897393613ab693a521318eb828..c70d8e5ea4b82371d7570bafdac12585885ccf6c 100644 (file)
@@ -481,6 +481,89 @@ function TestTypedArraySet() {
 
 TestTypedArraySet();
 
+function TestTypedArraysWithIllegalIndices() {
+  var a = new Int32Array(100);
+
+  a[-10] = 10;
+  assertEquals(undefined, a[-10]);
+  a["-10"] = 10;
+  assertEquals(undefined, a["-10"]);
+
+  var s = "    -10";
+  a[s] = 10;
+  assertEquals(10, a[s]);
+  var s1 = "    -10   ";
+  a[s] = 10;
+  assertEquals(10, a[s]);
+
+  a["-1e2"] = 10;
+  assertEquals(10, a["-1e2"]);
+  assertEquals(undefined, a[-1e2]);
+
+  /* Chromium bug: 424619
+   * a[-Infinity] = 50;
+   * assertEquals(undefined, a[-Infinity]);
+   */
+  a[1.5] = 10;
+  assertEquals(undefined, a[1.5]);
+  var nan = Math.sqrt(-1);
+  a[nan] = 5;
+  assertEquals(5, a[nan]);
+
+  var x = 0;
+  var y = -0;
+  assertEquals(Infinity, 1/x);
+  assertEquals(-Infinity, 1/y);
+  a[x] = 5;
+  a[y] = 27;
+  assertEquals(27, a[x]);
+  assertEquals(27, a[y]);
+}
+
+TestTypedArraysWithIllegalIndices();
+
+function TestTypedArraysWithIllegalIndicesStrict() {
+  'use strict';
+  var a = new Int32Array(100);
+
+  a[-10] = 10;
+  assertEquals(undefined, a[-10]);
+  a["-10"] = 10;
+  assertEquals(undefined, a["-10"]);
+
+  var s = "    -10";
+  a[s] = 10;
+  assertEquals(10, a[s]);
+  var s1 = "    -10   ";
+  a[s] = 10;
+  assertEquals(10, a[s]);
+
+  a["-1e2"] = 10;
+  assertEquals(10, a["-1e2"]);
+  assertEquals(undefined, a[-1e2]);
+
+  /* Chromium bug: 424619
+   * a[-Infinity] = 50;
+   * assertEquals(undefined, a[-Infinity]);
+   */
+  a[1.5] = 10;
+  assertEquals(undefined, a[1.5]);
+  var nan = Math.sqrt(-1);
+  a[nan] = 5;
+  assertEquals(5, a[nan]);
+
+  var x = 0;
+  var y = -0;
+  assertEquals(Infinity, 1/x);
+  assertEquals(-Infinity, 1/y);
+  a[x] = 5;
+  a[y] = 27;
+  assertEquals(27, a[x]);
+  assertEquals(27, a[y]);
+}
+
+TestTypedArraysWithIllegalIndicesStrict();
+
 // DataView
 function TestDataViewConstructor() {
   var ab = new ArrayBuffer(256);