Revision: 21415
Author:   [email protected]
Date:     Thu May 22 00:04:38 2014 UTC
Log:      Version 3.27.10 (based on bleeding_edge revision r21414)

Implement Mirror object for Symbols (issue 3290).

Allow debugger to step into Map and Set forEach callbacks (issue 3341).

Fix ArrayShift hydrogen support (Chromium issue 374838).

Use SameValueZero for Map and Set (issue 1622).

Array Iterator next should check for own property.

Performance and stability improvements on all platforms.
http://code.google.com/p/v8/source/detail?r=21415

Added:
 /trunk/test/mjsunit/es6/mirror-symbols.js
 /trunk/test/mjsunit/harmony/debug-stepin-collections-foreach.js
 /trunk/test/mjsunit/regress/regress-crbug-374838.js
Modified:
 /trunk/ChangeLog
 /trunk/src/api.cc
 /trunk/src/array-iterator.js
 /trunk/src/collection.js
 /trunk/src/debug.cc
 /trunk/src/debug.h
 /trunk/src/hydrogen-instructions.h
 /trunk/src/hydrogen.cc
 /trunk/src/mirror-debugger.js
 /trunk/src/objects.cc
 /trunk/src/objects.h
 /trunk/src/runtime.cc
 /trunk/src/version.cc
 /trunk/test/cctest/test-api.cc
 /trunk/test/cctest/test-dictionary.cc
 /trunk/test/cctest/test-ordered-hash-table.cc
 /trunk/test/mjsunit/harmony/array-iterator.js
 /trunk/test/promises-aplus/testcfg.py
 /trunk/test/test262/testcfg.py
 /trunk/tools/testrunner/local/utils.py

=======================================
--- /dev/null
+++ /trunk/test/mjsunit/es6/mirror-symbols.js   Thu May 22 00:04:38 2014 UTC
@@ -0,0 +1,38 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Flags: --expose-debug-as debug --harmony-symbols
+// Test the mirror object for symbols.
+
+function testSymbolMirror(symbol, description) {
+  // Create mirror and JSON representation.
+  var mirror = debug.MakeMirror(symbol);
+  var serializer = debug.MakeMirrorSerializer();
+  var json = JSON.stringify(serializer.serializeValue(mirror));
+
+  // Check the mirror hierachy.
+  assertTrue(mirror instanceof debug.Mirror);
+  assertTrue(mirror instanceof debug.ValueMirror);
+  assertTrue(mirror instanceof debug.SymbolMirror);
+
+  // Check the mirror properties.
+  assertTrue(mirror.isSymbol());
+  assertEquals(description, mirror.description());
+  assertEquals('symbol', mirror.type());
+  assertTrue(mirror.isPrimitive());
+  var description_text = description === undefined ? "" : description;
+  assertEquals('Symbol(' + description_text + ')', mirror.toText());
+  assertSame(symbol, mirror.value());
+
+  // Parse JSON representation and check.
+  var fromJSON = eval('(' + json + ')');
+  assertEquals('symbol', fromJSON.type);
+  assertEquals(description, fromJSON.description);
+}
+
+// Test a number of different symbols.
+testSymbolMirror(Symbol("a"), "a");
+testSymbolMirror(Symbol(12), "12");
+testSymbolMirror(Symbol.for("b"), "b");
+testSymbolMirror(Symbol(), undefined);
=======================================
--- /dev/null
+++ /trunk/test/mjsunit/harmony/debug-stepin-collections-foreach.js Thu May 22 00:04:38 2014 UTC
@@ -0,0 +1,118 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// Flags: --expose-debug-as debug --harmony-collections
+
+Debug = debug.Debug
+
+var exception = false;
+
+function listener(event, exec_state, event_data, data) {
+  try {
+    if (event == Debug.DebugEvent.Break) {
+      if (breaks == 0) {
+        exec_state.prepareStep(Debug.StepAction.StepIn, 2);
+        breaks = 1;
+      } else if (breaks <= 3) {
+        breaks++;
+        // Check whether we break at the expected line.
+        print(event_data.sourceLineText());
+ assertTrue(event_data.sourceLineText().indexOf("Expected to step")
0);
+        exec_state.prepareStep(Debug.StepAction.StepIn, 3);
+      }
+    }
+  } catch (e) {
+    exception = true;
+  }
+}
+
+function cb_set(num) {
+  print("element " + num);  // Expected to step to this point.
+  return true;
+}
+
+function cb_map(key, val) {
+ print("key " + key + ", value " + val); // Expected to step to this point.
+  return true;
+}
+
+var s = new Set();
+s.add(1);
+s.add(2);
+s.add(3);
+s.add(4);
+
+var m = new Map();
+m.set('foo', 1);
+m.set('bar', 2);
+m.set('baz', 3);
+m.set('bat', 4);
+
+Debug.setListener(listener);
+
+var breaks = 0;
+debugger;
+s.forEach(cb_set);
+assertFalse(exception);
+assertEquals(4, breaks);
+
+breaks = 0;
+debugger;
+m.forEach(cb_map);
+assertFalse(exception);
+assertEquals(4, breaks);
+
+Debug.setListener(null);
+
+
+// Test two levels of builtin callbacks:
+// Array.forEach calls a callback function, which by itself uses
+// Array.forEach with another callback function.
+
+function second_level_listener(event, exec_state, event_data, data) {
+  try {
+    if (event == Debug.DebugEvent.Break) {
+      if (breaks == 0) {
+        exec_state.prepareStep(Debug.StepAction.StepIn, 3);
+        breaks = 1;
+      } else if (breaks <= 16) {
+        breaks++;
+        // Check whether we break at the expected line.
+ assertTrue(event_data.sourceLineText().indexOf("Expected to step")
0);
+        // Step two steps further every four breaks to skip the
+        // forEach call in the first level of recurision.
+        var step = (breaks % 4 == 1) ? 6 : 3;
+        exec_state.prepareStep(Debug.StepAction.StepIn, step);
+      }
+    }
+  } catch (e) {
+    exception = true;
+  }
+}
+
+function cb_set_foreach(num) {
+  s.forEach(cb_set);
+  print("back to the first level of recursion.");
+}
+
+function cb_map_foreach(key, val) {
+  m.forEach(cb_set);
+  print("back to the first level of recursion.");
+}
+
+Debug.setListener(second_level_listener);
+
+breaks = 0;
+debugger;
+s.forEach(cb_set_foreach);
+assertFalse(exception);
+assertEquals(17, breaks);
+
+breaks = 0;
+debugger;
+m.forEach(cb_map_foreach);
+assertFalse(exception);
+assertEquals(17, breaks);
+
+Debug.setListener(null);
=======================================
--- /dev/null
+++ /trunk/test/mjsunit/regress/regress-crbug-374838.js Thu May 22 00:04:38 2014 UTC
@@ -0,0 +1,20 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Flags: --allow-natives-syntax
+
+function foo() {
+  var a = [0];
+  result = 0;
+  for (var i = 0; i < 4; i++) {
+    result += a.length;
+    a.shift();
+  }
+  return result;
+}
+
+assertEquals(1, foo());
+assertEquals(1, foo());
+%OptimizeFunctionOnNextCall(foo);
+assertEquals(1, foo());
=======================================
--- /trunk/ChangeLog    Wed May 21 00:04:49 2014 UTC
+++ /trunk/ChangeLog    Thu May 22 00:04:38 2014 UTC
@@ -1,3 +1,18 @@
+2014-05-22: Version 3.27.10
+
+        Implement Mirror object for Symbols (issue 3290).
+
+ Allow debugger to step into Map and Set forEach callbacks (issue 3341).
+
+        Fix ArrayShift hydrogen support (Chromium issue 374838).
+
+        Use SameValueZero for Map and Set (issue 1622).
+
+        Array Iterator next should check for own property.
+
+        Performance and stability improvements on all platforms.
+
+
 2014-05-21: Version 3.27.9

         Disable ArrayShift hydrogen support (Chromium issue 374838).
=======================================
--- /trunk/src/api.cc   Wed May 21 00:04:49 2014 UTC
+++ /trunk/src/api.cc   Thu May 22 00:04:38 2014 UTC
@@ -1586,13 +1586,13 @@


 int UnboundScript::GetLineNumber(int code_pos) {
-  i::Handle<i::HeapObject> obj =
-      i::Handle<i::HeapObject>::cast(Utils::OpenHandle(this));
+  i::Handle<i::SharedFunctionInfo> obj =
+      i::Handle<i::SharedFunctionInfo>::cast(Utils::OpenHandle(this));
   i::Isolate* isolate = obj->GetIsolate();
   ON_BAILOUT(isolate, "v8::UnboundScript::GetLineNumber()", return -1);
   LOG_API(isolate, "UnboundScript::GetLineNumber");
-  if (obj->IsScript()) {
-    i::Handle<i::Script> script(i::Script::cast(*obj));
+  if (obj->script()->IsScript()) {
+    i::Handle<i::Script> script(i::Script::cast(obj->script()));
     return i::Script::GetLineNumber(script, code_pos);
   } else {
     return -1;
@@ -1601,14 +1601,14 @@


 Handle<Value> UnboundScript::GetScriptName() {
-  i::Handle<i::HeapObject> obj =
-      i::Handle<i::HeapObject>::cast(Utils::OpenHandle(this));
+  i::Handle<i::SharedFunctionInfo> obj =
+      i::Handle<i::SharedFunctionInfo>::cast(Utils::OpenHandle(this));
   i::Isolate* isolate = obj->GetIsolate();
   ON_BAILOUT(isolate, "v8::UnboundScript::GetName()",
              return Handle<String>());
   LOG_API(isolate, "UnboundScript::GetName");
-  if (obj->IsScript()) {
-    i::Object* name = i::Script::cast(*obj)->name();
+  if (obj->script()->IsScript()) {
+    i::Object* name = i::Script::cast(obj->script())->name();
     return Utils::ToLocal(i::Handle<i::Object>(name, isolate));
   } else {
     return Handle<String>();
=======================================
--- /trunk/src/array-iterator.js        Tue May 13 00:04:55 2014 UTC
+++ /trunk/src/array-iterator.js        Thu May 22 00:04:38 2014 UTC
@@ -38,11 +38,16 @@
 // 15.4.5.2.2 ArrayIterator.prototype.next( )
 function ArrayIteratorNext() {
   var iterator = ToObject(this);
-  var array = GET_PRIVATE(iterator, arrayIteratorObjectSymbol);
-  if (!array) {
+
+  if (!HAS_PRIVATE(iterator, arrayIteratorObjectSymbol)) {
     throw MakeTypeError('incompatible_method_receiver',
                         ['Array Iterator.prototype.next']);
   }
+
+  var array = GET_PRIVATE(iterator, arrayIteratorObjectSymbol);
+  if (IS_UNDEFINED(array)) {
+    return CreateIteratorResultObject(UNDEFINED, true);
+  }

   var index = GET_PRIVATE(iterator, arrayIteratorNextIndexSymbol);
   var itemKind = GET_PRIVATE(iterator, arrayIterationKindSymbol);
@@ -51,17 +56,19 @@
   // "sparse" is never used.

   if (index >= length) {
-    SET_PRIVATE(iterator, arrayIteratorNextIndexSymbol, INFINITY);
+    SET_PRIVATE(iterator, arrayIteratorObjectSymbol, UNDEFINED);
     return CreateIteratorResultObject(UNDEFINED, true);
   }

   SET_PRIVATE(iterator, arrayIteratorNextIndexSymbol, index + 1);

-  if (itemKind == ITERATOR_KIND_VALUES)
+  if (itemKind == ITERATOR_KIND_VALUES) {
     return CreateIteratorResultObject(array[index], false);
+  }

-  if (itemKind == ITERATOR_KIND_ENTRIES)
+  if (itemKind == ITERATOR_KIND_ENTRIES) {
     return CreateIteratorResultObject([index, array[index]], false);
+  }

   return CreateIteratorResultObject(index, false);
 }
=======================================
--- /trunk/src/collection.js    Wed May 21 00:04:49 2014 UTC
+++ /trunk/src/collection.js    Thu May 22 00:04:38 2014 UTC
@@ -11,25 +11,6 @@
 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 @@
     throw MakeTypeError('incompatible_method_receiver',
                         ['Set.prototype.add', this]);
   }
-  return %SetAdd(this, NormalizeKey(key));
+  return %SetAdd(this, key);
 }


@@ -57,7 +38,7 @@
     throw MakeTypeError('incompatible_method_receiver',
                         ['Set.prototype.has', this]);
   }
-  return %SetHas(this, NormalizeKey(key));
+  return %SetHas(this, key);
 }


@@ -66,13 +47,7 @@
     throw MakeTypeError('incompatible_method_receiver',
                         ['Set.prototype.delete', this]);
   }
-  key = NormalizeKey(key);
-  if (%SetHas(this, key)) {
-    %SetDelete(this, key);
-    return true;
-  } else {
-    return false;
-  }
+  return %SetDelete(this, key);
 }


@@ -106,7 +81,9 @@

   var iterator = %SetCreateIterator(this, ITERATOR_KIND_VALUES);
   var entry;
+  var stepping = %_DebugCallbackSupportsStepping(f);
   while (!(entry = %SetIteratorNext(iterator)).done) {
+    if (stepping) %DebugPrepareStepInIfStepping(f);
     %_CallFunction(receiver, entry.value, entry.value, this, f);
   }
 }
@@ -154,7 +131,7 @@
     throw MakeTypeError('incompatible_method_receiver',
                         ['Map.prototype.get', this]);
   }
-  return %MapGet(this, NormalizeKey(key));
+  return %MapGet(this, key);
 }


@@ -163,7 +140,7 @@
     throw MakeTypeError('incompatible_method_receiver',
                         ['Map.prototype.set', this]);
   }
-  return %MapSet(this, NormalizeKey(key), value);
+  return %MapSet(this, key, value);
 }


@@ -172,7 +149,7 @@
     throw MakeTypeError('incompatible_method_receiver',
                         ['Map.prototype.has', this]);
   }
-  return %MapHas(this, NormalizeKey(key));
+  return %MapHas(this, key);
 }


@@ -181,7 +158,7 @@
     throw MakeTypeError('incompatible_method_receiver',
                         ['Map.prototype.delete', this]);
   }
-  return %MapDelete(this, NormalizeKey(key));
+  return %MapDelete(this, key);
 }


@@ -215,7 +192,9 @@

   var iterator = %MapCreateIterator(this, ITERATOR_KIND_ENTRIES);
   var entry;
+  var stepping = %_DebugCallbackSupportsStepping(f);
   while (!(entry = %MapIteratorNext(iterator)).done) {
+    if (stepping) %DebugPrepareStepInIfStepping(f);
     %_CallFunction(receiver, entry.value[1], entry.value[0], this, f);
   }
 }
=======================================
--- /trunk/src/debug.cc Wed May 21 00:04:49 2014 UTC
+++ /trunk/src/debug.cc Thu May 22 00:04:38 2014 UTC
@@ -37,8 +37,6 @@
       disable_break_(false),
       break_on_exception_(false),
       break_on_uncaught_exception_(false),
-      promise_catch_handlers_(0),
-      promise_getters_(0),
       isolate_(isolate) {
   ThreadInit();
 }
@@ -511,6 +509,7 @@
   thread_local_.debugger_entry_ = NULL;
   thread_local_.has_pending_interrupt_ = false;
   thread_local_.restarter_frame_function_pointer_ = NULL;
+  thread_local_.promise_on_stack_ = NULL;
 }


@@ -1247,31 +1246,44 @@
     return break_on_exception_;
   }
 }
+
+
+Debug::PromiseOnStack::PromiseOnStack(Isolate* isolate,
+                                      PromiseOnStack* prev,
+                                      Handle<JSFunction> getter)
+    : isolate_(isolate), prev_(prev) {
+  handler_ = StackHandler::FromAddress(
+      Isolate::handler(isolate->thread_local_top()));
+  getter_ = Handle<JSFunction>::cast(
+      isolate->global_handles()->Create(*getter));
+}
+
+
+Debug::PromiseOnStack::~PromiseOnStack() {
+ isolate_->global_handles()->Destroy(Handle<Object>::cast(getter_).location());
+}


 void Debug::PromiseHandlePrologue(Handle<JSFunction> promise_getter) {
-  Handle<JSFunction> promise_getter_global = Handle<JSFunction>::cast(
-      isolate_->global_handles()->Create(*promise_getter));
-  StackHandler* handler =
- StackHandler::FromAddress(Isolate::handler(isolate_->thread_local_top()));
-  promise_getters_.Add(promise_getter_global);
-  promise_catch_handlers_.Add(handler);
+  PromiseOnStack* prev = thread_local_.promise_on_stack_;
+  thread_local_.promise_on_stack_ =
+      new PromiseOnStack(isolate_, prev, promise_getter);
 }


 void Debug::PromiseHandleEpilogue() {
-  if (promise_catch_handlers_.length() == 0) return;
-  promise_catch_handlers_.RemoveLast();
-  Handle<Object> promise_getter = promise_getters_.RemoveLast();
-  isolate_->global_handles()->Destroy(promise_getter.location());
+  if (thread_local_.promise_on_stack_ == NULL) return;
+  PromiseOnStack* prev = thread_local_.promise_on_stack_->prev();
+  delete thread_local_.promise_on_stack_;
+  thread_local_.promise_on_stack_ = prev;
 }


 Handle<Object> Debug::GetPromiseForUncaughtException() {
   Handle<Object> undefined = isolate_->factory()->undefined_value();
-  if (promise_getters_.length() == 0) return undefined;
-  Handle<JSFunction> promise_getter = promise_getters_.last();
-  StackHandler* promise_catch = promise_catch_handlers_.last();
+  if (thread_local_.promise_on_stack_ == NULL) return undefined;
+ Handle<JSFunction> promise_getter = thread_local_.promise_on_stack_->getter();
+  StackHandler* promise_catch = thread_local_.promise_on_stack_->handler();
   // Find the top-most try-catch handler.
   StackHandler* handler = StackHandler::FromAddress(
       Isolate::handler(isolate_->thread_local_top()));
=======================================
--- /trunk/src/debug.h  Wed May 21 00:04:49 2014 UTC
+++ /trunk/src/debug.h  Thu May 22 00:04:38 2014 UTC
@@ -519,13 +519,21 @@
   bool break_on_exception_;
   bool break_on_uncaught_exception_;

- // When a promise is being resolved, we may want to trigger a debug event for
-  // the case we catch a throw.  For this purpose we remember the try-catch
-  // handler address that would catch the exception.  We also hold onto a
- // closure that returns a promise if the exception is considered uncaught.
-  // Due to the possibility of reentry we use a list to form a stack.
-  List<StackHandler*> promise_catch_handlers_;
-  List<Handle<JSFunction> > promise_getters_;
+  class PromiseOnStack {
+   public:
+    PromiseOnStack(Isolate* isolate,
+                   PromiseOnStack* prev,
+                   Handle<JSFunction> getter);
+    ~PromiseOnStack();
+    StackHandler* handler() { return handler_; }
+    Handle<JSFunction> getter() { return getter_; }
+    PromiseOnStack* prev() { return prev_; }
+   private:
+    Isolate* isolate_;
+    StackHandler* handler_;
+    Handle<JSFunction> getter_;
+    PromiseOnStack* prev_;
+  };

   // Per-thread data.
   class ThreadLocal {
@@ -578,6 +586,13 @@
// of the pointer to function being restarted. Otherwise (most of the time)
     // stores NULL. This pointer is used with 'step in' implementation.
     Object** restarter_frame_function_pointer_;
+
+ // When a promise is being resolved, we may want to trigger a debug event
+    // if we catch a throw.  For this purpose we remember the try-catch
+    // handler address that would catch the exception.  We also hold onto a
+ // closure that returns a promise if the exception is considered uncaught.
+    // Due to the possibility of reentry we use a linked list.
+    PromiseOnStack* promise_on_stack_;
   };

   // Storage location for registers when handling debug break calls
=======================================
--- /trunk/src/hydrogen-instructions.h  Wed May 21 00:04:49 2014 UTC
+++ /trunk/src/hydrogen-instructions.h  Thu May 22 00:04:38 2014 UTC
@@ -7123,6 +7123,7 @@
       : kind_(kind) {
     SetOperandAt(0, context);
     SetOperandAt(1, object);
+    SetChangesFlag(kArrayLengths);
     SetChangesFlag(kNewSpacePromotion);
     set_representation(Representation::Tagged());
     if (IsFastSmiOrObjectElementsKind(kind)) {
=======================================
--- /trunk/src/hydrogen.cc      Wed May 21 00:04:49 2014 UTC
+++ /trunk/src/hydrogen.cc      Thu May 22 00:04:38 2014 UTC
@@ -7927,10 +7927,6 @@
       return true;
     }
     case kArrayShift: {
-      // Something in here seems to be causing crbug.com/374838.
-      // TODO(bmeurer): Investigate the problem and re-enable this code.
-      return false;
-
       if (receiver_map.is_null()) return false;
       if (receiver_map->instance_type() != JS_ARRAY_TYPE) return false;
       ElementsKind kind = receiver_map->elements_kind();
=======================================
--- /trunk/src/mirror-debugger.js       Mon May 19 00:04:51 2014 UTC
+++ /trunk/src/mirror-debugger.js       Thu May 22 00:04:38 2014 UTC
@@ -68,6 +68,8 @@
     mirror = new NumberMirror(value);
   } else if (IS_STRING(value)) {
     mirror = new StringMirror(value);
+  } else if (IS_SYMBOL(value)) {
+    mirror = new SymbolMirror(value);
   } else if (IS_ARRAY(value)) {
     mirror = new ArrayMirror(value);
   } else if (IS_DATE(value)) {
@@ -141,6 +143,7 @@
 var BOOLEAN_TYPE = 'boolean';
 var NUMBER_TYPE = 'number';
 var STRING_TYPE = 'string';
+var SYMBOL_TYPE = 'symbol';
 var OBJECT_TYPE = 'object';
 var FUNCTION_TYPE = 'function';
 var REGEXP_TYPE = 'regexp';
@@ -198,6 +201,7 @@
 //       - NullMirror
 //       - NumberMirror
 //       - StringMirror
+//       - SymbolMirror
 //       - ObjectMirror
 //         - FunctionMirror
 //           - UnresolvedFunctionMirror
@@ -281,6 +285,15 @@
 };


+/**
+ * Check whether the mirror reflects a symbol.
+ * @returns {boolean} True if the mirror reflects a symbol
+ */
+Mirror.prototype.isSymbol = function() {
+  return this instanceof SymbolMirror;
+};
+
+
 /**
  * Check whether the mirror reflects an object.
  * @returns {boolean} True if the mirror reflects an object
@@ -466,7 +479,8 @@
          type === 'null' ||
          type === 'boolean' ||
          type === 'number' ||
-         type === 'string';
+         type === 'string' ||
+         type === 'symbol';
 };


@@ -572,6 +586,28 @@
 StringMirror.prototype.toText = function() {
   return this.getTruncatedValue(kMaxProtocolStringLength);
 };
+
+
+/**
+ * Mirror object for a Symbol
+ * @param {Object} value The Symbol
+ * @constructor
+ * @extends Mirror
+ */
+function SymbolMirror(value) {
+  %_CallFunction(this, SYMBOL_TYPE, value, ValueMirror);
+}
+inherits(SymbolMirror, ValueMirror);
+
+
+SymbolMirror.prototype.description = function() {
+  return %SymbolDescription(%_ValueOf(this.value_));
+}
+
+
+SymbolMirror.prototype.toText = function() {
+  return %_CallFunction(this.value_, builtins.SymbolToString);
+}


 /**
@@ -1184,9 +1220,9 @@

 /**
  * Mirror object for a Promise object.
- * @param {Object} data The Promise object
+ * @param {Object} value The Promise object
  * @constructor
- * @extends Mirror
+ * @extends ObjectMirror
  */
 function PromiseMirror(value) {
   %_CallFunction(this, value, PROMISE_TYPE, ObjectMirror);
@@ -2318,6 +2354,9 @@
     case STRING_TYPE:
       o.value = mirror.getTruncatedValue(this.maxStringLength_());
       break;
+    case SYMBOL_TYPE:
+      o.description = mirror.description();
+      break;
     case FUNCTION_TYPE:
       o.name = mirror.name();
       o.inferredName = mirror.inferredName();
@@ -2392,6 +2431,10 @@
       content.length = mirror.length();
       break;

+    case SYMBOL_TYPE:
+      content.description = mirror.description();
+      break;
+
     case OBJECT_TYPE:
     case FUNCTION_TYPE:
     case ERROR_TYPE:
=======================================
--- /trunk/src/objects.cc       Wed May 21 00:04:49 2014 UTC
+++ /trunk/src/objects.cc       Thu May 22 00:04:38 2014 UTC
@@ -973,6 +973,25 @@
   }
   return false;
 }
+
+
+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) {
@@ -16329,7 +16348,7 @@
        entry != kNotFound;
        entry = ChainAt(entry)) {
     Object* candidate = KeyAt(entry);
-    if (candidate->SameValue(*key))
+    if (candidate->SameValueZero(*key))
       return entry;
   }
   return kNotFound;
@@ -16437,9 +16456,14 @@


 Handle<OrderedHashSet> OrderedHashSet::Remove(Handle<OrderedHashSet> table,
-                                              Handle<Object> key) {
+                                              Handle<Object> key,
+                                              bool* was_present) {
   int entry = table->FindEntry(key);
-  if (entry == kNotFound) return table;
+  if (entry == kNotFound) {
+    *was_present = false;
+    return table;
+  }
+  *was_present = true;
   table->RemoveEntry(entry);
   return Shrink(table);
 }
=======================================
--- /trunk/src/objects.h        Wed May 21 00:04:49 2014 UTC
+++ /trunk/src/objects.h        Thu May 22 00:04:38 2014 UTC
@@ -1511,6 +1511,12 @@
   // 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 @@
 // 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
@@ -4317,7 +4323,7 @@
   static Handle<OrderedHashSet> Add(
       Handle<OrderedHashSet> table, Handle<Object> key);
   static Handle<OrderedHashSet> Remove(
-      Handle<OrderedHashSet> table, Handle<Object> key);
+      Handle<OrderedHashSet> table, Handle<Object> key, bool* was_present);
 };


=======================================
--- /trunk/src/runtime.cc       Wed May 21 00:04:49 2014 UTC
+++ /trunk/src/runtime.cc       Thu May 22 00:04:38 2014 UTC
@@ -960,13 +960,6 @@

   RUNTIME_ASSERT(arrayId >= Runtime::ARRAY_ID_FIRST &&
                  arrayId <= Runtime::ARRAY_ID_LAST);
- RUNTIME_ASSERT(maybe_buffer->IsNull() || maybe_buffer->IsJSArrayBuffer());
-
-  ASSERT(holder->GetInternalFieldCount() ==
-      v8::ArrayBufferView::kInternalFieldCount);
-  for (int i = 0; i < v8::ArrayBufferView::kInternalFieldCount; i++) {
-    holder->SetInternalField(i, Smi::FromInt(0));
-  }

ExternalArrayType array_type = kExternalInt8Array; // Bogus initialization.
   size_t element_size = 1;  // Bogus initialization.
@@ -978,7 +971,6 @@
       &external_elements_kind,
       &fixed_elements_kind,
       &element_size);
-
   RUNTIME_ASSERT(holder->map()->elements_kind() == fixed_elements_kind);

   size_t byte_offset = 0;
@@ -986,8 +978,15 @@
RUNTIME_ASSERT(TryNumberToSize(isolate, *byte_offset_object, &byte_offset)); RUNTIME_ASSERT(TryNumberToSize(isolate, *byte_length_object, &byte_length));

-  holder->set_byte_offset(*byte_offset_object);
-  holder->set_byte_length(*byte_length_object);
+  if (maybe_buffer->IsJSArrayBuffer()) {
+ Handle<JSArrayBuffer> buffer = Handle<JSArrayBuffer>::cast(maybe_buffer);
+    size_t array_buffer_byte_length =
+        NumberToSize(isolate, buffer->byte_length());
+    RUNTIME_ASSERT(byte_offset <= array_buffer_byte_length);
+    RUNTIME_ASSERT(array_buffer_byte_length - byte_offset >= byte_length);
+  } else {
+    RUNTIME_ASSERT(maybe_buffer->IsNull());
+  }

   RUNTIME_ASSERT(byte_length % element_size == 0);
   size_t length = byte_length / element_size;
@@ -998,16 +997,20 @@
                                            HandleVector<Object>(NULL, 0)));
   }

+  // All checks are done, now we can modify objects.
+
+  ASSERT(holder->GetInternalFieldCount() ==
+      v8::ArrayBufferView::kInternalFieldCount);
+  for (int i = 0; i < v8::ArrayBufferView::kInternalFieldCount; i++) {
+    holder->SetInternalField(i, Smi::FromInt(0));
+  }
Handle<Object> length_obj = isolate->factory()->NewNumberFromSize(length);
   holder->set_length(*length_obj);
-  if (!maybe_buffer->IsNull()) {
-    Handle<JSArrayBuffer> buffer(JSArrayBuffer::cast(*maybe_buffer));
-
-    size_t array_buffer_byte_length =
-        NumberToSize(isolate, buffer->byte_length());
-    RUNTIME_ASSERT(byte_offset <= array_buffer_byte_length);
-    RUNTIME_ASSERT(array_buffer_byte_length - byte_offset >= byte_length);
+  holder->set_byte_offset(*byte_offset_object);
+  holder->set_byte_length(*byte_length_object);

+  if (!maybe_buffer->IsNull()) {
+ Handle<JSArrayBuffer> buffer = Handle<JSArrayBuffer>::cast(maybe_buffer);
     holder->set_buffer(*buffer);
     holder->set_weak_next(buffer->weak_first_view());
     buffer->set_weak_first_view(*holder);
@@ -1047,12 +1050,6 @@

   RUNTIME_ASSERT(arrayId >= Runtime::ARRAY_ID_FIRST &&
                  arrayId <= Runtime::ARRAY_ID_LAST);
-
-  ASSERT(holder->GetInternalFieldCount() ==
-      v8::ArrayBufferView::kInternalFieldCount);
-  for (int i = 0; i < v8::ArrayBufferView::kInternalFieldCount; i++) {
-    holder->SetInternalField(i, Smi::FromInt(0));
-  }

ExternalArrayType array_type = kExternalInt8Array; // Bogus initialization.
   size_t element_size = 1;  // Bogus initialization.
@@ -1082,6 +1079,12 @@
             HandleVector<Object>(NULL, 0)));
   }
   size_t byte_length = length * element_size;
+
+  ASSERT(holder->GetInternalFieldCount() ==
+      v8::ArrayBufferView::kInternalFieldCount);
+  for (int i = 0; i < v8::ArrayBufferView::kInternalFieldCount; i++) {
+    holder->SetInternalField(i, Smi::FromInt(0));
+  }

   // NOTE: not initializing backing store.
   // We assume that the caller of this function will initialize holder
@@ -1554,9 +1557,10 @@
   CONVERT_ARG_HANDLE_CHECKED(JSSet, holder, 0);
   CONVERT_ARG_HANDLE_CHECKED(Object, key, 1);
   Handle<OrderedHashSet> table(OrderedHashSet::cast(holder->table()));
-  table = OrderedHashSet::Remove(table, key);
+  bool was_present = false;
+  table = OrderedHashSet::Remove(table, key, &was_present);
   holder->set_table(*table);
-  return isolate->heap()->undefined_value();
+  return isolate->heap()->ToBoolean(was_present);
 }


=======================================
--- /trunk/src/version.cc       Wed May 21 12:08:41 2014 UTC
+++ /trunk/src/version.cc       Thu May 22 00:04:38 2014 UTC
@@ -34,8 +34,8 @@
 // system so their names cannot be changed without changing the scripts.
 #define MAJOR_VERSION     3
 #define MINOR_VERSION     27
-#define BUILD_NUMBER      9
-#define PATCH_LEVEL       1
+#define BUILD_NUMBER      10
+#define PATCH_LEVEL       0
 // Use 1 for candidates and 0 otherwise.
 // (Boolean macro values are not supported by all preprocessors.)
 #define IS_CANDIDATE_VERSION 0
=======================================
--- /trunk/test/cctest/test-api.cc      Wed May 21 00:04:49 2014 UTC
+++ /trunk/test/cctest/test-api.cc      Thu May 22 00:04:38 2014 UTC
@@ -22614,3 +22614,22 @@
   CompileRun("(function f(x) { f(x+1); })(0)");
   CHECK(try_catch.HasCaught());
 }
+
+
+TEST(ScriptNameAndLineNumber) {
+  LocalContext env;
+  v8::Isolate* isolate = env->GetIsolate();
+  v8::HandleScope scope(isolate);
+  const char* url = "http://www.foo.com/foo.js";;
+  v8::ScriptOrigin origin(v8_str(url), v8::Integer::New(isolate, 13));
+  v8::ScriptCompiler::Source script_source(v8_str("var foo;"), origin);
+  Local<Script> script = v8::ScriptCompiler::Compile(
+      isolate, &script_source);
+  Local<Value> script_name = script->GetUnboundScript()->GetScriptName();
+  CHECK(!script_name.IsEmpty());
+  CHECK(script_name->IsString());
+  String::Utf8Value utf8_name(script_name);
+  CHECK_EQ(url, *utf8_name);
+  int line_number = script->GetUnboundScript()->GetLineNumber(0);
+  CHECK_EQ(13, line_number);
+}
=======================================
--- /trunk/test/cctest/test-dictionary.cc       Tue Apr 29 16:30:47 2014 UTC
+++ /trunk/test/cctest/test-dictionary.cc       Thu May 22 00:04:38 2014 UTC
@@ -187,7 +187,9 @@
   CHECK(gc_count == isolate->heap()->gc_count());

   // Calling Remove() will not cause GC in this case.
-  table = HashSet::Remove(table, key);
+  bool was_present = false;
+  table = HashSet::Remove(table, key, &was_present);
+  CHECK(!was_present);
   CHECK(gc_count == isolate->heap()->gc_count());

   // Calling Add() should cause GC.
=======================================
--- /trunk/test/cctest/test-ordered-hash-table.cc Tue Apr 29 16:30:47 2014 UTC +++ /trunk/test/cctest/test-ordered-hash-table.cc Thu May 22 00:04:38 2014 UTC
@@ -75,10 +75,16 @@
   ordered_set = OrderedHashSet::Add(ordered_set, obj);
   CHECK_EQ(1, ordered_set->NumberOfElements());
   CHECK(ordered_set->Contains(obj));
-  ordered_set = OrderedHashSet::Remove(ordered_set, obj);
+  bool was_present = false;
+  ordered_set = OrderedHashSet::Remove(ordered_set, obj, &was_present);
+  CHECK(was_present);
   CHECK_EQ(0, ordered_set->NumberOfElements());
   CHECK(!ordered_set->Contains(obj));

+  // Removing a not-present object should set was_present to false.
+  ordered_set = OrderedHashSet::Remove(ordered_set, obj, &was_present);
+  CHECK(!was_present);
+
   // Test for collisions/chaining
   Handle<JSObject> obj1 = factory->NewJSObjectFromMap(map);
   ordered_set = OrderedHashSet::Add(ordered_set, obj1);
@@ -133,10 +139,14 @@
                         true);

   // Test shrinking
-  ordered_set = OrderedHashSet::Remove(ordered_set, obj);
-  ordered_set = OrderedHashSet::Remove(ordered_set, obj1);
-  ordered_set = OrderedHashSet::Remove(ordered_set, obj2);
-  ordered_set = OrderedHashSet::Remove(ordered_set, obj3);
+  ordered_set = OrderedHashSet::Remove(ordered_set, obj, &was_present);
+  CHECK(was_present);
+  ordered_set = OrderedHashSet::Remove(ordered_set, obj1, &was_present);
+  CHECK(was_present);
+  ordered_set = OrderedHashSet::Remove(ordered_set, obj2, &was_present);
+  CHECK(was_present);
+  ordered_set = OrderedHashSet::Remove(ordered_set, obj3, &was_present);
+  CHECK(was_present);
   CHECK_EQ(1, ordered_set->NumberOfElements());
   CHECK_EQ(2, ordered_set->NumberOfBuckets());
 }
=======================================
--- /trunk/test/mjsunit/harmony/array-iterator.js Mon May 12 00:05:07 2014 UTC +++ /trunk/test/mjsunit/harmony/array-iterator.js Thu May 22 00:04:38 2014 UTC
@@ -214,3 +214,15 @@
   }
 }
 TestForArrayEntries();
+
+
+function TestNonOwnSlots() {
+  var array = [0];
+  var iterator = array.values();
+  var object = {__proto__: iterator};
+
+  assertThrows(function() {
+    object.next();
+  }, TypeError);
+}
+TestNonOwnSlots();
=======================================
--- /trunk/test/promises-aplus/testcfg.py       Tue Apr 29 16:30:47 2014 UTC
+++ /trunk/test/promises-aplus/testcfg.py       Thu May 22 00:04:38 2014 UTC
@@ -31,9 +31,9 @@
 import shutil
 import sys
 import tarfile
-import urllib

 from testrunner.local import testsuite
+from testrunner.local import utils
 from testrunner.objects import testcase


@@ -102,7 +102,7 @@
     directory = os.path.join(self.root, TEST_NAME)
     if not os.path.exists(archive):
       print('Downloading {0} from {1} ...'.format(TEST_NAME, TEST_URL))
-      urllib.urlretrieve(TEST_URL, archive)
+      utils.URLRetrieve(TEST_URL, archive)
       if os.path.exists(directory):
         shutil.rmtree(directory)

@@ -129,7 +129,7 @@
       os.mkdir(directory)
     path = os.path.join(directory, SINON_FILENAME)
     if not os.path.exists(path):
-      urllib.urlretrieve(SINON_URL, path)
+      utils.URLRetrieve(SINON_URL, path)
     hash = hashlib.sha256()
     with open(path, 'rb') as f:
       for chunk in iter(lambda: f.read(8192), ''):
=======================================
--- /trunk/test/test262/testcfg.py      Tue Mar  4 09:06:17 2014 UTC
+++ /trunk/test/test262/testcfg.py      Thu May 22 00:04:38 2014 UTC
@@ -31,9 +31,9 @@
 import shutil
 import sys
 import tarfile
-import urllib

 from testrunner.local import testsuite
+from testrunner.local import utils
 from testrunner.objects import testcase


@@ -97,7 +97,7 @@
     directory_old_name = os.path.join(self.root, "data.old")
     if not os.path.exists(archive_name):
       print "Downloading test data from %s ..." % archive_url
-      urllib.urlretrieve(archive_url, archive_name)
+      utils.URLRetrieve(archive_url, archive_name)
       if os.path.exists(directory_name):
         if os.path.exists(directory_old_name):
           shutil.rmtree(directory_old_name)
=======================================
--- /trunk/tools/testrunner/local/utils.py      Mon Mar 24 08:11:09 2014 UTC
+++ /trunk/tools/testrunner/local/utils.py      Thu May 22 00:04:38 2014 UTC
@@ -32,6 +32,7 @@
 from os.path import join
 import platform
 import re
+import urllib2


 def GetSuitePaths(test_root):
@@ -113,3 +114,10 @@

 def IsWindows():
   return GuessOS() == 'windows'
+
+
+def URLRetrieve(source, destination):
+  """urllib is broken for SSL connections via a proxy therefore we
+  can't use urllib.urlretrieve()."""
+  with open(destination, 'w') as f:
+    f.write(urllib2.urlopen(source).read())

--
--
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