// Copyright 2014 the V8 project authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. // Flags: --expose-debug-as debug --allow-natives-syntax var Debug = debug.Debug; var LiveEdit = Debug.LiveEdit; unique_id = 0; var Generator = (function*(){}).constructor; function assertIteratorResult(value, done, result) { assertEquals({value: value, done: done}, result); } function MakeGenerator() { // Prevents eval script caching. unique_id++; return Generator('callback', "/* " + unique_id + "*/\n" + "yield callback();\n" + "return 'Cat';\n"); } function MakeFunction() { // Prevents eval script caching. unique_id++; return Function('callback', "/* " + unique_id + "*/\n" + "callback();\n" + "return 'Cat';\n"); } // First, try MakeGenerator with no perturbations. (function(){ var generator = MakeGenerator(); function callback() {}; var iter = generator(callback); assertIteratorResult(undefined, false, iter.next()); assertIteratorResult("Cat", true, iter.next()); })(); function patch(fun, from, to) { function debug() { var log = new Array(); var script = Debug.findScript(fun); var pos = script.source.indexOf(from); try { LiveEdit.TestApi.ApplySingleChunkPatch(script, pos, from.length, to, log); } finally { print("Change log: " + JSON.stringify(log) + "\n"); } } %ExecuteInDebugContext(debug); } // Try to edit a MakeGenerator while it's running, then again while it's // stopped. (function(){ var generator = MakeGenerator(); var gen_patch_attempted = false; function attempt_gen_patch() { assertFalse(gen_patch_attempted); gen_patch_attempted = true; assertThrows(function() { patch(generator, "'Cat'", "'Capybara'") }, LiveEdit.Failure); }; var iter = generator(attempt_gen_patch); assertIteratorResult(undefined, false, iter.next()); // Patch should not succeed because there is a live generator activation on // the stack. assertIteratorResult("Cat", true, iter.next()); assertTrue(gen_patch_attempted); // At this point one iterator is live, but closed, so the patch will succeed. patch(generator, "'Cat'", "'Capybara'"); iter = generator(function(){}); assertIteratorResult(undefined, false, iter.next()); // Patch successful. assertIteratorResult("Capybara", true, iter.next()); // Patching will fail however when a live iterator is suspended. iter = generator(function(){}); assertIteratorResult(undefined, false, iter.next()); assertThrows(function() { patch(generator, "'Capybara'", "'Tapir'") }, LiveEdit.Failure); assertIteratorResult("Capybara", true, iter.next()); // Try to patch functions with activations inside and outside generator // function activations. We should succeed in the former case, but not in the // latter. var fun_outside = MakeFunction(); var fun_inside = MakeFunction(); var fun_patch_attempted = false; var fun_patch_restarted = false; function attempt_fun_patches() { if (fun_patch_attempted) { assertFalse(fun_patch_restarted); fun_patch_restarted = true; return; } fun_patch_attempted = true; // Patching outside a generator activation must fail. assertThrows(function() { patch(fun_outside, "'Cat'", "'Cobra'") }, LiveEdit.Failure); // Patching inside a generator activation may succeed. patch(fun_inside, "'Cat'", "'Koala'"); } iter = generator(function() { return fun_inside(attempt_fun_patches) }); assertEquals('Cat', fun_outside(function () { assertIteratorResult('Koala', false, iter.next()); assertTrue(fun_patch_restarted); })); })();