1b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch// Copyright 2014 the V8 project authors. All rights reserved.
2b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch// Use of this source code is governed by a BSD-style license that can be
3b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch// found in the LICENSE file.
4b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
5014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch// Flags: --expose-debug-as debug --allow-natives-syntax
6b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
7b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdochvar Debug = debug.Debug;
8b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdochvar LiveEdit = Debug.LiveEdit;
9b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
10b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdochunique_id = 0;
11b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
12b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdochvar Generator = (function*(){}).constructor;
13b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
14b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdochfunction assertIteratorResult(value, done, result) {
15b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  assertEquals({value: value, done: done}, result);
16b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch}
17b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
18b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdochfunction MakeGenerator() {
19b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  // Prevents eval script caching.
20b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  unique_id++;
21b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  return Generator('callback',
22b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      "/* " + unique_id + "*/\n" +
23b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      "yield callback();\n" +
24b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      "return 'Cat';\n");
25b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch}
26b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
27b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdochfunction MakeFunction() {
28b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  // Prevents eval script caching.
29b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  unique_id++;
30b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  return Function('callback',
31b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      "/* " + unique_id + "*/\n" +
32b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      "callback();\n" +
33b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      "return 'Cat';\n");
34b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch}
35b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
36b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch// First, try MakeGenerator with no perturbations.
37b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch(function(){
38b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  var generator = MakeGenerator();
39b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  function callback() {};
40b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  var iter = generator(callback);
41b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  assertIteratorResult(undefined, false, iter.next());
42b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  assertIteratorResult("Cat", true, iter.next());
43b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch})();
44b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
45b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdochfunction patch(fun, from, to) {
46b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  function debug() {
47b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    var log = new Array();
48b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    var script = Debug.findScript(fun);
49b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    var pos = script.source.indexOf(from);
50b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    try {
51b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      LiveEdit.TestApi.ApplySingleChunkPatch(script, pos, from.length, to,
52b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch                                             log);
53b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    } finally {
54b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      print("Change log: " + JSON.stringify(log) + "\n");
55b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    }
56b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  }
57014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  %ExecuteInDebugContext(debug);
58b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch}
59b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
60b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch// Try to edit a MakeGenerator while it's running, then again while it's
61b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch// stopped.
62b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch(function(){
63b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  var generator = MakeGenerator();
64b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
65b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  var gen_patch_attempted = false;
66b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  function attempt_gen_patch() {
67b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    assertFalse(gen_patch_attempted);
68b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    gen_patch_attempted = true;
69b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    assertThrows(function() { patch(generator, "'Cat'", "'Capybara'") },
70b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch                 LiveEdit.Failure);
71b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  };
72b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  var iter = generator(attempt_gen_patch);
73b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  assertIteratorResult(undefined, false, iter.next());
74b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  // Patch should not succeed because there is a live generator activation on
75b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  // the stack.
76b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  assertIteratorResult("Cat", true, iter.next());
77b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  assertTrue(gen_patch_attempted);
78b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
79b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  // At this point one iterator is live, but closed, so the patch will succeed.
80b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  patch(generator, "'Cat'", "'Capybara'");
81b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  iter = generator(function(){});
82b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  assertIteratorResult(undefined, false, iter.next());
83b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  // Patch successful.
84b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  assertIteratorResult("Capybara", true, iter.next());
85b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
86b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  // Patching will fail however when a live iterator is suspended.
87b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  iter = generator(function(){});
88b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  assertIteratorResult(undefined, false, iter.next());
89b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  assertThrows(function() { patch(generator, "'Capybara'", "'Tapir'") },
90b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch               LiveEdit.Failure);
91b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  assertIteratorResult("Capybara", true, iter.next());
92b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
93b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  // Try to patch functions with activations inside and outside generator
94b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  // function activations.  We should succeed in the former case, but not in the
95b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  // latter.
96b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  var fun_outside = MakeFunction();
97b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  var fun_inside = MakeFunction();
98b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  var fun_patch_attempted = false;
99b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  var fun_patch_restarted = false;
100b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  function attempt_fun_patches() {
101b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    if (fun_patch_attempted) {
102b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      assertFalse(fun_patch_restarted);
103b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      fun_patch_restarted = true;
104b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      return;
105b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    }
106b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    fun_patch_attempted = true;
107b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    // Patching outside a generator activation must fail.
108b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    assertThrows(function() { patch(fun_outside, "'Cat'", "'Cobra'") },
109b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch                 LiveEdit.Failure);
110b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    // Patching inside a generator activation may succeed.
111b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    patch(fun_inside, "'Cat'", "'Koala'");
112b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  }
113b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  iter = generator(function() { return fun_inside(attempt_fun_patches) });
114b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  assertEquals('Cat',
115b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch               fun_outside(function () {
116b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch                 assertIteratorResult('Koala', false, iter.next());
117b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch                 assertTrue(fun_patch_restarted);
118b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch               }));
119b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch})();
120