blob: c651ddba1633b371ce98071c161e8c759fc4e0c7 [file] [log] [blame]
Ben Murdoch61f157c2016-09-16 13:49:30 +01001// Copyright 2016 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: --harmony-async-await
6// Flags: --expose-debug-as debug --allow-natives-syntax --ignition-generators
7
8var Debug = debug.Debug;
9var LiveEdit = Debug.LiveEdit;
10
11unique_id = 0;
12
13var AsyncFunction = (async function(){}).constructor;
14
15function assertPromiseValue(value, promise) {
16 promise.then(resolve => {
17 went = true;
18 if (resolve !== value) {
19 print(`expected ${value} found ${resolve}`);
20 quit(1);
21 }
22 }, reject => {
23 print(`rejected ${reject}`);
24 quit(1);
25 });
26}
27
28function MakeAsyncFunction() {
29 // Prevents eval script caching.
30 unique_id++;
31 return AsyncFunction('callback',
32 "/* " + unique_id + "*/\n" +
33 "await callback();\n" +
34 "return 'Cat';\n");
35}
36
37function MakeFunction() {
38 // Prevents eval script caching.
39 unique_id++;
40 return Function('callback',
41 "/* " + unique_id + "*/\n" +
42 "callback();\n" +
43 "return 'Cat';\n");
44}
45
46// First, try MakeGenerator with no perturbations.
47(function(){
48 var asyncfn = MakeAsyncFunction();
49 function callback() {};
50 var promise = asyncfn(callback);
51 assertPromiseValue('Cat', promise);
52})();
53
54function patch(fun, from, to) {
55 function debug() {
56 var log = new Array();
57 var script = Debug.findScript(fun);
58 var pos = script.source.indexOf(from);
59 print(`pos ${pos}`);
60 try {
61 LiveEdit.TestApi.ApplySingleChunkPatch(script, pos, from.length, to,
62 log);
63 } finally {
64 print("Change log: " + JSON.stringify(log) + "\n");
65 }
66 }
67 %ExecuteInDebugContext(debug);
68}
69
70// Try to edit a MakeAsyncFunction while it's running, then again while it's
71// stopped.
72(function(){
73 var asyncfn = MakeAsyncFunction();
74
75 var patch_attempted = false;
76 function attempt_patch() {
77 assertFalse(patch_attempted);
78 patch_attempted = true;
79 assertThrows(function() { patch(asyncfn, "'Cat'", "'Capybara'") },
80 LiveEdit.Failure);
81 };
82 var promise = asyncfn(attempt_patch);
83 // Patch should not succeed because there is a live async function activation
84 // on the stack.
85 assertPromiseValue("Cat", promise);
86 assertTrue(patch_attempted);
87
88 %RunMicrotasks();
89
90 // At this point one iterator is live, but closed, so the patch will succeed.
91 patch(asyncfn, "'Cat'", "'Capybara'");
92 promise = asyncfn(function(){});
93 // Patch successful.
94 assertPromiseValue("Capybara", promise);
95
96 // Patching will fail however when an async function is suspended.
97 var resolve;
98 promise = asyncfn(function(){return new Promise(function(r){resolve = r})});
99 assertThrows(function() { patch(asyncfn, "'Capybara'", "'Tapir'") },
100 LiveEdit.Failure);
101 resolve();
102 assertPromiseValue("Capybara", promise);
103
104 // Try to patch functions with activations inside and outside async
105 // function activations. We should succeed in the former case, but not in the
106 // latter.
107 var fun_outside = MakeFunction();
108 var fun_inside = MakeFunction();
109 var fun_patch_attempted = false;
110 var fun_patch_restarted = false;
111 function attempt_fun_patches() {
112 if (fun_patch_attempted) {
113 assertFalse(fun_patch_restarted);
114 fun_patch_restarted = true;
115 return;
116 }
117 fun_patch_attempted = true;
118 // Patching outside an async function activation must fail.
119 assertThrows(function() { patch(fun_outside, "'Cat'", "'Cobra'") },
120 LiveEdit.Failure);
121 // Patching inside an async function activation may succeed.
122 patch(fun_inside, "'Cat'", "'Koala'");
123 }
124 promise = asyncfn(function() { return fun_inside(attempt_fun_patches) });
125 assertEquals('Cat',
126 fun_outside(function () {
127 assertPromiseValue('Capybara', promise);
128 assertTrue(fun_patch_restarted);
129 assertTrue(fun_inside.toString().includes("'Koala'"));
130 }));
131})();
132
133%RunMicrotasks();