Reland "Enable Object.observe by default"
authorrafaelw@chromium.org <rafaelw@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Sat, 8 Mar 2014 04:41:06 +0000 (04:41 +0000)
committerrafaelw@chromium.org <rafaelw@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Sat, 8 Mar 2014 04:41:06 +0000 (04:41 +0000)
Original Issue: https://codereview.chromium.org/183683022/

TBR=rossberg
BUG=v8:2409
LOG=Y

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

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

14 files changed:
src/accessors.cc
src/bootstrapper.cc
src/flag-definitions.h
src/ic.cc
src/object-observe.js
src/objects.cc
src/runtime.cc
test/cctest/test-heap.cc
test/cctest/test-microtask-delivery.cc
test/cctest/test-object-observe.cc
test/mjsunit/debug-script.js
test/mjsunit/es7/object-observe.js [moved from test/mjsunit/harmony/object-observe.js with 100% similarity]
test/webkit/fast/js/Object-getOwnPropertyNames-expected.txt
tools/gyp/v8.gyp

index 9bc728d..00ff201 100644 (file)
@@ -600,10 +600,7 @@ MaybeObject* Accessors::FunctionSetPrototype(Isolate* isolate,
   }
 
   Handle<Object> old_value;
-  bool is_observed =
-      FLAG_harmony_observation &&
-      *function == *object &&
-      function->map()->is_observed();
+  bool is_observed = *function == *object && function->map()->is_observed();
   if (is_observed) {
     if (function->has_prototype())
       old_value = handle(function->prototype(), isolate);
index 61361f8..2ff70f3 100644 (file)
@@ -1577,6 +1577,12 @@ void Genesis::InstallNativeFunctions() {
   INSTALL_NATIVE(JSObject, "functionCache", function_cache);
   INSTALL_NATIVE(JSFunction, "ToCompletePropertyDescriptor",
                  to_complete_property_descriptor);
+  INSTALL_NATIVE(JSFunction, "NotifyChange", observers_notify_change);
+  INSTALL_NATIVE(JSFunction, "EnqueueSpliceRecord", observers_enqueue_splice);
+  INSTALL_NATIVE(JSFunction, "BeginPerformSplice",
+                 observers_begin_perform_splice);
+  INSTALL_NATIVE(JSFunction, "EndPerformSplice",
+                 observers_end_perform_splice);
 }
 
 
@@ -1591,14 +1597,6 @@ void Genesis::InstallExperimentalNativeFunctions() {
     INSTALL_NATIVE(JSFunction, "DerivedSetTrap", derived_set_trap);
     INSTALL_NATIVE(JSFunction, "ProxyEnumerate", proxy_enumerate);
   }
-  if (FLAG_harmony_observation) {
-    INSTALL_NATIVE(JSFunction, "NotifyChange", observers_notify_change);
-    INSTALL_NATIVE(JSFunction, "EnqueueSpliceRecord", observers_enqueue_splice);
-    INSTALL_NATIVE(JSFunction, "BeginPerformSplice",
-                   observers_begin_perform_splice);
-    INSTALL_NATIVE(JSFunction, "EndPerformSplice",
-                   observers_end_perform_splice);
-  }
 }
 
 #undef INSTALL_NATIVE
@@ -2042,7 +2040,6 @@ bool Genesis::InstallExperimentalNatives() {
     INSTALL_EXPERIMENTAL_NATIVE(i, symbols, "symbol.js")
     INSTALL_EXPERIMENTAL_NATIVE(i, proxies, "proxy.js")
     INSTALL_EXPERIMENTAL_NATIVE(i, collections, "collection.js")
-    INSTALL_EXPERIMENTAL_NATIVE(i, observation, "object-observe.js")
     INSTALL_EXPERIMENTAL_NATIVE(i, promises, "promise.js")
     INSTALL_EXPERIMENTAL_NATIVE(i, generators, "generator.js")
     INSTALL_EXPERIMENTAL_NATIVE(i, iteration, "array-iterator.js")
index 36bef90..e1e8a4b 100644 (file)
@@ -179,8 +179,6 @@ DEFINE_bool(harmony_promises, false, "enable harmony promises")
 DEFINE_bool(harmony_proxies, false, "enable harmony proxies")
 DEFINE_bool(harmony_collections, false,
             "enable harmony collections (sets, maps, and weak maps)")
-DEFINE_bool(harmony_observation, false,
-            "enable harmony object observation (implies harmony collections")
 DEFINE_bool(harmony_generators, false, "enable harmony generators")
 DEFINE_bool(harmony_iteration, false, "enable harmony iteration (for-of)")
 DEFINE_bool(harmony_numeric_literals, false,
@@ -196,7 +194,6 @@ DEFINE_implication(harmony, harmony_symbols)
 DEFINE_implication(harmony, harmony_promises)
 DEFINE_implication(harmony, harmony_proxies)
 DEFINE_implication(harmony, harmony_collections)
-DEFINE_implication(harmony, harmony_observation)
 DEFINE_implication(harmony, harmony_generators)
 DEFINE_implication(harmony, harmony_iteration)
 DEFINE_implication(harmony, harmony_numeric_literals)
@@ -205,7 +202,6 @@ DEFINE_implication(harmony, harmony_arrays)
 DEFINE_implication(harmony, harmony_maths)
 DEFINE_implication(harmony_promises, harmony_collections)
 DEFINE_implication(harmony_modules, harmony_scoping)
-DEFINE_implication(harmony_observation, harmony_collections)
 
 // Flags for experimental implementation features.
 DEFINE_bool(packed_arrays, true, "optimizes arrays that have no holes")
index a5a7ba2..8019da7 100644 (file)
--- a/src/ic.cc
+++ b/src/ic.cc
@@ -1205,7 +1205,7 @@ MaybeObject* StoreIC::Store(Handle<Object> object,
   }
 
   // Observed objects are always modified through the runtime.
-  if (FLAG_harmony_observation && receiver->map()->is_observed()) {
+  if (receiver->map()->is_observed()) {
     Handle<Object> result = JSReceiver::SetProperty(
         receiver, name, value, NONE, strict_mode(), store_mode);
     RETURN_IF_EMPTY_HANDLE(isolate(), result);
@@ -1671,7 +1671,7 @@ MaybeObject* KeyedStoreIC::Store(Handle<Object> object,
     if (maybe_object->IsFailure()) return maybe_object;
   } else {
     bool use_ic = FLAG_use_ic && !object->IsAccessCheckNeeded() &&
-        !(FLAG_harmony_observation && object->IsJSObject() &&
+        !(object->IsJSObject() &&
           JSObject::cast(*object)->map()->is_observed());
     if (use_ic && !object->IsSmi()) {
       // Don't use ICs for maps of the objects in Array's prototype chain. We
index 468da31..e822f0b 100644 (file)
 // implementation of (1) and (2) have "optimized" states which represent
 // common cases which can be handled more efficiently.
 
-var observationState = %GetObservationState();
-if (IS_UNDEFINED(observationState.callbackInfoMap)) {
-  observationState.callbackInfoMap = %ObservationWeakMapCreate();
-  observationState.objectInfoMap = %ObservationWeakMapCreate();
-  observationState.notifierObjectInfoMap = %ObservationWeakMapCreate();
-  observationState.pendingObservers = null;
-  observationState.nextCallbackPriority = 0;
-}
-
-function ObservationWeakMap(map) {
-  this.map_ = map;
-}
-
-ObservationWeakMap.prototype = {
-  get: function(key) {
-    key = %UnwrapGlobalProxy(key);
-    if (!IS_SPEC_OBJECT(key)) return UNDEFINED;
-    return %WeakCollectionGet(this.map_, key);
-  },
-  set: function(key, value) {
-    key = %UnwrapGlobalProxy(key);
-    if (!IS_SPEC_OBJECT(key)) return UNDEFINED;
-    %WeakCollectionSet(this.map_, key, value);
-  },
-  has: function(key) {
-    return !IS_UNDEFINED(this.get(key));
+var observationState;
+
+function GetObservationState() {
+  if (IS_UNDEFINED(observationState))
+    observationState = %GetObservationState();
+
+  if (IS_UNDEFINED(observationState.callbackInfoMap)) {
+    observationState.callbackInfoMap = %ObservationWeakMapCreate();
+    observationState.objectInfoMap = %ObservationWeakMapCreate();
+    observationState.notifierObjectInfoMap = %ObservationWeakMapCreate();
+    observationState.pendingObservers = null;
+    observationState.nextCallbackPriority = 0;
+  }
+
+  return observationState;
+}
+
+function GetWeakMapWrapper() {
+  function MapWrapper(map) {
+    this.map_ = map;
+  };
+
+  MapWrapper.prototype = {
+    get: function(key) {
+      key = %UnwrapGlobalProxy(key);
+      if (!IS_SPEC_OBJECT(key)) return UNDEFINED;
+      return %WeakCollectionGet(this.map_, key);
+    },
+    set: function(key, value) {
+      key = %UnwrapGlobalProxy(key);
+      if (!IS_SPEC_OBJECT(key)) return UNDEFINED;
+      %WeakCollectionSet(this.map_, key, value);
+    },
+    has: function(key) {
+      return !IS_UNDEFINED(this.get(key));
+    }
+  };
+
+  return MapWrapper;
+}
+
+var contextMaps;
+
+function GetContextMaps() {
+  if (IS_UNDEFINED(contextMaps)) {
+    var map = GetWeakMapWrapper();
+    var observationState = GetObservationState();
+    contextMaps = {
+      callbackInfoMap: new map(observationState.callbackInfoMap),
+      objectInfoMap: new map(observationState.objectInfoMap),
+      notifierObjectInfoMap: new map(observationState.notifierObjectInfoMap)
+    };
   }
-};
 
-var callbackInfoMap =
-    new ObservationWeakMap(observationState.callbackInfoMap);
-var objectInfoMap = new ObservationWeakMap(observationState.objectInfoMap);
-var notifierObjectInfoMap =
-    new ObservationWeakMap(observationState.notifierObjectInfoMap);
+  return contextMaps;
+}
+
+function GetCallbackInfoMap() {
+  return GetContextMaps().callbackInfoMap;
+}
+
+function GetObjectInfoMap() {
+  return GetContextMaps().objectInfoMap;
+}
+
+function GetNotifierObjectInfoMap() {
+  return GetContextMaps().notifierObjectInfoMap;
+}
+
+function GetPendingObservers() {
+  return GetObservationState().pendingObservers;
+}
+
+function SetPendingObservers(pendingObservers) {
+  GetObservationState().pendingObservers = pendingObservers;
+}
+
+function GetNextCallbackPriority() {
+  return GetObservationState().nextCallbackPriority++;
+}
 
 function nullProtoObject() {
   return { __proto__: null };
@@ -180,23 +226,23 @@ function ObjectInfoGetOrCreate(object) {
       performing: null,
       performingCount: 0,
     };
-    objectInfoMap.set(object, objectInfo);
+    GetObjectInfoMap().set(object, objectInfo);
   }
   return objectInfo;
 }
 
 function ObjectInfoGet(object) {
-  return objectInfoMap.get(object);
+  return GetObjectInfoMap().get(object);
 }
 
 function ObjectInfoGetFromNotifier(notifier) {
-  return notifierObjectInfoMap.get(notifier);
+  return GetNotifierObjectInfoMap().get(notifier);
 }
 
 function ObjectInfoGetNotifier(objectInfo) {
   if (IS_NULL(objectInfo.notifier)) {
     objectInfo.notifier = { __proto__: notifierPrototype };
-    notifierObjectInfoMap.set(objectInfo.notifier, objectInfo);
+    GetNotifierObjectInfoMap().set(objectInfo.notifier, objectInfo);
   }
 
   return objectInfo.notifier;
@@ -302,16 +348,16 @@ function AcceptArgIsValid(arg) {
 // priority. When a change record must be enqueued for the callback, it
 // normalizes. When delivery clears any pending change records, it re-optimizes.
 function CallbackInfoGet(callback) {
-  return callbackInfoMap.get(callback);
+  return GetCallbackInfoMap().get(callback);
 }
 
 function CallbackInfoGetOrCreate(callback) {
-  var callbackInfo = callbackInfoMap.get(callback);
+  var callbackInfo = GetCallbackInfoMap().get(callback);
   if (!IS_UNDEFINED(callbackInfo))
     return callbackInfo;
 
-  var priority = observationState.nextCallbackPriority++
-  callbackInfoMap.set(callback, priority);
+  var priority =  GetNextCallbackPriority();
+  GetCallbackInfoMap().set(callback, priority);
   return priority;
 }
 
@@ -323,12 +369,12 @@ function CallbackInfoGetPriority(callbackInfo) {
 }
 
 function CallbackInfoNormalize(callback) {
-  var callbackInfo = callbackInfoMap.get(callback);
+  var callbackInfo = GetCallbackInfoMap().get(callback);
   if (IS_NUMBER(callbackInfo)) {
     var priority = callbackInfo;
     callbackInfo = new InternalArray;
     callbackInfo.priority = priority;
-    callbackInfoMap.set(callback, callbackInfo);
+    GetCallbackInfoMap().set(callback, callbackInfo);
   }
   return callbackInfo;
 }
@@ -390,12 +436,12 @@ function ObserverEnqueueIfActive(observer, objectInfo, changeRecord,
   }
 
   var callbackInfo = CallbackInfoNormalize(callback);
-  if (IS_NULL(observationState.pendingObservers)) {
-    observationState.pendingObservers = nullProtoObject();
+  if (IS_NULL(GetPendingObservers())) {
+    SetPendingObservers(nullProtoObject())
     GetMicrotaskQueue().push(ObserveMicrotaskRunner);
     %SetMicrotaskPending(true);
   }
-  observationState.pendingObservers[callbackInfo.priority] = callback;
+  GetPendingObservers()[callbackInfo.priority] = callback;
   callbackInfo.push(changeRecord);
 }
 
@@ -548,17 +594,17 @@ function ObjectGetNotifier(object) {
 }
 
 function CallbackDeliverPending(callback) {
-  var callbackInfo = callbackInfoMap.get(callback);
+  var callbackInfo = GetCallbackInfoMap().get(callback);
   if (IS_UNDEFINED(callbackInfo) || IS_NUMBER(callbackInfo))
     return false;
 
   // Clear the pending change records from callback and return it to its
   // "optimized" state.
   var priority = callbackInfo.priority;
-  callbackInfoMap.set(callback, priority);
+  GetCallbackInfoMap().set(callback, priority);
 
-  if (observationState.pendingObservers)
-    delete observationState.pendingObservers[priority];
+  if (GetPendingObservers())
+    delete GetPendingObservers()[priority];
 
   var delivered = [];
   %MoveArrayContents(callbackInfo, delivered);
@@ -577,9 +623,9 @@ function ObjectDeliverChangeRecords(callback) {
 }
 
 function ObserveMicrotaskRunner() {
-  var pendingObservers = observationState.pendingObservers;
+  var pendingObservers = GetPendingObservers();
   if (pendingObservers) {
-    observationState.pendingObservers = null;
+    SetPendingObservers(null);
     for (var i in pendingObservers) {
       CallbackDeliverPending(pendingObservers[i]);
     }
index 8e96c85..32b1d2c 100644 (file)
@@ -2199,8 +2199,7 @@ Handle<Object> JSObject::AddProperty(Handle<JSObject> object,
     AddSlowProperty(object, name, value, attributes);
   }
 
-  if (FLAG_harmony_observation &&
-      object->map()->is_observed() &&
+  if (object->map()->is_observed() &&
       *name != isolate->heap()->hidden_string()) {
     Handle<Object> old_value = isolate->factory()->the_hole_value();
     EnqueueChangeRecord(object, "add", name, old_value);
@@ -4090,8 +4089,7 @@ Handle<Object> JSObject::SetPropertyForResult(Handle<JSObject> object,
   }
 
   Handle<Object> old_value = isolate->factory()->the_hole_value();
-  bool is_observed = FLAG_harmony_observation &&
-                     object->map()->is_observed() &&
+  bool is_observed = object->map()->is_observed() &&
                      *name != isolate->heap()->hidden_string();
   if (is_observed && lookup->IsDataProperty()) {
     old_value = Object::GetProperty(object, name);
@@ -4213,8 +4211,7 @@ Handle<Object> JSObject::SetLocalPropertyIgnoreAttributes(
 
   Handle<Object> old_value = isolate->factory()->the_hole_value();
   PropertyAttributes old_attributes = ABSENT;
-  bool is_observed = FLAG_harmony_observation &&
-                     object->map()->is_observed() &&
+  bool is_observed = object->map()->is_observed() &&
                      *name != isolate->heap()->hidden_string();
   if (is_observed && lookup.IsProperty()) {
     if (lookup.IsDataProperty()) old_value =
@@ -5196,7 +5193,7 @@ Handle<Object> JSObject::DeleteElement(Handle<JSObject> object,
 
   Handle<Object> old_value;
   bool should_enqueue_change_record = false;
-  if (FLAG_harmony_observation && object->map()->is_observed()) {
+  if (object->map()->is_observed()) {
     should_enqueue_change_record = HasLocalElement(object, index);
     if (should_enqueue_change_record) {
       old_value = object->GetLocalElementAccessorPair(index) != NULL
@@ -5267,8 +5264,7 @@ Handle<Object> JSObject::DeleteProperty(Handle<JSObject> object,
   }
 
   Handle<Object> old_value = isolate->factory()->the_hole_value();
-  bool is_observed = FLAG_harmony_observation &&
-                     object->map()->is_observed() &&
+  bool is_observed = object->map()->is_observed() &&
                      *name != isolate->heap()->hidden_string();
   if (is_observed && lookup.IsDataProperty()) {
     old_value = Object::GetProperty(object, name);
@@ -5504,7 +5500,7 @@ Handle<Object> JSObject::PreventExtensions(Handle<JSObject> object) {
   object->set_map(*new_map);
   ASSERT(!object->map()->is_extensible());
 
-  if (FLAG_harmony_observation && object->map()->is_observed()) {
+  if (object->map()->is_observed()) {
     EnqueueChangeRecord(object, "preventExtensions", Handle<Name>(),
                         isolate->factory()->the_hole_value());
   }
@@ -6361,8 +6357,7 @@ void JSObject::DefineAccessor(Handle<JSObject> object,
   bool is_element = name->AsArrayIndex(&index);
 
   Handle<Object> old_value = isolate->factory()->the_hole_value();
-  bool is_observed = FLAG_harmony_observation &&
-                     object->map()->is_observed() &&
+  bool is_observed = object->map()->is_observed() &&
                      *name != isolate->heap()->hidden_string();
   bool preexists = false;
   if (is_observed) {
@@ -11422,7 +11417,7 @@ static void EndPerformSplice(Handle<JSArray> object) {
 MaybeObject* JSArray::SetElementsLength(Object* len) {
   // We should never end in here with a pixel or external array.
   ASSERT(AllowsSetElementsLength());
-  if (!(FLAG_harmony_observation && map()->is_observed()))
+  if (!map()->is_observed())
     return GetElementsAccessor()->SetLength(this, len);
 
   Isolate* isolate = GetIsolate();
@@ -12553,7 +12548,7 @@ Handle<Object> JSObject::SetElement(Handle<JSObject> object,
     dictionary->set_requires_slow_elements();
   }
 
-  if (!(FLAG_harmony_observation && object->map()->is_observed())) {
+  if (!object->map()->is_observed()) {
     return object->HasIndexedInterceptor()
       ? SetElementWithInterceptor(object, index, value, attributes, strict_mode,
                                   check_prototype,
@@ -13154,7 +13149,7 @@ bool JSObject::ShouldConvertToFastElements() {
   if (IsAccessCheckNeeded()) return false;
   // Observed objects may not go to fast mode because they rely on map checks,
   // and for fast element accesses we sometimes check element kinds only.
-  if (FLAG_harmony_observation && map()->is_observed()) return false;
+  if (map()->is_observed()) return false;
 
   FixedArray* elements = FixedArray::cast(this->elements());
   SeededNumberDictionary* dictionary = NULL;
index c0c87a4..2d760a4 100644 (file)
@@ -1648,7 +1648,7 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_SetPrototype) {
   ASSERT(args.length() == 2);
   CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0);
   CONVERT_ARG_HANDLE_CHECKED(Object, prototype, 1);
-  if (FLAG_harmony_observation && obj->map()->is_observed()) {
+  if (obj->map()->is_observed()) {
     Handle<Object> old_value(
         GetPrototypeSkipHiddenPrototypes(isolate, *obj), isolate);
 
index 3157f3e..933172e 100644 (file)
@@ -2004,8 +2004,14 @@ TEST(PrototypeTransitionClearing) {
   Factory* factory = isolate->factory();
   v8::HandleScope scope(CcTest::isolate());
 
+  CompileRun("var base = {};");
+  Handle<JSObject> baseObject =
+      v8::Utils::OpenHandle(
+          *v8::Handle<v8::Object>::Cast(
+              CcTest::global()->Get(v8_str("base"))));
+  int initialTransitions = baseObject->map()->NumberOfProtoTransitions();
+
   CompileRun(
-      "var base = {};"
       "var live = [];"
       "for (var i = 0; i < 10; i++) {"
       "  var object = {};"
@@ -2014,25 +2020,22 @@ TEST(PrototypeTransitionClearing) {
       "  if (i >= 3) live.push(object, prototype);"
       "}");
 
-  Handle<JSObject> baseObject =
-      v8::Utils::OpenHandle(
-          *v8::Handle<v8::Object>::Cast(
-              CcTest::global()->Get(v8_str("base"))));
-
   // Verify that only dead prototype transitions are cleared.
-  CHECK_EQ(10, baseObject->map()->NumberOfProtoTransitions());
+  CHECK_EQ(initialTransitions + 10,
+      baseObject->map()->NumberOfProtoTransitions());
   CcTest::heap()->CollectAllGarbage(Heap::kAbortIncrementalMarkingMask);
   const int transitions = 10 - 3;
-  CHECK_EQ(transitions, baseObject->map()->NumberOfProtoTransitions());
+  CHECK_EQ(initialTransitions + transitions,
+      baseObject->map()->NumberOfProtoTransitions());
 
   // Verify that prototype transitions array was compacted.
   FixedArray* trans = baseObject->map()->GetPrototypeTransitions();
-  for (int i = 0; i < transitions; i++) {
+  for (int i = initialTransitions; i < initialTransitions + transitions; i++) {
     int j = Map::kProtoTransitionHeaderSize +
         i * Map::kProtoTransitionElementsPerEntry;
     CHECK(trans->get(j + Map::kProtoTransitionMapOffset)->IsMap());
     Object* proto = trans->get(j + Map::kProtoTransitionPrototypeOffset);
-    CHECK(proto->IsTheHole() || proto->IsJSObject());
+    CHECK(proto->IsJSObject());
   }
 
   // Make sure next prototype is placed on an old-space evacuation candidate.
index 4db760d..108337a 100644 (file)
@@ -36,7 +36,6 @@ namespace {
 class HarmonyIsolate {
  public:
   HarmonyIsolate() {
-    i::FLAG_harmony_observation = true;
     i::FLAG_harmony_promises = true;
     isolate_ = Isolate::New();
     isolate_->Enter();
index 0a30d4e..6bde5b3 100644 (file)
 using namespace v8;
 namespace i = v8::internal;
 
-namespace {
-// Need to create a new isolate when FLAG_harmony_observation is on.
-class HarmonyIsolate {
- public:
-  HarmonyIsolate() {
-    i::FLAG_harmony_observation = true;
-    isolate_ = Isolate::New();
-    isolate_->Enter();
-  }
-
-  ~HarmonyIsolate() {
-    isolate_->Exit();
-    isolate_->Dispose();
-  }
-
-  Isolate* GetIsolate() const { return isolate_; }
-
- private:
-  Isolate* isolate_;
-};
-}
-
 
 TEST(PerIsolateState) {
-  HarmonyIsolate isolate;
-  HandleScope scope(isolate.GetIsolate());
-  LocalContext context1(isolate.GetIsolate());
+  HandleScope scope(CcTest::isolate());
+  LocalContext context1(CcTest::isolate());
   CompileRun(
       "var count = 0;"
       "var calls = 0;"
@@ -71,29 +48,29 @@ TEST(PerIsolateState) {
       "(function() { obj.foo = 'bar'; })");
   Handle<Value> notify_fun2;
   {
-    LocalContext context2(isolate.GetIsolate());
-    context2->Global()->Set(String::NewFromUtf8(isolate.GetIsolate(), "obj"),
+    LocalContext context2(CcTest::isolate());
+    context2->Global()->Set(String::NewFromUtf8(CcTest::isolate(), "obj"),
                             obj);
     notify_fun2 = CompileRun(
         "(function() { obj.foo = 'baz'; })");
   }
   Handle<Value> notify_fun3;
   {
-    LocalContext context3(isolate.GetIsolate());
-    context3->Global()->Set(String::NewFromUtf8(isolate.GetIsolate(), "obj"),
+    LocalContext context3(CcTest::isolate());
+    context3->Global()->Set(String::NewFromUtf8(CcTest::isolate(), "obj"),
                             obj);
     notify_fun3 = CompileRun(
         "(function() { obj.foo = 'bat'; })");
   }
   {
-    LocalContext context4(isolate.GetIsolate());
+    LocalContext context4(CcTest::isolate());
     context4->Global()->Set(
-        String::NewFromUtf8(isolate.GetIsolate(), "observer"), observer);
-    context4->Global()->Set(String::NewFromUtf8(isolate.GetIsolate(), "fun1"),
+        String::NewFromUtf8(CcTest::isolate(), "observer"), observer);
+    context4->Global()->Set(String::NewFromUtf8(CcTest::isolate(), "fun1"),
                             notify_fun1);
-    context4->Global()->Set(String::NewFromUtf8(isolate.GetIsolate(), "fun2"),
+    context4->Global()->Set(String::NewFromUtf8(CcTest::isolate(), "fun2"),
                             notify_fun2);
-    context4->Global()->Set(String::NewFromUtf8(isolate.GetIsolate(), "fun3"),
+    context4->Global()->Set(String::NewFromUtf8(CcTest::isolate(), "fun3"),
                             notify_fun3);
     CompileRun("fun1(); fun2(); fun3(); Object.deliverChangeRecords(observer)");
   }
@@ -103,9 +80,8 @@ TEST(PerIsolateState) {
 
 
 TEST(EndOfMicrotaskDelivery) {
-  HarmonyIsolate isolate;
-  HandleScope scope(isolate.GetIsolate());
-  LocalContext context(isolate.GetIsolate());
+  HandleScope scope(CcTest::isolate());
+  LocalContext context(CcTest::isolate());
   CompileRun(
       "var obj = {};"
       "var count = 0;"
@@ -117,9 +93,8 @@ TEST(EndOfMicrotaskDelivery) {
 
 
 TEST(DeliveryOrdering) {
-  HarmonyIsolate isolate;
-  HandleScope scope(isolate.GetIsolate());
-  LocalContext context(isolate.GetIsolate());
+  HandleScope scope(CcTest::isolate());
+  LocalContext context(CcTest::isolate());
   CompileRun(
       "var obj1 = {};"
       "var obj2 = {};"
@@ -149,9 +124,8 @@ TEST(DeliveryOrdering) {
 
 
 TEST(DeliveryOrderingReentrant) {
-  HarmonyIsolate isolate;
-  HandleScope scope(isolate.GetIsolate());
-  LocalContext context(isolate.GetIsolate());
+  HandleScope scope(CcTest::isolate());
+  LocalContext context(CcTest::isolate());
   CompileRun(
       "var obj = {};"
       "var reentered = false;"
@@ -181,9 +155,8 @@ TEST(DeliveryOrderingReentrant) {
 
 
 TEST(DeliveryOrderingDeliverChangeRecords) {
-  HarmonyIsolate isolate;
-  HandleScope scope(isolate.GetIsolate());
-  LocalContext context(isolate.GetIsolate());
+  HandleScope scope(CcTest::isolate());
+  LocalContext context(CcTest::isolate());
   CompileRun(
       "var obj = {};"
       "var ordering = [];"
@@ -206,21 +179,20 @@ TEST(DeliveryOrderingDeliverChangeRecords) {
 
 
 TEST(ObjectHashTableGrowth) {
-  HarmonyIsolate isolate;
-  HandleScope scope(isolate.GetIsolate());
+  HandleScope scope(CcTest::isolate());
   // Initializing this context sets up initial hash tables.
-  LocalContext context(isolate.GetIsolate());
+  LocalContext context(CcTest::isolate());
   Handle<Value> obj = CompileRun("obj = {};");
   Handle<Value> observer = CompileRun(
       "var ran = false;"
       "(function() { ran = true })");
   {
     // As does initializing this context.
-    LocalContext context2(isolate.GetIsolate());
-    context2->Global()->Set(String::NewFromUtf8(isolate.GetIsolate(), "obj"),
+    LocalContext context2(CcTest::isolate());
+    context2->Global()->Set(String::NewFromUtf8(CcTest::isolate(), "obj"),
                             obj);
     context2->Global()->Set(
-        String::NewFromUtf8(isolate.GetIsolate(), "observer"), observer);
+        String::NewFromUtf8(CcTest::isolate(), "observer"), observer);
     CompileRun(
         "var objArr = [];"
         // 100 objects should be enough to make the hash table grow
@@ -238,9 +210,8 @@ TEST(ObjectHashTableGrowth) {
 
 
 TEST(GlobalObjectObservation) {
-  HarmonyIsolate isolate;
-  LocalContext context(isolate.GetIsolate());
-  HandleScope scope(isolate.GetIsolate());
+  LocalContext context(CcTest::isolate());
+  HandleScope scope(CcTest::isolate());
   Handle<Object> global_proxy = context->Global();
   CompileRun(
       "var records = [];"
@@ -261,7 +232,7 @@ TEST(GlobalObjectObservation) {
   // to the old context.
   context->DetachGlobal();
   {
-    LocalContext context2(isolate.GetIsolate());
+    LocalContext context2(CcTest::isolate());
     CompileRun(
         "var records2 = [];"
         "var global = this;"
@@ -279,7 +250,7 @@ TEST(GlobalObjectObservation) {
   {
     // Delegates to Context::New
     LocalContext context3(
-        isolate.GetIsolate(), NULL, Handle<ObjectTemplate>(), global_proxy);
+        CcTest::isolate(), NULL, Handle<ObjectTemplate>(), global_proxy);
     CompileRun(
         "var records3 = [];"
         "Object.observe(this, function(r) { [].push.apply(records3, r) });"
@@ -327,12 +298,11 @@ static void ExpectRecords(v8::Isolate* isolate,
 }
 
 #define EXPECT_RECORDS(records, expectations)                \
-  ExpectRecords(isolate.GetIsolate(), records, expectations, \
+  ExpectRecords(CcTest::isolate(), records, expectations, \
                 ARRAY_SIZE(expectations))
 
 TEST(APITestBasicMutation) {
-  HarmonyIsolate isolate;
-  v8::Isolate* v8_isolate = isolate.GetIsolate();
+  v8::Isolate* v8_isolate = CcTest::isolate();
   HandleScope scope(v8_isolate);
   LocalContext context(v8_isolate);
   Handle<Object> obj = Handle<Object>::Cast(CompileRun(
@@ -379,8 +349,7 @@ TEST(APITestBasicMutation) {
 
 
 TEST(HiddenPrototypeObservation) {
-  HarmonyIsolate isolate;
-  v8::Isolate* v8_isolate = isolate.GetIsolate();
+  v8::Isolate* v8_isolate = CcTest::isolate();
   HandleScope scope(v8_isolate);
   LocalContext context(v8_isolate);
   Handle<FunctionTemplate> tmpl = FunctionTemplate::New(v8_isolate);
@@ -431,15 +400,14 @@ static int NumberOfElements(i::Handle<i::JSWeakMap> map) {
 
 
 TEST(ObservationWeakMap) {
-  HarmonyIsolate isolate;
-  HandleScope scope(isolate.GetIsolate());
-  LocalContext context(isolate.GetIsolate());
+  HandleScope scope(CcTest::isolate());
+  LocalContext context(CcTest::isolate());
   CompileRun(
       "var obj = {};"
       "Object.observe(obj, function(){});"
       "Object.getNotifier(obj);"
       "obj = null;");
-  i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate.GetIsolate());
+  i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(CcTest::isolate());
   i::Handle<i::JSObject> observation_state =
       i_isolate->factory()->observation_state();
   i::Handle<i::JSWeakMap> callbackInfoMap =
@@ -528,17 +496,16 @@ static Handle<Object> CreateAccessCheckedObject(
 
 
 TEST(NamedAccessCheck) {
-  HarmonyIsolate isolate;
   const AccessType types[] = { ACCESS_GET, ACCESS_HAS };
   for (size_t i = 0; i < ARRAY_SIZE(types); ++i) {
-    HandleScope scope(isolate.GetIsolate());
-    LocalContext context(isolate.GetIsolate());
+    HandleScope scope(CcTest::isolate());
+    LocalContext context(CcTest::isolate());
     g_access_block_type = types[i];
     Handle<Object> instance = CreateAccessCheckedObject(
-        isolate.GetIsolate(),
+        CcTest::isolate(),
         NamedAccessAllowUnlessBlocked,
         IndexedAccessAlwaysAllowed,
-        String::NewFromUtf8(isolate.GetIsolate(), "foo"));
+        String::NewFromUtf8(CcTest::isolate(), "foo"));
     CompileRun("var records = null;"
                "var objNoCheck = {};"
                "var observer = function(r) { records = r };"
@@ -546,11 +513,11 @@ TEST(NamedAccessCheck) {
                "Object.observe(objNoCheck, observer);");
     Handle<Value> obj_no_check = CompileRun("objNoCheck");
     {
-      LocalContext context2(isolate.GetIsolate());
-      context2->Global()->Set(String::NewFromUtf8(isolate.GetIsolate(), "obj"),
+      LocalContext context2(CcTest::isolate());
+      context2->Global()->Set(String::NewFromUtf8(CcTest::isolate(), "obj"),
                               instance);
       context2->Global()->Set(
-          String::NewFromUtf8(isolate.GetIsolate(), "objNoCheck"),
+          String::NewFromUtf8(CcTest::isolate(), "objNoCheck"),
           obj_no_check);
       CompileRun("var records2 = null;"
                  "var observer2 = function(r) { records2 = r };"
@@ -564,9 +531,9 @@ TEST(NamedAccessCheck) {
       const RecordExpectation expected_records2[] = {
         { instance, "add", "foo", Handle<Value>() },
         { instance, "update", "foo",
-          String::NewFromUtf8(isolate.GetIsolate(), "bar") },
+          String::NewFromUtf8(CcTest::isolate(), "bar") },
         { instance, "reconfigure", "foo",
-          Number::New(isolate.GetIsolate(), 5) },
+          Number::New(CcTest::isolate(), 5) },
         { instance, "add", "bar", Handle<Value>() },
         { obj_no_check, "add", "baz", Handle<Value>() },
       };
@@ -582,15 +549,14 @@ TEST(NamedAccessCheck) {
 
 
 TEST(IndexedAccessCheck) {
-  HarmonyIsolate isolate;
   const AccessType types[] = { ACCESS_GET, ACCESS_HAS };
   for (size_t i = 0; i < ARRAY_SIZE(types); ++i) {
-    HandleScope scope(isolate.GetIsolate());
-    LocalContext context(isolate.GetIsolate());
+    HandleScope scope(CcTest::isolate());
+    LocalContext context(CcTest::isolate());
     g_access_block_type = types[i];
     Handle<Object> instance = CreateAccessCheckedObject(
-        isolate.GetIsolate(), NamedAccessAlwaysAllowed,
-        IndexedAccessAllowUnlessBlocked, Number::New(isolate.GetIsolate(), 7));
+        CcTest::isolate(), NamedAccessAlwaysAllowed,
+        IndexedAccessAllowUnlessBlocked, Number::New(CcTest::isolate(), 7));
     CompileRun("var records = null;"
                "var objNoCheck = {};"
                "var observer = function(r) { records = r };"
@@ -598,11 +564,11 @@ TEST(IndexedAccessCheck) {
                "Object.observe(objNoCheck, observer);");
     Handle<Value> obj_no_check = CompileRun("objNoCheck");
     {
-      LocalContext context2(isolate.GetIsolate());
-      context2->Global()->Set(String::NewFromUtf8(isolate.GetIsolate(), "obj"),
+      LocalContext context2(CcTest::isolate());
+      context2->Global()->Set(String::NewFromUtf8(CcTest::isolate(), "obj"),
                               instance);
       context2->Global()->Set(
-          String::NewFromUtf8(isolate.GetIsolate(), "objNoCheck"),
+          String::NewFromUtf8(CcTest::isolate(), "objNoCheck"),
           obj_no_check);
       CompileRun("var records2 = null;"
                  "var observer2 = function(r) { records2 = r };"
@@ -616,8 +582,8 @@ TEST(IndexedAccessCheck) {
       const RecordExpectation expected_records2[] = {
         { instance, "add", "7", Handle<Value>() },
         { instance, "update", "7",
-          String::NewFromUtf8(isolate.GetIsolate(), "foo") },
-        { instance, "reconfigure", "7", Number::New(isolate.GetIsolate(), 5) },
+          String::NewFromUtf8(CcTest::isolate(), "foo") },
+        { instance, "reconfigure", "7", Number::New(CcTest::isolate(), 5) },
         { instance, "add", "8", Handle<Value>() },
         { obj_no_check, "add", "42", Handle<Value>() }
       };
@@ -633,13 +599,12 @@ TEST(IndexedAccessCheck) {
 
 
 TEST(SpliceAccessCheck) {
-  HarmonyIsolate isolate;
-  HandleScope scope(isolate.GetIsolate());
-  LocalContext context(isolate.GetIsolate());
+  HandleScope scope(CcTest::isolate());
+  LocalContext context(CcTest::isolate());
   g_access_block_type = ACCESS_GET;
   Handle<Object> instance = CreateAccessCheckedObject(
-      isolate.GetIsolate(), NamedAccessAlwaysAllowed,
-      IndexedAccessAllowUnlessBlocked, Number::New(isolate.GetIsolate(), 1));
+      CcTest::isolate(), NamedAccessAlwaysAllowed,
+      IndexedAccessAllowUnlessBlocked, Number::New(CcTest::isolate(), 1));
   CompileRun("var records = null;"
              "obj[1] = 'foo';"
              "obj.length = 2;"
@@ -649,11 +614,11 @@ TEST(SpliceAccessCheck) {
              "Array.observe(objNoCheck, observer);");
   Handle<Value> obj_no_check = CompileRun("objNoCheck");
   {
-    LocalContext context2(isolate.GetIsolate());
-    context2->Global()->Set(String::NewFromUtf8(isolate.GetIsolate(), "obj"),
+    LocalContext context2(CcTest::isolate());
+    context2->Global()->Set(String::NewFromUtf8(CcTest::isolate(), "obj"),
                             instance);
     context2->Global()->Set(
-        String::NewFromUtf8(isolate.GetIsolate(), "objNoCheck"), obj_no_check);
+        String::NewFromUtf8(CcTest::isolate(), "objNoCheck"), obj_no_check);
     CompileRun("var records2 = null;"
                "var observer2 = function(r) { records2 = r };"
                "Array.observe(obj, observer2);"
@@ -680,11 +645,10 @@ TEST(SpliceAccessCheck) {
 
 
 TEST(DisallowAllForAccessKeys) {
-  HarmonyIsolate isolate;
-  HandleScope scope(isolate.GetIsolate());
-  LocalContext context(isolate.GetIsolate());
+  HandleScope scope(CcTest::isolate());
+  LocalContext context(CcTest::isolate());
   Handle<Object> instance = CreateAccessCheckedObject(
-      isolate.GetIsolate(), BlockAccessKeys, IndexedAccessAlwaysAllowed);
+      CcTest::isolate(), BlockAccessKeys, IndexedAccessAlwaysAllowed);
   CompileRun("var records = null;"
              "var objNoCheck = {};"
              "var observer = function(r) { records = r };"
@@ -692,11 +656,11 @@ TEST(DisallowAllForAccessKeys) {
              "Object.observe(objNoCheck, observer);");
   Handle<Value> obj_no_check = CompileRun("objNoCheck");
   {
-    LocalContext context2(isolate.GetIsolate());
-    context2->Global()->Set(String::NewFromUtf8(isolate.GetIsolate(), "obj"),
+    LocalContext context2(CcTest::isolate());
+    context2->Global()->Set(String::NewFromUtf8(CcTest::isolate(), "obj"),
                             instance);
     context2->Global()->Set(
-        String::NewFromUtf8(isolate.GetIsolate(), "objNoCheck"), obj_no_check);
+        String::NewFromUtf8(CcTest::isolate(), "objNoCheck"), obj_no_check);
     CompileRun("var records2 = null;"
                "var observer2 = function(r) { records2 = r };"
                "Object.observe(obj, observer2);"
@@ -719,24 +683,23 @@ TEST(DisallowAllForAccessKeys) {
 
 
 TEST(AccessCheckDisallowApiModifications) {
-  HarmonyIsolate isolate;
-  HandleScope scope(isolate.GetIsolate());
-  LocalContext context(isolate.GetIsolate());
+  HandleScope scope(CcTest::isolate());
+  LocalContext context(CcTest::isolate());
   Handle<Object> instance = CreateAccessCheckedObject(
-      isolate.GetIsolate(), BlockAccessKeys, IndexedAccessAlwaysAllowed);
+      CcTest::isolate(), BlockAccessKeys, IndexedAccessAlwaysAllowed);
   CompileRun("var records = null;"
              "var observer = function(r) { records = r };"
              "Object.observe(obj, observer);");
   {
-    LocalContext context2(isolate.GetIsolate());
-    context2->Global()->Set(String::NewFromUtf8(isolate.GetIsolate(), "obj"),
+    LocalContext context2(CcTest::isolate());
+    context2->Global()->Set(String::NewFromUtf8(CcTest::isolate(), "obj"),
                             instance);
     CompileRun("var records2 = null;"
                "var observer2 = function(r) { records2 = r };"
                "Object.observe(obj, observer2);");
-    instance->Set(5, String::NewFromUtf8(isolate.GetIsolate(), "bar"));
-    instance->Set(String::NewFromUtf8(isolate.GetIsolate(), "foo"),
-                  String::NewFromUtf8(isolate.GetIsolate(), "bar"));
+    instance->Set(5, String::NewFromUtf8(CcTest::isolate(), "bar"));
+    instance->Set(String::NewFromUtf8(CcTest::isolate(), "foo"),
+                  String::NewFromUtf8(CcTest::isolate(), "bar"));
     CompileRun("");  // trigger delivery
     const RecordExpectation expected_records2[] = {
       { instance, "add", "5", Handle<Value>() },
@@ -749,18 +712,17 @@ TEST(AccessCheckDisallowApiModifications) {
 
 
 TEST(HiddenPropertiesLeakage) {
-  HarmonyIsolate isolate;
-  HandleScope scope(isolate.GetIsolate());
-  LocalContext context(isolate.GetIsolate());
+  HandleScope scope(CcTest::isolate());
+  LocalContext context(CcTest::isolate());
   CompileRun("var obj = {};"
              "var records = null;"
              "var observer = function(r) { records = r };"
              "Object.observe(obj, observer);");
   Handle<Value> obj =
-      context->Global()->Get(String::NewFromUtf8(isolate.GetIsolate(), "obj"));
+      context->Global()->Get(String::NewFromUtf8(CcTest::isolate(), "obj"));
   Handle<Object>::Cast(obj)
-      ->SetHiddenValue(String::NewFromUtf8(isolate.GetIsolate(), "foo"),
-                       Null(isolate.GetIsolate()));
+      ->SetHiddenValue(String::NewFromUtf8(CcTest::isolate(), "foo"),
+                       Null(CcTest::isolate()));
   CompileRun("");  // trigger delivery
   CHECK(CompileRun("records")->IsNull());
 }
index 1cbdb37..1a7283c 100644 (file)
@@ -59,7 +59,7 @@ for (i = 0; i < scripts.length; i++) {
 }
 
 // This has to be updated if the number of native scripts change.
-assertTrue(named_native_count == 16 || named_native_count == 17);
+assertTrue(named_native_count == 17 || named_native_count == 18);
 // Only the 'gc' extension is loaded.
 assertEquals(1, extension_count);
 // This script and mjsunit.js has been loaded.  If using d8, d8 loads
index b8c4bec..52babed 100644 (file)
@@ -63,11 +63,11 @@ FAIL getSortedOwnPropertyNames(decodeURI) should be length,name. Was arguments,c
 FAIL getSortedOwnPropertyNames(decodeURIComponent) should be length,name. Was arguments,caller,length,name.
 FAIL getSortedOwnPropertyNames(encodeURI) should be length,name. Was arguments,caller,length,name.
 FAIL getSortedOwnPropertyNames(encodeURIComponent) should be length,name. Was arguments,caller,length,name.
-FAIL getSortedOwnPropertyNames(Object) should be create,defineProperties,defineProperty,freeze,getOwnPropertyDescriptor,getOwnPropertyNames,getPrototypeOf,isExtensible,isFrozen,isSealed,keys,length,name,preventExtensions,prototype,seal,setPrototypeOf. Was arguments,caller,create,defineProperties,defineProperty,freeze,getOwnPropertyDescriptor,getOwnPropertyNames,getPrototypeOf,is,isExtensible,isFrozen,isSealed,keys,length,name,preventExtensions,prototype,seal,setPrototypeOf.
+FAIL getSortedOwnPropertyNames(Object) should be create,defineProperties,defineProperty,freeze,getOwnPropertyDescriptor,getOwnPropertyNames,getPrototypeOf,isExtensible,isFrozen,isSealed,keys,length,name,preventExtensions,prototype,seal,setPrototypeOf. Was arguments,caller,create,defineProperties,defineProperty,deliverChangeRecords,freeze,getNotifier,getOwnPropertyDescriptor,getOwnPropertyNames,getPrototypeOf,is,isExtensible,isFrozen,isSealed,keys,length,name,observe,preventExtensions,prototype,seal,setPrototypeOf,unobserve.
 PASS getSortedOwnPropertyNames(Object.prototype) is ['__defineGetter__', '__defineSetter__', '__lookupGetter__', '__lookupSetter__', '__proto__', 'constructor', 'hasOwnProperty', 'isPrototypeOf', 'propertyIsEnumerable', 'toLocaleString', 'toString', 'valueOf']
 FAIL getSortedOwnPropertyNames(Function) should be length,name,prototype. Was arguments,caller,length,name,prototype.
 FAIL getSortedOwnPropertyNames(Function.prototype) should be apply,bind,call,constructor,length,name,toString. Was apply,arguments,bind,call,caller,constructor,length,name,toString.
-FAIL getSortedOwnPropertyNames(Array) should be isArray,length,name,prototype. Was arguments,caller,isArray,length,name,prototype.
+FAIL getSortedOwnPropertyNames(Array) should be isArray,length,name,prototype. Was arguments,caller,isArray,length,name,observe,prototype,unobserve.
 PASS getSortedOwnPropertyNames(Array.prototype) is ['concat', 'constructor', 'every', 'filter', 'forEach', 'indexOf', 'join', 'lastIndexOf', 'length', 'map', 'pop', 'push', 'reduce', 'reduceRight', 'reverse', 'shift', 'slice', 'some', 'sort', 'splice', 'toLocaleString', 'toString', 'unshift']
 FAIL getSortedOwnPropertyNames(String) should be fromCharCode,length,name,prototype. Was arguments,caller,fromCharCode,length,name,prototype.
 PASS getSortedOwnPropertyNames(String.prototype) is ['anchor', 'big', 'blink', 'bold', 'charAt', 'charCodeAt', 'concat', 'constructor', 'fixed', 'fontcolor', 'fontsize', 'indexOf', 'italics', 'lastIndexOf', 'length', 'link', 'localeCompare', 'match', 'normalize', 'replace', 'search', 'slice', 'small', 'split', 'strike', 'sub', 'substr', 'substring', 'sup', 'toLocaleLowerCase', 'toLocaleUpperCase', 'toLowerCase', 'toString', 'toUpperCase', 'trim', 'trimLeft', 'trimRight', 'valueOf']
index d5a4270..7acb7e1 100644 (file)
           '../../src/regexp.js',
           '../../src/arraybuffer.js',
           '../../src/typedarray.js',
+          '../../src/object-observe.js',
           '../../src/macros.py',
         ],
         'experimental_library_files': [
           '../../src/symbol.js',
           '../../src/proxy.js',
           '../../src/collection.js',
-          '../../src/object-observe.js',
           '../../src/promise.js',
           '../../src/generator.js',
           '../../src/array-iterator.js',