Catch exceptions thrown when enqueuing change records.
authoryangguo@chromium.org <yangguo@chromium.org>
Tue, 14 Oct 2014 14:46:11 +0000 (14:46 +0000)
committeryangguo@chromium.org <yangguo@chromium.org>
Tue, 14 Oct 2014 14:46:11 +0000 (14:46 +0000)
R=ishell@chromium.org
BUG=chromium:417709
LOG=N

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

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

src/accessors.cc
src/accessors.h
src/bootstrapper.cc
src/objects.cc
src/objects.h
src/runtime/runtime-function.cc
src/runtime/runtime-object.cc
test/mjsunit/regress/regress-417709a.js [new file with mode: 0644]

index 9bd6e5b..ed9d294 100644 (file)
@@ -172,7 +172,10 @@ void Accessors::ArgumentsIteratorSetter(
   LookupIterator it(object, Utils::OpenHandle(*name));
   CHECK_EQ(LookupIterator::ACCESSOR, it.state());
   DCHECK(it.HolderIsReceiverOrHiddenPrototype());
-  Object::SetDataProperty(&it, value);
+
+  if (Object::SetDataProperty(&it, value).is_null()) {
+    isolate->OptionalRescheduleException(false);
+  }
 }
 
 
@@ -247,7 +250,7 @@ void Accessors::ArrayLengthSetter(
 
   if (uint32_v->Number() == number_v->Number()) {
     maybe = JSArray::SetElementsLength(array_handle, uint32_v);
-    maybe.Check();
+    if (maybe.is_null()) isolate->OptionalRescheduleException(false);
     return;
   }
 
@@ -881,9 +884,8 @@ static Handle<Object> GetFunctionPrototype(Isolate* isolate,
 }
 
 
-static Handle<Object> SetFunctionPrototype(Isolate* isolate,
-                                           Handle<JSFunction> function,
-                                           Handle<Object> value) {
+MUST_USE_RESULT static MaybeHandle<Object> SetFunctionPrototype(
+    Isolate* isolate, Handle<JSFunction> function, Handle<Object> value) {
   Handle<Object> old_value;
   bool is_observed = function->map()->is_observed();
   if (is_observed) {
@@ -897,16 +899,17 @@ static Handle<Object> SetFunctionPrototype(Isolate* isolate,
   DCHECK(function->prototype() == *value);
 
   if (is_observed && !old_value->SameValue(*value)) {
-    JSObject::EnqueueChangeRecord(
+    MaybeHandle<Object> result = JSObject::EnqueueChangeRecord(
         function, "update", isolate->factory()->prototype_string(), old_value);
+    if (result.is_null()) return MaybeHandle<Object>();
   }
 
   return function;
 }
 
 
-Handle<Object> Accessors::FunctionSetPrototype(Handle<JSFunction> function,
-                                               Handle<Object> prototype) {
+MaybeHandle<Object> Accessors::FunctionSetPrototype(Handle<JSFunction> function,
+                                                    Handle<Object> prototype) {
   DCHECK(function->should_have_prototype());
   Isolate* isolate = function->GetIsolate();
   return SetFunctionPrototype(isolate, function, prototype);
@@ -937,7 +940,9 @@ void Accessors::FunctionPrototypeSetter(
   }
   Handle<JSFunction> object =
       Handle<JSFunction>::cast(Utils::OpenHandle(*info.Holder()));
-  SetFunctionPrototype(isolate, object, value);
+  if (SetFunctionPrototype(isolate, object, value).is_null()) {
+    isolate->OptionalRescheduleException(false);
+  }
 }
 
 
index 1677c1d..678064d 100644 (file)
@@ -66,8 +66,8 @@ class Accessors : public AllStatic {
   };
 
   // Accessor functions called directly from the runtime system.
-  static Handle<Object> FunctionSetPrototype(Handle<JSFunction> object,
-                                             Handle<Object> value);
+  MUST_USE_RESULT static MaybeHandle<Object> FunctionSetPrototype(
+      Handle<JSFunction> object, Handle<Object> value);
   static Handle<Object> FunctionGetArguments(Handle<JSFunction> object);
 
   // Accessor infos.
index c36156d..2dde719 100644 (file)
@@ -509,7 +509,7 @@ Handle<JSFunction> Genesis::CreateEmptyFunction(Isolate* isolate) {
     // prototype, otherwise the missing initial_array_prototype will cause
     // assertions during startup.
     native_context()->set_initial_array_prototype(*prototype);
-    Accessors::FunctionSetPrototype(object_fun, prototype);
+    Accessors::FunctionSetPrototype(object_fun, prototype).Assert();
   }
 
   // Allocate the empty function as the prototype for function ECMAScript
@@ -1673,7 +1673,7 @@ bool Genesis::InstallNatives() {
         isolate()->initial_object_prototype(), Builtins::kIllegal);
     Handle<JSObject> prototype =
         factory()->NewJSObject(isolate()->object_function(), TENURED);
-    Accessors::FunctionSetPrototype(script_fun, prototype);
+    Accessors::FunctionSetPrototype(script_fun, prototype).Assert();
     native_context()->set_script_function(*script_fun);
 
     Handle<Map> script_map = Handle<Map>(script_fun->initial_map());
@@ -1815,7 +1815,7 @@ bool Genesis::InstallNatives() {
         isolate()->initial_object_prototype(), Builtins::kIllegal);
     Handle<JSObject> prototype =
         factory()->NewJSObject(isolate()->object_function(), TENURED);
-    Accessors::FunctionSetPrototype(opaque_reference_fun, prototype);
+    Accessors::FunctionSetPrototype(opaque_reference_fun, prototype).Assert();
     native_context()->set_opaque_reference_function(*opaque_reference_fun);
   }
 
index 3e9ae3e..4f23ea5 100644 (file)
@@ -1811,10 +1811,10 @@ Context* JSObject::GetCreationContext() {
 }
 
 
-void JSObject::EnqueueChangeRecord(Handle<JSObject> object,
-                                   const char* type_str,
-                                   Handle<Name> name,
-                                   Handle<Object> old_value) {
+MaybeHandle<Object> JSObject::EnqueueChangeRecord(Handle<JSObject> object,
+                                                  const char* type_str,
+                                                  Handle<Name> name,
+                                                  Handle<Object> old_value) {
   DCHECK(!object->IsJSGlobalProxy());
   DCHECK(!object->IsJSGlobalObject());
   Isolate* isolate = object->GetIsolate();
@@ -1823,10 +1823,9 @@ void JSObject::EnqueueChangeRecord(Handle<JSObject> object,
   Handle<Object> args[] = { type, object, name, old_value };
   int argc = name.is_null() ? 2 : old_value->IsTheHole() ? 3 : 4;
 
-  Execution::Call(isolate,
-                  Handle<JSFunction>(isolate->observers_notify_change()),
-                  isolate->factory()->undefined_value(),
-                  argc, args).Assert();
+  return Execution::Call(isolate,
+                         Handle<JSFunction>(isolate->observers_notify_change()),
+                         isolate->factory()->undefined_value(), argc, args);
 }
 
 
@@ -2933,8 +2932,8 @@ MaybeHandle<Object> Object::WriteToReadOnlyProperty(LookupIterator* it,
 }
 
 
-Handle<Object> Object::SetDataProperty(LookupIterator* it,
-                                       Handle<Object> value) {
+MaybeHandle<Object> Object::SetDataProperty(LookupIterator* it,
+                                            Handle<Object> value) {
   // Proxies are handled on the WithHandler path. Other non-JSObjects cannot
   // have own properties.
   Handle<JSObject> receiver = Handle<JSObject>::cast(it->GetReceiver());
@@ -2960,8 +2959,10 @@ Handle<Object> Object::SetDataProperty(LookupIterator* it,
 
   // Send the change record if there are observers.
   if (is_observed && !value->SameValue(*maybe_old.ToHandleChecked())) {
-    JSObject::EnqueueChangeRecord(receiver, "update", it->name(),
-                                  maybe_old.ToHandleChecked());
+    RETURN_ON_EXCEPTION(it->isolate(), JSObject::EnqueueChangeRecord(
+                                           receiver, "update", it->name(),
+                                           maybe_old.ToHandleChecked()),
+                        Object);
   }
 
   return value;
@@ -3012,8 +3013,10 @@ MaybeHandle<Object> Object::AddDataProperty(LookupIterator* it,
   // Send the change record if there are observers.
   if (receiver->map()->is_observed() &&
       !it->name().is_identical_to(it->factory()->hidden_string())) {
-    JSObject::EnqueueChangeRecord(receiver, "add", it->name(),
-                                  it->factory()->the_hole_value());
+    RETURN_ON_EXCEPTION(it->isolate(), JSObject::EnqueueChangeRecord(
+                                           receiver, "add", it->name(),
+                                           it->factory()->the_hole_value()),
+                        Object);
   }
 
   return value;
@@ -3862,7 +3865,10 @@ MaybeHandle<Object> JSObject::SetOwnPropertyIgnoreAttributes(
                   !Name::Equals(it.isolate()->factory()->prototype_string(),
                                 name) ||
                   !Handle<JSFunction>::cast(object)->should_have_prototype()) {
-                EnqueueChangeRecord(object, "update", name, old_value);
+                RETURN_ON_EXCEPTION(
+                    it.isolate(),
+                    EnqueueChangeRecord(object, "update", name, old_value),
+                    Object);
               }
             }
             return value;
@@ -3881,7 +3887,10 @@ MaybeHandle<Object> JSObject::SetOwnPropertyIgnoreAttributes(
             if (old_value->SameValue(*value)) {
               old_value = it.isolate()->factory()->the_hole_value();
             }
-            EnqueueChangeRecord(object, "reconfigure", name, old_value);
+            RETURN_ON_EXCEPTION(
+                it.isolate(),
+                EnqueueChangeRecord(object, "reconfigure", name, old_value),
+                Object);
           }
           return value;
         }
@@ -3894,7 +3903,10 @@ MaybeHandle<Object> JSObject::SetOwnPropertyIgnoreAttributes(
           if (old_value->SameValue(*value)) {
             old_value = it.isolate()->factory()->the_hole_value();
           }
-          EnqueueChangeRecord(object, "reconfigure", name, old_value);
+          RETURN_ON_EXCEPTION(
+              it.isolate(),
+              EnqueueChangeRecord(object, "reconfigure", name, old_value),
+              Object);
         }
 
         return value;
@@ -3918,7 +3930,10 @@ MaybeHandle<Object> JSObject::SetOwnPropertyIgnoreAttributes(
           if (old_value->SameValue(*value)) {
             old_value = it.isolate()->factory()->the_hole_value();
           }
-          EnqueueChangeRecord(object, "reconfigure", name, old_value);
+          RETURN_ON_EXCEPTION(
+              it.isolate(),
+              EnqueueChangeRecord(object, "reconfigure", name, old_value),
+              Object);
         }
 
         return value;
@@ -4891,7 +4906,9 @@ MaybeHandle<Object> JSObject::DeleteElement(Handle<JSObject> object,
     if (!maybe.has_value) return MaybeHandle<Object>();
     if (!maybe.value) {
       Handle<String> name = factory->Uint32ToString(index);
-      EnqueueChangeRecord(object, "delete", name, old_value);
+      RETURN_ON_EXCEPTION(
+          isolate, EnqueueChangeRecord(object, "delete", name, old_value),
+          Object);
     }
   }
 
@@ -4977,7 +4994,9 @@ MaybeHandle<Object> JSObject::DeleteProperty(Handle<JSObject> object,
         ReoptimizeIfPrototype(holder);
 
         if (is_observed) {
-          EnqueueChangeRecord(object, "delete", name, old_value);
+          RETURN_ON_EXCEPTION(
+              it.isolate(),
+              EnqueueChangeRecord(object, "delete", name, old_value), Object);
         }
 
         return result;
@@ -5194,8 +5213,11 @@ MaybeHandle<Object> JSObject::PreventExtensions(Handle<JSObject> object) {
   DCHECK(!object->map()->is_extensible());
 
   if (object->map()->is_observed()) {
-    EnqueueChangeRecord(object, "preventExtensions", Handle<Name>(),
-                        isolate->factory()->the_hole_value());
+    RETURN_ON_EXCEPTION(
+        isolate,
+        EnqueueChangeRecord(object, "preventExtensions", Handle<Name>(),
+                            isolate->factory()->the_hole_value()),
+        Object);
   }
   return object;
 }
@@ -6168,7 +6190,8 @@ MaybeHandle<Object> JSObject::DefineAccessor(Handle<JSObject> object,
 
   if (is_observed) {
     const char* type = preexists ? "reconfigure" : "add";
-    EnqueueChangeRecord(object, type, name, old_value);
+    RETURN_ON_EXCEPTION(
+        isolate, EnqueueChangeRecord(object, type, name, old_value), Object);
   }
 
   return isolate->factory()->undefined_value();
@@ -11237,13 +11260,18 @@ MaybeHandle<Object> JSArray::SetElementsLength(
     // For deletions where the property was an accessor, old_values[i]
     // will be the hole, which instructs EnqueueChangeRecord to elide
     // the "oldValue" property.
-    JSObject::EnqueueChangeRecord(
-        array, "delete", isolate->factory()->Uint32ToString(indices[i]),
-        old_values[i]);
+    RETURN_ON_EXCEPTION(
+        isolate,
+        JSObject::EnqueueChangeRecord(
+            array, "delete", isolate->factory()->Uint32ToString(indices[i]),
+            old_values[i]),
+        Object);
   }
-  JSObject::EnqueueChangeRecord(
-      array, "update", isolate->factory()->length_string(),
-      old_length_handle);
+  RETURN_ON_EXCEPTION(isolate,
+                      JSObject::EnqueueChangeRecord(
+                          array, "update", isolate->factory()->length_string(),
+                          old_length_handle),
+                      Object);
 
   EndPerformSplice(array);
 
@@ -12451,27 +12479,38 @@ MaybeHandle<Object> JSObject::SetElement(Handle<JSObject> object,
       CHECK(new_length_handle->ToArrayIndex(&new_length));
 
       BeginPerformSplice(Handle<JSArray>::cast(object));
-      EnqueueChangeRecord(object, "add", name, old_value);
-      EnqueueChangeRecord(object, "update", isolate->factory()->length_string(),
-                          old_length_handle);
+      RETURN_ON_EXCEPTION(
+          isolate, EnqueueChangeRecord(object, "add", name, old_value), Object);
+      RETURN_ON_EXCEPTION(
+          isolate, EnqueueChangeRecord(object, "update",
+                                       isolate->factory()->length_string(),
+                                       old_length_handle),
+          Object);
       EndPerformSplice(Handle<JSArray>::cast(object));
       Handle<JSArray> deleted = isolate->factory()->NewJSArray(0);
       EnqueueSpliceRecord(Handle<JSArray>::cast(object), old_length, deleted,
                           new_length - old_length);
     } else {
-      EnqueueChangeRecord(object, "add", name, old_value);
+      RETURN_ON_EXCEPTION(
+          isolate, EnqueueChangeRecord(object, "add", name, old_value), Object);
     }
   } else if (old_value->IsTheHole()) {
-    EnqueueChangeRecord(object, "reconfigure", name, old_value);
+    RETURN_ON_EXCEPTION(
+        isolate, EnqueueChangeRecord(object, "reconfigure", name, old_value),
+        Object);
   } else {
     Handle<Object> new_value =
         Object::GetElement(isolate, object, index).ToHandleChecked();
     bool value_changed = !old_value->SameValue(*new_value);
     if (old_attributes != new_attributes) {
       if (!value_changed) old_value = isolate->factory()->the_hole_value();
-      EnqueueChangeRecord(object, "reconfigure", name, old_value);
+      RETURN_ON_EXCEPTION(
+          isolate, EnqueueChangeRecord(object, "reconfigure", name, old_value),
+          Object);
     } else if (value_changed) {
-      EnqueueChangeRecord(object, "update", name, old_value);
+      RETURN_ON_EXCEPTION(
+          isolate, EnqueueChangeRecord(object, "update", name, old_value),
+          Object);
     }
   }
 
index a0741cc..6937557 100644 (file)
@@ -1130,8 +1130,8 @@ class Object {
       StorePropertyMode data_store_mode = NORMAL_PROPERTY);
   MUST_USE_RESULT static MaybeHandle<Object> WriteToReadOnlyProperty(
       LookupIterator* it, Handle<Object> value, StrictMode strict_mode);
-  static Handle<Object> SetDataProperty(LookupIterator* it,
-                                        Handle<Object> value);
+  MUST_USE_RESULT static MaybeHandle<Object> SetDataProperty(
+      LookupIterator* it, Handle<Object> value);
   MUST_USE_RESULT static MaybeHandle<Object> AddDataProperty(
       LookupIterator* it, Handle<Object> value, PropertyAttributes attributes,
       StrictMode strict_mode, StoreFromKeyed store_mode);
@@ -2215,10 +2215,9 @@ class JSObject: public JSReceiver {
   Context* GetCreationContext();
 
   // Enqueue change record for Object.observe. May cause GC.
-  static void EnqueueChangeRecord(Handle<JSObject> object,
-                                  const char* type,
-                                  Handle<Name> name,
-                                  Handle<Object> old_value);
+  MUST_USE_RESULT static MaybeHandle<Object> EnqueueChangeRecord(
+      Handle<JSObject> object, const char* type, Handle<Name> name,
+      Handle<Object> old_value);
 
  private:
   friend class DictionaryElementsAccessor;
index dfd9835..a720f81 100644 (file)
@@ -201,7 +201,8 @@ RUNTIME_FUNCTION(Runtime_FunctionSetPrototype) {
   CONVERT_ARG_HANDLE_CHECKED(JSFunction, fun, 0);
   CONVERT_ARG_HANDLE_CHECKED(Object, value, 1);
   RUNTIME_ASSERT(fun->should_have_prototype());
-  Accessors::FunctionSetPrototype(fun, value);
+  RETURN_FAILURE_ON_EXCEPTION(isolate,
+                              Accessors::FunctionSetPrototype(fun, value));
   return args[0];  // return TOS
 }
 
index 3868011..b3e0b25 100644 (file)
@@ -362,8 +362,10 @@ RUNTIME_FUNCTION(Runtime_SetPrototype) {
     Handle<Object> new_value =
         Object::GetPrototypeSkipHiddenPrototypes(isolate, obj);
     if (!new_value->SameValue(*old_value)) {
-      JSObject::EnqueueChangeRecord(
-          obj, "setPrototype", isolate->factory()->proto_string(), old_value);
+      RETURN_FAILURE_ON_EXCEPTION(
+          isolate, JSObject::EnqueueChangeRecord(
+                       obj, "setPrototype", isolate->factory()->proto_string(),
+                       old_value));
     }
     return *result;
   }
diff --git a/test/mjsunit/regress/regress-417709a.js b/test/mjsunit/regress/regress-417709a.js
new file mode 100644 (file)
index 0000000..d210c10
--- /dev/null
@@ -0,0 +1,16 @@
+// 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: --stack-size=100
+
+var a = [];
+
+Object.observe(a, function() {});
+
+function f(a, x) {
+  a.length = x;
+  f(a, x + 1);
+}
+
+assertThrows(function() { f(a, 1); }, RangeError);