text: // Copyright 2016 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: --validate-asm --allow-natives-syntax
  
  InspectorTest.log(
      'This test runs asm.js which calls back to JS. JS triggers a break, on ' +
      'pause we set breakpoints in the asm.js code.');
  
  function testFunction() {
    function generateAsmJs(stdlib, foreign, heap) {
      'use asm';
      var debugger_fun = foreign.call_debugger;
      function callDebugger() {
        debugger_fun();
      }
      function redirectFun() {
        callDebugger();
      }
      return redirectFun;
    }
  
    function call_debugger() {
      debugger;
    }
  
    %OptimizeFunctionOnNextCall(generateAsmJs);
    var fun = generateAsmJs(this, {'call_debugger': call_debugger}, undefined);
    fun();
  
    var finished = 'finished';
    debugger;
  }
  
  Protocol.Debugger.onPaused(handleDebuggerPaused);
  Protocol.Debugger.onScriptParsed(handleScriptParsed);
  
  function printResultAndContinue(next, message) {
    if (message.result && message.result.exceptionDetails)
      InspectorTest.logMessage(message.result.exceptionDetails);
    else if (message.error)
      InspectorTest.logMessage(message.error);
    else if (message.result && message.result.type !== undefined)
      InspectorTest.logMessage(message.result);
    if (next) next();
  }
  
  InspectorTest.runTestSuite([
    function enableDebugger(next) {
      Protocol.Debugger.enable().then(next);
    },
  
    function addScript(next) {
      afterScriptParsedCallback = next;
      InspectorTest.addScript(testFunction.toString());
    },
  
    function runTestFunction(next) {
      afterFinishedTestFunctionCallback = next;
      Protocol.Runtime.evaluate({'expression': 'testFunction()'})
          .then(printResultAndContinue.bind(null, null));
    },
  
    function finished(next) {
      InspectorTest.log('Finished TestSuite.');
      next();
    },
  ]);
  
  function locationToString(callFrame) {
    var res = {functionName: callFrame.functionName};
    for (var attr in callFrame.functionLocation) {
      if (attr == 'scriptId') continue;
      res['function_' + attr] = callFrame.functionLocation[attr];
    }
    for (var attr in callFrame.location) {
      if (attr == 'scriptId') continue;
      res[attr] = callFrame.location[attr];
    }
    return JSON.stringify(res);
  }
  
  function logStackTrace(messageObject) {
    var frames = messageObject.params.callFrames;
    for (var i = 0; i < frames.length; ++i) {
      InspectorTest.log('  - [' + i + '] ' + locationToString(frames[i]));
    }
  }
  
  var numPaused = 0;
  var parsedScriptParams;
  
  function handleDebuggerPaused(messageObject)
  {
    ++numPaused;
    InspectorTest.log('Paused #' + numPaused);
    logStackTrace(messageObject);
  
    function cont() {
      var topFrameId = messageObject.params.callFrames[0].callFrameId;
      Protocol.Debugger
          .evaluateOnCallFrame({
            callFrameId: topFrameId,
            expression: 'typeof finished'
          })
          .then(callbackEvaluate);
      function callbackEvaluate(message) {
        var finished = message.result && message.result.result &&
            message.result.result.value === 'string';
  
        InspectorTest.log('Resuming...');
        Protocol.Debugger.resume();
  
        if (finished)
          afterFinishedTestFunctionCallback();
      }
    }
  
    if (numPaused > 1) {
      cont();
      return;
    }
  
    InspectorTest.log('First time paused, setting breakpoints!');
  
    var startLine = parsedScriptParams.startLine;
    var endLine = parsedScriptParams.endLine;
    InspectorTest.log(
        'Flooding script with breakpoints for all lines (' + startLine + ' - ' +
        endLine + ')...');
    var currentLine = startLine;
    function setNextBreakpoint(message) {
      if (message) InspectorTest.logMessage('error: ' + message.error);
      if (currentLine == endLine) {
        cont();
        return;
      }
      var thisLine = currentLine;
      currentLine += 1;
      InspectorTest.log('Setting breakpoint on line ' + thisLine);
      Protocol.Debugger
          .setBreakpoint({
            'location': {
              'scriptId': parsedScriptParams.scriptId,
              'lineNumber': thisLine
            }
          })
          .then(setNextBreakpoint);
    }
    setNextBreakpoint();
  }
  
  var numScripts = 0;
  
  function handleScriptParsed(messageObject)
  {
    var scriptId = messageObject.params.scriptId;
    ++numScripts;
    InspectorTest.log('Script nr ' + numScripts + ' parsed!');
    if (numScripts == 1) {
      parsedScriptParams = JSON.parse(JSON.stringify(messageObject.params));
      afterScriptParsedCallback();
    }
  }
  