| OLD | NEW |
| (Empty) |
| 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 | |
| 7 | |
| 8 var Debug = debug.Debug; | |
| 9 var LiveEdit = Debug.LiveEdit; | |
| 10 | |
| 11 unique_id = 0; | |
| 12 | |
| 13 var AsyncFunction = (async function(){}).constructor; | |
| 14 | |
| 15 function 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 | |
| 28 function 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 | |
| 37 function 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 | |
| 54 function 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(); | |
| OLD | NEW |