Version 3.15.8

Enforced stack allocation of TryCatch blocks. (issue 2166,chromium:152389)

Fixed external exceptions in external try-catch handlers. (issue 2166)

Activated incremental code flushing by default.

Performance and stability improvements on all platforms.

git-svn-id: http://v8.googlecode.com/svn/trunk@13133 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
diff --git a/test/cctest/test-api.cc b/test/cctest/test-api.cc
index aa85e2a..1610dcd 100644
--- a/test/cctest/test-api.cc
+++ b/test/cctest/test-api.cc
@@ -3720,6 +3720,30 @@
 }
 
 
+static void TryCatchNestedHelper(int depth) {
+  if (depth > 0) {
+    v8::TryCatch try_catch;
+    try_catch.SetVerbose(true);
+    TryCatchNestedHelper(depth - 1);
+    CHECK(try_catch.HasCaught());
+    try_catch.ReThrow();
+  } else {
+    v8::ThrowException(v8_str("back"));
+  }
+}
+
+
+TEST(TryCatchNested) {
+  v8::V8::Initialize();
+  v8::HandleScope scope;
+  LocalContext context;
+  v8::TryCatch try_catch;
+  TryCatchNestedHelper(5);
+  CHECK(try_catch.HasCaught());
+  CHECK_EQ(0, strcmp(*v8::String::Utf8Value(try_catch.Exception()), "back"));
+}
+
+
 THREADED_TEST(Equality) {
   v8::HandleScope scope;
   LocalContext context;
@@ -8069,12 +8093,8 @@
   Local<ObjectTemplate> proto = t->PrototypeTemplate();
   Local<ObjectTemplate> instance = t->InstanceTemplate();
 
-  // Only allow calls of f on instances of t.
-  Local<v8::Signature> signature = v8::Signature::New(t);
   proto->Set(v8_str("f"),
-             v8::FunctionTemplate::New(ShadowFunctionCallback,
-                                       Local<Value>(),
-                                       signature));
+             v8::FunctionTemplate::New(ShadowFunctionCallback, Local<Value>()));
   proto->Set(v8_str("x"), v8_num(12));
 
   instance->SetAccessor(v8_str("y"), ShadowYGetter, ShadowYSetter);
@@ -9939,6 +9959,7 @@
                                 v8::Signature::New(fun_templ));
   v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
   proto_templ->Set(v8_str("method"), method_templ);
+  fun_templ->SetHiddenPrototype(true);
   v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
   templ->SetNamedPropertyHandler(InterceptorCallICFastApi,
                                  NULL, NULL, NULL, NULL,
@@ -9969,6 +9990,7 @@
                                 v8::Signature::New(fun_templ));
   v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
   proto_templ->Set(v8_str("method"), method_templ);
+  fun_templ->SetHiddenPrototype(true);
   v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
   templ->SetNamedPropertyHandler(InterceptorCallICFastApi,
                                  NULL, NULL, NULL, NULL,
@@ -10005,6 +10027,7 @@
                                 v8::Signature::New(fun_templ));
   v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
   proto_templ->Set(v8_str("method"), method_templ);
+  fun_templ->SetHiddenPrototype(true);
   v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
   templ->SetNamedPropertyHandler(InterceptorCallICFastApi,
                                  NULL, NULL, NULL, NULL,
@@ -10041,6 +10064,7 @@
                                 v8::Signature::New(fun_templ));
   v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
   proto_templ->Set(v8_str("method"), method_templ);
+  fun_templ->SetHiddenPrototype(true);
   v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
   templ->SetNamedPropertyHandler(InterceptorCallICFastApi,
                                  NULL, NULL, NULL, NULL,
@@ -10080,6 +10104,7 @@
                                 v8::Signature::New(fun_templ));
   v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
   proto_templ->Set(v8_str("method"), method_templ);
+  fun_templ->SetHiddenPrototype(true);
   v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
   templ->SetNamedPropertyHandler(InterceptorCallICFastApi,
                                  NULL, NULL, NULL, NULL,
@@ -10142,6 +10167,7 @@
                                 v8::Signature::New(fun_templ));
   v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
   proto_templ->Set(v8_str("method"), method_templ);
+  fun_templ->SetHiddenPrototype(true);
   v8::Handle<v8::ObjectTemplate> templ(fun_templ->InstanceTemplate());
   CHECK(!templ.IsEmpty());
   LocalContext context;
@@ -10169,6 +10195,7 @@
                                 v8::Signature::New(fun_templ));
   v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
   proto_templ->Set(v8_str("method"), method_templ);
+  fun_templ->SetHiddenPrototype(true);
   v8::Handle<v8::ObjectTemplate> templ(fun_templ->InstanceTemplate());
   CHECK(!templ.IsEmpty());
   LocalContext context;
@@ -10201,6 +10228,7 @@
                                 v8::Signature::New(fun_templ));
   v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
   proto_templ->Set(v8_str("method"), method_templ);
+  fun_templ->SetHiddenPrototype(true);
   v8::Handle<v8::ObjectTemplate> templ(fun_templ->InstanceTemplate());
   CHECK(!templ.IsEmpty());
   LocalContext context;
@@ -10227,6 +10255,42 @@
   CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
 }
 
+THREADED_TEST(CallICFastApi_SimpleSignature_TypeError) {
+  v8::HandleScope scope;
+  v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
+  v8::Handle<v8::FunctionTemplate> method_templ =
+      v8::FunctionTemplate::New(FastApiCallback_SimpleSignature,
+                                v8_str("method_data"),
+                                v8::Signature::New(fun_templ));
+  v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
+  proto_templ->Set(v8_str("method"), method_templ);
+  fun_templ->SetHiddenPrototype(true);
+  v8::Handle<v8::ObjectTemplate> templ(fun_templ->InstanceTemplate());
+  CHECK(!templ.IsEmpty());
+  LocalContext context;
+  v8::Handle<v8::Function> fun = fun_templ->GetFunction();
+  GenerateSomeGarbage();
+  context->Global()->Set(v8_str("o"), fun->NewInstance());
+  v8::TryCatch try_catch;
+  CompileRun(
+      "o.foo = 17;"
+      "var receiver = {};"
+      "receiver.__proto__ = o;"
+      "var result = 0;"
+      "var saved_result = 0;"
+      "for (var i = 0; i < 100; i++) {"
+      "  result = receiver.method(41);"
+      "  if (i == 50) {"
+      "    saved_result = result;"
+      "    receiver = Object.create(receiver);"
+      "  }"
+      "}");
+  CHECK(try_catch.HasCaught());
+  CHECK_EQ(v8_str("TypeError: Illegal invocation"),
+           try_catch.Exception()->ToString());
+  CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
+}
+
 
 v8::Handle<Value> keyed_call_ic_function;
 
diff --git a/test/cctest/test-cpu-profiler.cc b/test/cctest/test-cpu-profiler.cc
index 589e6d8..b10e688 100644
--- a/test/cctest/test-cpu-profiler.cc
+++ b/test/cctest/test-cpu-profiler.cc
@@ -5,7 +5,6 @@
 #include "v8.h"
 #include "cpu-profiler-inl.h"
 #include "cctest.h"
-#include "platform.h"
 #include "../include/v8-profiler.h"
 
 using i::CodeEntry;
@@ -21,7 +20,7 @@
 TEST(StartStop) {
   CpuProfilesCollection profiles;
   ProfileGenerator generator(&profiles);
-  ProfilerEventsProcessor processor(&generator, NULL, 1000);
+  ProfilerEventsProcessor processor(&generator);
   processor.Start();
   processor.Stop();
   processor.Join();
@@ -39,13 +38,11 @@
   return reinterpret_cast<i::Address>(n);
 }
 
-static void AddTickSampleEvent(ProfilerEventsProcessor* processor,
-                               i::Address frame1,
-                               i::Address frame2 = NULL,
-                               i::Address frame3 = NULL) {
-  i::TickSample* sample;
-  i::OS::Sleep(20);
-  while ((sample = processor->StartTickSampleEvent()) == NULL) i::OS::Sleep(20);
+static void EnqueueTickSampleEvent(ProfilerEventsProcessor* proc,
+                                   i::Address frame1,
+                                   i::Address frame2 = NULL,
+                                   i::Address frame3 = NULL) {
+  i::TickSample* sample = proc->TickSampleEvent();
   sample->pc = frame1;
   sample->tos = frame1;
   sample->frames_count = 0;
@@ -57,7 +54,6 @@
     sample->stack[1] = frame3;
     sample->frames_count = 2;
   }
-  processor->FinishTickSampleEvent();
 }
 
 namespace {
@@ -85,7 +81,7 @@
   CpuProfilesCollection profiles;
   profiles.StartProfiling("", 1);
   ProfileGenerator generator(&profiles);
-  ProfilerEventsProcessor processor(&generator, NULL, 1000);
+  ProfilerEventsProcessor processor(&generator);
   processor.Start();
 
   // Enqueue code creation events.
@@ -112,8 +108,8 @@
   processor.CodeMoveEvent(ToAddress(0x1400), ToAddress(0x1500));
   processor.CodeCreateEvent(i::Logger::STUB_TAG, 3, ToAddress(0x1600), 0x10);
   processor.CodeCreateEvent(i::Logger::STUB_TAG, 4, ToAddress(0x1605), 0x10);
-  // Add a tick event to enable code events processing.
-  AddTickSampleEvent(&processor, ToAddress(0x1000));
+  // Enqueue a tick event to enable code events processing.
+  EnqueueTickSampleEvent(&processor, ToAddress(0x1000));
 
   processor.Stop();
   processor.Join();
@@ -146,7 +142,7 @@
   CpuProfilesCollection profiles;
   profiles.StartProfiling("", 1);
   ProfileGenerator generator(&profiles);
-  ProfilerEventsProcessor processor(&generator, NULL, 1000);
+  ProfilerEventsProcessor processor(&generator);
   processor.Start();
 
   processor.CodeCreateEvent(i::Logger::BUILTIN_TAG,
@@ -158,12 +154,12 @@
                             "ddd",
                             ToAddress(0x1400),
                             0x80);
-  AddTickSampleEvent(&processor, ToAddress(0x1210));
-  AddTickSampleEvent(&processor, ToAddress(0x1305), ToAddress(0x1220));
-  AddTickSampleEvent(&processor,
-                     ToAddress(0x1404),
-                     ToAddress(0x1305),
-                     ToAddress(0x1230));
+  EnqueueTickSampleEvent(&processor, ToAddress(0x1210));
+  EnqueueTickSampleEvent(&processor, ToAddress(0x1305), ToAddress(0x1220));
+  EnqueueTickSampleEvent(&processor,
+                         ToAddress(0x1404),
+                         ToAddress(0x1305),
+                         ToAddress(0x1230));
 
   processor.Stop();
   processor.Join();
@@ -236,7 +232,7 @@
   CpuProfilesCollection profiles;
   profiles.StartProfiling("", 1);
   ProfileGenerator generator(&profiles);
-  ProfilerEventsProcessor processor(&generator, NULL, 1000);
+  ProfilerEventsProcessor processor(&generator);
   processor.Start();
 
   processor.CodeCreateEvent(i::Logger::BUILTIN_TAG,
@@ -244,14 +240,13 @@
                             ToAddress(0x1200),
                             0x80);
 
-  i::TickSample* sample = processor.StartTickSampleEvent();
+  i::TickSample* sample = processor.TickSampleEvent();
   sample->pc = ToAddress(0x1200);
   sample->tos = 0;
   sample->frames_count = i::TickSample::kMaxFramesCount;
   for (int i = 0; i < sample->frames_count; ++i) {
     sample->stack[i] = ToAddress(0x1200);
   }
-  processor.FinishTickSampleEvent();
 
   processor.Stop();
   processor.Join();
diff --git a/test/cctest/test-heap.cc b/test/cctest/test-heap.cc
index f5bac2c..dc5247d 100644
--- a/test/cctest/test-heap.cc
+++ b/test/cctest/test-heap.cc
@@ -1116,8 +1116,10 @@
   // Bump the code age so that flushing is triggered while the function
   // object is still located in new-space.
   const int kAgingThreshold = 6;
-  function->shared()->set_code_age(kAgingThreshold);
-  function2->shared()->set_code_age(kAgingThreshold);
+  for (int i = 0; i < kAgingThreshold; i++) {
+    function->shared()->code()->MakeOlder(static_cast<MarkingParity>(i % 2));
+    function2->shared()->code()->MakeOlder(static_cast<MarkingParity>(i % 2));
+  }
 
   // Simulate incremental marking so that the functions are enqueued as
   // code flushing candidates. Then kill one of the functions. Finally
@@ -1166,7 +1168,9 @@
 
   // Bump the code age so that flushing is triggered.
   const int kAgingThreshold = 6;
-  function->shared()->set_code_age(kAgingThreshold);
+  for (int i = 0; i < kAgingThreshold; i++) {
+    function->shared()->code()->MakeOlder(static_cast<MarkingParity>(i % 2));
+  }
 
   // Simulate incremental marking so that the function is enqueued as
   // code flushing candidate.
diff --git a/test/mjsunit/debug-liveedit-compile-error.js b/test/mjsunit/debug-liveedit-compile-error.js
new file mode 100644
index 0000000..2fd6aed
--- /dev/null
+++ b/test/mjsunit/debug-liveedit-compile-error.js
@@ -0,0 +1,60 @@
+// Copyright 2012 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Flags: --expose-debug-as debug
+// Get the Debug object exposed from the debug context global object.
+
+Debug = debug.Debug
+
+eval("var something1 = 25; \n"
+     + " function ChooseAnimal() { return          'Cat';          } \n"
+     + " ChooseAnimal.Helper = function() { return 'Help!'; }\n");
+
+assertEquals("Cat", ChooseAnimal());
+
+var script = Debug.findScript(ChooseAnimal);
+
+var orig_animal = "Cat";
+var patch_pos = script.source.indexOf(orig_animal);
+var new_animal_patch = "Cap' + ) + 'bara";
+
+var change_log = new Array();
+var caught_exception = null;
+try {
+  Debug.LiveEdit.TestApi.ApplySingleChunkPatch(script, patch_pos,
+      orig_animal.length, new_animal_patch, change_log);
+} catch (e) {
+  caught_exception = e;
+}
+
+assertNotNull(caught_exception);
+assertEquals("Unexpected token )",
+    caught_exception.details.syntaxErrorMessage);
+
+assertEquals(2, caught_exception.details.position.start.line);
+
+
diff --git a/test/mjsunit/debug-set-variable-value.js b/test/mjsunit/debug-set-variable-value.js
new file mode 100644
index 0000000..dac8861
--- /dev/null
+++ b/test/mjsunit/debug-set-variable-value.js
@@ -0,0 +1,176 @@
+// Copyright 2012 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Flags: --expose-debug-as debug
+
+// Get the Debug object exposed from the debug context global object.
+var Debug = debug.Debug;
+
+// Accepts a function/closure 'fun' that must have a debugger statement inside.
+// A variable 'variable_name' must be initialized before debugger statement
+// and returned after the statement. The test will alter variable value when
+// on debugger statement and check that returned value reflects the change.
+function RunPauseTest(scope_number, variable_name, expected_new_value, fun) {
+  var old_value = fun();
+
+  var listener_delegate;
+  var listener_called = false;
+  var exception = null;
+
+  function listener_delegate(exec_state) {
+    var scope = exec_state.frame(0).scope(scope_number);
+    scope.setVariableValue(variable_name, expected_new_value);
+  }
+
+  function listener(event, exec_state, event_data, data) {
+    try {
+      if (event == Debug.DebugEvent.Break) {
+        listener_called = true;
+        listener_delegate(exec_state);
+      }
+    } catch (e) {
+      exception = e;
+    }
+  }
+
+  // Add the debug event listener.
+  Debug.setListener(listener);
+
+  var actual_new_value;
+  try {
+    actual_new_value = fun();
+  } finally {
+    Debug.setListener(null);
+  }
+
+  if (exception != null) {
+   assertUnreachable("Exception: " + exception);
+  }
+  assertTrue(listener_called);
+
+  assertTrue(old_value != actual_new_value);
+  assertTrue(expected_new_value == actual_new_value);
+}
+
+// Accepts a closure 'fun' that returns a variable from it's outer scope.
+// The test changes the value of variable via the handle to function and checks
+// that the return value changed accordingly.
+function RunClosureTest(scope_number, variable_name, expected_new_value, fun) {
+  var old_value = fun();
+
+  var fun_mirror = Debug.MakeMirror(fun);
+
+  var scope = fun_mirror.scope(scope_number);
+  scope.setVariableValue(variable_name, expected_new_value);
+
+  var actual_new_value = fun();
+
+  assertTrue(old_value != actual_new_value);
+  assertTrue(expected_new_value == actual_new_value);
+}
+
+// Test changing variable value when in pause
+RunPauseTest(1, 'v1', 5, (function Factory() {
+  var v1 = 'cat';
+  return function() {
+    debugger;
+    return v1;
+  }
+})());
+
+RunPauseTest(1, 'v2', 11, (function Factory(v2) {
+  return function() {
+    debugger;
+    return v2;
+  }
+})('dog'));
+
+RunPauseTest(3, 'foo', 77, (function Factory() {
+  var foo = "capybara";
+  return (function() {
+    var bar = "fish";
+    try {
+      throw {name: "test exception"};
+    } catch (e) {
+      return function() {
+        debugger;
+        bar = "beast";
+        return foo;
+      }
+    }
+  })();
+})());
+
+
+
+// Test changing variable value in closure by handle
+RunClosureTest(0, 'v1', 5, (function Factory() {
+  var v1 = 'cat';
+  return function() {
+    return v1;
+  }
+})());
+
+RunClosureTest(0, 'v2', 11, (function Factory(v2) {
+  return function() {
+    return v2;
+  }
+})('dog'));
+
+RunClosureTest(2, 'foo', 77, (function Factory() {
+  var foo = "capybara";
+  return (function() {
+    var bar = "fish";
+    try {
+      throw {name: "test exception"};
+    } catch (e) {
+      return function() {
+        bar = "beast";
+        return foo;
+      }
+    }
+  })();
+})());
+
+
+// Test value description protocol JSON
+assertEquals(true, Debug.TestApi.CommandProcessorResolveValue({value: true}));
+
+assertSame(null, Debug.TestApi.CommandProcessorResolveValue({type: "null"}));
+assertSame(undefined,
+    Debug.TestApi.CommandProcessorResolveValue({type: "undefined"}));
+
+assertSame("123", Debug.TestApi.CommandProcessorResolveValue(
+    {type: "string", stringDescription: "123"}));
+assertSame(123, Debug.TestApi.CommandProcessorResolveValue(
+    {type: "number", stringDescription: "123"}));
+
+assertSame(Number, Debug.TestApi.CommandProcessorResolveValue(
+    {handle: Debug.MakeMirror(Number).handle()}));
+assertSame(RunClosureTest, Debug.TestApi.CommandProcessorResolveValue(
+    {handle: Debug.MakeMirror(RunClosureTest).handle()}));
+
diff --git a/test/mjsunit/harmony/object-observe.js b/test/mjsunit/harmony/object-observe.js
index 474bfcd..d88c24e 100644
--- a/test/mjsunit/harmony/object-observe.js
+++ b/test/mjsunit/harmony/object-observe.js
@@ -584,8 +584,7 @@
 Object.deliverChangeRecords(observer.callback);
 observer.assertCallbackRecords([
   { object: arr, name: '3', type: 'deleted', oldValue: 'd' },
-  // TODO(adamk): oldValue should not be present below
-  { object: arr, name: '2', type: 'deleted', oldValue: undefined },
+  { object: arr, name: '2', type: 'deleted' },
   { object: arr, name: 'length', type: 'updated', oldValue: 4 },
   { object: arr, name: '1', type: 'deleted', oldValue: 'b' },
   { object: arr, name: 'length', type: 'updated', oldValue: 2 },
diff --git a/test/mjsunit/string-split.js b/test/mjsunit/string-split.js
index d8412f0..1308244 100644
--- a/test/mjsunit/string-split.js
+++ b/test/mjsunit/string-split.js
@@ -66,6 +66,23 @@
 
 assertArrayEquals(["a", "b", "c"], "abc".split(/(?=.)/));
 
+assertArrayEquals(["Wenige", "sind", "auserwählt."],
+                  "Wenige sind auserwählt.".split(" "));
+
+assertArrayEquals([], "Wenige sind auserwählt.".split(" ", 0));
+
+assertArrayEquals(["Wenige"], "Wenige sind auserwählt.".split(" ", 1));
+
+assertArrayEquals(["Wenige", "sind"], "Wenige sind auserwählt.".split(" ", 2));
+
+assertArrayEquals(["Wenige", "sind", "auserwählt."],
+                  "Wenige sind auserwählt.".split(" ", 3));
+
+assertArrayEquals(["Wenige sind auserw", "hlt."],
+                  "Wenige sind auserwählt.".split("ä"));
+
+assertArrayEquals(["Wenige sind ", "."],
+                  "Wenige sind auserwählt.".split("auserwählt"));
 
 /* "ab".split(/((?=.))/)
  *