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