Handle<Value> data) {
HandleScope scope;
- // Currently only handles break and exception events.
- if (event != Break && event != Exception) return;
+ // Check for handled event.
+ if (event != Break && event != Exception && event != AfterCompile) {
+ return;
+ }
TryCatch try_catch;
// Print the event details.
Handle<String> details = Shell::DebugEventToText(event_data);
+ if (details->Length() == 0) {
+ // Empty string is used to signal not to process this event.
+ return;
+ }
String::Utf8Value str(details);
printf("%s\n", *str);
// Debug events which can occour in the V8 JavaScript engine. These originate
-// from the API include file debug.h.
+// from the API include file v8-debug.h.
Debug.DebugEvent = { Break: 1,
Exception: 2,
NewFunction: 3,
currentFrame: kNoFrame,
currentSourceLine: -1
}
+var trace_compile = false; // Tracing all compile events?
function DebugEventToText(event) {
- if (event.eventType() == 1) {
- // Build the break details.
- var details = '';
- if (event.breakPointsHit()) {
- details += 'breakpoint';
- if (event.breakPointsHit().length > 1) {
- details += 's';
- }
- details += ' #';
- for (var i = 0; i < event.breakPointsHit().length; i++) {
- if (i > 0) {
- details += ', #';
+ switch (event.eventType()) {
+ case Debug.DebugEvent.Break:
+ // Build the break details.
+ var details = '';
+ if (event.breakPointsHit()) {
+ details += 'breakpoint';
+ if (event.breakPointsHit().length > 1) {
+ details += 's';
}
- // Find the break point number. For break points originating from a
- // script break point display the script break point number.
- var break_point = event.breakPointsHit()[i];
- var script_break_point = break_point.script_break_point();
- if (script_break_point) {
- details += script_break_point.number();
- } else {
- details += break_point.number();
+ details += ' #';
+ for (var i = 0; i < event.breakPointsHit().length; i++) {
+ if (i > 0) {
+ details += ', #';
+ }
+ // Find the break point number. For break points originating from a
+ // script break point display the script break point number.
+ var break_point = event.breakPointsHit()[i];
+ var script_break_point = break_point.script_break_point();
+ if (script_break_point) {
+ details += script_break_point.number();
+ } else {
+ details += break_point.number();
+ }
}
+ } else {
+ details += 'break';
}
- } else {
- details += 'break';
- }
- details += ' in ';
- details += event.executionState().frame(0).invocationText();
- details += ' at ';
- details += event.executionState().frame(0).sourceAndPositionText();
- details += '\n'
- if (event.func().script()) {
- details += FrameSourceUnderline(event.executionState().frame(0));
- }
- Debug.State.currentSourceLine =
- event.executionState().frame(0).sourceLine();
- Debug.State.currentFrame = 0;
- return details;
- } else if (event.eventType() == 2) {
- var details = '';
- if (event.uncaught_) {
- details += 'Uncaught: ';
- } else {
- details += 'Exception: ';
- }
-
- details += '"';
- details += event.exception();
- details += '"';
- if (event.executionState().frameCount() > 0) {
- details += '"';
- details += event.exception();
+ details += ' in ';
+ details += event.executionState().frame(0).invocationText();
details += ' at ';
details += event.executionState().frame(0).sourceAndPositionText();
- details += '\n';
- details += FrameSourceUnderline(event.executionState().frame(0));
+ details += '\n'
+ if (event.func().script()) {
+ details += FrameSourceUnderline(event.executionState().frame(0));
+ }
Debug.State.currentSourceLine =
event.executionState().frame(0).sourceLine();
Debug.State.currentFrame = 0;
- } else {
- details += ' (empty stack)';
- Debug.State.currentSourceLine = -1;
- Debug.State.currentFrame = kNoFrame;
- }
+ return details;
+
+ case Debug.DebugEvent.Exception:
+ var details = '';
+ if (event.uncaught_) {
+ details += 'Uncaught: ';
+ } else {
+ details += 'Exception: ';
+ }
- return details;
+ details += '"';
+ details += event.exception();
+ details += '"';
+ if (event.executionState().frameCount() > 0) {
+ details += '"';
+ details += event.exception();
+ details += ' at ';
+ details += event.executionState().frame(0).sourceAndPositionText();
+ details += '\n';
+ details += FrameSourceUnderline(event.executionState().frame(0));
+ Debug.State.currentSourceLine =
+ event.executionState().frame(0).sourceLine();
+ Debug.State.currentFrame = 0;
+ } else {
+ details += ' (empty stack)';
+ Debug.State.currentSourceLine = -1;
+ Debug.State.currentFrame = kNoFrame;
+ }
+ return details;
+
+ case Debug.DebugEvent.AfterCompile:
+ if (trace_compile) {
+ details = 'Source ' + event.script().name() + ' compiled:\n'
+ var source = event.script().source();
+ if (!(source[source.length - 1] == '\n')) {
+ details += source;
+ } else {
+ details += source.substring(0, source.length - 1);
+ }
+ return details;
+ } else {
+ return '';
+ }
}
return 'Unknown debug event ' + event.eventType();
this.request_ = this.clearCommandToJSONRequest_(args);
break;
+ case 'trace':
+ // Return undefined to indicate command handled internally (no JSON).
+ this.request_ = void 0;
+ this.traceCommand_(args);
+ break;
+
case 'help':
case '?':
this.helpCommand_(args);
- // Return null to indicate no JSON to send (command handled internally).
- this.request_ = void 0;
+ // Return undefined to indicate command handled internally (no JSON).
+ this.request_ = void 0;
break;
default:
};
-// Create a JSON request for the break command.
+// Handle the trace command.
+DebugRequest.prototype.traceCommand_ = function(args) {
+ // Process arguments.
+ if (args && args.length > 0) {
+ if (args == 'compile') {
+ trace_compile = !trace_compile;
+ print('Tracing of compiled scripts ' + (trace_compile ? 'on' : 'off'));
+ } else {
+ throw new Error('Invalid trace arguments.');
+ }
+ } else {
+ throw new Error('Invalid trace arguments.');
+ }
+}
+
+// Handle the help command.
DebugRequest.prototype.helpCommand_ = function(args) {
// Help os quite simple.
if (args && args.length > 0) {
print('source [from line [num lines]]');
print('scripts');
print('continue');
+ print('trace compile');
print('help');
}
};
-function MakeCompileEvent(script_source, script_name, script_function, before) {
- return new CompileEvent(script_source, script_name, script_function, before);
+function MakeCompileEvent(exec_state, script, before) {
+ return new CompileEvent(exec_state, script, before);
}
-function CompileEvent(script_source, script_name, script_function, before) {
- this.scriptSource = script_source;
- this.scriptName = script_name;
- this.scriptFunction = script_function;
- this.before = before;
+function CompileEvent(exec_state, script, before) {
+ this.exec_state_ = exec_state;
+ this.script_ = MakeMirror(script);
+ this.before_ = before;
}
+CompileEvent.prototype.executionState = function() {
+ return this.exec_state_;
+};
+
+
CompileEvent.prototype.eventType = function() {
- if (this.before) {
- return Debug.DebugEvent.BeforeComplie;
+ if (this.before_) {
+ return Debug.DebugEvent.BeforeCompile;
} else {
- return Debug.DebugEvent.AfterComplie;
+ return Debug.DebugEvent.AfterCompile;
}
};
+CompileEvent.prototype.script = function() {
+ return this.script_;
+};
+
+
function MakeNewFunctionEvent(func) {
return new NewFunctionEvent(func);
}
Handle<Object> Debugger::MakeCompileEvent(Handle<Script> script,
- Handle<Object> script_function,
+ bool before,
bool* caught_exception) {
// Create the compile event object.
Handle<Object> exec_state = MakeExecutionState(caught_exception);
- Handle<Object> script_source(script->source());
- Handle<Object> script_name(script->name());
+ Handle<Object> script_wrapper = GetScriptWrapper(script);
const int argc = 3;
- Object** argv[argc] = { script_source.location(),
- script_name.location(),
- script_function.location() };
+ Object** argv[argc] = { exec_state.location(),
+ script_wrapper.location(),
+ before ? Factory::true_value().location() :
+ Factory::false_value().location() };
+
return MakeJSObject(CStrVector("MakeCompileEvent"),
argc,
argv,
// Create the event data object.
bool caught_exception = false;
- Handle<Object> event_data = MakeCompileEvent(script,
- Factory::undefined_value(),
- &caught_exception);
+ Handle<Object> event_data = MakeCompileEvent(script, true, &caught_exception);
// Bail out and don't call debugger if exception.
if (caught_exception) {
return;
// No more to do if not debugging.
if (!debugger_active()) return;
+ // Store whether in debugger before entering debugger.
+ bool in_debugger = Debug::InDebugger();
+
// Enter the debugger.
EnterDebugger debugger;
if (debugger.FailedToEnter()) return;
return;
}
// Bail out based on state or if there is no listener for this event
- if (Debug::InDebugger()) return;
+ if (in_debugger) return;
if (!Debugger::EventActive(v8::AfterCompile)) return;
// Create the compile state object.
Handle<Object> event_data = MakeCompileEvent(script,
- Factory::undefined_value(),
+ false,
&caught_exception);
// Bail out and don't call debugger if exception.
if (caught_exception) {
static Handle<Object> MakeNewFunctionEvent(Handle<Object> func,
bool* caught_exception);
static Handle<Object> MakeCompileEvent(Handle<Script> script,
- Handle<Object> script_function,
+ bool before,
bool* caught_exception);
static void OnDebugBreak(Handle<Object> break_points_hit);
static void OnException(Handle<Object> exception, bool uncaught);
--- /dev/null
+// Copyright 2009 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following
+// disclaimer in the documentation and/or other materials provided
+// with the distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived
+// from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Flags: --expose-debug-as debug
+// Get the Debug object exposed from the debug context global object.
+Debug = debug.Debug
+
+var exception = false; // Exception in debug event listener.
+var before_compile_count = 0;
+var after_compile_count = 0;
+var current_source = ''; // Current source compiled.
+var source_count = 0; // Total number of scource sompiled.
+
+
+function compileSource(source) {
+ current_source = source;
+ eval(current_source);
+ source_count++;
+}
+
+
+function listener(event, exec_state, event_data, data) {
+ try {
+ if (event == Debug.DebugEvent.BeforeCompile ||
+ event == Debug.DebugEvent.AfterCompile) {
+ // Count the events.
+ if (event == Debug.DebugEvent.BeforeCompile) {
+ before_compile_count++;
+ } else {
+ after_compile_count++;
+ }
+
+ // If the compiled source contains 'eval' there will be additional compile
+ // events for the source inside eval.
+ if (current_source.indexOf('eval') == 0) {
+ // For source with 'eval' there will be compile events with substrings
+ // as well as with with the exact source.
+ assertTrue(current_source.indexOf(event_data.script().source()) >= 0);
+ } else {
+ // For source without 'eval' there will be a compile events with the
+ // exact source.
+ assertEquals(current_source, event_data.script().source());
+ }
+ }
+ } catch (e) {
+ exception = e
+ }
+};
+
+
+// Add the debug event listener.
+Debug.setListener(listener);
+
+// Compile different sources.
+compileSource('a=1');
+compileSource('function(){}');
+compileSource('eval("a=2")');
+source_count++; // Using eval causes additional compilation event.
+compileSource('eval("eval(\'function(){return a;}\')")');
+source_count += 2; // Using eval causes additional compilation event.
+
+// Make sure that the debug event listener was invoked.
+assertFalse(exception, "exception in listener")
+
+// Number of before and after compile events should be the same.
+assertEquals(before_compile_count, after_compile_count);
+
+// Check the actual number of events.
+assertEquals(source_count, after_compile_count);
+
+Debug.setListener(null);