Home | History | Annotate | Download | only in mjsunit
      1 // Copyright 2010 the V8 project authors. All rights reserved.
      2 // Redistribution and use in source and binary forms, with or without
      3 // modification, are permitted provided that the following conditions are
      4 // met:
      5 //
      6 //     * Redistributions of source code must retain the above copyright
      7 //       notice, this list of conditions and the following disclaimer.
      8 //     * Redistributions in binary form must reproduce the above
      9 //       copyright notice, this list of conditions and the following
     10 //       disclaimer in the documentation and/or other materials provided
     11 //       with the distribution.
     12 //     * Neither the name of Google Inc. nor the names of its
     13 //       contributors may be used to endorse or promote products derived
     14 //       from this software without specific prior written permission.
     15 //
     16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
     17 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
     18 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
     19 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
     20 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
     21 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
     22 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     23 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     24 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     25 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
     26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     27 
     28 // Flags: --expose-debug-as debug --allow-natives-syntax
     29 // Get the Debug object exposed from the debug context global object.
     30 
     31 Debug = debug.Debug
     32 
     33 unique_id = 1;
     34 
     35 function TestBase(name) {
     36   print("TestBase constructor: " + name);
     37 
     38   this.ChooseAnimal = eval(
     39       "/* " + unique_id + "*/\n" +
     40       "(function ChooseAnimal(callback) {\n " +
     41       "  callback();\n" +
     42       "  return 'Cat';\n" +
     43       "})\n"
     44   );
     45   // Prevents eval script caching.
     46   unique_id++;
     47 
     48   var script = Debug.findScript(this.ChooseAnimal);
     49 
     50   var orig_animal = "'Cat'";
     51   var patch_pos = script.source.indexOf(orig_animal);
     52   var new_animal_patch = "'Capybara'";
     53 
     54   var got_exception = false;
     55   var successfully_changed = false;
     56 
     57   // Should be called from Debug context.
     58   this.ScriptChanger = function() {
     59     assertEquals(false, successfully_changed, "applying patch second time");
     60     // Runs in debugger context.
     61     var change_log = new Array();
     62     try {
     63       Debug.LiveEdit.TestApi.ApplySingleChunkPatch(script, patch_pos, orig_animal.length, new_animal_patch, change_log);
     64     } finally {
     65       print("Change log: " + JSON.stringify(change_log) + "\n");
     66     }
     67     successfully_changed = true;
     68   };
     69 }
     70 
     71 function Noop() {}
     72 
     73 function WrapInCatcher(f, holder) {
     74   return function() {
     75     delete holder[0];
     76     try {
     77       f();
     78     } catch (e) {
     79       if (e instanceof Debug.LiveEdit.Failure) {
     80         holder[0] = e;
     81       } else {
     82         throw e;
     83       }
     84     }
     85   };
     86 }
     87 
     88 function WrapInNativeCall(f) {
     89   return function() {
     90     return %Call(f, undefined);
     91   };
     92 }
     93 
     94 function WrapInDebuggerCall(f) {
     95   return function() {
     96     return %ExecuteInDebugContext(f);
     97   };
     98 }
     99 
    100 function WrapInRestartProof(f) {
    101   var already_called = false;
    102   return function() {
    103     if (already_called) {
    104       return;
    105     }
    106     already_called = true;
    107     f();
    108   }
    109 }
    110 
    111 function WrapInConstructor(f) {
    112   return function() {
    113     return new function() {
    114       f();
    115     };
    116   }
    117 }
    118 
    119 
    120 // A series of tests. In each test we call ChooseAnimal function that calls
    121 // a callback that attempts to modify the function on the fly.
    122 
    123 test = new TestBase("First test ChooseAnimal without edit");
    124 assertEquals("Cat", test.ChooseAnimal(Noop));
    125 
    126 test = new TestBase("Test without function on stack");
    127 test.ScriptChanger();
    128 assertEquals("Capybara", test.ChooseAnimal(Noop));
    129 
    130 test = new TestBase("Test with function on stack");
    131 assertEquals("Capybara", test.ChooseAnimal(WrapInDebuggerCall(WrapInRestartProof(test.ScriptChanger))));
    132 
    133 
    134 test = new TestBase("Test with function on stack and with constructor frame");
    135 assertEquals("Capybara", test.ChooseAnimal(WrapInConstructor(WrapInDebuggerCall(WrapInRestartProof(test.ScriptChanger)))));
    136 
    137 test = new TestBase("Test with C++ frame above ChooseAnimal frame");
    138 exception_holder = {};
    139 assertEquals("Cat", test.ChooseAnimal(WrapInNativeCall(WrapInDebuggerCall(WrapInCatcher(test.ScriptChanger, exception_holder)))));
    140 assertTrue(!!exception_holder[0]);
    141