1// 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(); 134