summaryrefslogtreecommitdiffstats
path: root/test/cctest/test-debug.cc
diff options
context:
space:
mode:
Diffstat (limited to 'test/cctest/test-debug.cc')
-rw-r--r--test/cctest/test-debug.cc366
1 files changed, 292 insertions, 74 deletions
diff --git a/test/cctest/test-debug.cc b/test/cctest/test-debug.cc
index 7791185c..87f9cab9 100644
--- a/test/cctest/test-debug.cc
+++ b/test/cctest/test-debug.cc
@@ -1,4 +1,4 @@
-// Copyright 2007-2008 the V8 project authors. All rights reserved.
+// Copyright 2010 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:
@@ -32,11 +32,13 @@
#include "v8.h"
#include "api.h"
+#include "cctest.h"
#include "compilation-cache.h"
#include "debug.h"
+#include "deoptimizer.h"
#include "platform.h"
#include "stub-cache.h"
-#include "cctest.h"
+#include "utils.h"
using ::v8::internal::EmbeddedVector;
@@ -515,16 +517,52 @@ void CheckDebugBreakFunction(DebugLocalContext* env,
// ---
-// Source for The JavaScript function which picks out the function name of the
-// top frame.
+// Source for the JavaScript function which picks out the function
+// name of a frame.
const char* frame_function_name_source =
- "function frame_function_name(exec_state) {"
- " return exec_state.frame(0).func().name();"
+ "function frame_function_name(exec_state, frame_number) {"
+ " return exec_state.frame(frame_number).func().name();"
"}";
v8::Local<v8::Function> frame_function_name;
-// Source for The JavaScript function which picks out the source line for the
+// Source for the JavaScript function which pick out the name of the
+// first argument of a frame.
+const char* frame_argument_name_source =
+ "function frame_argument_name(exec_state, frame_number) {"
+ " return exec_state.frame(frame_number).argumentName(0);"
+ "}";
+v8::Local<v8::Function> frame_argument_name;
+
+
+// Source for the JavaScript function which pick out the value of the
+// first argument of a frame.
+const char* frame_argument_value_source =
+ "function frame_argument_value(exec_state, frame_number) {"
+ " return exec_state.frame(frame_number).argumentValue(0).value_;"
+ "}";
+v8::Local<v8::Function> frame_argument_value;
+
+
+// Source for the JavaScript function which pick out the name of the
+// first argument of a frame.
+const char* frame_local_name_source =
+ "function frame_local_name(exec_state, frame_number) {"
+ " return exec_state.frame(frame_number).localName(0);"
+ "}";
+v8::Local<v8::Function> frame_local_name;
+
+
+// Source for the JavaScript function which pick out the value of the
+// first argument of a frame.
+const char* frame_local_value_source =
+ "function frame_local_value(exec_state, frame_number) {"
+ " return exec_state.frame(frame_number).localValue(0).value_;"
+ "}";
+v8::Local<v8::Function> frame_local_value;
+
+
+// Source for the JavaScript function which picks out the source line for the
// top frame.
const char* frame_source_line_source =
"function frame_source_line(exec_state) {"
@@ -533,7 +571,7 @@ const char* frame_source_line_source =
v8::Local<v8::Function> frame_source_line;
-// Source for The JavaScript function which picks out the source column for the
+// Source for the JavaScript function which picks out the source column for the
// top frame.
const char* frame_source_column_source =
"function frame_source_column(exec_state) {"
@@ -542,7 +580,7 @@ const char* frame_source_column_source =
v8::Local<v8::Function> frame_source_column;
-// Source for The JavaScript function which picks out the script name for the
+// Source for the JavaScript function which picks out the script name for the
// top frame.
const char* frame_script_name_source =
"function frame_script_name(exec_state) {"
@@ -551,7 +589,7 @@ const char* frame_script_name_source =
v8::Local<v8::Function> frame_script_name;
-// Source for The JavaScript function which picks out the script data for the
+// Source for the JavaScript function which picks out the script data for the
// top frame.
const char* frame_script_data_source =
"function frame_script_data(exec_state) {"
@@ -560,7 +598,7 @@ const char* frame_script_data_source =
v8::Local<v8::Function> frame_script_data;
-// Source for The JavaScript function which picks out the script data from
+// Source for the JavaScript function which picks out the script data from
// AfterCompile event
const char* compiled_script_data_source =
"function compiled_script_data(event_data) {"
@@ -569,7 +607,7 @@ const char* compiled_script_data_source =
v8::Local<v8::Function> compiled_script_data;
-// Source for The JavaScript function which returns the number of frames.
+// Source for the JavaScript function which returns the number of frames.
static const char* frame_count_source =
"function frame_count(exec_state) {"
" return exec_state.frameCount();"
@@ -603,8 +641,8 @@ static void DebugEventBreakPointHitCount(v8::DebugEvent event,
break_point_hit_count++;
if (!frame_function_name.IsEmpty()) {
// Get the name of the function.
- const int argc = 1;
- v8::Handle<v8::Value> argv[argc] = { exec_state };
+ const int argc = 2;
+ v8::Handle<v8::Value> argv[argc] = { exec_state, v8::Integer::New(0) };
v8::Handle<v8::Value> result = frame_function_name->Call(exec_state,
argc, argv);
if (result->IsUndefined()) {
@@ -834,8 +872,8 @@ static void DebugEventStepSequence(v8::DebugEvent event,
// Check that the current function is the expected.
CHECK(break_point_hit_count <
StrLength(expected_step_sequence));
- const int argc = 1;
- v8::Handle<v8::Value> argv[argc] = { exec_state };
+ const int argc = 2;
+ v8::Handle<v8::Value> argv[argc] = { exec_state, v8::Integer::New(0) };
v8::Handle<v8::Value> result = frame_function_name->Call(exec_state,
argc, argv);
CHECK(result->IsString());
@@ -2586,6 +2624,10 @@ TEST(DebugStepLinear) {
v8::Local<v8::Function> foo = CompileFunction(&env,
"function foo(){a=1;b=1;c=1;}",
"foo");
+
+ // Run foo to allow it to get optimized.
+ CompileRun("a=0; b=0; c=0; foo();");
+
SetBreakPoint(foo, 3);
// Register a debug event listener which steps and counts.
@@ -2635,7 +2677,8 @@ TEST(DebugStepKeyedLoadLoop) {
" y = 1;\n"
" x = a[i];\n"
" }\n"
- "}\n",
+ "}\n"
+ "y=0\n",
"foo");
// Create array [0,1,2,3,4,5,6,7,8,9]
@@ -2681,7 +2724,8 @@ TEST(DebugStepKeyedStoreLoop) {
" y = 1;\n"
" a[i] = 42;\n"
" }\n"
- "}\n",
+ "}\n"
+ "y=0\n",
"foo");
// Create array [0,1,2,3,4,5,6,7,8,9]
@@ -2753,15 +2797,12 @@ TEST(DebugStepNamedLoadLoop) {
}
-static void DoDebugStepNamedStoreLoop(int expected, bool full_compiler = true) {
+static void DoDebugStepNamedStoreLoop(int expected) {
v8::HandleScope scope;
DebugLocalContext env;
- // Register a debug event listener which steps and counts before compiling the
- // function to ensure the full compiler is used.
- if (full_compiler) {
- v8::Debug::SetDebugEventListener(DebugEventStep);
- }
+ // Register a debug event listener which steps and counts.
+ v8::Debug::SetDebugEventListener(DebugEventStep);
// Create a function for testing stepping of named store.
v8::Local<v8::Function> foo = CompileFunction(
@@ -2777,12 +2818,6 @@ static void DoDebugStepNamedStoreLoop(int expected, bool full_compiler = true) {
// Call function without any break points to ensure inlining is in place.
foo->Call(env->Global(), 0, NULL);
- // Register a debug event listener which steps and counts after compiling the
- // function to ensure the optimizing compiler is used.
- if (!full_compiler) {
- v8::Debug::SetDebugEventListener(DebugEventStep);
- }
-
// Setup break point and step through the function.
SetBreakPoint(foo, 3);
step_action = StepNext;
@@ -2798,20 +2833,11 @@ static void DoDebugStepNamedStoreLoop(int expected, bool full_compiler = true) {
// Test of the stepping mechanism for named load in a loop.
-TEST(DebugStepNamedStoreLoopFull) {
- // With the full compiler it is possible to break on the for statement.
+TEST(DebugStepNamedStoreLoop) {
DoDebugStepNamedStoreLoop(22);
}
-// Test of the stepping mechanism for named load in a loop.
-TEST(DebugStepNamedStoreLoopOptimizing) {
- // With the optimizing compiler it is not possible to break on the for
- // statement as it uses a local variable thus no IC's.
- DoDebugStepNamedStoreLoop(11, false);
-}
-
-
// Test the stepping mechanism with different ICs.
TEST(DebugStepLinearMixedICs) {
v8::HandleScope scope;
@@ -2828,6 +2854,10 @@ TEST(DebugStepLinearMixedICs) {
" var index='name';"
" var y = {};"
" a=1;b=2;x=a;y[index]=3;x=y[index];bar();}", "foo");
+
+ // Run functions to allow them to get optimized.
+ CompileRun("a=0; b=0; bar(); foo();");
+
SetBreakPoint(foo, 0);
step_action = StepIn;
@@ -2862,15 +2892,18 @@ TEST(DebugStepDeclarations) {
// Register a debug event listener which steps and counts.
v8::Debug::SetDebugEventListener(DebugEventStep);
- // Create a function for testing stepping.
+ // Create a function for testing stepping. Run it to allow it to get
+ // optimized.
const char* src = "function foo() { "
" var a;"
" var b = 1;"
" var c = foo;"
" var d = Math.floor;"
" var e = b + d(1.2);"
- "}";
+ "}"
+ "foo()";
v8::Local<v8::Function> foo = CompileFunction(&env, src, "foo");
+
SetBreakPoint(foo, 0);
// Stepping through the declarations.
@@ -2892,15 +2925,18 @@ TEST(DebugStepLocals) {
// Register a debug event listener which steps and counts.
v8::Debug::SetDebugEventListener(DebugEventStep);
- // Create a function for testing stepping.
+ // Create a function for testing stepping. Run it to allow it to get
+ // optimized.
const char* src = "function foo() { "
" var a,b;"
" a = 1;"
" b = a + 2;"
" b = 1 + 2 + 3;"
" a = Math.floor(b);"
- "}";
+ "}"
+ "foo()";
v8::Local<v8::Function> foo = CompileFunction(&env, src, "foo");
+
SetBreakPoint(foo, 0);
// Stepping through the declarations.
@@ -2922,7 +2958,8 @@ TEST(DebugStepIf) {
// Register a debug event listener which steps and counts.
v8::Debug::SetDebugEventListener(DebugEventStep);
- // Create a function for testing stepping.
+ // Create a function for testing stepping. Run it to allow it to get
+ // optimized.
const int argc = 1;
const char* src = "function foo(x) { "
" a = 1;"
@@ -2932,7 +2969,8 @@ TEST(DebugStepIf) {
" c = 1;"
" d = 1;"
" }"
- "}";
+ "}"
+ "a=0; b=0; c=0; d=0; foo()";
v8::Local<v8::Function> foo = CompileFunction(&env, src, "foo");
SetBreakPoint(foo, 0);
@@ -2963,7 +3001,8 @@ TEST(DebugStepSwitch) {
// Register a debug event listener which steps and counts.
v8::Debug::SetDebugEventListener(DebugEventStep);
- // Create a function for testing stepping.
+ // Create a function for testing stepping. Run it to allow it to get
+ // optimized.
const int argc = 1;
const char* src = "function foo(x) { "
" a = 1;"
@@ -2979,7 +3018,8 @@ TEST(DebugStepSwitch) {
" f = 1;"
" break;"
" }"
- "}";
+ "}"
+ "a=0; b=0; c=0; d=0; e=0; f=0; foo()";
v8::Local<v8::Function> foo = CompileFunction(&env, src, "foo");
SetBreakPoint(foo, 0);
@@ -3017,14 +3057,16 @@ TEST(DebugStepWhile) {
// Register a debug event listener which steps and counts.
v8::Debug::SetDebugEventListener(DebugEventStep);
- // Create a function for testing stepping.
+ // Create a function for testing stepping. Run it to allow it to get
+ // optimized.
const int argc = 1;
const char* src = "function foo(x) { "
" var a = 0;"
" while (a < x) {"
" a++;"
" }"
- "}";
+ "}"
+ "foo()";
v8::Local<v8::Function> foo = CompileFunction(&env, src, "foo");
SetBreakPoint(foo, 8); // "var a = 0;"
@@ -3033,14 +3075,14 @@ TEST(DebugStepWhile) {
break_point_hit_count = 0;
v8::Handle<v8::Value> argv_10[argc] = { v8::Number::New(10) };
foo->Call(env->Global(), argc, argv_10);
- CHECK_EQ(23, break_point_hit_count);
+ CHECK_EQ(22, break_point_hit_count);
// Looping 100 times.
step_action = StepIn;
break_point_hit_count = 0;
v8::Handle<v8::Value> argv_100[argc] = { v8::Number::New(100) };
foo->Call(env->Global(), argc, argv_100);
- CHECK_EQ(203, break_point_hit_count);
+ CHECK_EQ(202, break_point_hit_count);
// Get rid of the debug event listener.
v8::Debug::SetDebugEventListener(NULL);
@@ -3055,14 +3097,16 @@ TEST(DebugStepDoWhile) {
// Register a debug event listener which steps and counts.
v8::Debug::SetDebugEventListener(DebugEventStep);
- // Create a function for testing stepping.
+ // Create a function for testing stepping. Run it to allow it to get
+ // optimized.
const int argc = 1;
const char* src = "function foo(x) { "
" var a = 0;"
" do {"
" a++;"
" } while (a < x)"
- "}";
+ "}"
+ "foo()";
v8::Local<v8::Function> foo = CompileFunction(&env, src, "foo");
SetBreakPoint(foo, 8); // "var a = 0;"
@@ -3093,15 +3137,18 @@ TEST(DebugStepFor) {
// Register a debug event listener which steps and counts.
v8::Debug::SetDebugEventListener(DebugEventStep);
- // Create a function for testing stepping.
+ // Create a function for testing stepping. Run it to allow it to get
+ // optimized.
const int argc = 1;
const char* src = "function foo(x) { "
" a = 1;"
" for (i = 0; i < x; i++) {"
" b = 1;"
" }"
- "}";
+ "}"
+ "a=0; b=0; i=0; foo()";
v8::Local<v8::Function> foo = CompileFunction(&env, src, "foo");
+
SetBreakPoint(foo, 8); // "a = 1;"
// Looping 10 times.
@@ -3131,7 +3178,8 @@ TEST(DebugStepForContinue) {
// Register a debug event listener which steps and counts.
v8::Debug::SetDebugEventListener(DebugEventStep);
- // Create a function for testing stepping.
+ // Create a function for testing stepping. Run it to allow it to get
+ // optimized.
const int argc = 1;
const char* src = "function foo(x) { "
" var a = 0;"
@@ -3144,7 +3192,8 @@ TEST(DebugStepForContinue) {
" c++;"
" }"
" return b;"
- "}";
+ "}"
+ "foo()";
v8::Local<v8::Function> foo = CompileFunction(&env, src, "foo");
v8::Handle<v8::Value> result;
SetBreakPoint(foo, 8); // "var a = 0;"
@@ -3180,7 +3229,8 @@ TEST(DebugStepForBreak) {
// Register a debug event listener which steps and counts.
v8::Debug::SetDebugEventListener(DebugEventStep);
- // Create a function for testing stepping.
+ // Create a function for testing stepping. Run it to allow it to get
+ // optimized.
const int argc = 1;
const char* src = "function foo(x) { "
" var a = 0;"
@@ -3193,7 +3243,8 @@ TEST(DebugStepForBreak) {
" c++;"
" }"
" return b;"
- "}";
+ "}"
+ "foo()";
v8::Local<v8::Function> foo = CompileFunction(&env, src, "foo");
v8::Handle<v8::Value> result;
SetBreakPoint(foo, 8); // "var a = 0;"
@@ -3230,13 +3281,16 @@ TEST(DebugStepForIn) {
// Register a debug event listener which steps and counts.
v8::Debug::SetDebugEventListener(DebugEventStep);
+ // Create a function for testing stepping. Run it to allow it to get
+ // optimized.
v8::Local<v8::Function> foo;
const char* src_1 = "function foo() { "
" var a = [1, 2];"
" for (x in a) {"
" b = 0;"
" }"
- "}";
+ "}"
+ "foo()";
foo = CompileFunction(&env, src_1, "foo");
SetBreakPoint(foo, 0); // "var a = ..."
@@ -3245,12 +3299,15 @@ TEST(DebugStepForIn) {
foo->Call(env->Global(), 0, NULL);
CHECK_EQ(6, break_point_hit_count);
+ // Create a function for testing stepping. Run it to allow it to get
+ // optimized.
const char* src_2 = "function foo() { "
" var a = {a:[1, 2, 3]};"
" for (x in a.a) {"
" b = 0;"
" }"
- "}";
+ "}"
+ "foo()";
foo = CompileFunction(&env, src_2, "foo");
SetBreakPoint(foo, 0); // "var a = ..."
@@ -3272,12 +3329,14 @@ TEST(DebugStepWith) {
// Register a debug event listener which steps and counts.
v8::Debug::SetDebugEventListener(DebugEventStep);
- // Create a function for testing stepping.
+ // Create a function for testing stepping. Run it to allow it to get
+ // optimized.
const char* src = "function foo(x) { "
" var a = {};"
" with (a) {}"
" with (b) {}"
- "}";
+ "}"
+ "foo()";
env->Global()->Set(v8::String::New("b"), v8::Object::New());
v8::Local<v8::Function> foo = CompileFunction(&env, src, "foo");
v8::Handle<v8::Value> result;
@@ -3301,12 +3360,14 @@ TEST(DebugConditional) {
// Register a debug event listener which steps and counts.
v8::Debug::SetDebugEventListener(DebugEventStep);
- // Create a function for testing stepping.
+ // Create a function for testing stepping. Run it to allow it to get
+ // optimized.
const char* src = "function foo(x) { "
" var a;"
" a = x ? 1 : 2;"
" return a;"
- "}";
+ "}"
+ "foo()";
v8::Local<v8::Function> foo = CompileFunction(&env, src, "foo");
SetBreakPoint(foo, 0); // "var a;"
@@ -3340,10 +3401,12 @@ TEST(StepInOutSimple) {
// Register a debug event listener which steps and counts.
v8::Debug::SetDebugEventListener(DebugEventStepSequence);
- // Create functions for testing stepping.
+ // Create a function for testing stepping. Run it to allow it to get
+ // optimized.
const char* src = "function a() {b();c();}; "
"function b() {c();}; "
- "function c() {}; ";
+ "function c() {}; "
+ "a(); b(); c()";
v8::Local<v8::Function> a = CompileFunction(&env, src, "a");
SetBreakPoint(a, 0);
@@ -3389,11 +3452,13 @@ TEST(StepInOutTree) {
// Register a debug event listener which steps and counts.
v8::Debug::SetDebugEventListener(DebugEventStepSequence);
- // Create functions for testing stepping.
+ // Create a function for testing stepping. Run it to allow it to get
+ // optimized.
const char* src = "function a() {b(c(d()),d());c(d());d()}; "
"function b(x,y) {c();}; "
"function c(x) {}; "
- "function d() {}; ";
+ "function d() {}; "
+ "a(); b(); c(); d()";
v8::Local<v8::Function> a = CompileFunction(&env, src, "a");
SetBreakPoint(a, 0);
@@ -3439,10 +3504,12 @@ TEST(StepInOutBranch) {
// Register a debug event listener which steps and counts.
v8::Debug::SetDebugEventListener(DebugEventStepSequence);
- // Create functions for testing stepping.
+ // Create a function for testing stepping. Run it to allow it to get
+ // optimized.
const char* src = "function a() {b(false);c();}; "
"function b(x) {if(x){c();};}; "
- "function c() {}; ";
+ "function c() {}; "
+ "a(); b(); c()";
v8::Local<v8::Function> a = CompileFunction(&env, src, "a");
SetBreakPoint(a, 0);
@@ -6116,8 +6183,8 @@ static void DebugEventDebugBreak(
// Get the name of the top frame function.
if (!frame_function_name.IsEmpty()) {
// Get the name of the function.
- const int argc = 1;
- v8::Handle<v8::Value> argv[argc] = { exec_state };
+ const int argc = 2;
+ v8::Handle<v8::Value> argv[argc] = { exec_state, v8::Integer::New(0) };
v8::Handle<v8::Value> result = frame_function_name->Call(exec_state,
argc, argv);
if (result->IsUndefined()) {
@@ -6846,6 +6913,7 @@ static void DebugEventBreakDataChecker(const v8::Debug::EventDetails& details) {
}
}
+
// Check that event details contain context where debug event occured.
TEST(DebugEventBreakData) {
v8::HandleScope scope;
@@ -6898,6 +6966,156 @@ TEST(DebugEventBreakData) {
CheckDebuggerUnloaded();
}
+static bool debug_event_break_deoptimize_done = false;
+
+static void DebugEventBreakDeoptimize(v8::DebugEvent event,
+ v8::Handle<v8::Object> exec_state,
+ v8::Handle<v8::Object> event_data,
+ v8::Handle<v8::Value> data) {
+ if (event == v8::Break) {
+ if (!frame_function_name.IsEmpty()) {
+ // Get the name of the function.
+ const int argc = 2;
+ v8::Handle<v8::Value> argv[argc] = { exec_state, v8::Integer::New(0) };
+ v8::Handle<v8::Value> result =
+ frame_function_name->Call(exec_state, argc, argv);
+ if (!result->IsUndefined()) {
+ char fn[80];
+ CHECK(result->IsString());
+ v8::Handle<v8::String> function_name(result->ToString());
+ function_name->WriteAscii(fn);
+ if (strcmp(fn, "bar") == 0) {
+ i::Deoptimizer::DeoptimizeAll();
+ debug_event_break_deoptimize_done = true;
+ }
+ }
+ }
+
+ v8::Debug::DebugBreak();
+ }
+}
+
+
+// Test deoptimization when execution is broken using the debug break stack
+// check interrupt.
+TEST(DeoptimizeDuringDebugBreak) {
+ v8::HandleScope scope;
+ DebugLocalContext env;
+ env.ExposeDebug();
+
+ // Create a function for checking the function when hitting a break point.
+ frame_function_name = CompileFunction(&env,
+ frame_function_name_source,
+ "frame_function_name");
+
+
+ // Set a debug event listener which will keep interrupting execution until
+ // debug break. When inside function bar it will deoptimize all functions.
+ // This tests lazy deoptimization bailout for the stack check, as the first
+ // time in function bar when using debug break and no break points will be at
+ // the initial stack check.
+ v8::Debug::SetDebugEventListener(DebugEventBreakDeoptimize,
+ v8::Undefined());
+
+ // Compile and run function bar which will optimize it for some flag settings.
+ v8::Script::Compile(v8::String::New("function bar(){}; bar()"))->Run();
+
+ // Set debug break and call bar again.
+ v8::Debug::DebugBreak();
+ v8::Script::Compile(v8::String::New("bar()"))->Run();
+
+ CHECK(debug_event_break_deoptimize_done);
+
+ v8::Debug::SetDebugEventListener(NULL);
+}
+
+
+static void DebugEventBreakWithOptimizedStack(v8::DebugEvent event,
+ v8::Handle<v8::Object> exec_state,
+ v8::Handle<v8::Object> event_data,
+ v8::Handle<v8::Value> data) {
+ if (event == v8::Break) {
+ if (!frame_function_name.IsEmpty()) {
+ for (int i = 0; i < 2; i++) {
+ const int argc = 2;
+ v8::Handle<v8::Value> argv[argc] = { exec_state, v8::Integer::New(i) };
+ // Get the name of the function in frame i.
+ v8::Handle<v8::Value> result =
+ frame_function_name->Call(exec_state, argc, argv);
+ CHECK(result->IsString());
+ v8::Handle<v8::String> function_name(result->ToString());
+ CHECK(function_name->Equals(v8::String::New("loop")));
+ // Get the name of the first argument in frame i.
+ result = frame_argument_name->Call(exec_state, argc, argv);
+ CHECK(result->IsString());
+ v8::Handle<v8::String> argument_name(result->ToString());
+ CHECK(argument_name->Equals(v8::String::New("count")));
+ // Get the value of the first argument in frame i. If the
+ // funtion is optimized the value will be undefined, otherwise
+ // the value will be '1 - i'.
+ //
+ // TODO(3141533): We should be able to get the real value for
+ // optimized frames.
+ result = frame_argument_value->Call(exec_state, argc, argv);
+ CHECK(result->IsUndefined() || (result->Int32Value() == 1 - i));
+ // Get the name of the first local variable.
+ result = frame_local_name->Call(exec_state, argc, argv);
+ CHECK(result->IsString());
+ v8::Handle<v8::String> local_name(result->ToString());
+ CHECK(local_name->Equals(v8::String::New("local")));
+ // Get the value of the first local variable. If the function
+ // is optimized the value will be undefined, otherwise it will
+ // be 42.
+ //
+ // TODO(3141533): We should be able to get the real value for
+ // optimized frames.
+ result = frame_local_value->Call(exec_state, argc, argv);
+ CHECK(result->IsUndefined() || (result->Int32Value() == 42));
+ }
+ }
+ }
+}
+
+
+static v8::Handle<v8::Value> ScheduleBreak(const v8::Arguments& args) {
+ v8::Debug::SetDebugEventListener(DebugEventBreakWithOptimizedStack,
+ v8::Undefined());
+ v8::Debug::DebugBreak();
+ return v8::Undefined();
+}
+
+
+TEST(DebugBreakStackInspection) {
+ v8::HandleScope scope;
+ DebugLocalContext env;
+
+ frame_function_name =
+ CompileFunction(&env, frame_function_name_source, "frame_function_name");
+ frame_argument_name =
+ CompileFunction(&env, frame_argument_name_source, "frame_argument_name");
+ frame_argument_value = CompileFunction(&env,
+ frame_argument_value_source,
+ "frame_argument_value");
+ frame_local_name =
+ CompileFunction(&env, frame_local_name_source, "frame_local_name");
+ frame_local_value =
+ CompileFunction(&env, frame_local_value_source, "frame_local_value");
+
+ v8::Handle<v8::FunctionTemplate> schedule_break_template =
+ v8::FunctionTemplate::New(ScheduleBreak);
+ v8::Handle<v8::Function> schedule_break =
+ schedule_break_template->GetFunction();
+ env->Global()->Set(v8_str("scheduleBreak"), schedule_break);
+
+ const char* src =
+ "function loop(count) {"
+ " var local = 42;"
+ " if (count < 1) { scheduleBreak(); loop(count + 1); }"
+ "}"
+ "loop(0);";
+ v8::Script::Compile(v8::String::New(src))->Run();
+}
+
// Test that setting the terminate execution flag during debug break processing.
static void TestDebugBreakInLoop(const char* loop_head,