blob: 73b84b78f067f1be724684e45c83155e813f920b [file] [log] [blame]
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00001// Copyright 2011 the V8 project authors. All rights reserved.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002// 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
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +000028#ifdef ENABLE_DEBUGGER_SUPPORT
29
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000030#include <stdlib.h>
31
32#include "v8.h"
33
34#include "api.h"
kasperl@chromium.orga5551262010-12-07 12:49:48 +000035#include "cctest.h"
kasperl@chromium.orgb3284ad2009-05-18 06:12:45 +000036#include "compilation-cache.h"
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000037#include "debug.h"
kasperl@chromium.orga5551262010-12-07 12:49:48 +000038#include "deoptimizer.h"
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000039#include "platform.h"
40#include "stub-cache.h"
kasperl@chromium.orga5551262010-12-07 12:49:48 +000041#include "utils.h"
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000042
kasperl@chromium.orgb9123622008-09-17 14:05:56 +000043
44using ::v8::internal::EmbeddedVector;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000045using ::v8::internal::Object;
46using ::v8::internal::OS;
47using ::v8::internal::Handle;
48using ::v8::internal::Heap;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +000049using ::v8::internal::JSGlobalProxy;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000050using ::v8::internal::Code;
51using ::v8::internal::Debug;
52using ::v8::internal::Debugger;
ager@chromium.org3a37e9b2009-04-27 09:26:21 +000053using ::v8::internal::CommandMessage;
54using ::v8::internal::CommandMessageQueue;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000055using ::v8::internal::StepAction;
56using ::v8::internal::StepIn; // From StepAction enum
57using ::v8::internal::StepNext; // From StepAction enum
58using ::v8::internal::StepOut; // From StepAction enum
ager@chromium.org65dad4b2009-04-23 08:48:43 +000059using ::v8::internal::Vector;
ager@chromium.orgc4c92722009-11-18 14:12:51 +000060using ::v8::internal::StrLength;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000061
62// Size of temp buffer for formatting small strings.
63#define SMALL_STRING_BUFFER_SIZE 80
64
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000065// --- A d d i t i o n a l C h e c k H e l p e r s
66
67
68// Helper function used by the CHECK_EQ function when given Address
69// arguments. Should not be called directly.
70static inline void CheckEqualsHelper(const char* file, int line,
71 const char* expected_source,
72 ::v8::internal::Address expected,
73 const char* value_source,
74 ::v8::internal::Address value) {
75 if (expected != value) {
76 V8_Fatal(file, line, "CHECK_EQ(%s, %s) failed\n# "
77 "Expected: %i\n# Found: %i",
78 expected_source, value_source, expected, value);
79 }
80}
81
82
83// Helper function used by the CHECK_NE function when given Address
84// arguments. Should not be called directly.
85static inline void CheckNonEqualsHelper(const char* file, int line,
86 const char* unexpected_source,
87 ::v8::internal::Address unexpected,
88 const char* value_source,
89 ::v8::internal::Address value) {
90 if (unexpected == value) {
91 V8_Fatal(file, line, "CHECK_NE(%s, %s) failed\n# Value: %i",
92 unexpected_source, value_source, value);
93 }
94}
95
96
97// Helper function used by the CHECK function when given code
98// arguments. Should not be called directly.
99static inline void CheckEqualsHelper(const char* file, int line,
100 const char* expected_source,
101 const Code* expected,
102 const char* value_source,
103 const Code* value) {
104 if (expected != value) {
105 V8_Fatal(file, line, "CHECK_EQ(%s, %s) failed\n# "
106 "Expected: %p\n# Found: %p",
107 expected_source, value_source, expected, value);
108 }
109}
110
111
112static inline void CheckNonEqualsHelper(const char* file, int line,
113 const char* expected_source,
114 const Code* expected,
115 const char* value_source,
116 const Code* value) {
117 if (expected == value) {
118 V8_Fatal(file, line, "CHECK_NE(%s, %s) failed\n# Value: %p",
119 expected_source, value_source, value);
120 }
121}
122
123
124// --- H e l p e r C l a s s e s
125
126
127// Helper class for creating a V8 enviromnent for running tests
128class DebugLocalContext {
129 public:
130 inline DebugLocalContext(
131 v8::ExtensionConfiguration* extensions = 0,
132 v8::Handle<v8::ObjectTemplate> global_template =
133 v8::Handle<v8::ObjectTemplate>(),
134 v8::Handle<v8::Value> global_object = v8::Handle<v8::Value>())
135 : context_(v8::Context::New(extensions, global_template, global_object)) {
136 context_->Enter();
137 }
138 inline ~DebugLocalContext() {
139 context_->Exit();
140 context_.Dispose();
141 }
142 inline v8::Context* operator->() { return *context_; }
143 inline v8::Context* operator*() { return *context_; }
144 inline bool IsReady() { return !context_.IsEmpty(); }
145 void ExposeDebug() {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000146 v8::internal::Debug* debug = v8::internal::Isolate::Current()->debug();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000147 // Expose the debug context global object in the global object for testing.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000148 debug->Load();
149 debug->debug_context()->set_security_token(
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000150 v8::Utils::OpenHandle(*context_)->security_token());
151
152 Handle<JSGlobalProxy> global(Handle<JSGlobalProxy>::cast(
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000153 v8::Utils::OpenHandle(*context_->Global())));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000154 Handle<v8::internal::String> debug_string =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000155 FACTORY->LookupAsciiSymbol("debug");
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000156 SetProperty(global, debug_string,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000157 Handle<Object>(debug->debug_context()->global_proxy()), DONT_ENUM,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000158 ::v8::internal::kNonStrictMode);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000159 }
160 private:
161 v8::Persistent<v8::Context> context_;
162};
163
164
165// --- H e l p e r F u n c t i o n s
166
167
168// Compile and run the supplied source and return the fequested function.
169static v8::Local<v8::Function> CompileFunction(DebugLocalContext* env,
170 const char* source,
171 const char* function_name) {
172 v8::Script::Compile(v8::String::New(source))->Run();
173 return v8::Local<v8::Function>::Cast(
174 (*env)->Global()->Get(v8::String::New(function_name)));
175}
176
ager@chromium.org9085a012009-05-11 19:22:57 +0000177
178// Compile and run the supplied source and return the requested function.
179static v8::Local<v8::Function> CompileFunction(const char* source,
180 const char* function_name) {
181 v8::Script::Compile(v8::String::New(source))->Run();
182 return v8::Local<v8::Function>::Cast(
183 v8::Context::GetCurrent()->Global()->Get(v8::String::New(function_name)));
184}
185
186
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000187// Is there any debug info for the function?
188static bool HasDebugInfo(v8::Handle<v8::Function> fun) {
189 Handle<v8::internal::JSFunction> f = v8::Utils::OpenHandle(*fun);
190 Handle<v8::internal::SharedFunctionInfo> shared(f->shared());
191 return Debug::HasDebugInfo(shared);
192}
193
194
195// Set a break point in a function and return the associated break point
196// number.
197static int SetBreakPoint(Handle<v8::internal::JSFunction> fun, int position) {
198 static int break_point = 0;
199 Handle<v8::internal::SharedFunctionInfo> shared(fun->shared());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000200 v8::internal::Debug* debug = v8::internal::Isolate::Current()->debug();
201 debug->SetBreakPoint(
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +0000202 shared,
203 Handle<Object>(v8::internal::Smi::FromInt(++break_point)),
204 &position);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000205 return break_point;
206}
207
208
209// Set a break point in a function and return the associated break point
210// number.
211static int SetBreakPoint(v8::Handle<v8::Function> fun, int position) {
212 return SetBreakPoint(v8::Utils::OpenHandle(*fun), position);
213}
214
215
216// Set a break point in a function using the Debug object and return the
217// associated break point number.
218static int SetBreakPointFromJS(const char* function_name,
219 int line, int position) {
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000220 EmbeddedVector<char, SMALL_STRING_BUFFER_SIZE> buffer;
221 OS::SNPrintF(buffer,
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000222 "debug.Debug.setBreakPoint(%s,%d,%d)",
223 function_name, line, position);
224 buffer[SMALL_STRING_BUFFER_SIZE - 1] = '\0';
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000225 v8::Handle<v8::String> str = v8::String::New(buffer.start());
226 return v8::Script::Compile(str)->Run()->Int32Value();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000227}
228
229
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000230// Set a break point in a script identified by id using the global Debug object.
231static int SetScriptBreakPointByIdFromJS(int script_id, int line, int column) {
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000232 EmbeddedVector<char, SMALL_STRING_BUFFER_SIZE> buffer;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000233 if (column >= 0) {
234 // Column specified set script break point on precise location.
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000235 OS::SNPrintF(buffer,
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000236 "debug.Debug.setScriptBreakPointById(%d,%d,%d)",
237 script_id, line, column);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000238 } else {
239 // Column not specified set script break point on line.
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000240 OS::SNPrintF(buffer,
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000241 "debug.Debug.setScriptBreakPointById(%d,%d)",
242 script_id, line);
243 }
244 buffer[SMALL_STRING_BUFFER_SIZE - 1] = '\0';
245 {
246 v8::TryCatch try_catch;
247 v8::Handle<v8::String> str = v8::String::New(buffer.start());
248 v8::Handle<v8::Value> value = v8::Script::Compile(str)->Run();
ager@chromium.org3a37e9b2009-04-27 09:26:21 +0000249 CHECK(!try_catch.HasCaught());
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000250 return value->Int32Value();
251 }
252}
253
254
255// Set a break point in a script identified by name using the global Debug
256// object.
257static int SetScriptBreakPointByNameFromJS(const char* script_name,
258 int line, int column) {
259 EmbeddedVector<char, SMALL_STRING_BUFFER_SIZE> buffer;
260 if (column >= 0) {
261 // Column specified set script break point on precise location.
262 OS::SNPrintF(buffer,
263 "debug.Debug.setScriptBreakPointByName(\"%s\",%d,%d)",
264 script_name, line, column);
265 } else {
266 // Column not specified set script break point on line.
267 OS::SNPrintF(buffer,
268 "debug.Debug.setScriptBreakPointByName(\"%s\",%d)",
269 script_name, line);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000270 }
271 buffer[SMALL_STRING_BUFFER_SIZE - 1] = '\0';
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000272 {
273 v8::TryCatch try_catch;
274 v8::Handle<v8::String> str = v8::String::New(buffer.start());
275 v8::Handle<v8::Value> value = v8::Script::Compile(str)->Run();
ager@chromium.org3a37e9b2009-04-27 09:26:21 +0000276 CHECK(!try_catch.HasCaught());
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000277 return value->Int32Value();
278 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000279}
280
281
282// Clear a break point.
283static void ClearBreakPoint(int break_point) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000284 v8::internal::Debug* debug = v8::internal::Isolate::Current()->debug();
285 debug->ClearBreakPoint(
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000286 Handle<Object>(v8::internal::Smi::FromInt(break_point)));
287}
288
289
290// Clear a break point using the global Debug object.
291static void ClearBreakPointFromJS(int break_point_number) {
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000292 EmbeddedVector<char, SMALL_STRING_BUFFER_SIZE> buffer;
293 OS::SNPrintF(buffer,
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000294 "debug.Debug.clearBreakPoint(%d)",
295 break_point_number);
296 buffer[SMALL_STRING_BUFFER_SIZE - 1] = '\0';
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000297 v8::Script::Compile(v8::String::New(buffer.start()))->Run();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000298}
299
300
301static void EnableScriptBreakPointFromJS(int break_point_number) {
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000302 EmbeddedVector<char, SMALL_STRING_BUFFER_SIZE> buffer;
303 OS::SNPrintF(buffer,
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000304 "debug.Debug.enableScriptBreakPoint(%d)",
305 break_point_number);
306 buffer[SMALL_STRING_BUFFER_SIZE - 1] = '\0';
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000307 v8::Script::Compile(v8::String::New(buffer.start()))->Run();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000308}
309
310
311static void DisableScriptBreakPointFromJS(int break_point_number) {
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000312 EmbeddedVector<char, SMALL_STRING_BUFFER_SIZE> buffer;
313 OS::SNPrintF(buffer,
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000314 "debug.Debug.disableScriptBreakPoint(%d)",
315 break_point_number);
316 buffer[SMALL_STRING_BUFFER_SIZE - 1] = '\0';
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000317 v8::Script::Compile(v8::String::New(buffer.start()))->Run();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000318}
319
320
321static void ChangeScriptBreakPointConditionFromJS(int break_point_number,
322 const char* condition) {
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000323 EmbeddedVector<char, SMALL_STRING_BUFFER_SIZE> buffer;
324 OS::SNPrintF(buffer,
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000325 "debug.Debug.changeScriptBreakPointCondition(%d, \"%s\")",
326 break_point_number, condition);
327 buffer[SMALL_STRING_BUFFER_SIZE - 1] = '\0';
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000328 v8::Script::Compile(v8::String::New(buffer.start()))->Run();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000329}
330
331
332static void ChangeScriptBreakPointIgnoreCountFromJS(int break_point_number,
333 int ignoreCount) {
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000334 EmbeddedVector<char, SMALL_STRING_BUFFER_SIZE> buffer;
335 OS::SNPrintF(buffer,
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000336 "debug.Debug.changeScriptBreakPointIgnoreCount(%d, %d)",
337 break_point_number, ignoreCount);
338 buffer[SMALL_STRING_BUFFER_SIZE - 1] = '\0';
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000339 v8::Script::Compile(v8::String::New(buffer.start()))->Run();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000340}
341
342
343// Change break on exception.
344static void ChangeBreakOnException(bool caught, bool uncaught) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000345 v8::internal::Debug* debug = v8::internal::Isolate::Current()->debug();
346 debug->ChangeBreakOnException(v8::internal::BreakException, caught);
347 debug->ChangeBreakOnException(v8::internal::BreakUncaughtException, uncaught);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000348}
349
350
351// Change break on exception using the global Debug object.
352static void ChangeBreakOnExceptionFromJS(bool caught, bool uncaught) {
353 if (caught) {
354 v8::Script::Compile(
355 v8::String::New("debug.Debug.setBreakOnException()"))->Run();
356 } else {
357 v8::Script::Compile(
358 v8::String::New("debug.Debug.clearBreakOnException()"))->Run();
359 }
360 if (uncaught) {
361 v8::Script::Compile(
362 v8::String::New("debug.Debug.setBreakOnUncaughtException()"))->Run();
363 } else {
364 v8::Script::Compile(
365 v8::String::New("debug.Debug.clearBreakOnUncaughtException()"))->Run();
366 }
367}
368
369
370// Prepare to step to next break location.
371static void PrepareStep(StepAction step_action) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000372 v8::internal::Debug* debug = v8::internal::Isolate::Current()->debug();
373 debug->PrepareStep(step_action, 1);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000374}
375
376
377// This function is in namespace v8::internal to be friend with class
378// v8::internal::Debug.
kasperl@chromium.org71affb52009-05-26 05:44:31 +0000379namespace v8 {
380namespace internal {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000381
382// Collect the currently debugged functions.
383Handle<FixedArray> GetDebuggedFunctions() {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000384 Debug* debug = Isolate::Current()->debug();
385
386 v8::internal::DebugInfoListNode* node = debug->debug_info_list_;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000387
388 // Find the number of debugged functions.
389 int count = 0;
390 while (node) {
391 count++;
392 node = node->next();
393 }
394
395 // Allocate array for the debugged functions
396 Handle<FixedArray> debugged_functions =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000397 FACTORY->NewFixedArray(count);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000398
399 // Run through the debug info objects and collect all functions.
400 count = 0;
401 while (node) {
402 debugged_functions->set(count++, *node->debug_info());
403 node = node->next();
404 }
405
406 return debugged_functions;
407}
408
409
410static Handle<Code> ComputeCallDebugBreak(int argc) {
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +0000411 CALL_HEAP_FUNCTION(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000412 v8::internal::Isolate::Current(),
413 v8::internal::Isolate::Current()->stub_cache()->ComputeCallDebugBreak(
414 argc, Code::CALL_IC),
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +0000415 Code);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000416}
417
ager@chromium.org381abbb2009-02-25 13:23:22 +0000418
ager@chromium.org381abbb2009-02-25 13:23:22 +0000419// Check that the debugger has been fully unloaded.
420void CheckDebuggerUnloaded(bool check_functions) {
421 // Check that the debugger context is cleared and that there is no debug
422 // information stored for the debugger.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000423 CHECK(Isolate::Current()->debug()->debug_context().is_null());
424 CHECK_EQ(NULL, Isolate::Current()->debug()->debug_info_list_);
ager@chromium.org381abbb2009-02-25 13:23:22 +0000425
426 // Collect garbage to ensure weak handles are cleared.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000427 HEAP->CollectAllGarbage(false);
428 HEAP->CollectAllGarbage(false);
ager@chromium.org381abbb2009-02-25 13:23:22 +0000429
430 // Iterate the head and check that there are no debugger related objects left.
431 HeapIterator iterator;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000432 for (HeapObject* obj = iterator.next(); obj != NULL; obj = iterator.next()) {
ager@chromium.org381abbb2009-02-25 13:23:22 +0000433 CHECK(!obj->IsDebugInfo());
434 CHECK(!obj->IsBreakPointInfo());
435
436 // If deep check of functions is requested check that no debug break code
437 // is left in all functions.
438 if (check_functions) {
439 if (obj->IsJSFunction()) {
440 JSFunction* fun = JSFunction::cast(obj);
441 for (RelocIterator it(fun->shared()->code()); !it.done(); it.next()) {
442 RelocInfo::Mode rmode = it.rinfo()->rmode();
443 if (RelocInfo::IsCodeTarget(rmode)) {
444 CHECK(!Debug::IsDebugBreak(it.rinfo()->target_address()));
445 } else if (RelocInfo::IsJSReturn(rmode)) {
446 CHECK(!Debug::IsDebugBreakAtReturn(it.rinfo()));
447 }
448 }
449 }
450 }
451 }
452}
453
454
lrn@chromium.orgc34f5802010-04-28 12:53:43 +0000455void ForceUnloadDebugger() {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000456 Isolate::Current()->debugger()->never_unload_debugger_ = false;
457 Isolate::Current()->debugger()->UnloadDebugger();
lrn@chromium.orgc34f5802010-04-28 12:53:43 +0000458}
459
460
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000461} } // namespace v8::internal
462
ager@chromium.org381abbb2009-02-25 13:23:22 +0000463
ager@chromium.org381abbb2009-02-25 13:23:22 +0000464// Check that the debugger has been fully unloaded.
465static void CheckDebuggerUnloaded(bool check_functions = false) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000466 // Let debugger to unload itself synchronously
467 v8::Debug::ProcessDebugMessages();
468
ager@chromium.org381abbb2009-02-25 13:23:22 +0000469 v8::internal::CheckDebuggerUnloaded(check_functions);
470}
471
472
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000473// Inherit from BreakLocationIterator to get access to protected parts for
474// testing.
475class TestBreakLocationIterator: public v8::internal::BreakLocationIterator {
476 public:
477 explicit TestBreakLocationIterator(Handle<v8::internal::DebugInfo> debug_info)
478 : BreakLocationIterator(debug_info, v8::internal::SOURCE_BREAK_LOCATIONS) {}
479 v8::internal::RelocIterator* it() { return reloc_iterator_; }
480 v8::internal::RelocIterator* it_original() {
481 return reloc_iterator_original_;
482 }
483};
484
485
486// Compile a function, set a break point and check that the call at the break
487// location in the code is the expected debug_break function.
488void CheckDebugBreakFunction(DebugLocalContext* env,
489 const char* source, const char* name,
ager@chromium.org236ad962008-09-25 09:45:57 +0000490 int position, v8::internal::RelocInfo::Mode mode,
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000491 Code* debug_break) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000492 v8::internal::Debug* debug = v8::internal::Isolate::Current()->debug();
493
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000494 // Create function and set the break point.
495 Handle<v8::internal::JSFunction> fun = v8::Utils::OpenHandle(
496 *CompileFunction(env, source, name));
497 int bp = SetBreakPoint(fun, position);
498
499 // Check that the debug break function is as expected.
500 Handle<v8::internal::SharedFunctionInfo> shared(fun->shared());
501 CHECK(Debug::HasDebugInfo(shared));
502 TestBreakLocationIterator it1(Debug::GetDebugInfo(shared));
503 it1.FindBreakLocationFromPosition(position);
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +0000504 v8::internal::RelocInfo::Mode actual_mode = it1.it()->rinfo()->rmode();
505 if (actual_mode == v8::internal::RelocInfo::CODE_TARGET_WITH_ID) {
506 actual_mode = v8::internal::RelocInfo::CODE_TARGET;
507 }
508 CHECK_EQ(mode, actual_mode);
ager@chromium.org236ad962008-09-25 09:45:57 +0000509 if (mode != v8::internal::RelocInfo::JS_RETURN) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000510 CHECK_EQ(debug_break,
ager@chromium.org8bb60582008-12-11 12:02:20 +0000511 Code::GetCodeFromTargetAddress(it1.it()->rinfo()->target_address()));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000512 } else {
sgjesse@chromium.org911335c2009-08-19 12:59:44 +0000513 CHECK(Debug::IsDebugBreakAtReturn(it1.it()->rinfo()));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000514 }
515
516 // Clear the break point and check that the debug break function is no longer
517 // there
518 ClearBreakPoint(bp);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000519 CHECK(!debug->HasDebugInfo(shared));
520 CHECK(debug->EnsureDebugInfo(shared));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000521 TestBreakLocationIterator it2(Debug::GetDebugInfo(shared));
522 it2.FindBreakLocationFromPosition(position);
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +0000523 actual_mode = it2.it()->rinfo()->rmode();
524 if (actual_mode == v8::internal::RelocInfo::CODE_TARGET_WITH_ID) {
525 actual_mode = v8::internal::RelocInfo::CODE_TARGET;
526 }
527 CHECK_EQ(mode, actual_mode);
ager@chromium.org236ad962008-09-25 09:45:57 +0000528 if (mode == v8::internal::RelocInfo::JS_RETURN) {
sgjesse@chromium.org911335c2009-08-19 12:59:44 +0000529 CHECK(!Debug::IsDebugBreakAtReturn(it2.it()->rinfo()));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000530 }
531}
532
533
534// --- D e b u g E v e n t H a n d l e r s
535// ---
536// --- The different tests uses a number of debug event handlers.
537// ---
538
539
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000540// Source for the JavaScript function which picks out the function
541// name of a frame.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000542const char* frame_function_name_source =
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000543 "function frame_function_name(exec_state, frame_number) {"
544 " return exec_state.frame(frame_number).func().name();"
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000545 "}";
546v8::Local<v8::Function> frame_function_name;
547
ager@chromium.org8bb60582008-12-11 12:02:20 +0000548
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000549// Source for the JavaScript function which pick out the name of the
550// first argument of a frame.
551const char* frame_argument_name_source =
552 "function frame_argument_name(exec_state, frame_number) {"
553 " return exec_state.frame(frame_number).argumentName(0);"
554 "}";
555v8::Local<v8::Function> frame_argument_name;
556
557
558// Source for the JavaScript function which pick out the value of the
559// first argument of a frame.
560const char* frame_argument_value_source =
561 "function frame_argument_value(exec_state, frame_number) {"
562 " return exec_state.frame(frame_number).argumentValue(0).value_;"
563 "}";
564v8::Local<v8::Function> frame_argument_value;
565
566
567// Source for the JavaScript function which pick out the name of the
568// first argument of a frame.
569const char* frame_local_name_source =
570 "function frame_local_name(exec_state, frame_number) {"
571 " return exec_state.frame(frame_number).localName(0);"
572 "}";
573v8::Local<v8::Function> frame_local_name;
574
575
576// Source for the JavaScript function which pick out the value of the
577// first argument of a frame.
578const char* frame_local_value_source =
579 "function frame_local_value(exec_state, frame_number) {"
580 " return exec_state.frame(frame_number).localValue(0).value_;"
581 "}";
582v8::Local<v8::Function> frame_local_value;
583
584
585// Source for the JavaScript function which picks out the source line for the
kasperl@chromium.org2d18d102009-04-15 13:27:32 +0000586// top frame.
587const char* frame_source_line_source =
588 "function frame_source_line(exec_state) {"
589 " return exec_state.frame(0).sourceLine();"
590 "}";
591v8::Local<v8::Function> frame_source_line;
592
593
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000594// Source for the JavaScript function which picks out the source column for the
kasperl@chromium.org2d18d102009-04-15 13:27:32 +0000595// top frame.
596const char* frame_source_column_source =
597 "function frame_source_column(exec_state) {"
598 " return exec_state.frame(0).sourceColumn();"
599 "}";
600v8::Local<v8::Function> frame_source_column;
601
602
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000603// Source for the JavaScript function which picks out the script name for the
ager@chromium.org65dad4b2009-04-23 08:48:43 +0000604// top frame.
605const char* frame_script_name_source =
606 "function frame_script_name(exec_state) {"
607 " return exec_state.frame(0).func().script().name();"
608 "}";
609v8::Local<v8::Function> frame_script_name;
610
611
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000612// Source for the JavaScript function which picks out the script data for the
ager@chromium.org65dad4b2009-04-23 08:48:43 +0000613// top frame.
614const char* frame_script_data_source =
615 "function frame_script_data(exec_state) {"
616 " return exec_state.frame(0).func().script().data();"
617 "}";
618v8::Local<v8::Function> frame_script_data;
619
620
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000621// Source for the JavaScript function which picks out the script data from
ager@chromium.org5c838252010-02-19 08:53:10 +0000622// AfterCompile event
623const char* compiled_script_data_source =
624 "function compiled_script_data(event_data) {"
625 " return event_data.script().data();"
626 "}";
627v8::Local<v8::Function> compiled_script_data;
628
629
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000630// Source for the JavaScript function which returns the number of frames.
ager@chromium.org8bb60582008-12-11 12:02:20 +0000631static const char* frame_count_source =
632 "function frame_count(exec_state) {"
633 " return exec_state.frameCount();"
634 "}";
635v8::Handle<v8::Function> frame_count;
636
637
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000638// Global variable to store the last function hit - used by some tests.
639char last_function_hit[80];
640
ager@chromium.org65dad4b2009-04-23 08:48:43 +0000641// Global variable to store the name and data for last script hit - used by some
642// tests.
643char last_script_name_hit[80];
644char last_script_data_hit[80];
645
kasperl@chromium.org2d18d102009-04-15 13:27:32 +0000646// Global variables to store the last source position - used by some tests.
647int last_source_line = -1;
648int last_source_column = -1;
649
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000650// Debug event handler which counts the break points which have been hit.
651int break_point_hit_count = 0;
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +0000652int break_point_hit_count_deoptimize = 0;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000653static void DebugEventBreakPointHitCount(v8::DebugEvent event,
654 v8::Handle<v8::Object> exec_state,
655 v8::Handle<v8::Object> event_data,
656 v8::Handle<v8::Value> data) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000657 Debug* debug = v8::internal::Isolate::Current()->debug();
ager@chromium.org8bb60582008-12-11 12:02:20 +0000658 // When hitting a debug event listener there must be a break set.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000659 CHECK_NE(debug->break_id(), 0);
ager@chromium.org8bb60582008-12-11 12:02:20 +0000660
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000661 // Count the number of breaks.
662 if (event == v8::Break) {
663 break_point_hit_count++;
664 if (!frame_function_name.IsEmpty()) {
665 // Get the name of the function.
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000666 const int argc = 2;
667 v8::Handle<v8::Value> argv[argc] = { exec_state, v8::Integer::New(0) };
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000668 v8::Handle<v8::Value> result = frame_function_name->Call(exec_state,
669 argc, argv);
670 if (result->IsUndefined()) {
671 last_function_hit[0] = '\0';
672 } else {
673 CHECK(result->IsString());
674 v8::Handle<v8::String> function_name(result->ToString());
675 function_name->WriteAscii(last_function_hit);
676 }
677 }
kasperl@chromium.org2d18d102009-04-15 13:27:32 +0000678
679 if (!frame_source_line.IsEmpty()) {
680 // Get the source line.
681 const int argc = 1;
682 v8::Handle<v8::Value> argv[argc] = { exec_state };
683 v8::Handle<v8::Value> result = frame_source_line->Call(exec_state,
684 argc, argv);
685 CHECK(result->IsNumber());
686 last_source_line = result->Int32Value();
687 }
688
689 if (!frame_source_column.IsEmpty()) {
690 // Get the source column.
691 const int argc = 1;
692 v8::Handle<v8::Value> argv[argc] = { exec_state };
693 v8::Handle<v8::Value> result = frame_source_column->Call(exec_state,
694 argc, argv);
695 CHECK(result->IsNumber());
696 last_source_column = result->Int32Value();
697 }
ager@chromium.org65dad4b2009-04-23 08:48:43 +0000698
699 if (!frame_script_name.IsEmpty()) {
700 // Get the script name of the function script.
701 const int argc = 1;
702 v8::Handle<v8::Value> argv[argc] = { exec_state };
703 v8::Handle<v8::Value> result = frame_script_name->Call(exec_state,
704 argc, argv);
705 if (result->IsUndefined()) {
706 last_script_name_hit[0] = '\0';
707 } else {
708 CHECK(result->IsString());
709 v8::Handle<v8::String> script_name(result->ToString());
710 script_name->WriteAscii(last_script_name_hit);
711 }
712 }
713
714 if (!frame_script_data.IsEmpty()) {
715 // Get the script data of the function script.
716 const int argc = 1;
717 v8::Handle<v8::Value> argv[argc] = { exec_state };
718 v8::Handle<v8::Value> result = frame_script_data->Call(exec_state,
719 argc, argv);
720 if (result->IsUndefined()) {
721 last_script_data_hit[0] = '\0';
722 } else {
723 result = result->ToString();
724 CHECK(result->IsString());
725 v8::Handle<v8::String> script_data(result->ToString());
726 script_data->WriteAscii(last_script_data_hit);
727 }
728 }
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +0000729
730 // Perform a full deoptimization when the specified number of
731 // breaks have been hit.
732 if (break_point_hit_count == break_point_hit_count_deoptimize) {
733 i::Deoptimizer::DeoptimizeAll();
734 }
ager@chromium.org5c838252010-02-19 08:53:10 +0000735 } else if (event == v8::AfterCompile && !compiled_script_data.IsEmpty()) {
736 const int argc = 1;
737 v8::Handle<v8::Value> argv[argc] = { event_data };
738 v8::Handle<v8::Value> result = compiled_script_data->Call(exec_state,
739 argc, argv);
740 if (result->IsUndefined()) {
741 last_script_data_hit[0] = '\0';
742 } else {
743 result = result->ToString();
744 CHECK(result->IsString());
745 v8::Handle<v8::String> script_data(result->ToString());
746 script_data->WriteAscii(last_script_data_hit);
747 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000748 }
749}
750
751
ager@chromium.org8bb60582008-12-11 12:02:20 +0000752// Debug event handler which counts a number of events and collects the stack
753// height if there is a function compiled for that.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000754int exception_hit_count = 0;
755int uncaught_exception_hit_count = 0;
ager@chromium.org8bb60582008-12-11 12:02:20 +0000756int last_js_stack_height = -1;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000757
758static void DebugEventCounterClear() {
759 break_point_hit_count = 0;
760 exception_hit_count = 0;
761 uncaught_exception_hit_count = 0;
762}
763
764static void DebugEventCounter(v8::DebugEvent event,
765 v8::Handle<v8::Object> exec_state,
766 v8::Handle<v8::Object> event_data,
767 v8::Handle<v8::Value> data) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000768 v8::internal::Debug* debug = v8::internal::Isolate::Current()->debug();
769
ager@chromium.org8bb60582008-12-11 12:02:20 +0000770 // When hitting a debug event listener there must be a break set.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000771 CHECK_NE(debug->break_id(), 0);
ager@chromium.org8bb60582008-12-11 12:02:20 +0000772
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000773 // Count the number of breaks.
774 if (event == v8::Break) {
775 break_point_hit_count++;
776 } else if (event == v8::Exception) {
777 exception_hit_count++;
778
779 // Check whether the exception was uncaught.
780 v8::Local<v8::String> fun_name = v8::String::New("uncaught");
781 v8::Local<v8::Function> fun =
782 v8::Function::Cast(*event_data->Get(fun_name));
783 v8::Local<v8::Value> result = *fun->Call(event_data, 0, NULL);
784 if (result->IsTrue()) {
785 uncaught_exception_hit_count++;
786 }
787 }
ager@chromium.org8bb60582008-12-11 12:02:20 +0000788
789 // Collect the JavsScript stack height if the function frame_count is
790 // compiled.
791 if (!frame_count.IsEmpty()) {
792 static const int kArgc = 1;
793 v8::Handle<v8::Value> argv[kArgc] = { exec_state };
794 // Using exec_state as receiver is just to have a receiver.
795 v8::Handle<v8::Value> result = frame_count->Call(exec_state, kArgc, argv);
796 last_js_stack_height = result->Int32Value();
797 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000798}
799
800
801// Debug event handler which evaluates a number of expressions when a break
802// point is hit. Each evaluated expression is compared with an expected value.
803// For this debug event handler to work the following two global varaibles
804// must be initialized.
805// checks: An array of expressions and expected results
806// evaluate_check_function: A JavaScript function (see below)
807
808// Structure for holding checks to do.
809struct EvaluateCheck {
810 const char* expr; // An expression to evaluate when a break point is hit.
811 v8::Handle<v8::Value> expected; // The expected result.
812};
813// Array of checks to do.
814struct EvaluateCheck* checks = NULL;
815// Source for The JavaScript function which can do the evaluation when a break
816// point is hit.
817const char* evaluate_check_source =
818 "function evaluate_check(exec_state, expr, expected) {"
819 " return exec_state.frame(0).evaluate(expr).value() === expected;"
820 "}";
821v8::Local<v8::Function> evaluate_check_function;
822
823// The actual debug event described by the longer comment above.
824static void DebugEventEvaluate(v8::DebugEvent event,
825 v8::Handle<v8::Object> exec_state,
826 v8::Handle<v8::Object> event_data,
827 v8::Handle<v8::Value> data) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000828 v8::internal::Debug* debug = v8::internal::Isolate::Current()->debug();
ager@chromium.org8bb60582008-12-11 12:02:20 +0000829 // When hitting a debug event listener there must be a break set.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000830 CHECK_NE(debug->break_id(), 0);
ager@chromium.org8bb60582008-12-11 12:02:20 +0000831
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000832 if (event == v8::Break) {
833 for (int i = 0; checks[i].expr != NULL; i++) {
834 const int argc = 3;
835 v8::Handle<v8::Value> argv[argc] = { exec_state,
836 v8::String::New(checks[i].expr),
837 checks[i].expected };
838 v8::Handle<v8::Value> result =
839 evaluate_check_function->Call(exec_state, argc, argv);
840 if (!result->IsTrue()) {
841 v8::String::AsciiValue ascii(checks[i].expected->ToString());
842 V8_Fatal(__FILE__, __LINE__, "%s != %s", checks[i].expr, *ascii);
843 }
844 }
845 }
846}
847
848
849// This debug event listener removes a breakpoint in a function
850int debug_event_remove_break_point = 0;
851static void DebugEventRemoveBreakPoint(v8::DebugEvent event,
852 v8::Handle<v8::Object> exec_state,
853 v8::Handle<v8::Object> event_data,
854 v8::Handle<v8::Value> data) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000855 v8::internal::Debug* debug = v8::internal::Isolate::Current()->debug();
ager@chromium.org8bb60582008-12-11 12:02:20 +0000856 // When hitting a debug event listener there must be a break set.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000857 CHECK_NE(debug->break_id(), 0);
ager@chromium.org8bb60582008-12-11 12:02:20 +0000858
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000859 if (event == v8::Break) {
860 break_point_hit_count++;
861 v8::Handle<v8::Function> fun = v8::Handle<v8::Function>::Cast(data);
862 ClearBreakPoint(debug_event_remove_break_point);
863 }
864}
865
866
867// Debug event handler which counts break points hit and performs a step
868// afterwards.
869StepAction step_action = StepIn; // Step action to perform when stepping.
870static void DebugEventStep(v8::DebugEvent event,
871 v8::Handle<v8::Object> exec_state,
872 v8::Handle<v8::Object> event_data,
873 v8::Handle<v8::Value> data) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000874 v8::internal::Debug* debug = v8::internal::Isolate::Current()->debug();
ager@chromium.org8bb60582008-12-11 12:02:20 +0000875 // When hitting a debug event listener there must be a break set.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000876 CHECK_NE(debug->break_id(), 0);
ager@chromium.org8bb60582008-12-11 12:02:20 +0000877
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000878 if (event == v8::Break) {
879 break_point_hit_count++;
880 PrepareStep(step_action);
881 }
882}
883
884
885// Debug event handler which counts break points hit and performs a step
886// afterwards. For each call the expected function is checked.
887// For this debug event handler to work the following two global varaibles
888// must be initialized.
889// expected_step_sequence: An array of the expected function call sequence.
890// frame_function_name: A JavaScript function (see below).
891
892// String containing the expected function call sequence. Note: this only works
893// if functions have name length of one.
894const char* expected_step_sequence = NULL;
895
896// The actual debug event described by the longer comment above.
897static void DebugEventStepSequence(v8::DebugEvent event,
898 v8::Handle<v8::Object> exec_state,
899 v8::Handle<v8::Object> event_data,
900 v8::Handle<v8::Value> data) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000901 v8::internal::Debug* debug = v8::internal::Isolate::Current()->debug();
ager@chromium.org8bb60582008-12-11 12:02:20 +0000902 // When hitting a debug event listener there must be a break set.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000903 CHECK_NE(debug->break_id(), 0);
ager@chromium.org8bb60582008-12-11 12:02:20 +0000904
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000905 if (event == v8::Break || event == v8::Exception) {
906 // Check that the current function is the expected.
907 CHECK(break_point_hit_count <
ager@chromium.orgc4c92722009-11-18 14:12:51 +0000908 StrLength(expected_step_sequence));
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000909 const int argc = 2;
910 v8::Handle<v8::Value> argv[argc] = { exec_state, v8::Integer::New(0) };
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000911 v8::Handle<v8::Value> result = frame_function_name->Call(exec_state,
912 argc, argv);
913 CHECK(result->IsString());
914 v8::String::AsciiValue function_name(result->ToString());
ager@chromium.orgc4c92722009-11-18 14:12:51 +0000915 CHECK_EQ(1, StrLength(*function_name));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000916 CHECK_EQ((*function_name)[0],
917 expected_step_sequence[break_point_hit_count]);
918
919 // Perform step.
920 break_point_hit_count++;
921 PrepareStep(step_action);
922 }
923}
924
925
926// Debug event handler which performs a garbage collection.
927static void DebugEventBreakPointCollectGarbage(
928 v8::DebugEvent event,
929 v8::Handle<v8::Object> exec_state,
930 v8::Handle<v8::Object> event_data,
931 v8::Handle<v8::Value> data) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000932 v8::internal::Debug* debug = v8::internal::Isolate::Current()->debug();
ager@chromium.org8bb60582008-12-11 12:02:20 +0000933 // When hitting a debug event listener there must be a break set.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000934 CHECK_NE(debug->break_id(), 0);
ager@chromium.org8bb60582008-12-11 12:02:20 +0000935
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000936 // Perform a garbage collection when break point is hit and continue. Based
937 // on the number of break points hit either scavenge or mark compact
938 // collector is used.
939 if (event == v8::Break) {
940 break_point_hit_count++;
941 if (break_point_hit_count % 2 == 0) {
942 // Scavenge.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000943 HEAP->CollectGarbage(v8::internal::NEW_SPACE);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000944 } else {
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +0000945 // Mark sweep compact.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000946 HEAP->CollectAllGarbage(true);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000947 }
948 }
949}
950
951
952// Debug event handler which re-issues a debug break and calls the garbage
953// collector to have the heap verified.
954static void DebugEventBreak(v8::DebugEvent event,
955 v8::Handle<v8::Object> exec_state,
956 v8::Handle<v8::Object> event_data,
957 v8::Handle<v8::Value> data) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000958 v8::internal::Debug* debug = v8::internal::Isolate::Current()->debug();
ager@chromium.org8bb60582008-12-11 12:02:20 +0000959 // When hitting a debug event listener there must be a break set.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000960 CHECK_NE(debug->break_id(), 0);
ager@chromium.org8bb60582008-12-11 12:02:20 +0000961
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000962 if (event == v8::Break) {
963 // Count the number of breaks.
964 break_point_hit_count++;
965
966 // Run the garbage collector to enforce heap verification if option
967 // --verify-heap is set.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000968 HEAP->CollectGarbage(v8::internal::NEW_SPACE);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000969
970 // Set the break flag again to come back here as soon as possible.
971 v8::Debug::DebugBreak();
972 }
973}
974
975
ager@chromium.orgc4c92722009-11-18 14:12:51 +0000976// Debug event handler which re-issues a debug break until a limit has been
977// reached.
978int max_break_point_hit_count = 0;
whesse@chromium.orgf0ac72d2010-11-08 12:47:26 +0000979bool terminate_after_max_break_point_hit = false;
ager@chromium.orgc4c92722009-11-18 14:12:51 +0000980static void DebugEventBreakMax(v8::DebugEvent event,
981 v8::Handle<v8::Object> exec_state,
982 v8::Handle<v8::Object> event_data,
983 v8::Handle<v8::Value> data) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000984 v8::internal::Debug* debug = v8::internal::Isolate::Current()->debug();
ager@chromium.orgc4c92722009-11-18 14:12:51 +0000985 // When hitting a debug event listener there must be a break set.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000986 CHECK_NE(debug->break_id(), 0);
ager@chromium.orgc4c92722009-11-18 14:12:51 +0000987
whesse@chromium.orgf0ac72d2010-11-08 12:47:26 +0000988 if (event == v8::Break) {
989 if (break_point_hit_count < max_break_point_hit_count) {
990 // Count the number of breaks.
991 break_point_hit_count++;
ager@chromium.orgc4c92722009-11-18 14:12:51 +0000992
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +0000993 // Collect the JavsScript stack height if the function frame_count is
994 // compiled.
995 if (!frame_count.IsEmpty()) {
996 static const int kArgc = 1;
997 v8::Handle<v8::Value> argv[kArgc] = { exec_state };
998 // Using exec_state as receiver is just to have a receiver.
999 v8::Handle<v8::Value> result =
1000 frame_count->Call(exec_state, kArgc, argv);
1001 last_js_stack_height = result->Int32Value();
1002 }
1003
whesse@chromium.orgf0ac72d2010-11-08 12:47:26 +00001004 // Set the break flag again to come back here as soon as possible.
1005 v8::Debug::DebugBreak();
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00001006
whesse@chromium.orgf0ac72d2010-11-08 12:47:26 +00001007 } else if (terminate_after_max_break_point_hit) {
1008 // Terminate execution after the last break if requested.
1009 v8::V8::TerminateExecution();
1010 }
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00001011
1012 // Perform a full deoptimization when the specified number of
1013 // breaks have been hit.
1014 if (break_point_hit_count == break_point_hit_count_deoptimize) {
1015 i::Deoptimizer::DeoptimizeAll();
1016 }
ager@chromium.orgc4c92722009-11-18 14:12:51 +00001017 }
1018}
1019
1020
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001021// --- M e s s a g e C a l l b a c k
1022
1023
1024// Message callback which counts the number of messages.
1025int message_callback_count = 0;
1026
1027static void MessageCallbackCountClear() {
1028 message_callback_count = 0;
1029}
1030
1031static void MessageCallbackCount(v8::Handle<v8::Message> message,
1032 v8::Handle<v8::Value> data) {
1033 message_callback_count++;
1034}
1035
1036
1037// --- T h e A c t u a l T e s t s
1038
1039
1040// Test that the debug break function is the expected one for different kinds
1041// of break locations.
1042TEST(DebugStub) {
1043 using ::v8::internal::Builtins;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001044 using ::v8::internal::Isolate;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001045 v8::HandleScope scope;
1046 DebugLocalContext env;
1047
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001048 CheckDebugBreakFunction(&env,
1049 "function f1(){}", "f1",
1050 0,
ager@chromium.org236ad962008-09-25 09:45:57 +00001051 v8::internal::RelocInfo::JS_RETURN,
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001052 NULL);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001053 CheckDebugBreakFunction(&env,
1054 "function f2(){x=1;}", "f2",
1055 0,
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00001056 v8::internal::RelocInfo::CODE_TARGET_CONTEXT,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001057 Isolate::Current()->builtins()->builtin(
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001058 Builtins::kStoreIC_DebugBreak));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001059 CheckDebugBreakFunction(&env,
1060 "function f3(){var a=x;}", "f3",
1061 0,
ager@chromium.org236ad962008-09-25 09:45:57 +00001062 v8::internal::RelocInfo::CODE_TARGET_CONTEXT,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001063 Isolate::Current()->builtins()->builtin(
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001064 Builtins::kLoadIC_DebugBreak));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001065
ager@chromium.org236ad962008-09-25 09:45:57 +00001066// TODO(1240753): Make the test architecture independent or split
1067// parts of the debugger into architecture dependent files. This
1068// part currently disabled as it is not portable between IA32/ARM.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001069// Currently on ICs for keyed store/load on ARM.
1070#if !defined (__arm__) && !defined(__thumb__)
1071 CheckDebugBreakFunction(
1072 &env,
1073 "function f4(){var index='propertyName'; var a={}; a[index] = 'x';}",
1074 "f4",
1075 0,
ager@chromium.org236ad962008-09-25 09:45:57 +00001076 v8::internal::RelocInfo::CODE_TARGET,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001077 Isolate::Current()->builtins()->builtin(
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001078 Builtins::kKeyedStoreIC_DebugBreak));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001079 CheckDebugBreakFunction(
1080 &env,
1081 "function f5(){var index='propertyName'; var a={}; return a[index];}",
1082 "f5",
1083 0,
ager@chromium.org236ad962008-09-25 09:45:57 +00001084 v8::internal::RelocInfo::CODE_TARGET,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001085 Isolate::Current()->builtins()->builtin(
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001086 Builtins::kKeyedLoadIC_DebugBreak));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001087#endif
1088
1089 // Check the debug break code stubs for call ICs with different number of
1090 // parameters.
1091 Handle<Code> debug_break_0 = v8::internal::ComputeCallDebugBreak(0);
1092 Handle<Code> debug_break_1 = v8::internal::ComputeCallDebugBreak(1);
1093 Handle<Code> debug_break_4 = v8::internal::ComputeCallDebugBreak(4);
1094
1095 CheckDebugBreakFunction(&env,
1096 "function f4_0(){x();}", "f4_0",
1097 0,
ager@chromium.org236ad962008-09-25 09:45:57 +00001098 v8::internal::RelocInfo::CODE_TARGET_CONTEXT,
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001099 *debug_break_0);
1100
1101 CheckDebugBreakFunction(&env,
1102 "function f4_1(){x(1);}", "f4_1",
1103 0,
ager@chromium.org236ad962008-09-25 09:45:57 +00001104 v8::internal::RelocInfo::CODE_TARGET_CONTEXT,
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001105 *debug_break_1);
1106
1107 CheckDebugBreakFunction(&env,
1108 "function f4_4(){x(1,2,3,4);}", "f4_4",
1109 0,
ager@chromium.org236ad962008-09-25 09:45:57 +00001110 v8::internal::RelocInfo::CODE_TARGET_CONTEXT,
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001111 *debug_break_4);
1112}
1113
1114
1115// Test that the debug info in the VM is in sync with the functions being
1116// debugged.
1117TEST(DebugInfo) {
1118 v8::HandleScope scope;
1119 DebugLocalContext env;
1120 // Create a couple of functions for the test.
1121 v8::Local<v8::Function> foo =
1122 CompileFunction(&env, "function foo(){}", "foo");
1123 v8::Local<v8::Function> bar =
1124 CompileFunction(&env, "function bar(){}", "bar");
1125 // Initially no functions are debugged.
1126 CHECK_EQ(0, v8::internal::GetDebuggedFunctions()->length());
1127 CHECK(!HasDebugInfo(foo));
1128 CHECK(!HasDebugInfo(bar));
1129 // One function (foo) is debugged.
1130 int bp1 = SetBreakPoint(foo, 0);
1131 CHECK_EQ(1, v8::internal::GetDebuggedFunctions()->length());
1132 CHECK(HasDebugInfo(foo));
1133 CHECK(!HasDebugInfo(bar));
1134 // Two functions are debugged.
1135 int bp2 = SetBreakPoint(bar, 0);
1136 CHECK_EQ(2, v8::internal::GetDebuggedFunctions()->length());
1137 CHECK(HasDebugInfo(foo));
1138 CHECK(HasDebugInfo(bar));
1139 // One function (bar) is debugged.
1140 ClearBreakPoint(bp1);
1141 CHECK_EQ(1, v8::internal::GetDebuggedFunctions()->length());
1142 CHECK(!HasDebugInfo(foo));
1143 CHECK(HasDebugInfo(bar));
1144 // No functions are debugged.
1145 ClearBreakPoint(bp2);
1146 CHECK_EQ(0, v8::internal::GetDebuggedFunctions()->length());
1147 CHECK(!HasDebugInfo(foo));
1148 CHECK(!HasDebugInfo(bar));
1149}
1150
1151
1152// Test that a break point can be set at an IC store location.
1153TEST(BreakPointICStore) {
1154 break_point_hit_count = 0;
1155 v8::HandleScope scope;
1156 DebugLocalContext env;
ager@chromium.org381abbb2009-02-25 13:23:22 +00001157
iposva@chromium.org245aa852009-02-10 00:49:54 +00001158 v8::Debug::SetDebugEventListener(DebugEventBreakPointHitCount,
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001159 v8::Undefined());
1160 v8::Script::Compile(v8::String::New("function foo(){bar=0;}"))->Run();
1161 v8::Local<v8::Function> foo =
1162 v8::Local<v8::Function>::Cast(env->Global()->Get(v8::String::New("foo")));
1163
1164 // Run without breakpoints.
1165 foo->Call(env->Global(), 0, NULL);
1166 CHECK_EQ(0, break_point_hit_count);
1167
1168 // Run with breakpoint
1169 int bp = SetBreakPoint(foo, 0);
1170 foo->Call(env->Global(), 0, NULL);
1171 CHECK_EQ(1, break_point_hit_count);
1172 foo->Call(env->Global(), 0, NULL);
1173 CHECK_EQ(2, break_point_hit_count);
1174
1175 // Run without breakpoints.
1176 ClearBreakPoint(bp);
1177 foo->Call(env->Global(), 0, NULL);
1178 CHECK_EQ(2, break_point_hit_count);
1179
iposva@chromium.org245aa852009-02-10 00:49:54 +00001180 v8::Debug::SetDebugEventListener(NULL);
ager@chromium.org381abbb2009-02-25 13:23:22 +00001181 CheckDebuggerUnloaded();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001182}
1183
1184
1185// Test that a break point can be set at an IC load location.
1186TEST(BreakPointICLoad) {
1187 break_point_hit_count = 0;
1188 v8::HandleScope scope;
1189 DebugLocalContext env;
iposva@chromium.org245aa852009-02-10 00:49:54 +00001190 v8::Debug::SetDebugEventListener(DebugEventBreakPointHitCount,
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001191 v8::Undefined());
1192 v8::Script::Compile(v8::String::New("bar=1"))->Run();
1193 v8::Script::Compile(v8::String::New("function foo(){var x=bar;}"))->Run();
1194 v8::Local<v8::Function> foo =
1195 v8::Local<v8::Function>::Cast(env->Global()->Get(v8::String::New("foo")));
1196
1197 // Run without breakpoints.
1198 foo->Call(env->Global(), 0, NULL);
1199 CHECK_EQ(0, break_point_hit_count);
1200
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001201 // Run with breakpoint.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001202 int bp = SetBreakPoint(foo, 0);
1203 foo->Call(env->Global(), 0, NULL);
1204 CHECK_EQ(1, break_point_hit_count);
1205 foo->Call(env->Global(), 0, NULL);
1206 CHECK_EQ(2, break_point_hit_count);
1207
1208 // Run without breakpoints.
1209 ClearBreakPoint(bp);
1210 foo->Call(env->Global(), 0, NULL);
1211 CHECK_EQ(2, break_point_hit_count);
1212
iposva@chromium.org245aa852009-02-10 00:49:54 +00001213 v8::Debug::SetDebugEventListener(NULL);
ager@chromium.org381abbb2009-02-25 13:23:22 +00001214 CheckDebuggerUnloaded();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001215}
1216
1217
1218// Test that a break point can be set at an IC call location.
1219TEST(BreakPointICCall) {
1220 break_point_hit_count = 0;
1221 v8::HandleScope scope;
1222 DebugLocalContext env;
iposva@chromium.org245aa852009-02-10 00:49:54 +00001223 v8::Debug::SetDebugEventListener(DebugEventBreakPointHitCount,
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001224 v8::Undefined());
1225 v8::Script::Compile(v8::String::New("function bar(){}"))->Run();
1226 v8::Script::Compile(v8::String::New("function foo(){bar();}"))->Run();
1227 v8::Local<v8::Function> foo =
1228 v8::Local<v8::Function>::Cast(env->Global()->Get(v8::String::New("foo")));
1229
1230 // Run without breakpoints.
1231 foo->Call(env->Global(), 0, NULL);
1232 CHECK_EQ(0, break_point_hit_count);
1233
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001234 // Run with breakpoint
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001235 int bp = SetBreakPoint(foo, 0);
1236 foo->Call(env->Global(), 0, NULL);
1237 CHECK_EQ(1, break_point_hit_count);
1238 foo->Call(env->Global(), 0, NULL);
1239 CHECK_EQ(2, break_point_hit_count);
1240
1241 // Run without breakpoints.
1242 ClearBreakPoint(bp);
1243 foo->Call(env->Global(), 0, NULL);
1244 CHECK_EQ(2, break_point_hit_count);
1245
iposva@chromium.org245aa852009-02-10 00:49:54 +00001246 v8::Debug::SetDebugEventListener(NULL);
ager@chromium.org381abbb2009-02-25 13:23:22 +00001247 CheckDebuggerUnloaded();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001248}
1249
1250
ricow@chromium.org65fae842010-08-25 15:26:24 +00001251// Test that a break point can be set at an IC call location and survive a GC.
1252TEST(BreakPointICCallWithGC) {
1253 break_point_hit_count = 0;
1254 v8::HandleScope scope;
1255 DebugLocalContext env;
1256 v8::Debug::SetDebugEventListener(DebugEventBreakPointCollectGarbage,
1257 v8::Undefined());
1258 v8::Script::Compile(v8::String::New("function bar(){return 1;}"))->Run();
1259 v8::Script::Compile(v8::String::New("function foo(){return bar();}"))->Run();
1260 v8::Local<v8::Function> foo =
1261 v8::Local<v8::Function>::Cast(env->Global()->Get(v8::String::New("foo")));
1262
1263 // Run without breakpoints.
1264 CHECK_EQ(1, foo->Call(env->Global(), 0, NULL)->Int32Value());
1265 CHECK_EQ(0, break_point_hit_count);
1266
1267 // Run with breakpoint.
1268 int bp = SetBreakPoint(foo, 0);
1269 CHECK_EQ(1, foo->Call(env->Global(), 0, NULL)->Int32Value());
1270 CHECK_EQ(1, break_point_hit_count);
1271 CHECK_EQ(1, foo->Call(env->Global(), 0, NULL)->Int32Value());
1272 CHECK_EQ(2, break_point_hit_count);
1273
1274 // Run without breakpoints.
1275 ClearBreakPoint(bp);
1276 foo->Call(env->Global(), 0, NULL);
1277 CHECK_EQ(2, break_point_hit_count);
1278
1279 v8::Debug::SetDebugEventListener(NULL);
1280 CheckDebuggerUnloaded();
1281}
1282
1283
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001284// Test that a break point can be set at an IC call location and survive a GC.
1285TEST(BreakPointConstructCallWithGC) {
1286 break_point_hit_count = 0;
1287 v8::HandleScope scope;
1288 DebugLocalContext env;
1289 v8::Debug::SetDebugEventListener(DebugEventBreakPointCollectGarbage,
1290 v8::Undefined());
1291 v8::Script::Compile(v8::String::New("function bar(){ this.x = 1;}"))->Run();
1292 v8::Script::Compile(v8::String::New(
1293 "function foo(){return new bar(1).x;}"))->Run();
1294 v8::Local<v8::Function> foo =
1295 v8::Local<v8::Function>::Cast(env->Global()->Get(v8::String::New("foo")));
1296
1297 // Run without breakpoints.
1298 CHECK_EQ(1, foo->Call(env->Global(), 0, NULL)->Int32Value());
1299 CHECK_EQ(0, break_point_hit_count);
1300
1301 // Run with breakpoint.
1302 int bp = SetBreakPoint(foo, 0);
1303 CHECK_EQ(1, foo->Call(env->Global(), 0, NULL)->Int32Value());
1304 CHECK_EQ(1, break_point_hit_count);
1305 CHECK_EQ(1, foo->Call(env->Global(), 0, NULL)->Int32Value());
1306 CHECK_EQ(2, break_point_hit_count);
1307
1308 // Run without breakpoints.
1309 ClearBreakPoint(bp);
1310 foo->Call(env->Global(), 0, NULL);
1311 CHECK_EQ(2, break_point_hit_count);
1312
1313 v8::Debug::SetDebugEventListener(NULL);
1314 CheckDebuggerUnloaded();
1315}
1316
1317
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001318// Test that a break point can be set at a return store location.
1319TEST(BreakPointReturn) {
1320 break_point_hit_count = 0;
1321 v8::HandleScope scope;
1322 DebugLocalContext env;
kasperl@chromium.org2d18d102009-04-15 13:27:32 +00001323
1324 // Create a functions for checking the source line and column when hitting
1325 // a break point.
1326 frame_source_line = CompileFunction(&env,
1327 frame_source_line_source,
1328 "frame_source_line");
1329 frame_source_column = CompileFunction(&env,
1330 frame_source_column_source,
1331 "frame_source_column");
1332
1333
iposva@chromium.org245aa852009-02-10 00:49:54 +00001334 v8::Debug::SetDebugEventListener(DebugEventBreakPointHitCount,
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001335 v8::Undefined());
1336 v8::Script::Compile(v8::String::New("function foo(){}"))->Run();
1337 v8::Local<v8::Function> foo =
1338 v8::Local<v8::Function>::Cast(env->Global()->Get(v8::String::New("foo")));
1339
1340 // Run without breakpoints.
1341 foo->Call(env->Global(), 0, NULL);
1342 CHECK_EQ(0, break_point_hit_count);
1343
1344 // Run with breakpoint
1345 int bp = SetBreakPoint(foo, 0);
1346 foo->Call(env->Global(), 0, NULL);
1347 CHECK_EQ(1, break_point_hit_count);
kasperl@chromium.org2d18d102009-04-15 13:27:32 +00001348 CHECK_EQ(0, last_source_line);
whesse@chromium.orge90029b2010-08-02 11:52:17 +00001349 CHECK_EQ(15, last_source_column);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001350 foo->Call(env->Global(), 0, NULL);
1351 CHECK_EQ(2, break_point_hit_count);
kasperl@chromium.org2d18d102009-04-15 13:27:32 +00001352 CHECK_EQ(0, last_source_line);
whesse@chromium.orge90029b2010-08-02 11:52:17 +00001353 CHECK_EQ(15, last_source_column);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001354
1355 // Run without breakpoints.
1356 ClearBreakPoint(bp);
1357 foo->Call(env->Global(), 0, NULL);
1358 CHECK_EQ(2, break_point_hit_count);
1359
iposva@chromium.org245aa852009-02-10 00:49:54 +00001360 v8::Debug::SetDebugEventListener(NULL);
ager@chromium.org381abbb2009-02-25 13:23:22 +00001361 CheckDebuggerUnloaded();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001362}
1363
1364
1365static void CallWithBreakPoints(v8::Local<v8::Object> recv,
1366 v8::Local<v8::Function> f,
1367 int break_point_count,
1368 int call_count) {
1369 break_point_hit_count = 0;
1370 for (int i = 0; i < call_count; i++) {
1371 f->Call(recv, 0, NULL);
1372 CHECK_EQ((i + 1) * break_point_count, break_point_hit_count);
1373 }
1374}
1375
1376// Test GC during break point processing.
1377TEST(GCDuringBreakPointProcessing) {
1378 break_point_hit_count = 0;
1379 v8::HandleScope scope;
1380 DebugLocalContext env;
1381
iposva@chromium.org245aa852009-02-10 00:49:54 +00001382 v8::Debug::SetDebugEventListener(DebugEventBreakPointCollectGarbage,
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001383 v8::Undefined());
1384 v8::Local<v8::Function> foo;
1385
1386 // Test IC store break point with garbage collection.
1387 foo = CompileFunction(&env, "function foo(){bar=0;}", "foo");
1388 SetBreakPoint(foo, 0);
1389 CallWithBreakPoints(env->Global(), foo, 1, 10);
1390
1391 // Test IC load break point with garbage collection.
1392 foo = CompileFunction(&env, "bar=1;function foo(){var x=bar;}", "foo");
1393 SetBreakPoint(foo, 0);
1394 CallWithBreakPoints(env->Global(), foo, 1, 10);
1395
1396 // Test IC call break point with garbage collection.
1397 foo = CompileFunction(&env, "function bar(){};function foo(){bar();}", "foo");
1398 SetBreakPoint(foo, 0);
1399 CallWithBreakPoints(env->Global(), foo, 1, 10);
1400
1401 // Test return break point with garbage collection.
1402 foo = CompileFunction(&env, "function foo(){}", "foo");
1403 SetBreakPoint(foo, 0);
1404 CallWithBreakPoints(env->Global(), foo, 1, 25);
1405
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +00001406 // Test debug break slot break point with garbage collection.
1407 foo = CompileFunction(&env, "function foo(){var a;}", "foo");
1408 SetBreakPoint(foo, 0);
1409 CallWithBreakPoints(env->Global(), foo, 1, 25);
1410
iposva@chromium.org245aa852009-02-10 00:49:54 +00001411 v8::Debug::SetDebugEventListener(NULL);
ager@chromium.org381abbb2009-02-25 13:23:22 +00001412 CheckDebuggerUnloaded();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001413}
1414
1415
1416// Call the function three times with different garbage collections in between
1417// and make sure that the break point survives.
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00001418static void CallAndGC(v8::Local<v8::Object> recv,
1419 v8::Local<v8::Function> f,
1420 bool force_compaction) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001421 break_point_hit_count = 0;
1422
1423 for (int i = 0; i < 3; i++) {
1424 // Call function.
1425 f->Call(recv, 0, NULL);
1426 CHECK_EQ(1 + i * 3, break_point_hit_count);
1427
1428 // Scavenge and call function.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001429 HEAP->CollectGarbage(v8::internal::NEW_SPACE);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001430 f->Call(recv, 0, NULL);
1431 CHECK_EQ(2 + i * 3, break_point_hit_count);
1432
1433 // Mark sweep (and perhaps compact) and call function.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001434 HEAP->CollectAllGarbage(force_compaction);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001435 f->Call(recv, 0, NULL);
1436 CHECK_EQ(3 + i * 3, break_point_hit_count);
1437 }
1438}
1439
1440
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00001441static void TestBreakPointSurviveGC(bool force_compaction) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001442 break_point_hit_count = 0;
1443 v8::HandleScope scope;
1444 DebugLocalContext env;
1445
iposva@chromium.org245aa852009-02-10 00:49:54 +00001446 v8::Debug::SetDebugEventListener(DebugEventBreakPointHitCount,
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001447 v8::Undefined());
1448 v8::Local<v8::Function> foo;
1449
1450 // Test IC store break point with garbage collection.
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00001451 {
1452 v8::Local<v8::Function> bar =
1453 CompileFunction(&env, "function foo(){}", "foo");
1454 foo = CompileFunction(&env, "function foo(){bar=0;}", "foo");
1455 SetBreakPoint(foo, 0);
1456 }
1457 CallAndGC(env->Global(), foo, force_compaction);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001458
1459 // Test IC load break point with garbage collection.
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00001460 {
1461 v8::Local<v8::Function> bar =
1462 CompileFunction(&env, "function foo(){}", "foo");
1463 foo = CompileFunction(&env, "bar=1;function foo(){var x=bar;}", "foo");
1464 SetBreakPoint(foo, 0);
1465 }
1466 CallAndGC(env->Global(), foo, force_compaction);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001467
1468 // Test IC call break point with garbage collection.
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00001469 {
1470 v8::Local<v8::Function> bar =
1471 CompileFunction(&env, "function foo(){}", "foo");
1472 foo = CompileFunction(&env,
1473 "function bar(){};function foo(){bar();}",
1474 "foo");
1475 SetBreakPoint(foo, 0);
1476 }
1477 CallAndGC(env->Global(), foo, force_compaction);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001478
1479 // Test return break point with garbage collection.
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00001480 {
1481 v8::Local<v8::Function> bar =
1482 CompileFunction(&env, "function foo(){}", "foo");
1483 foo = CompileFunction(&env, "function foo(){}", "foo");
1484 SetBreakPoint(foo, 0);
1485 }
1486 CallAndGC(env->Global(), foo, force_compaction);
1487
1488 // Test non IC break point with garbage collection.
1489 {
1490 v8::Local<v8::Function> bar =
1491 CompileFunction(&env, "function foo(){}", "foo");
1492 foo = CompileFunction(&env, "function foo(){var bar=0;}", "foo");
1493 SetBreakPoint(foo, 0);
1494 }
1495 CallAndGC(env->Global(), foo, force_compaction);
1496
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001497
iposva@chromium.org245aa852009-02-10 00:49:54 +00001498 v8::Debug::SetDebugEventListener(NULL);
ager@chromium.org381abbb2009-02-25 13:23:22 +00001499 CheckDebuggerUnloaded();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001500}
1501
1502
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00001503// Test that a break point can be set at a return store location.
1504TEST(BreakPointSurviveGC) {
1505 TestBreakPointSurviveGC(false);
1506 TestBreakPointSurviveGC(true);
1507}
1508
1509
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001510// Test that break points can be set using the global Debug object.
1511TEST(BreakPointThroughJavaScript) {
1512 break_point_hit_count = 0;
1513 v8::HandleScope scope;
1514 DebugLocalContext env;
1515 env.ExposeDebug();
1516
iposva@chromium.org245aa852009-02-10 00:49:54 +00001517 v8::Debug::SetDebugEventListener(DebugEventBreakPointHitCount,
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001518 v8::Undefined());
1519 v8::Script::Compile(v8::String::New("function bar(){}"))->Run();
1520 v8::Script::Compile(v8::String::New("function foo(){bar();bar();}"))->Run();
1521 // 012345678901234567890
1522 // 1 2
1523 // Break points are set at position 3 and 9
1524 v8::Local<v8::Script> foo = v8::Script::Compile(v8::String::New("foo()"));
1525
1526 // Run without breakpoints.
1527 foo->Run();
1528 CHECK_EQ(0, break_point_hit_count);
1529
1530 // Run with one breakpoint
1531 int bp1 = SetBreakPointFromJS("foo", 0, 3);
1532 foo->Run();
1533 CHECK_EQ(1, break_point_hit_count);
1534 foo->Run();
1535 CHECK_EQ(2, break_point_hit_count);
1536
1537 // Run with two breakpoints
1538 int bp2 = SetBreakPointFromJS("foo", 0, 9);
1539 foo->Run();
1540 CHECK_EQ(4, break_point_hit_count);
1541 foo->Run();
1542 CHECK_EQ(6, break_point_hit_count);
1543
1544 // Run with one breakpoint
1545 ClearBreakPointFromJS(bp2);
1546 foo->Run();
1547 CHECK_EQ(7, break_point_hit_count);
1548 foo->Run();
1549 CHECK_EQ(8, break_point_hit_count);
1550
1551 // Run without breakpoints.
1552 ClearBreakPointFromJS(bp1);
1553 foo->Run();
1554 CHECK_EQ(8, break_point_hit_count);
1555
iposva@chromium.org245aa852009-02-10 00:49:54 +00001556 v8::Debug::SetDebugEventListener(NULL);
ager@chromium.org381abbb2009-02-25 13:23:22 +00001557 CheckDebuggerUnloaded();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001558
1559 // Make sure that the break point numbers are consecutive.
1560 CHECK_EQ(1, bp1);
1561 CHECK_EQ(2, bp2);
1562}
1563
1564
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001565// Test that break points on scripts identified by name can be set using the
1566// global Debug object.
1567TEST(ScriptBreakPointByNameThroughJavaScript) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001568 break_point_hit_count = 0;
1569 v8::HandleScope scope;
1570 DebugLocalContext env;
1571 env.ExposeDebug();
1572
iposva@chromium.org245aa852009-02-10 00:49:54 +00001573 v8::Debug::SetDebugEventListener(DebugEventBreakPointHitCount,
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001574 v8::Undefined());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001575
1576 v8::Local<v8::String> script = v8::String::New(
1577 "function f() {\n"
1578 " function h() {\n"
1579 " a = 0; // line 2\n"
1580 " }\n"
1581 " b = 1; // line 4\n"
1582 " return h();\n"
1583 "}\n"
1584 "\n"
1585 "function g() {\n"
1586 " function h() {\n"
1587 " a = 0;\n"
1588 " }\n"
1589 " b = 2; // line 12\n"
1590 " h();\n"
1591 " b = 3; // line 14\n"
1592 " f(); // line 15\n"
1593 "}");
1594
1595 // Compile the script and get the two functions.
1596 v8::ScriptOrigin origin =
1597 v8::ScriptOrigin(v8::String::New("test"));
1598 v8::Script::Compile(script, &origin)->Run();
1599 v8::Local<v8::Function> f =
1600 v8::Local<v8::Function>::Cast(env->Global()->Get(v8::String::New("f")));
1601 v8::Local<v8::Function> g =
1602 v8::Local<v8::Function>::Cast(env->Global()->Get(v8::String::New("g")));
1603
1604 // Call f and g without break points.
1605 break_point_hit_count = 0;
1606 f->Call(env->Global(), 0, NULL);
1607 CHECK_EQ(0, break_point_hit_count);
1608 g->Call(env->Global(), 0, NULL);
1609 CHECK_EQ(0, break_point_hit_count);
1610
1611 // Call f and g with break point on line 12.
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001612 int sbp1 = SetScriptBreakPointByNameFromJS("test", 12, 0);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001613 break_point_hit_count = 0;
1614 f->Call(env->Global(), 0, NULL);
1615 CHECK_EQ(0, break_point_hit_count);
1616 g->Call(env->Global(), 0, NULL);
1617 CHECK_EQ(1, break_point_hit_count);
1618
1619 // Remove the break point again.
1620 break_point_hit_count = 0;
1621 ClearBreakPointFromJS(sbp1);
1622 f->Call(env->Global(), 0, NULL);
1623 CHECK_EQ(0, break_point_hit_count);
1624 g->Call(env->Global(), 0, NULL);
1625 CHECK_EQ(0, break_point_hit_count);
1626
1627 // Call f and g with break point on line 2.
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001628 int sbp2 = SetScriptBreakPointByNameFromJS("test", 2, 0);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001629 break_point_hit_count = 0;
1630 f->Call(env->Global(), 0, NULL);
1631 CHECK_EQ(1, break_point_hit_count);
1632 g->Call(env->Global(), 0, NULL);
1633 CHECK_EQ(2, break_point_hit_count);
1634
1635 // Call f and g with break point on line 2, 4, 12, 14 and 15.
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001636 int sbp3 = SetScriptBreakPointByNameFromJS("test", 4, 0);
1637 int sbp4 = SetScriptBreakPointByNameFromJS("test", 12, 0);
1638 int sbp5 = SetScriptBreakPointByNameFromJS("test", 14, 0);
1639 int sbp6 = SetScriptBreakPointByNameFromJS("test", 15, 0);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001640 break_point_hit_count = 0;
1641 f->Call(env->Global(), 0, NULL);
1642 CHECK_EQ(2, break_point_hit_count);
1643 g->Call(env->Global(), 0, NULL);
1644 CHECK_EQ(7, break_point_hit_count);
1645
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001646 // Remove all the break points again.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001647 break_point_hit_count = 0;
1648 ClearBreakPointFromJS(sbp2);
1649 ClearBreakPointFromJS(sbp3);
1650 ClearBreakPointFromJS(sbp4);
1651 ClearBreakPointFromJS(sbp5);
1652 ClearBreakPointFromJS(sbp6);
1653 f->Call(env->Global(), 0, NULL);
1654 CHECK_EQ(0, break_point_hit_count);
1655 g->Call(env->Global(), 0, NULL);
1656 CHECK_EQ(0, break_point_hit_count);
1657
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001658 v8::Debug::SetDebugEventListener(NULL);
1659 CheckDebuggerUnloaded();
1660
1661 // Make sure that the break point numbers are consecutive.
1662 CHECK_EQ(1, sbp1);
1663 CHECK_EQ(2, sbp2);
1664 CHECK_EQ(3, sbp3);
1665 CHECK_EQ(4, sbp4);
1666 CHECK_EQ(5, sbp5);
1667 CHECK_EQ(6, sbp6);
1668}
1669
1670
1671TEST(ScriptBreakPointByIdThroughJavaScript) {
1672 break_point_hit_count = 0;
1673 v8::HandleScope scope;
1674 DebugLocalContext env;
1675 env.ExposeDebug();
1676
1677 v8::Debug::SetDebugEventListener(DebugEventBreakPointHitCount,
1678 v8::Undefined());
1679
1680 v8::Local<v8::String> source = v8::String::New(
1681 "function f() {\n"
1682 " function h() {\n"
1683 " a = 0; // line 2\n"
1684 " }\n"
1685 " b = 1; // line 4\n"
1686 " return h();\n"
1687 "}\n"
1688 "\n"
1689 "function g() {\n"
1690 " function h() {\n"
1691 " a = 0;\n"
1692 " }\n"
1693 " b = 2; // line 12\n"
1694 " h();\n"
1695 " b = 3; // line 14\n"
1696 " f(); // line 15\n"
1697 "}");
1698
1699 // Compile the script and get the two functions.
1700 v8::ScriptOrigin origin =
1701 v8::ScriptOrigin(v8::String::New("test"));
1702 v8::Local<v8::Script> script = v8::Script::Compile(source, &origin);
1703 script->Run();
1704 v8::Local<v8::Function> f =
1705 v8::Local<v8::Function>::Cast(env->Global()->Get(v8::String::New("f")));
1706 v8::Local<v8::Function> g =
1707 v8::Local<v8::Function>::Cast(env->Global()->Get(v8::String::New("g")));
1708
1709 // Get the script id knowing that internally it is a 32 integer.
1710 uint32_t script_id = script->Id()->Uint32Value();
1711
1712 // Call f and g without break points.
1713 break_point_hit_count = 0;
1714 f->Call(env->Global(), 0, NULL);
1715 CHECK_EQ(0, break_point_hit_count);
1716 g->Call(env->Global(), 0, NULL);
1717 CHECK_EQ(0, break_point_hit_count);
1718
1719 // Call f and g with break point on line 12.
1720 int sbp1 = SetScriptBreakPointByIdFromJS(script_id, 12, 0);
1721 break_point_hit_count = 0;
1722 f->Call(env->Global(), 0, NULL);
1723 CHECK_EQ(0, break_point_hit_count);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001724 g->Call(env->Global(), 0, NULL);
1725 CHECK_EQ(1, break_point_hit_count);
1726
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001727 // Remove the break point again.
1728 break_point_hit_count = 0;
1729 ClearBreakPointFromJS(sbp1);
1730 f->Call(env->Global(), 0, NULL);
1731 CHECK_EQ(0, break_point_hit_count);
1732 g->Call(env->Global(), 0, NULL);
1733 CHECK_EQ(0, break_point_hit_count);
1734
1735 // Call f and g with break point on line 2.
1736 int sbp2 = SetScriptBreakPointByIdFromJS(script_id, 2, 0);
1737 break_point_hit_count = 0;
1738 f->Call(env->Global(), 0, NULL);
1739 CHECK_EQ(1, break_point_hit_count);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001740 g->Call(env->Global(), 0, NULL);
1741 CHECK_EQ(2, break_point_hit_count);
1742
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001743 // Call f and g with break point on line 2, 4, 12, 14 and 15.
1744 int sbp3 = SetScriptBreakPointByIdFromJS(script_id, 4, 0);
1745 int sbp4 = SetScriptBreakPointByIdFromJS(script_id, 12, 0);
1746 int sbp5 = SetScriptBreakPointByIdFromJS(script_id, 14, 0);
1747 int sbp6 = SetScriptBreakPointByIdFromJS(script_id, 15, 0);
1748 break_point_hit_count = 0;
1749 f->Call(env->Global(), 0, NULL);
1750 CHECK_EQ(2, break_point_hit_count);
1751 g->Call(env->Global(), 0, NULL);
1752 CHECK_EQ(7, break_point_hit_count);
1753
1754 // Remove all the break points again.
1755 break_point_hit_count = 0;
1756 ClearBreakPointFromJS(sbp2);
1757 ClearBreakPointFromJS(sbp3);
1758 ClearBreakPointFromJS(sbp4);
1759 ClearBreakPointFromJS(sbp5);
1760 ClearBreakPointFromJS(sbp6);
1761 f->Call(env->Global(), 0, NULL);
1762 CHECK_EQ(0, break_point_hit_count);
1763 g->Call(env->Global(), 0, NULL);
1764 CHECK_EQ(0, break_point_hit_count);
1765
iposva@chromium.org245aa852009-02-10 00:49:54 +00001766 v8::Debug::SetDebugEventListener(NULL);
ager@chromium.org381abbb2009-02-25 13:23:22 +00001767 CheckDebuggerUnloaded();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001768
1769 // Make sure that the break point numbers are consecutive.
1770 CHECK_EQ(1, sbp1);
1771 CHECK_EQ(2, sbp2);
1772 CHECK_EQ(3, sbp3);
1773 CHECK_EQ(4, sbp4);
1774 CHECK_EQ(5, sbp5);
1775 CHECK_EQ(6, sbp6);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001776}
1777
1778
1779// Test conditional script break points.
1780TEST(EnableDisableScriptBreakPoint) {
1781 break_point_hit_count = 0;
1782 v8::HandleScope scope;
1783 DebugLocalContext env;
1784 env.ExposeDebug();
1785
iposva@chromium.org245aa852009-02-10 00:49:54 +00001786 v8::Debug::SetDebugEventListener(DebugEventBreakPointHitCount,
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001787 v8::Undefined());
1788
1789 v8::Local<v8::String> script = v8::String::New(
1790 "function f() {\n"
1791 " a = 0; // line 1\n"
1792 "};");
1793
1794 // Compile the script and get function f.
1795 v8::ScriptOrigin origin =
1796 v8::ScriptOrigin(v8::String::New("test"));
1797 v8::Script::Compile(script, &origin)->Run();
1798 v8::Local<v8::Function> f =
1799 v8::Local<v8::Function>::Cast(env->Global()->Get(v8::String::New("f")));
1800
1801 // Set script break point on line 1 (in function f).
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001802 int sbp = SetScriptBreakPointByNameFromJS("test", 1, 0);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001803
1804 // Call f while enabeling and disabling the script break point.
1805 break_point_hit_count = 0;
1806 f->Call(env->Global(), 0, NULL);
1807 CHECK_EQ(1, break_point_hit_count);
1808
1809 DisableScriptBreakPointFromJS(sbp);
1810 f->Call(env->Global(), 0, NULL);
1811 CHECK_EQ(1, break_point_hit_count);
1812
1813 EnableScriptBreakPointFromJS(sbp);
1814 f->Call(env->Global(), 0, NULL);
1815 CHECK_EQ(2, break_point_hit_count);
1816
1817 DisableScriptBreakPointFromJS(sbp);
1818 f->Call(env->Global(), 0, NULL);
1819 CHECK_EQ(2, break_point_hit_count);
1820
1821 // Reload the script and get f again checking that the disabeling survives.
1822 v8::Script::Compile(script, &origin)->Run();
1823 f = v8::Local<v8::Function>::Cast(env->Global()->Get(v8::String::New("f")));
1824 f->Call(env->Global(), 0, NULL);
1825 CHECK_EQ(2, break_point_hit_count);
1826
1827 EnableScriptBreakPointFromJS(sbp);
1828 f->Call(env->Global(), 0, NULL);
1829 CHECK_EQ(3, break_point_hit_count);
1830
iposva@chromium.org245aa852009-02-10 00:49:54 +00001831 v8::Debug::SetDebugEventListener(NULL);
ager@chromium.org381abbb2009-02-25 13:23:22 +00001832 CheckDebuggerUnloaded();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001833}
1834
1835
1836// Test conditional script break points.
1837TEST(ConditionalScriptBreakPoint) {
1838 break_point_hit_count = 0;
1839 v8::HandleScope scope;
1840 DebugLocalContext env;
1841 env.ExposeDebug();
1842
iposva@chromium.org245aa852009-02-10 00:49:54 +00001843 v8::Debug::SetDebugEventListener(DebugEventBreakPointHitCount,
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001844 v8::Undefined());
1845
1846 v8::Local<v8::String> script = v8::String::New(
1847 "count = 0;\n"
1848 "function f() {\n"
1849 " g(count++); // line 2\n"
1850 "};\n"
1851 "function g(x) {\n"
1852 " var a=x; // line 5\n"
1853 "};");
1854
1855 // Compile the script and get function f.
1856 v8::ScriptOrigin origin =
1857 v8::ScriptOrigin(v8::String::New("test"));
1858 v8::Script::Compile(script, &origin)->Run();
1859 v8::Local<v8::Function> f =
1860 v8::Local<v8::Function>::Cast(env->Global()->Get(v8::String::New("f")));
1861
1862 // Set script break point on line 5 (in function g).
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001863 int sbp1 = SetScriptBreakPointByNameFromJS("test", 5, 0);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001864
1865 // Call f with different conditions on the script break point.
1866 break_point_hit_count = 0;
1867 ChangeScriptBreakPointConditionFromJS(sbp1, "false");
1868 f->Call(env->Global(), 0, NULL);
1869 CHECK_EQ(0, break_point_hit_count);
1870
1871 ChangeScriptBreakPointConditionFromJS(sbp1, "true");
1872 break_point_hit_count = 0;
1873 f->Call(env->Global(), 0, NULL);
1874 CHECK_EQ(1, break_point_hit_count);
1875
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +00001876 ChangeScriptBreakPointConditionFromJS(sbp1, "x % 2 == 0");
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001877 break_point_hit_count = 0;
1878 for (int i = 0; i < 10; i++) {
1879 f->Call(env->Global(), 0, NULL);
1880 }
1881 CHECK_EQ(5, break_point_hit_count);
1882
1883 // Reload the script and get f again checking that the condition survives.
1884 v8::Script::Compile(script, &origin)->Run();
1885 f = v8::Local<v8::Function>::Cast(env->Global()->Get(v8::String::New("f")));
1886
1887 break_point_hit_count = 0;
1888 for (int i = 0; i < 10; i++) {
1889 f->Call(env->Global(), 0, NULL);
1890 }
1891 CHECK_EQ(5, break_point_hit_count);
1892
iposva@chromium.org245aa852009-02-10 00:49:54 +00001893 v8::Debug::SetDebugEventListener(NULL);
ager@chromium.org381abbb2009-02-25 13:23:22 +00001894 CheckDebuggerUnloaded();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001895}
1896
1897
1898// Test ignore count on script break points.
1899TEST(ScriptBreakPointIgnoreCount) {
1900 break_point_hit_count = 0;
1901 v8::HandleScope scope;
1902 DebugLocalContext env;
1903 env.ExposeDebug();
1904
iposva@chromium.org245aa852009-02-10 00:49:54 +00001905 v8::Debug::SetDebugEventListener(DebugEventBreakPointHitCount,
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001906 v8::Undefined());
1907
1908 v8::Local<v8::String> script = v8::String::New(
1909 "function f() {\n"
1910 " a = 0; // line 1\n"
1911 "};");
1912
1913 // Compile the script and get function f.
1914 v8::ScriptOrigin origin =
1915 v8::ScriptOrigin(v8::String::New("test"));
1916 v8::Script::Compile(script, &origin)->Run();
1917 v8::Local<v8::Function> f =
1918 v8::Local<v8::Function>::Cast(env->Global()->Get(v8::String::New("f")));
1919
1920 // Set script break point on line 1 (in function f).
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001921 int sbp = SetScriptBreakPointByNameFromJS("test", 1, 0);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001922
1923 // Call f with different ignores on the script break point.
1924 break_point_hit_count = 0;
1925 ChangeScriptBreakPointIgnoreCountFromJS(sbp, 1);
1926 f->Call(env->Global(), 0, NULL);
1927 CHECK_EQ(0, break_point_hit_count);
1928 f->Call(env->Global(), 0, NULL);
1929 CHECK_EQ(1, break_point_hit_count);
1930
1931 ChangeScriptBreakPointIgnoreCountFromJS(sbp, 5);
1932 break_point_hit_count = 0;
1933 for (int i = 0; i < 10; i++) {
1934 f->Call(env->Global(), 0, NULL);
1935 }
1936 CHECK_EQ(5, break_point_hit_count);
1937
1938 // Reload the script and get f again checking that the ignore survives.
1939 v8::Script::Compile(script, &origin)->Run();
1940 f = v8::Local<v8::Function>::Cast(env->Global()->Get(v8::String::New("f")));
1941
1942 break_point_hit_count = 0;
1943 for (int i = 0; i < 10; i++) {
1944 f->Call(env->Global(), 0, NULL);
1945 }
1946 CHECK_EQ(5, break_point_hit_count);
1947
iposva@chromium.org245aa852009-02-10 00:49:54 +00001948 v8::Debug::SetDebugEventListener(NULL);
ager@chromium.org381abbb2009-02-25 13:23:22 +00001949 CheckDebuggerUnloaded();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001950}
1951
1952
1953// Test that script break points survive when a script is reloaded.
1954TEST(ScriptBreakPointReload) {
1955 break_point_hit_count = 0;
1956 v8::HandleScope scope;
1957 DebugLocalContext env;
1958 env.ExposeDebug();
1959
iposva@chromium.org245aa852009-02-10 00:49:54 +00001960 v8::Debug::SetDebugEventListener(DebugEventBreakPointHitCount,
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001961 v8::Undefined());
1962
1963 v8::Local<v8::Function> f;
1964 v8::Local<v8::String> script = v8::String::New(
1965 "function f() {\n"
1966 " function h() {\n"
1967 " a = 0; // line 2\n"
1968 " }\n"
1969 " b = 1; // line 4\n"
1970 " return h();\n"
1971 "}");
1972
1973 v8::ScriptOrigin origin_1 = v8::ScriptOrigin(v8::String::New("1"));
1974 v8::ScriptOrigin origin_2 = v8::ScriptOrigin(v8::String::New("2"));
1975
1976 // Set a script break point before the script is loaded.
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001977 SetScriptBreakPointByNameFromJS("1", 2, 0);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001978
1979 // Compile the script and get the function.
1980 v8::Script::Compile(script, &origin_1)->Run();
1981 f = v8::Local<v8::Function>::Cast(env->Global()->Get(v8::String::New("f")));
1982
1983 // Call f and check that the script break point is active.
1984 break_point_hit_count = 0;
1985 f->Call(env->Global(), 0, NULL);
1986 CHECK_EQ(1, break_point_hit_count);
1987
1988 // Compile the script again with a different script data and get the
1989 // function.
1990 v8::Script::Compile(script, &origin_2)->Run();
1991 f = v8::Local<v8::Function>::Cast(env->Global()->Get(v8::String::New("f")));
1992
1993 // Call f and check that no break points are set.
1994 break_point_hit_count = 0;
1995 f->Call(env->Global(), 0, NULL);
1996 CHECK_EQ(0, break_point_hit_count);
1997
1998 // Compile the script again and get the function.
1999 v8::Script::Compile(script, &origin_1)->Run();
2000 f = v8::Local<v8::Function>::Cast(env->Global()->Get(v8::String::New("f")));
2001
2002 // Call f and check that the script break point is active.
2003 break_point_hit_count = 0;
2004 f->Call(env->Global(), 0, NULL);
2005 CHECK_EQ(1, break_point_hit_count);
2006
iposva@chromium.org245aa852009-02-10 00:49:54 +00002007 v8::Debug::SetDebugEventListener(NULL);
ager@chromium.org381abbb2009-02-25 13:23:22 +00002008 CheckDebuggerUnloaded();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002009}
2010
2011
2012// Test when several scripts has the same script data
2013TEST(ScriptBreakPointMultiple) {
2014 break_point_hit_count = 0;
2015 v8::HandleScope scope;
2016 DebugLocalContext env;
2017 env.ExposeDebug();
2018
iposva@chromium.org245aa852009-02-10 00:49:54 +00002019 v8::Debug::SetDebugEventListener(DebugEventBreakPointHitCount,
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002020 v8::Undefined());
2021
2022 v8::Local<v8::Function> f;
2023 v8::Local<v8::String> script_f = v8::String::New(
2024 "function f() {\n"
2025 " a = 0; // line 1\n"
2026 "}");
2027
2028 v8::Local<v8::Function> g;
2029 v8::Local<v8::String> script_g = v8::String::New(
2030 "function g() {\n"
2031 " b = 0; // line 1\n"
2032 "}");
2033
2034 v8::ScriptOrigin origin =
2035 v8::ScriptOrigin(v8::String::New("test"));
2036
2037 // Set a script break point before the scripts are loaded.
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00002038 int sbp = SetScriptBreakPointByNameFromJS("test", 1, 0);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002039
2040 // Compile the scripts with same script data and get the functions.
2041 v8::Script::Compile(script_f, &origin)->Run();
2042 f = v8::Local<v8::Function>::Cast(env->Global()->Get(v8::String::New("f")));
2043 v8::Script::Compile(script_g, &origin)->Run();
2044 g = v8::Local<v8::Function>::Cast(env->Global()->Get(v8::String::New("g")));
2045
2046 // Call f and g and check that the script break point is active.
2047 break_point_hit_count = 0;
2048 f->Call(env->Global(), 0, NULL);
2049 CHECK_EQ(1, break_point_hit_count);
2050 g->Call(env->Global(), 0, NULL);
2051 CHECK_EQ(2, break_point_hit_count);
2052
2053 // Clear the script break point.
2054 ClearBreakPointFromJS(sbp);
2055
2056 // Call f and g and check that the script break point is no longer active.
2057 break_point_hit_count = 0;
2058 f->Call(env->Global(), 0, NULL);
2059 CHECK_EQ(0, break_point_hit_count);
2060 g->Call(env->Global(), 0, NULL);
2061 CHECK_EQ(0, break_point_hit_count);
2062
2063 // Set script break point with the scripts loaded.
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00002064 sbp = SetScriptBreakPointByNameFromJS("test", 1, 0);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002065
2066 // Call f and g and check that the script break point is active.
2067 break_point_hit_count = 0;
2068 f->Call(env->Global(), 0, NULL);
2069 CHECK_EQ(1, break_point_hit_count);
2070 g->Call(env->Global(), 0, NULL);
2071 CHECK_EQ(2, break_point_hit_count);
2072
iposva@chromium.org245aa852009-02-10 00:49:54 +00002073 v8::Debug::SetDebugEventListener(NULL);
ager@chromium.org381abbb2009-02-25 13:23:22 +00002074 CheckDebuggerUnloaded();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002075}
2076
2077
2078// Test the script origin which has both name and line offset.
2079TEST(ScriptBreakPointLineOffset) {
2080 break_point_hit_count = 0;
2081 v8::HandleScope scope;
2082 DebugLocalContext env;
2083 env.ExposeDebug();
2084
iposva@chromium.org245aa852009-02-10 00:49:54 +00002085 v8::Debug::SetDebugEventListener(DebugEventBreakPointHitCount,
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002086 v8::Undefined());
2087
2088 v8::Local<v8::Function> f;
2089 v8::Local<v8::String> script = v8::String::New(
2090 "function f() {\n"
2091 " a = 0; // line 8 as this script has line offset 7\n"
2092 " b = 0; // line 9 as this script has line offset 7\n"
2093 "}");
2094
2095 // Create script origin both name and line offset.
2096 v8::ScriptOrigin origin(v8::String::New("test.html"),
2097 v8::Integer::New(7));
2098
2099 // Set two script break points before the script is loaded.
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00002100 int sbp1 = SetScriptBreakPointByNameFromJS("test.html", 8, 0);
2101 int sbp2 = SetScriptBreakPointByNameFromJS("test.html", 9, 0);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002102
2103 // Compile the script and get the function.
2104 v8::Script::Compile(script, &origin)->Run();
2105 f = v8::Local<v8::Function>::Cast(env->Global()->Get(v8::String::New("f")));
2106
2107 // Call f and check that the script break point is active.
2108 break_point_hit_count = 0;
2109 f->Call(env->Global(), 0, NULL);
2110 CHECK_EQ(2, break_point_hit_count);
2111
2112 // Clear the script break points.
2113 ClearBreakPointFromJS(sbp1);
2114 ClearBreakPointFromJS(sbp2);
2115
2116 // Call f and check that no script break points are active.
2117 break_point_hit_count = 0;
2118 f->Call(env->Global(), 0, NULL);
2119 CHECK_EQ(0, break_point_hit_count);
2120
2121 // Set a script break point with the script loaded.
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00002122 sbp1 = SetScriptBreakPointByNameFromJS("test.html", 9, 0);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002123
2124 // Call f and check that the script break point is active.
2125 break_point_hit_count = 0;
2126 f->Call(env->Global(), 0, NULL);
2127 CHECK_EQ(1, break_point_hit_count);
2128
iposva@chromium.org245aa852009-02-10 00:49:54 +00002129 v8::Debug::SetDebugEventListener(NULL);
ager@chromium.org381abbb2009-02-25 13:23:22 +00002130 CheckDebuggerUnloaded();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002131}
2132
2133
2134// Test script break points set on lines.
2135TEST(ScriptBreakPointLine) {
2136 v8::HandleScope scope;
2137 DebugLocalContext env;
2138 env.ExposeDebug();
2139
2140 // Create a function for checking the function when hitting a break point.
2141 frame_function_name = CompileFunction(&env,
2142 frame_function_name_source,
2143 "frame_function_name");
2144
iposva@chromium.org245aa852009-02-10 00:49:54 +00002145 v8::Debug::SetDebugEventListener(DebugEventBreakPointHitCount,
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002146 v8::Undefined());
2147
2148 v8::Local<v8::Function> f;
2149 v8::Local<v8::Function> g;
2150 v8::Local<v8::String> script = v8::String::New(
2151 "a = 0 // line 0\n"
2152 "function f() {\n"
2153 " a = 1; // line 2\n"
2154 "}\n"
2155 " a = 2; // line 4\n"
2156 " /* xx */ function g() { // line 5\n"
2157 " function h() { // line 6\n"
2158 " a = 3; // line 7\n"
2159 " }\n"
2160 " h(); // line 9\n"
2161 " a = 4; // line 10\n"
2162 " }\n"
2163 " a=5; // line 12");
2164
2165 // Set a couple script break point before the script is loaded.
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00002166 int sbp1 = SetScriptBreakPointByNameFromJS("test.html", 0, -1);
2167 int sbp2 = SetScriptBreakPointByNameFromJS("test.html", 1, -1);
2168 int sbp3 = SetScriptBreakPointByNameFromJS("test.html", 5, -1);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002169
2170 // Compile the script and get the function.
2171 break_point_hit_count = 0;
2172 v8::ScriptOrigin origin(v8::String::New("test.html"), v8::Integer::New(0));
2173 v8::Script::Compile(script, &origin)->Run();
2174 f = v8::Local<v8::Function>::Cast(env->Global()->Get(v8::String::New("f")));
2175 g = v8::Local<v8::Function>::Cast(env->Global()->Get(v8::String::New("g")));
2176
2177 // Chesk that a break point was hit when the script was run.
2178 CHECK_EQ(1, break_point_hit_count);
ager@chromium.orgc4c92722009-11-18 14:12:51 +00002179 CHECK_EQ(0, StrLength(last_function_hit));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002180
2181 // Call f and check that the script break point.
2182 f->Call(env->Global(), 0, NULL);
2183 CHECK_EQ(2, break_point_hit_count);
2184 CHECK_EQ("f", last_function_hit);
2185
2186 // Call g and check that the script break point.
2187 g->Call(env->Global(), 0, NULL);
2188 CHECK_EQ(3, break_point_hit_count);
2189 CHECK_EQ("g", last_function_hit);
2190
2191 // Clear the script break point on g and set one on h.
2192 ClearBreakPointFromJS(sbp3);
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00002193 int sbp4 = SetScriptBreakPointByNameFromJS("test.html", 6, -1);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002194
2195 // Call g and check that the script break point in h is hit.
2196 g->Call(env->Global(), 0, NULL);
2197 CHECK_EQ(4, break_point_hit_count);
2198 CHECK_EQ("h", last_function_hit);
2199
2200 // Clear break points in f and h. Set a new one in the script between
2201 // functions f and g and test that there is no break points in f and g any
2202 // more.
2203 ClearBreakPointFromJS(sbp2);
2204 ClearBreakPointFromJS(sbp4);
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00002205 int sbp5 = SetScriptBreakPointByNameFromJS("test.html", 4, -1);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002206 break_point_hit_count = 0;
2207 f->Call(env->Global(), 0, NULL);
2208 g->Call(env->Global(), 0, NULL);
2209 CHECK_EQ(0, break_point_hit_count);
2210
2211 // Reload the script which should hit two break points.
2212 break_point_hit_count = 0;
2213 v8::Script::Compile(script, &origin)->Run();
2214 CHECK_EQ(2, break_point_hit_count);
ager@chromium.orgc4c92722009-11-18 14:12:51 +00002215 CHECK_EQ(0, StrLength(last_function_hit));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002216
2217 // Set a break point in the code after the last function decleration.
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00002218 int sbp6 = SetScriptBreakPointByNameFromJS("test.html", 12, -1);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002219
2220 // Reload the script which should hit three break points.
2221 break_point_hit_count = 0;
2222 v8::Script::Compile(script, &origin)->Run();
2223 CHECK_EQ(3, break_point_hit_count);
ager@chromium.orgc4c92722009-11-18 14:12:51 +00002224 CHECK_EQ(0, StrLength(last_function_hit));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002225
2226 // Clear the last break points, and reload the script which should not hit any
2227 // break points.
2228 ClearBreakPointFromJS(sbp1);
2229 ClearBreakPointFromJS(sbp5);
2230 ClearBreakPointFromJS(sbp6);
2231 break_point_hit_count = 0;
2232 v8::Script::Compile(script, &origin)->Run();
2233 CHECK_EQ(0, break_point_hit_count);
2234
iposva@chromium.org245aa852009-02-10 00:49:54 +00002235 v8::Debug::SetDebugEventListener(NULL);
ager@chromium.org381abbb2009-02-25 13:23:22 +00002236 CheckDebuggerUnloaded();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002237}
2238
2239
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00002240// Test top level script break points set on lines.
2241TEST(ScriptBreakPointLineTopLevel) {
2242 v8::HandleScope scope;
2243 DebugLocalContext env;
2244 env.ExposeDebug();
2245
2246 v8::Debug::SetDebugEventListener(DebugEventBreakPointHitCount,
2247 v8::Undefined());
2248
2249 v8::Local<v8::String> script = v8::String::New(
2250 "function f() {\n"
2251 " a = 1; // line 1\n"
2252 "}\n"
2253 "a = 2; // line 3\n");
2254 v8::Local<v8::Function> f;
2255 {
2256 v8::HandleScope scope;
2257 v8::Script::Compile(script, v8::String::New("test.html"))->Run();
2258 }
2259 f = v8::Local<v8::Function>::Cast(env->Global()->Get(v8::String::New("f")));
2260
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002261 HEAP->CollectAllGarbage(false);
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00002262
2263 SetScriptBreakPointByNameFromJS("test.html", 3, -1);
2264
2265 // Call f and check that there was no break points.
2266 break_point_hit_count = 0;
2267 f->Call(env->Global(), 0, NULL);
2268 CHECK_EQ(0, break_point_hit_count);
2269
2270 // Recompile and run script and check that break point was hit.
2271 break_point_hit_count = 0;
2272 v8::Script::Compile(script, v8::String::New("test.html"))->Run();
2273 CHECK_EQ(1, break_point_hit_count);
2274
2275 // Call f and check that there are still no break points.
2276 break_point_hit_count = 0;
2277 f = v8::Local<v8::Function>::Cast(env->Global()->Get(v8::String::New("f")));
2278 CHECK_EQ(0, break_point_hit_count);
2279
2280 v8::Debug::SetDebugEventListener(NULL);
2281 CheckDebuggerUnloaded();
2282}
2283
2284
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +00002285// Test that it is possible to add and remove break points in a top level
2286// function which has no references but has not been collected yet.
2287TEST(ScriptBreakPointTopLevelCrash) {
2288 v8::HandleScope scope;
2289 DebugLocalContext env;
2290 env.ExposeDebug();
2291
2292 v8::Debug::SetDebugEventListener(DebugEventBreakPointHitCount,
2293 v8::Undefined());
2294
2295 v8::Local<v8::String> script_source = v8::String::New(
2296 "function f() {\n"
2297 " return 0;\n"
2298 "}\n"
2299 "f()");
2300
2301 int sbp1 = SetScriptBreakPointByNameFromJS("test.html", 3, -1);
2302 {
2303 v8::HandleScope scope;
2304 break_point_hit_count = 0;
2305 v8::Script::Compile(script_source, v8::String::New("test.html"))->Run();
2306 CHECK_EQ(1, break_point_hit_count);
2307 }
2308
2309 int sbp2 = SetScriptBreakPointByNameFromJS("test.html", 3, -1);
2310 ClearBreakPointFromJS(sbp1);
2311 ClearBreakPointFromJS(sbp2);
2312
2313 v8::Debug::SetDebugEventListener(NULL);
2314 CheckDebuggerUnloaded();
2315}
2316
2317
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002318// Test that it is possible to remove the last break point for a function
2319// inside the break handling of that break point.
2320TEST(RemoveBreakPointInBreak) {
2321 v8::HandleScope scope;
2322 DebugLocalContext env;
2323
2324 v8::Local<v8::Function> foo =
2325 CompileFunction(&env, "function foo(){a=1;}", "foo");
2326 debug_event_remove_break_point = SetBreakPoint(foo, 0);
2327
2328 // Register the debug event listener pasing the function
iposva@chromium.org245aa852009-02-10 00:49:54 +00002329 v8::Debug::SetDebugEventListener(DebugEventRemoveBreakPoint, foo);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002330
2331 break_point_hit_count = 0;
2332 foo->Call(env->Global(), 0, NULL);
2333 CHECK_EQ(1, break_point_hit_count);
2334
2335 break_point_hit_count = 0;
2336 foo->Call(env->Global(), 0, NULL);
2337 CHECK_EQ(0, break_point_hit_count);
2338
iposva@chromium.org245aa852009-02-10 00:49:54 +00002339 v8::Debug::SetDebugEventListener(NULL);
ager@chromium.org381abbb2009-02-25 13:23:22 +00002340 CheckDebuggerUnloaded();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002341}
2342
2343
2344// Test that the debugger statement causes a break.
2345TEST(DebuggerStatement) {
2346 break_point_hit_count = 0;
2347 v8::HandleScope scope;
2348 DebugLocalContext env;
iposva@chromium.org245aa852009-02-10 00:49:54 +00002349 v8::Debug::SetDebugEventListener(DebugEventBreakPointHitCount,
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002350 v8::Undefined());
2351 v8::Script::Compile(v8::String::New("function bar(){debugger}"))->Run();
2352 v8::Script::Compile(v8::String::New(
2353 "function foo(){debugger;debugger;}"))->Run();
2354 v8::Local<v8::Function> foo =
2355 v8::Local<v8::Function>::Cast(env->Global()->Get(v8::String::New("foo")));
2356 v8::Local<v8::Function> bar =
2357 v8::Local<v8::Function>::Cast(env->Global()->Get(v8::String::New("bar")));
2358
2359 // Run function with debugger statement
2360 bar->Call(env->Global(), 0, NULL);
2361 CHECK_EQ(1, break_point_hit_count);
2362
2363 // Run function with two debugger statement
2364 foo->Call(env->Global(), 0, NULL);
2365 CHECK_EQ(3, break_point_hit_count);
2366
iposva@chromium.org245aa852009-02-10 00:49:54 +00002367 v8::Debug::SetDebugEventListener(NULL);
ager@chromium.org381abbb2009-02-25 13:23:22 +00002368 CheckDebuggerUnloaded();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002369}
2370
2371
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +00002372// Test setting a breakpoint on the debugger statement.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002373TEST(DebuggerStatementBreakpoint) {
2374 break_point_hit_count = 0;
2375 v8::HandleScope scope;
2376 DebugLocalContext env;
2377 v8::Debug::SetDebugEventListener(DebugEventBreakPointHitCount,
2378 v8::Undefined());
2379 v8::Script::Compile(v8::String::New("function foo(){debugger;}"))->Run();
2380 v8::Local<v8::Function> foo =
2381 v8::Local<v8::Function>::Cast(env->Global()->Get(v8::String::New("foo")));
2382
2383 // The debugger statement triggers breakpint hit
2384 foo->Call(env->Global(), 0, NULL);
2385 CHECK_EQ(1, break_point_hit_count);
2386
2387 int bp = SetBreakPoint(foo, 0);
2388
2389 // Set breakpoint does not duplicate hits
2390 foo->Call(env->Global(), 0, NULL);
2391 CHECK_EQ(2, break_point_hit_count);
2392
2393 ClearBreakPoint(bp);
2394 v8::Debug::SetDebugEventListener(NULL);
2395 CheckDebuggerUnloaded();
2396}
2397
2398
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002399// Thest that the evaluation of expressions when a break point is hit generates
2400// the correct results.
2401TEST(DebugEvaluate) {
2402 v8::HandleScope scope;
2403 DebugLocalContext env;
2404 env.ExposeDebug();
2405
2406 // Create a function for checking the evaluation when hitting a break point.
2407 evaluate_check_function = CompileFunction(&env,
2408 evaluate_check_source,
2409 "evaluate_check");
2410 // Register the debug event listener
iposva@chromium.org245aa852009-02-10 00:49:54 +00002411 v8::Debug::SetDebugEventListener(DebugEventEvaluate);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002412
2413 // Different expected vaules of x and a when in a break point (u = undefined,
2414 // d = Hello, world!).
2415 struct EvaluateCheck checks_uu[] = {
2416 {"x", v8::Undefined()},
2417 {"a", v8::Undefined()},
2418 {NULL, v8::Handle<v8::Value>()}
2419 };
2420 struct EvaluateCheck checks_hu[] = {
2421 {"x", v8::String::New("Hello, world!")},
2422 {"a", v8::Undefined()},
2423 {NULL, v8::Handle<v8::Value>()}
2424 };
2425 struct EvaluateCheck checks_hh[] = {
2426 {"x", v8::String::New("Hello, world!")},
2427 {"a", v8::String::New("Hello, world!")},
2428 {NULL, v8::Handle<v8::Value>()}
2429 };
2430
2431 // Simple test function. The "y=0" is in the function foo to provide a break
2432 // location. For "y=0" the "y" is at position 15 in the barbar function
2433 // therefore setting breakpoint at position 15 will break at "y=0" and
2434 // setting it higher will break after.
2435 v8::Local<v8::Function> foo = CompileFunction(&env,
2436 "function foo(x) {"
2437 " var a;"
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +00002438 " y=0;" // To ensure break location 1.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002439 " a=x;"
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +00002440 " y=0;" // To ensure break location 2.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002441 "}",
2442 "foo");
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +00002443 const int foo_break_position_1 = 15;
2444 const int foo_break_position_2 = 29;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002445
2446 // Arguments with one parameter "Hello, world!"
2447 v8::Handle<v8::Value> argv_foo[1] = { v8::String::New("Hello, world!") };
2448
2449 // Call foo with breakpoint set before a=x and undefined as parameter.
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +00002450 int bp = SetBreakPoint(foo, foo_break_position_1);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002451 checks = checks_uu;
2452 foo->Call(env->Global(), 0, NULL);
2453
2454 // Call foo with breakpoint set before a=x and parameter "Hello, world!".
2455 checks = checks_hu;
2456 foo->Call(env->Global(), 1, argv_foo);
2457
2458 // Call foo with breakpoint set after a=x and parameter "Hello, world!".
2459 ClearBreakPoint(bp);
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +00002460 SetBreakPoint(foo, foo_break_position_2);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002461 checks = checks_hh;
2462 foo->Call(env->Global(), 1, argv_foo);
2463
2464 // Test function with an inner function. The "y=0" is in function barbar
2465 // to provide a break location. For "y=0" the "y" is at position 8 in the
2466 // barbar function therefore setting breakpoint at position 8 will break at
2467 // "y=0" and setting it higher will break after.
2468 v8::Local<v8::Function> bar = CompileFunction(&env,
2469 "y = 0;"
2470 "x = 'Goodbye, world!';"
2471 "function bar(x, b) {"
2472 " var a;"
2473 " function barbar() {"
2474 " y=0; /* To ensure break location.*/"
2475 " a=x;"
2476 " };"
2477 " debug.Debug.clearAllBreakPoints();"
2478 " barbar();"
2479 " y=0;a=x;"
2480 "}",
2481 "bar");
2482 const int barbar_break_position = 8;
2483
2484 // Call bar setting breakpoint before a=x in barbar and undefined as
2485 // parameter.
2486 checks = checks_uu;
2487 v8::Handle<v8::Value> argv_bar_1[2] = {
2488 v8::Undefined(),
2489 v8::Number::New(barbar_break_position)
2490 };
2491 bar->Call(env->Global(), 2, argv_bar_1);
2492
2493 // Call bar setting breakpoint before a=x in barbar and parameter
2494 // "Hello, world!".
2495 checks = checks_hu;
2496 v8::Handle<v8::Value> argv_bar_2[2] = {
2497 v8::String::New("Hello, world!"),
2498 v8::Number::New(barbar_break_position)
2499 };
2500 bar->Call(env->Global(), 2, argv_bar_2);
2501
2502 // Call bar setting breakpoint after a=x in barbar and parameter
2503 // "Hello, world!".
2504 checks = checks_hh;
2505 v8::Handle<v8::Value> argv_bar_3[2] = {
2506 v8::String::New("Hello, world!"),
2507 v8::Number::New(barbar_break_position + 1)
2508 };
2509 bar->Call(env->Global(), 2, argv_bar_3);
2510
iposva@chromium.org245aa852009-02-10 00:49:54 +00002511 v8::Debug::SetDebugEventListener(NULL);
ager@chromium.org381abbb2009-02-25 13:23:22 +00002512 CheckDebuggerUnloaded();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002513}
2514
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002515// Copies a C string to a 16-bit string. Does not check for buffer overflow.
2516// Does not use the V8 engine to convert strings, so it can be used
2517// in any thread. Returns the length of the string.
2518int AsciiToUtf16(const char* input_buffer, uint16_t* output_buffer) {
2519 int i;
2520 for (i = 0; input_buffer[i] != '\0'; ++i) {
2521 // ASCII does not use chars > 127, but be careful anyway.
2522 output_buffer[i] = static_cast<unsigned char>(input_buffer[i]);
2523 }
2524 output_buffer[i] = 0;
2525 return i;
2526}
2527
2528// Copies a 16-bit string to a C string by dropping the high byte of
2529// each character. Does not check for buffer overflow.
2530// Can be used in any thread. Requires string length as an input.
2531int Utf16ToAscii(const uint16_t* input_buffer, int length,
2532 char* output_buffer, int output_len = -1) {
2533 if (output_len >= 0) {
2534 if (length > output_len - 1) {
2535 length = output_len - 1;
2536 }
2537 }
2538
2539 for (int i = 0; i < length; ++i) {
2540 output_buffer[i] = static_cast<char>(input_buffer[i]);
2541 }
2542 output_buffer[length] = '\0';
2543 return length;
2544}
2545
2546
2547// We match parts of the message to get evaluate result int value.
2548bool GetEvaluateStringResult(char *message, char* buffer, int buffer_size) {
2549 if (strstr(message, "\"command\":\"evaluate\"") == NULL) {
2550 return false;
2551 }
2552 const char* prefix = "\"text\":\"";
2553 char* pos1 = strstr(message, prefix);
2554 if (pos1 == NULL) {
2555 return false;
2556 }
2557 pos1 += strlen(prefix);
2558 char* pos2 = strchr(pos1, '"');
2559 if (pos2 == NULL) {
2560 return false;
2561 }
2562 Vector<char> buf(buffer, buffer_size);
2563 int len = static_cast<int>(pos2 - pos1);
2564 if (len > buffer_size - 1) {
2565 len = buffer_size - 1;
2566 }
2567 OS::StrNCpy(buf, pos1, len);
2568 buffer[buffer_size - 1] = '\0';
2569 return true;
2570}
2571
2572
2573struct EvaluateResult {
2574 static const int kBufferSize = 20;
2575 char buffer[kBufferSize];
2576};
2577
2578struct DebugProcessDebugMessagesData {
2579 static const int kArraySize = 5;
2580 int counter;
2581 EvaluateResult results[kArraySize];
2582
2583 void reset() {
2584 counter = 0;
2585 }
2586 EvaluateResult* current() {
2587 return &results[counter % kArraySize];
2588 }
2589 void next() {
2590 counter++;
2591 }
2592};
2593
2594DebugProcessDebugMessagesData process_debug_messages_data;
2595
2596static void DebugProcessDebugMessagesHandler(
2597 const uint16_t* message,
2598 int length,
2599 v8::Debug::ClientData* client_data) {
2600
2601 const int kBufferSize = 100000;
2602 char print_buffer[kBufferSize];
2603 Utf16ToAscii(message, length, print_buffer, kBufferSize);
2604
2605 EvaluateResult* array_item = process_debug_messages_data.current();
2606
2607 bool res = GetEvaluateStringResult(print_buffer,
2608 array_item->buffer,
2609 EvaluateResult::kBufferSize);
2610 if (res) {
2611 process_debug_messages_data.next();
2612 }
2613}
2614
2615// Test that the evaluation of expressions works even from ProcessDebugMessages
2616// i.e. with empty stack.
2617TEST(DebugEvaluateWithoutStack) {
2618 v8::Debug::SetMessageHandler(DebugProcessDebugMessagesHandler);
2619
2620 v8::HandleScope scope;
2621 DebugLocalContext env;
2622
2623 const char* source =
2624 "var v1 = 'Pinguin';\n function getAnimal() { return 'Capy' + 'bara'; }";
2625
2626 v8::Script::Compile(v8::String::New(source))->Run();
2627
2628 v8::Debug::ProcessDebugMessages();
2629
2630 const int kBufferSize = 1000;
2631 uint16_t buffer[kBufferSize];
2632
2633 const char* command_111 = "{\"seq\":111,"
2634 "\"type\":\"request\","
2635 "\"command\":\"evaluate\","
2636 "\"arguments\":{"
2637 " \"global\":true,"
2638 " \"expression\":\"v1\",\"disable_break\":true"
2639 "}}";
2640
2641 v8::Debug::SendCommand(buffer, AsciiToUtf16(command_111, buffer));
2642
2643 const char* command_112 = "{\"seq\":112,"
2644 "\"type\":\"request\","
2645 "\"command\":\"evaluate\","
2646 "\"arguments\":{"
2647 " \"global\":true,"
2648 " \"expression\":\"getAnimal()\",\"disable_break\":true"
2649 "}}";
2650
2651 v8::Debug::SendCommand(buffer, AsciiToUtf16(command_112, buffer));
2652
2653 const char* command_113 = "{\"seq\":113,"
2654 "\"type\":\"request\","
2655 "\"command\":\"evaluate\","
2656 "\"arguments\":{"
2657 " \"global\":true,"
2658 " \"expression\":\"239 + 566\",\"disable_break\":true"
2659 "}}";
2660
2661 v8::Debug::SendCommand(buffer, AsciiToUtf16(command_113, buffer));
2662
2663 v8::Debug::ProcessDebugMessages();
2664
2665 CHECK_EQ(3, process_debug_messages_data.counter);
2666
2667 CHECK_EQ(strcmp("Pinguin", process_debug_messages_data.results[0].buffer), 0);
2668 CHECK_EQ(strcmp("Capybara", process_debug_messages_data.results[1].buffer),
2669 0);
2670 CHECK_EQ(strcmp("805", process_debug_messages_data.results[2].buffer), 0);
2671
2672 v8::Debug::SetMessageHandler(NULL);
2673 v8::Debug::SetDebugEventListener(NULL);
2674 CheckDebuggerUnloaded();
2675}
2676
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002677
2678// Simple test of the stepping mechanism using only store ICs.
2679TEST(DebugStepLinear) {
2680 v8::HandleScope scope;
2681 DebugLocalContext env;
2682
2683 // Create a function for testing stepping.
2684 v8::Local<v8::Function> foo = CompileFunction(&env,
2685 "function foo(){a=1;b=1;c=1;}",
2686 "foo");
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002687
2688 // Run foo to allow it to get optimized.
2689 CompileRun("a=0; b=0; c=0; foo();");
2690
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002691 SetBreakPoint(foo, 3);
2692
2693 // Register a debug event listener which steps and counts.
iposva@chromium.org245aa852009-02-10 00:49:54 +00002694 v8::Debug::SetDebugEventListener(DebugEventStep);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002695
2696 step_action = StepIn;
2697 break_point_hit_count = 0;
2698 foo->Call(env->Global(), 0, NULL);
2699
2700 // With stepping all break locations are hit.
2701 CHECK_EQ(4, break_point_hit_count);
2702
iposva@chromium.org245aa852009-02-10 00:49:54 +00002703 v8::Debug::SetDebugEventListener(NULL);
ager@chromium.org381abbb2009-02-25 13:23:22 +00002704 CheckDebuggerUnloaded();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002705
2706 // Register a debug event listener which just counts.
iposva@chromium.org245aa852009-02-10 00:49:54 +00002707 v8::Debug::SetDebugEventListener(DebugEventBreakPointHitCount);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002708
ager@chromium.org381abbb2009-02-25 13:23:22 +00002709 SetBreakPoint(foo, 3);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002710 break_point_hit_count = 0;
2711 foo->Call(env->Global(), 0, NULL);
2712
2713 // Without stepping only active break points are hit.
2714 CHECK_EQ(1, break_point_hit_count);
2715
iposva@chromium.org245aa852009-02-10 00:49:54 +00002716 v8::Debug::SetDebugEventListener(NULL);
ager@chromium.org381abbb2009-02-25 13:23:22 +00002717 CheckDebuggerUnloaded();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002718}
2719
2720
ager@chromium.org65dad4b2009-04-23 08:48:43 +00002721// Test of the stepping mechanism for keyed load in a loop.
2722TEST(DebugStepKeyedLoadLoop) {
2723 v8::HandleScope scope;
2724 DebugLocalContext env;
2725
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +00002726 // Register a debug event listener which steps and counts.
2727 v8::Debug::SetDebugEventListener(DebugEventStep);
2728
ager@chromium.org65dad4b2009-04-23 08:48:43 +00002729 // Create a function for testing stepping of keyed load. The statement 'y=1'
2730 // is there to have more than one breakable statement in the loop, TODO(315).
2731 v8::Local<v8::Function> foo = CompileFunction(
2732 &env,
2733 "function foo(a) {\n"
2734 " var x;\n"
2735 " var len = a.length;\n"
2736 " for (var i = 0; i < len; i++) {\n"
2737 " y = 1;\n"
2738 " x = a[i];\n"
2739 " }\n"
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002740 "}\n"
2741 "y=0\n",
ager@chromium.org65dad4b2009-04-23 08:48:43 +00002742 "foo");
2743
2744 // Create array [0,1,2,3,4,5,6,7,8,9]
2745 v8::Local<v8::Array> a = v8::Array::New(10);
2746 for (int i = 0; i < 10; i++) {
2747 a->Set(v8::Number::New(i), v8::Number::New(i));
2748 }
2749
2750 // Call function without any break points to ensure inlining is in place.
2751 const int kArgc = 1;
2752 v8::Handle<v8::Value> args[kArgc] = { a };
2753 foo->Call(env->Global(), kArgc, args);
2754
ager@chromium.org65dad4b2009-04-23 08:48:43 +00002755 // Setup break point and step through the function.
2756 SetBreakPoint(foo, 3);
2757 step_action = StepNext;
2758 break_point_hit_count = 0;
2759 foo->Call(env->Global(), kArgc, args);
2760
2761 // With stepping all break locations are hit.
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +00002762 CHECK_EQ(33, break_point_hit_count);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00002763
2764 v8::Debug::SetDebugEventListener(NULL);
2765 CheckDebuggerUnloaded();
2766}
2767
2768
ager@chromium.orgeadaf222009-06-16 09:43:10 +00002769// Test of the stepping mechanism for keyed store in a loop.
2770TEST(DebugStepKeyedStoreLoop) {
2771 v8::HandleScope scope;
2772 DebugLocalContext env;
2773
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +00002774 // Register a debug event listener which steps and counts.
2775 v8::Debug::SetDebugEventListener(DebugEventStep);
2776
ager@chromium.orgeadaf222009-06-16 09:43:10 +00002777 // Create a function for testing stepping of keyed store. The statement 'y=1'
2778 // is there to have more than one breakable statement in the loop, TODO(315).
2779 v8::Local<v8::Function> foo = CompileFunction(
2780 &env,
2781 "function foo(a) {\n"
2782 " var len = a.length;\n"
2783 " for (var i = 0; i < len; i++) {\n"
2784 " y = 1;\n"
2785 " a[i] = 42;\n"
2786 " }\n"
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002787 "}\n"
2788 "y=0\n",
ager@chromium.orgeadaf222009-06-16 09:43:10 +00002789 "foo");
2790
2791 // Create array [0,1,2,3,4,5,6,7,8,9]
2792 v8::Local<v8::Array> a = v8::Array::New(10);
2793 for (int i = 0; i < 10; i++) {
2794 a->Set(v8::Number::New(i), v8::Number::New(i));
2795 }
2796
2797 // Call function without any break points to ensure inlining is in place.
2798 const int kArgc = 1;
2799 v8::Handle<v8::Value> args[kArgc] = { a };
2800 foo->Call(env->Global(), kArgc, args);
2801
ager@chromium.orgeadaf222009-06-16 09:43:10 +00002802 // Setup break point and step through the function.
2803 SetBreakPoint(foo, 3);
2804 step_action = StepNext;
2805 break_point_hit_count = 0;
2806 foo->Call(env->Global(), kArgc, args);
2807
2808 // With stepping all break locations are hit.
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +00002809 CHECK_EQ(32, break_point_hit_count);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00002810
2811 v8::Debug::SetDebugEventListener(NULL);
2812 CheckDebuggerUnloaded();
2813}
2814
2815
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +00002816// Test of the stepping mechanism for named load in a loop.
2817TEST(DebugStepNamedLoadLoop) {
2818 v8::HandleScope scope;
2819 DebugLocalContext env;
2820
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +00002821 // Register a debug event listener which steps and counts.
2822 v8::Debug::SetDebugEventListener(DebugEventStep);
2823
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +00002824 // Create a function for testing stepping of named load.
2825 v8::Local<v8::Function> foo = CompileFunction(
2826 &env,
2827 "function foo() {\n"
2828 " var a = [];\n"
2829 " var s = \"\";\n"
2830 " for (var i = 0; i < 10; i++) {\n"
2831 " var v = new V(i, i + 1);\n"
2832 " v.y;\n"
2833 " a.length;\n" // Special case: array length.
2834 " s.length;\n" // Special case: string length.
2835 " }\n"
2836 "}\n"
2837 "function V(x, y) {\n"
2838 " this.x = x;\n"
2839 " this.y = y;\n"
2840 "}\n",
2841 "foo");
2842
2843 // Call function without any break points to ensure inlining is in place.
2844 foo->Call(env->Global(), 0, NULL);
2845
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +00002846 // Setup break point and step through the function.
2847 SetBreakPoint(foo, 4);
2848 step_action = StepNext;
2849 break_point_hit_count = 0;
2850 foo->Call(env->Global(), 0, NULL);
2851
2852 // With stepping all break locations are hit.
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +00002853 CHECK_EQ(53, break_point_hit_count);
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +00002854
2855 v8::Debug::SetDebugEventListener(NULL);
2856 CheckDebuggerUnloaded();
2857}
2858
2859
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002860static void DoDebugStepNamedStoreLoop(int expected) {
ricow@chromium.org0b9f8502010-08-18 07:45:01 +00002861 v8::HandleScope scope;
2862 DebugLocalContext env;
2863
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002864 // Register a debug event listener which steps and counts.
2865 v8::Debug::SetDebugEventListener(DebugEventStep);
ricow@chromium.org0b9f8502010-08-18 07:45:01 +00002866
2867 // Create a function for testing stepping of named store.
2868 v8::Local<v8::Function> foo = CompileFunction(
2869 &env,
2870 "function foo() {\n"
2871 " var a = {a:1};\n"
2872 " for (var i = 0; i < 10; i++) {\n"
2873 " a.a = 2\n"
2874 " }\n"
2875 "}\n",
2876 "foo");
2877
2878 // Call function without any break points to ensure inlining is in place.
2879 foo->Call(env->Global(), 0, NULL);
2880
ricow@chromium.org0b9f8502010-08-18 07:45:01 +00002881 // Setup break point and step through the function.
2882 SetBreakPoint(foo, 3);
2883 step_action = StepNext;
2884 break_point_hit_count = 0;
2885 foo->Call(env->Global(), 0, NULL);
2886
2887 // With stepping all expected break locations are hit.
2888 CHECK_EQ(expected, break_point_hit_count);
2889
2890 v8::Debug::SetDebugEventListener(NULL);
2891 CheckDebuggerUnloaded();
2892}
2893
2894
2895// Test of the stepping mechanism for named load in a loop.
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002896TEST(DebugStepNamedStoreLoop) {
ricow@chromium.org0b9f8502010-08-18 07:45:01 +00002897 DoDebugStepNamedStoreLoop(22);
2898}
2899
2900
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002901// Test the stepping mechanism with different ICs.
2902TEST(DebugStepLinearMixedICs) {
2903 v8::HandleScope scope;
2904 DebugLocalContext env;
2905
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +00002906 // Register a debug event listener which steps and counts.
2907 v8::Debug::SetDebugEventListener(DebugEventStep);
2908
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002909 // Create a function for testing stepping.
2910 v8::Local<v8::Function> foo = CompileFunction(&env,
2911 "function bar() {};"
2912 "function foo() {"
2913 " var x;"
2914 " var index='name';"
2915 " var y = {};"
2916 " a=1;b=2;x=a;y[index]=3;x=y[index];bar();}", "foo");
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002917
2918 // Run functions to allow them to get optimized.
2919 CompileRun("a=0; b=0; bar(); foo();");
2920
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002921 SetBreakPoint(foo, 0);
2922
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002923 step_action = StepIn;
2924 break_point_hit_count = 0;
2925 foo->Call(env->Global(), 0, NULL);
2926
ager@chromium.org4af710e2009-09-15 12:20:11 +00002927 // With stepping all break locations are hit.
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +00002928 CHECK_EQ(11, break_point_hit_count);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002929
iposva@chromium.org245aa852009-02-10 00:49:54 +00002930 v8::Debug::SetDebugEventListener(NULL);
ager@chromium.org381abbb2009-02-25 13:23:22 +00002931 CheckDebuggerUnloaded();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002932
2933 // Register a debug event listener which just counts.
iposva@chromium.org245aa852009-02-10 00:49:54 +00002934 v8::Debug::SetDebugEventListener(DebugEventBreakPointHitCount);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002935
ager@chromium.org381abbb2009-02-25 13:23:22 +00002936 SetBreakPoint(foo, 0);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002937 break_point_hit_count = 0;
2938 foo->Call(env->Global(), 0, NULL);
2939
2940 // Without stepping only active break points are hit.
2941 CHECK_EQ(1, break_point_hit_count);
2942
iposva@chromium.org245aa852009-02-10 00:49:54 +00002943 v8::Debug::SetDebugEventListener(NULL);
ager@chromium.org381abbb2009-02-25 13:23:22 +00002944 CheckDebuggerUnloaded();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002945}
2946
2947
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +00002948TEST(DebugStepDeclarations) {
2949 v8::HandleScope scope;
2950 DebugLocalContext env;
2951
2952 // Register a debug event listener which steps and counts.
2953 v8::Debug::SetDebugEventListener(DebugEventStep);
2954
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002955 // Create a function for testing stepping. Run it to allow it to get
2956 // optimized.
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +00002957 const char* src = "function foo() { "
2958 " var a;"
2959 " var b = 1;"
2960 " var c = foo;"
2961 " var d = Math.floor;"
2962 " var e = b + d(1.2);"
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002963 "}"
2964 "foo()";
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +00002965 v8::Local<v8::Function> foo = CompileFunction(&env, src, "foo");
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002966
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +00002967 SetBreakPoint(foo, 0);
2968
2969 // Stepping through the declarations.
2970 step_action = StepIn;
2971 break_point_hit_count = 0;
2972 foo->Call(env->Global(), 0, NULL);
2973 CHECK_EQ(6, break_point_hit_count);
2974
2975 // Get rid of the debug event listener.
2976 v8::Debug::SetDebugEventListener(NULL);
2977 CheckDebuggerUnloaded();
2978}
2979
2980
2981TEST(DebugStepLocals) {
2982 v8::HandleScope scope;
2983 DebugLocalContext env;
2984
2985 // Register a debug event listener which steps and counts.
2986 v8::Debug::SetDebugEventListener(DebugEventStep);
2987
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002988 // Create a function for testing stepping. Run it to allow it to get
2989 // optimized.
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +00002990 const char* src = "function foo() { "
2991 " var a,b;"
2992 " a = 1;"
2993 " b = a + 2;"
2994 " b = 1 + 2 + 3;"
2995 " a = Math.floor(b);"
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002996 "}"
2997 "foo()";
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +00002998 v8::Local<v8::Function> foo = CompileFunction(&env, src, "foo");
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002999
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +00003000 SetBreakPoint(foo, 0);
3001
3002 // Stepping through the declarations.
3003 step_action = StepIn;
3004 break_point_hit_count = 0;
3005 foo->Call(env->Global(), 0, NULL);
3006 CHECK_EQ(6, break_point_hit_count);
3007
3008 // Get rid of the debug event listener.
3009 v8::Debug::SetDebugEventListener(NULL);
3010 CheckDebuggerUnloaded();
3011}
3012
3013
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003014TEST(DebugStepIf) {
3015 v8::HandleScope scope;
3016 DebugLocalContext env;
3017
3018 // Register a debug event listener which steps and counts.
iposva@chromium.org245aa852009-02-10 00:49:54 +00003019 v8::Debug::SetDebugEventListener(DebugEventStep);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003020
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003021 // Create a function for testing stepping. Run it to allow it to get
3022 // optimized.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003023 const int argc = 1;
3024 const char* src = "function foo(x) { "
3025 " a = 1;"
3026 " if (x) {"
3027 " b = 1;"
3028 " } else {"
3029 " c = 1;"
3030 " d = 1;"
3031 " }"
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003032 "}"
3033 "a=0; b=0; c=0; d=0; foo()";
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003034 v8::Local<v8::Function> foo = CompileFunction(&env, src, "foo");
3035 SetBreakPoint(foo, 0);
3036
3037 // Stepping through the true part.
3038 step_action = StepIn;
3039 break_point_hit_count = 0;
3040 v8::Handle<v8::Value> argv_true[argc] = { v8::True() };
3041 foo->Call(env->Global(), argc, argv_true);
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +00003042 CHECK_EQ(4, break_point_hit_count);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003043
3044 // Stepping through the false part.
3045 step_action = StepIn;
3046 break_point_hit_count = 0;
3047 v8::Handle<v8::Value> argv_false[argc] = { v8::False() };
3048 foo->Call(env->Global(), argc, argv_false);
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +00003049 CHECK_EQ(5, break_point_hit_count);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003050
3051 // Get rid of the debug event listener.
iposva@chromium.org245aa852009-02-10 00:49:54 +00003052 v8::Debug::SetDebugEventListener(NULL);
ager@chromium.org381abbb2009-02-25 13:23:22 +00003053 CheckDebuggerUnloaded();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003054}
3055
3056
3057TEST(DebugStepSwitch) {
3058 v8::HandleScope scope;
3059 DebugLocalContext env;
3060
3061 // Register a debug event listener which steps and counts.
iposva@chromium.org245aa852009-02-10 00:49:54 +00003062 v8::Debug::SetDebugEventListener(DebugEventStep);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003063
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003064 // Create a function for testing stepping. Run it to allow it to get
3065 // optimized.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003066 const int argc = 1;
3067 const char* src = "function foo(x) { "
3068 " a = 1;"
3069 " switch (x) {"
3070 " case 1:"
3071 " b = 1;"
3072 " case 2:"
3073 " c = 1;"
3074 " break;"
3075 " case 3:"
3076 " d = 1;"
3077 " e = 1;"
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +00003078 " f = 1;"
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003079 " break;"
3080 " }"
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003081 "}"
3082 "a=0; b=0; c=0; d=0; e=0; f=0; foo()";
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003083 v8::Local<v8::Function> foo = CompileFunction(&env, src, "foo");
3084 SetBreakPoint(foo, 0);
3085
3086 // One case with fall-through.
3087 step_action = StepIn;
3088 break_point_hit_count = 0;
3089 v8::Handle<v8::Value> argv_1[argc] = { v8::Number::New(1) };
3090 foo->Call(env->Global(), argc, argv_1);
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +00003091 CHECK_EQ(6, break_point_hit_count);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003092
3093 // Another case.
3094 step_action = StepIn;
3095 break_point_hit_count = 0;
3096 v8::Handle<v8::Value> argv_2[argc] = { v8::Number::New(2) };
3097 foo->Call(env->Global(), argc, argv_2);
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +00003098 CHECK_EQ(5, break_point_hit_count);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003099
3100 // Last case.
3101 step_action = StepIn;
3102 break_point_hit_count = 0;
3103 v8::Handle<v8::Value> argv_3[argc] = { v8::Number::New(3) };
3104 foo->Call(env->Global(), argc, argv_3);
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +00003105 CHECK_EQ(7, break_point_hit_count);
3106
3107 // Get rid of the debug event listener.
3108 v8::Debug::SetDebugEventListener(NULL);
3109 CheckDebuggerUnloaded();
3110}
3111
3112
3113TEST(DebugStepWhile) {
3114 v8::HandleScope scope;
3115 DebugLocalContext env;
3116
3117 // Register a debug event listener which steps and counts.
3118 v8::Debug::SetDebugEventListener(DebugEventStep);
3119
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003120 // Create a function for testing stepping. Run it to allow it to get
3121 // optimized.
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +00003122 const int argc = 1;
3123 const char* src = "function foo(x) { "
3124 " var a = 0;"
3125 " while (a < x) {"
3126 " a++;"
3127 " }"
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003128 "}"
3129 "foo()";
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +00003130 v8::Local<v8::Function> foo = CompileFunction(&env, src, "foo");
3131 SetBreakPoint(foo, 8); // "var a = 0;"
3132
3133 // Looping 10 times.
3134 step_action = StepIn;
3135 break_point_hit_count = 0;
3136 v8::Handle<v8::Value> argv_10[argc] = { v8::Number::New(10) };
3137 foo->Call(env->Global(), argc, argv_10);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003138 CHECK_EQ(22, break_point_hit_count);
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +00003139
3140 // Looping 100 times.
3141 step_action = StepIn;
3142 break_point_hit_count = 0;
3143 v8::Handle<v8::Value> argv_100[argc] = { v8::Number::New(100) };
3144 foo->Call(env->Global(), argc, argv_100);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003145 CHECK_EQ(202, break_point_hit_count);
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +00003146
3147 // Get rid of the debug event listener.
3148 v8::Debug::SetDebugEventListener(NULL);
3149 CheckDebuggerUnloaded();
3150}
3151
3152
3153TEST(DebugStepDoWhile) {
3154 v8::HandleScope scope;
3155 DebugLocalContext env;
3156
3157 // Register a debug event listener which steps and counts.
3158 v8::Debug::SetDebugEventListener(DebugEventStep);
3159
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003160 // Create a function for testing stepping. Run it to allow it to get
3161 // optimized.
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +00003162 const int argc = 1;
3163 const char* src = "function foo(x) { "
3164 " var a = 0;"
3165 " do {"
3166 " a++;"
3167 " } while (a < x)"
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003168 "}"
3169 "foo()";
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +00003170 v8::Local<v8::Function> foo = CompileFunction(&env, src, "foo");
3171 SetBreakPoint(foo, 8); // "var a = 0;"
3172
3173 // Looping 10 times.
3174 step_action = StepIn;
3175 break_point_hit_count = 0;
3176 v8::Handle<v8::Value> argv_10[argc] = { v8::Number::New(10) };
3177 foo->Call(env->Global(), argc, argv_10);
3178 CHECK_EQ(22, break_point_hit_count);
3179
3180 // Looping 100 times.
3181 step_action = StepIn;
3182 break_point_hit_count = 0;
3183 v8::Handle<v8::Value> argv_100[argc] = { v8::Number::New(100) };
3184 foo->Call(env->Global(), argc, argv_100);
3185 CHECK_EQ(202, break_point_hit_count);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003186
3187 // Get rid of the debug event listener.
iposva@chromium.org245aa852009-02-10 00:49:54 +00003188 v8::Debug::SetDebugEventListener(NULL);
ager@chromium.org381abbb2009-02-25 13:23:22 +00003189 CheckDebuggerUnloaded();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003190}
3191
3192
3193TEST(DebugStepFor) {
3194 v8::HandleScope scope;
3195 DebugLocalContext env;
3196
3197 // Register a debug event listener which steps and counts.
iposva@chromium.org245aa852009-02-10 00:49:54 +00003198 v8::Debug::SetDebugEventListener(DebugEventStep);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003199
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003200 // Create a function for testing stepping. Run it to allow it to get
3201 // optimized.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003202 const int argc = 1;
3203 const char* src = "function foo(x) { "
3204 " a = 1;"
3205 " for (i = 0; i < x; i++) {"
3206 " b = 1;"
3207 " }"
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003208 "}"
3209 "a=0; b=0; i=0; foo()";
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003210 v8::Local<v8::Function> foo = CompileFunction(&env, src, "foo");
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003211
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003212 SetBreakPoint(foo, 8); // "a = 1;"
3213
3214 // Looping 10 times.
3215 step_action = StepIn;
3216 break_point_hit_count = 0;
3217 v8::Handle<v8::Value> argv_10[argc] = { v8::Number::New(10) };
3218 foo->Call(env->Global(), argc, argv_10);
3219 CHECK_EQ(23, break_point_hit_count);
3220
3221 // Looping 100 times.
3222 step_action = StepIn;
3223 break_point_hit_count = 0;
3224 v8::Handle<v8::Value> argv_100[argc] = { v8::Number::New(100) };
3225 foo->Call(env->Global(), argc, argv_100);
3226 CHECK_EQ(203, break_point_hit_count);
3227
3228 // Get rid of the debug event listener.
iposva@chromium.org245aa852009-02-10 00:49:54 +00003229 v8::Debug::SetDebugEventListener(NULL);
ager@chromium.org381abbb2009-02-25 13:23:22 +00003230 CheckDebuggerUnloaded();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003231}
3232
3233
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +00003234TEST(DebugStepForContinue) {
3235 v8::HandleScope scope;
3236 DebugLocalContext env;
3237
3238 // Register a debug event listener which steps and counts.
3239 v8::Debug::SetDebugEventListener(DebugEventStep);
3240
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003241 // Create a function for testing stepping. Run it to allow it to get
3242 // optimized.
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +00003243 const int argc = 1;
3244 const char* src = "function foo(x) { "
3245 " var a = 0;"
3246 " var b = 0;"
3247 " var c = 0;"
3248 " for (var i = 0; i < x; i++) {"
3249 " a++;"
3250 " if (a % 2 == 0) continue;"
3251 " b++;"
3252 " c++;"
3253 " }"
3254 " return b;"
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003255 "}"
3256 "foo()";
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +00003257 v8::Local<v8::Function> foo = CompileFunction(&env, src, "foo");
3258 v8::Handle<v8::Value> result;
3259 SetBreakPoint(foo, 8); // "var a = 0;"
3260
3261 // Each loop generates 4 or 5 steps depending on whether a is equal.
3262
3263 // Looping 10 times.
3264 step_action = StepIn;
3265 break_point_hit_count = 0;
3266 v8::Handle<v8::Value> argv_10[argc] = { v8::Number::New(10) };
3267 result = foo->Call(env->Global(), argc, argv_10);
3268 CHECK_EQ(5, result->Int32Value());
3269 CHECK_EQ(50, break_point_hit_count);
3270
3271 // Looping 100 times.
3272 step_action = StepIn;
3273 break_point_hit_count = 0;
3274 v8::Handle<v8::Value> argv_100[argc] = { v8::Number::New(100) };
3275 result = foo->Call(env->Global(), argc, argv_100);
3276 CHECK_EQ(50, result->Int32Value());
3277 CHECK_EQ(455, break_point_hit_count);
3278
3279 // Get rid of the debug event listener.
3280 v8::Debug::SetDebugEventListener(NULL);
3281 CheckDebuggerUnloaded();
3282}
3283
3284
3285TEST(DebugStepForBreak) {
3286 v8::HandleScope scope;
3287 DebugLocalContext env;
3288
3289 // Register a debug event listener which steps and counts.
3290 v8::Debug::SetDebugEventListener(DebugEventStep);
3291
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003292 // Create a function for testing stepping. Run it to allow it to get
3293 // optimized.
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +00003294 const int argc = 1;
3295 const char* src = "function foo(x) { "
3296 " var a = 0;"
3297 " var b = 0;"
3298 " var c = 0;"
3299 " for (var i = 0; i < 1000; i++) {"
3300 " a++;"
3301 " if (a == x) break;"
3302 " b++;"
3303 " c++;"
3304 " }"
3305 " return b;"
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003306 "}"
3307 "foo()";
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +00003308 v8::Local<v8::Function> foo = CompileFunction(&env, src, "foo");
3309 v8::Handle<v8::Value> result;
3310 SetBreakPoint(foo, 8); // "var a = 0;"
3311
3312 // Each loop generates 5 steps except for the last (when break is executed)
3313 // which only generates 4.
3314
3315 // Looping 10 times.
3316 step_action = StepIn;
3317 break_point_hit_count = 0;
3318 v8::Handle<v8::Value> argv_10[argc] = { v8::Number::New(10) };
3319 result = foo->Call(env->Global(), argc, argv_10);
3320 CHECK_EQ(9, result->Int32Value());
3321 CHECK_EQ(53, break_point_hit_count);
3322
3323 // Looping 100 times.
3324 step_action = StepIn;
3325 break_point_hit_count = 0;
3326 v8::Handle<v8::Value> argv_100[argc] = { v8::Number::New(100) };
3327 result = foo->Call(env->Global(), argc, argv_100);
3328 CHECK_EQ(99, result->Int32Value());
3329 CHECK_EQ(503, break_point_hit_count);
3330
3331 // Get rid of the debug event listener.
3332 v8::Debug::SetDebugEventListener(NULL);
3333 CheckDebuggerUnloaded();
3334}
3335
3336
3337TEST(DebugStepForIn) {
3338 v8::HandleScope scope;
3339 DebugLocalContext env;
3340
3341 // Register a debug event listener which steps and counts.
3342 v8::Debug::SetDebugEventListener(DebugEventStep);
3343
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003344 // Create a function for testing stepping. Run it to allow it to get
3345 // optimized.
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +00003346 v8::Local<v8::Function> foo;
3347 const char* src_1 = "function foo() { "
3348 " var a = [1, 2];"
3349 " for (x in a) {"
3350 " b = 0;"
3351 " }"
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003352 "}"
3353 "foo()";
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +00003354 foo = CompileFunction(&env, src_1, "foo");
3355 SetBreakPoint(foo, 0); // "var a = ..."
3356
3357 step_action = StepIn;
3358 break_point_hit_count = 0;
3359 foo->Call(env->Global(), 0, NULL);
3360 CHECK_EQ(6, break_point_hit_count);
3361
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003362 // Create a function for testing stepping. Run it to allow it to get
3363 // optimized.
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +00003364 const char* src_2 = "function foo() { "
3365 " var a = {a:[1, 2, 3]};"
3366 " for (x in a.a) {"
3367 " b = 0;"
3368 " }"
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003369 "}"
3370 "foo()";
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +00003371 foo = CompileFunction(&env, src_2, "foo");
3372 SetBreakPoint(foo, 0); // "var a = ..."
3373
3374 step_action = StepIn;
3375 break_point_hit_count = 0;
3376 foo->Call(env->Global(), 0, NULL);
3377 CHECK_EQ(8, break_point_hit_count);
3378
3379 // Get rid of the debug event listener.
3380 v8::Debug::SetDebugEventListener(NULL);
3381 CheckDebuggerUnloaded();
3382}
3383
3384
3385TEST(DebugStepWith) {
3386 v8::HandleScope scope;
3387 DebugLocalContext env;
3388
3389 // Register a debug event listener which steps and counts.
3390 v8::Debug::SetDebugEventListener(DebugEventStep);
3391
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003392 // Create a function for testing stepping. Run it to allow it to get
3393 // optimized.
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +00003394 const char* src = "function foo(x) { "
3395 " var a = {};"
3396 " with (a) {}"
3397 " with (b) {}"
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003398 "}"
3399 "foo()";
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +00003400 env->Global()->Set(v8::String::New("b"), v8::Object::New());
3401 v8::Local<v8::Function> foo = CompileFunction(&env, src, "foo");
3402 v8::Handle<v8::Value> result;
3403 SetBreakPoint(foo, 8); // "var a = {};"
3404
3405 step_action = StepIn;
3406 break_point_hit_count = 0;
3407 foo->Call(env->Global(), 0, NULL);
3408 CHECK_EQ(4, break_point_hit_count);
3409
3410 // Get rid of the debug event listener.
3411 v8::Debug::SetDebugEventListener(NULL);
3412 CheckDebuggerUnloaded();
3413}
3414
3415
3416TEST(DebugConditional) {
3417 v8::HandleScope scope;
3418 DebugLocalContext env;
3419
3420 // Register a debug event listener which steps and counts.
3421 v8::Debug::SetDebugEventListener(DebugEventStep);
3422
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003423 // Create a function for testing stepping. Run it to allow it to get
3424 // optimized.
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +00003425 const char* src = "function foo(x) { "
3426 " var a;"
3427 " a = x ? 1 : 2;"
3428 " return a;"
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003429 "}"
3430 "foo()";
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +00003431 v8::Local<v8::Function> foo = CompileFunction(&env, src, "foo");
3432 SetBreakPoint(foo, 0); // "var a;"
3433
3434 step_action = StepIn;
3435 break_point_hit_count = 0;
3436 foo->Call(env->Global(), 0, NULL);
3437 CHECK_EQ(5, break_point_hit_count);
3438
3439 step_action = StepIn;
3440 break_point_hit_count = 0;
3441 const int argc = 1;
3442 v8::Handle<v8::Value> argv_true[argc] = { v8::True() };
3443 foo->Call(env->Global(), argc, argv_true);
3444 CHECK_EQ(5, break_point_hit_count);
3445
3446 // Get rid of the debug event listener.
3447 v8::Debug::SetDebugEventListener(NULL);
3448 CheckDebuggerUnloaded();
3449}
3450
3451
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003452TEST(StepInOutSimple) {
3453 v8::HandleScope scope;
3454 DebugLocalContext env;
3455
3456 // Create a function for checking the function when hitting a break point.
3457 frame_function_name = CompileFunction(&env,
3458 frame_function_name_source,
3459 "frame_function_name");
3460
3461 // Register a debug event listener which steps and counts.
iposva@chromium.org245aa852009-02-10 00:49:54 +00003462 v8::Debug::SetDebugEventListener(DebugEventStepSequence);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003463
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003464 // Create a function for testing stepping. Run it to allow it to get
3465 // optimized.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003466 const char* src = "function a() {b();c();}; "
3467 "function b() {c();}; "
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003468 "function c() {}; "
3469 "a(); b(); c()";
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003470 v8::Local<v8::Function> a = CompileFunction(&env, src, "a");
3471 SetBreakPoint(a, 0);
3472
3473 // Step through invocation of a with step in.
3474 step_action = StepIn;
3475 break_point_hit_count = 0;
3476 expected_step_sequence = "abcbaca";
3477 a->Call(env->Global(), 0, NULL);
ager@chromium.orgc4c92722009-11-18 14:12:51 +00003478 CHECK_EQ(StrLength(expected_step_sequence),
3479 break_point_hit_count);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003480
3481 // Step through invocation of a with step next.
3482 step_action = StepNext;
3483 break_point_hit_count = 0;
3484 expected_step_sequence = "aaa";
3485 a->Call(env->Global(), 0, NULL);
ager@chromium.orgc4c92722009-11-18 14:12:51 +00003486 CHECK_EQ(StrLength(expected_step_sequence),
3487 break_point_hit_count);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003488
3489 // Step through invocation of a with step out.
3490 step_action = StepOut;
3491 break_point_hit_count = 0;
3492 expected_step_sequence = "a";
3493 a->Call(env->Global(), 0, NULL);
ager@chromium.orgc4c92722009-11-18 14:12:51 +00003494 CHECK_EQ(StrLength(expected_step_sequence),
3495 break_point_hit_count);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003496
3497 // Get rid of the debug event listener.
iposva@chromium.org245aa852009-02-10 00:49:54 +00003498 v8::Debug::SetDebugEventListener(NULL);
ager@chromium.org381abbb2009-02-25 13:23:22 +00003499 CheckDebuggerUnloaded();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003500}
3501
3502
3503TEST(StepInOutTree) {
3504 v8::HandleScope scope;
3505 DebugLocalContext env;
3506
3507 // Create a function for checking the function when hitting a break point.
3508 frame_function_name = CompileFunction(&env,
3509 frame_function_name_source,
3510 "frame_function_name");
3511
3512 // Register a debug event listener which steps and counts.
iposva@chromium.org245aa852009-02-10 00:49:54 +00003513 v8::Debug::SetDebugEventListener(DebugEventStepSequence);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003514
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003515 // Create a function for testing stepping. Run it to allow it to get
3516 // optimized.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003517 const char* src = "function a() {b(c(d()),d());c(d());d()}; "
3518 "function b(x,y) {c();}; "
3519 "function c(x) {}; "
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003520 "function d() {}; "
3521 "a(); b(); c(); d()";
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003522 v8::Local<v8::Function> a = CompileFunction(&env, src, "a");
3523 SetBreakPoint(a, 0);
3524
3525 // Step through invocation of a with step in.
3526 step_action = StepIn;
3527 break_point_hit_count = 0;
3528 expected_step_sequence = "adacadabcbadacada";
3529 a->Call(env->Global(), 0, NULL);
ager@chromium.orgc4c92722009-11-18 14:12:51 +00003530 CHECK_EQ(StrLength(expected_step_sequence),
3531 break_point_hit_count);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003532
3533 // Step through invocation of a with step next.
3534 step_action = StepNext;
3535 break_point_hit_count = 0;
3536 expected_step_sequence = "aaaa";
3537 a->Call(env->Global(), 0, NULL);
ager@chromium.orgc4c92722009-11-18 14:12:51 +00003538 CHECK_EQ(StrLength(expected_step_sequence),
3539 break_point_hit_count);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003540
3541 // Step through invocation of a with step out.
3542 step_action = StepOut;
3543 break_point_hit_count = 0;
3544 expected_step_sequence = "a";
3545 a->Call(env->Global(), 0, NULL);
ager@chromium.orgc4c92722009-11-18 14:12:51 +00003546 CHECK_EQ(StrLength(expected_step_sequence),
3547 break_point_hit_count);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003548
3549 // Get rid of the debug event listener.
iposva@chromium.org245aa852009-02-10 00:49:54 +00003550 v8::Debug::SetDebugEventListener(NULL);
ager@chromium.org381abbb2009-02-25 13:23:22 +00003551 CheckDebuggerUnloaded(true);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003552}
3553
3554
3555TEST(StepInOutBranch) {
3556 v8::HandleScope scope;
3557 DebugLocalContext env;
3558
3559 // Create a function for checking the function when hitting a break point.
3560 frame_function_name = CompileFunction(&env,
3561 frame_function_name_source,
3562 "frame_function_name");
3563
3564 // Register a debug event listener which steps and counts.
iposva@chromium.org245aa852009-02-10 00:49:54 +00003565 v8::Debug::SetDebugEventListener(DebugEventStepSequence);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003566
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003567 // Create a function for testing stepping. Run it to allow it to get
3568 // optimized.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003569 const char* src = "function a() {b(false);c();}; "
3570 "function b(x) {if(x){c();};}; "
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003571 "function c() {}; "
3572 "a(); b(); c()";
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003573 v8::Local<v8::Function> a = CompileFunction(&env, src, "a");
3574 SetBreakPoint(a, 0);
3575
3576 // Step through invocation of a.
3577 step_action = StepIn;
3578 break_point_hit_count = 0;
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +00003579 expected_step_sequence = "abbaca";
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003580 a->Call(env->Global(), 0, NULL);
ager@chromium.orgc4c92722009-11-18 14:12:51 +00003581 CHECK_EQ(StrLength(expected_step_sequence),
3582 break_point_hit_count);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003583
3584 // Get rid of the debug event listener.
iposva@chromium.org245aa852009-02-10 00:49:54 +00003585 v8::Debug::SetDebugEventListener(NULL);
ager@chromium.org381abbb2009-02-25 13:23:22 +00003586 CheckDebuggerUnloaded();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003587}
3588
3589
3590// Test that step in does not step into native functions.
3591TEST(DebugStepNatives) {
3592 v8::HandleScope scope;
3593 DebugLocalContext env;
3594
3595 // Create a function for testing stepping.
3596 v8::Local<v8::Function> foo = CompileFunction(
3597 &env,
3598 "function foo(){debugger;Math.sin(1);}",
3599 "foo");
3600
3601 // Register a debug event listener which steps and counts.
iposva@chromium.org245aa852009-02-10 00:49:54 +00003602 v8::Debug::SetDebugEventListener(DebugEventStep);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003603
3604 step_action = StepIn;
3605 break_point_hit_count = 0;
3606 foo->Call(env->Global(), 0, NULL);
3607
3608 // With stepping all break locations are hit.
3609 CHECK_EQ(3, break_point_hit_count);
3610
iposva@chromium.org245aa852009-02-10 00:49:54 +00003611 v8::Debug::SetDebugEventListener(NULL);
ager@chromium.org381abbb2009-02-25 13:23:22 +00003612 CheckDebuggerUnloaded();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003613
3614 // Register a debug event listener which just counts.
iposva@chromium.org245aa852009-02-10 00:49:54 +00003615 v8::Debug::SetDebugEventListener(DebugEventBreakPointHitCount);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003616
3617 break_point_hit_count = 0;
3618 foo->Call(env->Global(), 0, NULL);
3619
3620 // Without stepping only active break points are hit.
3621 CHECK_EQ(1, break_point_hit_count);
3622
iposva@chromium.org245aa852009-02-10 00:49:54 +00003623 v8::Debug::SetDebugEventListener(NULL);
ager@chromium.org381abbb2009-02-25 13:23:22 +00003624 CheckDebuggerUnloaded();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003625}
3626
3627
kasperl@chromium.orgacae3782009-04-11 09:17:08 +00003628// Test that step in works with function.apply.
3629TEST(DebugStepFunctionApply) {
3630 v8::HandleScope scope;
3631 DebugLocalContext env;
3632
3633 // Create a function for testing stepping.
3634 v8::Local<v8::Function> foo = CompileFunction(
3635 &env,
3636 "function bar(x, y, z) { if (x == 1) { a = y; b = z; } }"
3637 "function foo(){ debugger; bar.apply(this, [1,2,3]); }",
3638 "foo");
3639
3640 // Register a debug event listener which steps and counts.
3641 v8::Debug::SetDebugEventListener(DebugEventStep);
3642
3643 step_action = StepIn;
3644 break_point_hit_count = 0;
3645 foo->Call(env->Global(), 0, NULL);
3646
3647 // With stepping all break locations are hit.
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +00003648 CHECK_EQ(7, break_point_hit_count);
kasperl@chromium.orgacae3782009-04-11 09:17:08 +00003649
3650 v8::Debug::SetDebugEventListener(NULL);
3651 CheckDebuggerUnloaded();
3652
3653 // Register a debug event listener which just counts.
3654 v8::Debug::SetDebugEventListener(DebugEventBreakPointHitCount);
3655
3656 break_point_hit_count = 0;
3657 foo->Call(env->Global(), 0, NULL);
3658
3659 // Without stepping only the debugger statement is hit.
3660 CHECK_EQ(1, break_point_hit_count);
3661
3662 v8::Debug::SetDebugEventListener(NULL);
3663 CheckDebuggerUnloaded();
3664}
3665
3666
3667// Test that step in works with function.call.
3668TEST(DebugStepFunctionCall) {
3669 v8::HandleScope scope;
3670 DebugLocalContext env;
3671
3672 // Create a function for testing stepping.
3673 v8::Local<v8::Function> foo = CompileFunction(
3674 &env,
3675 "function bar(x, y, z) { if (x == 1) { a = y; b = z; } }"
3676 "function foo(a){ debugger;"
3677 " if (a) {"
3678 " bar.call(this, 1, 2, 3);"
3679 " } else {"
3680 " bar.call(this, 0);"
3681 " }"
3682 "}",
3683 "foo");
3684
3685 // Register a debug event listener which steps and counts.
3686 v8::Debug::SetDebugEventListener(DebugEventStep);
3687 step_action = StepIn;
3688
3689 // Check stepping where the if condition in bar is false.
3690 break_point_hit_count = 0;
3691 foo->Call(env->Global(), 0, NULL);
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +00003692 CHECK_EQ(6, break_point_hit_count);
kasperl@chromium.orgacae3782009-04-11 09:17:08 +00003693
3694 // Check stepping where the if condition in bar is true.
3695 break_point_hit_count = 0;
3696 const int argc = 1;
3697 v8::Handle<v8::Value> argv[argc] = { v8::True() };
3698 foo->Call(env->Global(), argc, argv);
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +00003699 CHECK_EQ(8, break_point_hit_count);
kasperl@chromium.orgacae3782009-04-11 09:17:08 +00003700
3701 v8::Debug::SetDebugEventListener(NULL);
3702 CheckDebuggerUnloaded();
3703
3704 // Register a debug event listener which just counts.
3705 v8::Debug::SetDebugEventListener(DebugEventBreakPointHitCount);
3706
3707 break_point_hit_count = 0;
3708 foo->Call(env->Global(), 0, NULL);
3709
3710 // Without stepping only the debugger statement is hit.
3711 CHECK_EQ(1, break_point_hit_count);
3712
3713 v8::Debug::SetDebugEventListener(NULL);
3714 CheckDebuggerUnloaded();
3715}
3716
3717
ager@chromium.orgc4c92722009-11-18 14:12:51 +00003718// Tests that breakpoint will be hit if it's set in script.
3719TEST(PauseInScript) {
3720 v8::HandleScope scope;
3721 DebugLocalContext env;
3722 env.ExposeDebug();
3723
3724 // Register a debug event listener which counts.
3725 v8::Debug::SetDebugEventListener(DebugEventCounter);
3726
3727 // Create a script that returns a function.
3728 const char* src = "(function (evt) {})";
3729 const char* script_name = "StepInHandlerTest";
3730
3731 // Set breakpoint in the script.
3732 SetScriptBreakPointByNameFromJS(script_name, 0, -1);
3733 break_point_hit_count = 0;
3734
3735 v8::ScriptOrigin origin(v8::String::New(script_name), v8::Integer::New(0));
3736 v8::Handle<v8::Script> script = v8::Script::Compile(v8::String::New(src),
3737 &origin);
3738 v8::Local<v8::Value> r = script->Run();
3739
3740 CHECK(r->IsFunction());
3741 CHECK_EQ(1, break_point_hit_count);
3742
3743 // Get rid of the debug event listener.
3744 v8::Debug::SetDebugEventListener(NULL);
3745 CheckDebuggerUnloaded();
3746}
3747
3748
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003749// Test break on exceptions. For each exception break combination the number
3750// of debug event exception callbacks and message callbacks are collected. The
ager@chromium.org8bb60582008-12-11 12:02:20 +00003751// number of debug event exception callbacks are used to check that the
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003752// debugger is called correctly and the number of message callbacks is used to
3753// check that uncaught exceptions are still returned even if there is a break
3754// for them.
3755TEST(BreakOnException) {
3756 v8::HandleScope scope;
3757 DebugLocalContext env;
3758 env.ExposeDebug();
3759
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003760 v8::internal::Isolate::Current()->TraceException(false);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003761
3762 // Create functions for testing break on exception.
3763 v8::Local<v8::Function> throws =
3764 CompileFunction(&env, "function throws(){throw 1;}", "throws");
3765 v8::Local<v8::Function> caught =
3766 CompileFunction(&env,
3767 "function caught(){try {throws();} catch(e) {};}",
3768 "caught");
3769 v8::Local<v8::Function> notCaught =
3770 CompileFunction(&env, "function notCaught(){throws();}", "notCaught");
3771
3772 v8::V8::AddMessageListener(MessageCallbackCount);
iposva@chromium.org245aa852009-02-10 00:49:54 +00003773 v8::Debug::SetDebugEventListener(DebugEventCounter);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003774
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00003775 // Initial state should be no break on exceptions.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003776 DebugEventCounterClear();
3777 MessageCallbackCountClear();
3778 caught->Call(env->Global(), 0, NULL);
3779 CHECK_EQ(0, exception_hit_count);
3780 CHECK_EQ(0, uncaught_exception_hit_count);
3781 CHECK_EQ(0, message_callback_count);
3782 notCaught->Call(env->Global(), 0, NULL);
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00003783 CHECK_EQ(0, exception_hit_count);
3784 CHECK_EQ(0, uncaught_exception_hit_count);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003785 CHECK_EQ(1, message_callback_count);
3786
3787 // No break on exception
3788 DebugEventCounterClear();
3789 MessageCallbackCountClear();
3790 ChangeBreakOnException(false, false);
3791 caught->Call(env->Global(), 0, NULL);
3792 CHECK_EQ(0, exception_hit_count);
3793 CHECK_EQ(0, uncaught_exception_hit_count);
3794 CHECK_EQ(0, message_callback_count);
3795 notCaught->Call(env->Global(), 0, NULL);
3796 CHECK_EQ(0, exception_hit_count);
3797 CHECK_EQ(0, uncaught_exception_hit_count);
3798 CHECK_EQ(1, message_callback_count);
3799
3800 // Break on uncaught exception
3801 DebugEventCounterClear();
3802 MessageCallbackCountClear();
3803 ChangeBreakOnException(false, true);
3804 caught->Call(env->Global(), 0, NULL);
3805 CHECK_EQ(0, exception_hit_count);
3806 CHECK_EQ(0, uncaught_exception_hit_count);
3807 CHECK_EQ(0, message_callback_count);
3808 notCaught->Call(env->Global(), 0, NULL);
3809 CHECK_EQ(1, exception_hit_count);
3810 CHECK_EQ(1, uncaught_exception_hit_count);
3811 CHECK_EQ(1, message_callback_count);
3812
3813 // Break on exception and uncaught exception
3814 DebugEventCounterClear();
3815 MessageCallbackCountClear();
3816 ChangeBreakOnException(true, true);
3817 caught->Call(env->Global(), 0, NULL);
3818 CHECK_EQ(1, exception_hit_count);
3819 CHECK_EQ(0, uncaught_exception_hit_count);
3820 CHECK_EQ(0, message_callback_count);
3821 notCaught->Call(env->Global(), 0, NULL);
3822 CHECK_EQ(2, exception_hit_count);
3823 CHECK_EQ(1, uncaught_exception_hit_count);
3824 CHECK_EQ(1, message_callback_count);
3825
3826 // Break on exception
3827 DebugEventCounterClear();
3828 MessageCallbackCountClear();
3829 ChangeBreakOnException(true, false);
3830 caught->Call(env->Global(), 0, NULL);
3831 CHECK_EQ(1, exception_hit_count);
3832 CHECK_EQ(0, uncaught_exception_hit_count);
3833 CHECK_EQ(0, message_callback_count);
3834 notCaught->Call(env->Global(), 0, NULL);
3835 CHECK_EQ(2, exception_hit_count);
3836 CHECK_EQ(1, uncaught_exception_hit_count);
3837 CHECK_EQ(1, message_callback_count);
3838
3839 // No break on exception using JavaScript
3840 DebugEventCounterClear();
3841 MessageCallbackCountClear();
3842 ChangeBreakOnExceptionFromJS(false, false);
3843 caught->Call(env->Global(), 0, NULL);
3844 CHECK_EQ(0, exception_hit_count);
3845 CHECK_EQ(0, uncaught_exception_hit_count);
3846 CHECK_EQ(0, message_callback_count);
3847 notCaught->Call(env->Global(), 0, NULL);
3848 CHECK_EQ(0, exception_hit_count);
3849 CHECK_EQ(0, uncaught_exception_hit_count);
3850 CHECK_EQ(1, message_callback_count);
3851
3852 // Break on uncaught exception using JavaScript
3853 DebugEventCounterClear();
3854 MessageCallbackCountClear();
3855 ChangeBreakOnExceptionFromJS(false, true);
3856 caught->Call(env->Global(), 0, NULL);
3857 CHECK_EQ(0, exception_hit_count);
3858 CHECK_EQ(0, uncaught_exception_hit_count);
3859 CHECK_EQ(0, message_callback_count);
3860 notCaught->Call(env->Global(), 0, NULL);
3861 CHECK_EQ(1, exception_hit_count);
3862 CHECK_EQ(1, uncaught_exception_hit_count);
3863 CHECK_EQ(1, message_callback_count);
3864
3865 // Break on exception and uncaught exception using JavaScript
3866 DebugEventCounterClear();
3867 MessageCallbackCountClear();
3868 ChangeBreakOnExceptionFromJS(true, true);
3869 caught->Call(env->Global(), 0, NULL);
3870 CHECK_EQ(1, exception_hit_count);
3871 CHECK_EQ(0, message_callback_count);
3872 CHECK_EQ(0, uncaught_exception_hit_count);
3873 notCaught->Call(env->Global(), 0, NULL);
3874 CHECK_EQ(2, exception_hit_count);
3875 CHECK_EQ(1, uncaught_exception_hit_count);
3876 CHECK_EQ(1, message_callback_count);
3877
3878 // Break on exception using JavaScript
3879 DebugEventCounterClear();
3880 MessageCallbackCountClear();
3881 ChangeBreakOnExceptionFromJS(true, false);
3882 caught->Call(env->Global(), 0, NULL);
3883 CHECK_EQ(1, exception_hit_count);
3884 CHECK_EQ(0, uncaught_exception_hit_count);
3885 CHECK_EQ(0, message_callback_count);
3886 notCaught->Call(env->Global(), 0, NULL);
3887 CHECK_EQ(2, exception_hit_count);
3888 CHECK_EQ(1, uncaught_exception_hit_count);
3889 CHECK_EQ(1, message_callback_count);
3890
iposva@chromium.org245aa852009-02-10 00:49:54 +00003891 v8::Debug::SetDebugEventListener(NULL);
ager@chromium.org381abbb2009-02-25 13:23:22 +00003892 CheckDebuggerUnloaded();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003893 v8::V8::RemoveMessageListeners(MessageCallbackCount);
3894}
3895
3896
ager@chromium.org8bb60582008-12-11 12:02:20 +00003897// Test break on exception from compiler errors. When compiling using
3898// v8::Script::Compile there is no JavaScript stack whereas when compiling using
3899// eval there are JavaScript frames.
3900TEST(BreakOnCompileException) {
3901 v8::HandleScope scope;
3902 DebugLocalContext env;
3903
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00003904 // For this test, we want to break on uncaught exceptions:
3905 ChangeBreakOnException(false, true);
3906
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003907 v8::internal::Isolate::Current()->TraceException(false);
ager@chromium.org8bb60582008-12-11 12:02:20 +00003908
3909 // Create a function for checking the function when hitting a break point.
3910 frame_count = CompileFunction(&env, frame_count_source, "frame_count");
3911
3912 v8::V8::AddMessageListener(MessageCallbackCount);
iposva@chromium.org245aa852009-02-10 00:49:54 +00003913 v8::Debug::SetDebugEventListener(DebugEventCounter);
ager@chromium.org8bb60582008-12-11 12:02:20 +00003914
3915 DebugEventCounterClear();
3916 MessageCallbackCountClear();
3917
3918 // Check initial state.
3919 CHECK_EQ(0, exception_hit_count);
3920 CHECK_EQ(0, uncaught_exception_hit_count);
3921 CHECK_EQ(0, message_callback_count);
3922 CHECK_EQ(-1, last_js_stack_height);
3923
3924 // Throws SyntaxError: Unexpected end of input
3925 v8::Script::Compile(v8::String::New("+++"));
3926 CHECK_EQ(1, exception_hit_count);
3927 CHECK_EQ(1, uncaught_exception_hit_count);
3928 CHECK_EQ(1, message_callback_count);
3929 CHECK_EQ(0, last_js_stack_height); // No JavaScript stack.
3930
3931 // Throws SyntaxError: Unexpected identifier
3932 v8::Script::Compile(v8::String::New("x x"));
3933 CHECK_EQ(2, exception_hit_count);
3934 CHECK_EQ(2, uncaught_exception_hit_count);
3935 CHECK_EQ(2, message_callback_count);
3936 CHECK_EQ(0, last_js_stack_height); // No JavaScript stack.
3937
3938 // Throws SyntaxError: Unexpected end of input
3939 v8::Script::Compile(v8::String::New("eval('+++')"))->Run();
3940 CHECK_EQ(3, exception_hit_count);
3941 CHECK_EQ(3, uncaught_exception_hit_count);
3942 CHECK_EQ(3, message_callback_count);
3943 CHECK_EQ(1, last_js_stack_height);
3944
3945 // Throws SyntaxError: Unexpected identifier
3946 v8::Script::Compile(v8::String::New("eval('x x')"))->Run();
3947 CHECK_EQ(4, exception_hit_count);
3948 CHECK_EQ(4, uncaught_exception_hit_count);
3949 CHECK_EQ(4, message_callback_count);
3950 CHECK_EQ(1, last_js_stack_height);
3951}
3952
3953
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003954TEST(StepWithException) {
3955 v8::HandleScope scope;
3956 DebugLocalContext env;
3957
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00003958 // For this test, we want to break on uncaught exceptions:
3959 ChangeBreakOnException(false, true);
3960
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003961 // Create a function for checking the function when hitting a break point.
3962 frame_function_name = CompileFunction(&env,
3963 frame_function_name_source,
3964 "frame_function_name");
3965
3966 // Register a debug event listener which steps and counts.
iposva@chromium.org245aa852009-02-10 00:49:54 +00003967 v8::Debug::SetDebugEventListener(DebugEventStepSequence);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003968
3969 // Create functions for testing stepping.
3970 const char* src = "function a() { n(); }; "
3971 "function b() { c(); }; "
3972 "function c() { n(); }; "
3973 "function d() { x = 1; try { e(); } catch(x) { x = 2; } }; "
3974 "function e() { n(); }; "
3975 "function f() { x = 1; try { g(); } catch(x) { x = 2; } }; "
3976 "function g() { h(); }; "
3977 "function h() { x = 1; throw 1; }; ";
3978
3979 // Step through invocation of a.
3980 v8::Local<v8::Function> a = CompileFunction(&env, src, "a");
3981 SetBreakPoint(a, 0);
3982 step_action = StepIn;
3983 break_point_hit_count = 0;
3984 expected_step_sequence = "aa";
3985 a->Call(env->Global(), 0, NULL);
ager@chromium.orgc4c92722009-11-18 14:12:51 +00003986 CHECK_EQ(StrLength(expected_step_sequence),
3987 break_point_hit_count);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003988
3989 // Step through invocation of b + c.
3990 v8::Local<v8::Function> b = CompileFunction(&env, src, "b");
3991 SetBreakPoint(b, 0);
3992 step_action = StepIn;
3993 break_point_hit_count = 0;
3994 expected_step_sequence = "bcc";
3995 b->Call(env->Global(), 0, NULL);
ager@chromium.orgc4c92722009-11-18 14:12:51 +00003996 CHECK_EQ(StrLength(expected_step_sequence),
3997 break_point_hit_count);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003998 // Step through invocation of d + e.
3999 v8::Local<v8::Function> d = CompileFunction(&env, src, "d");
4000 SetBreakPoint(d, 0);
4001 ChangeBreakOnException(false, true);
4002 step_action = StepIn;
4003 break_point_hit_count = 0;
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +00004004 expected_step_sequence = "ddedd";
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004005 d->Call(env->Global(), 0, NULL);
ager@chromium.orgc4c92722009-11-18 14:12:51 +00004006 CHECK_EQ(StrLength(expected_step_sequence),
4007 break_point_hit_count);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004008
4009 // Step through invocation of d + e now with break on caught exceptions.
4010 ChangeBreakOnException(true, true);
4011 step_action = StepIn;
4012 break_point_hit_count = 0;
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +00004013 expected_step_sequence = "ddeedd";
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004014 d->Call(env->Global(), 0, NULL);
ager@chromium.orgc4c92722009-11-18 14:12:51 +00004015 CHECK_EQ(StrLength(expected_step_sequence),
4016 break_point_hit_count);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004017
4018 // Step through invocation of f + g + h.
4019 v8::Local<v8::Function> f = CompileFunction(&env, src, "f");
4020 SetBreakPoint(f, 0);
4021 ChangeBreakOnException(false, true);
4022 step_action = StepIn;
4023 break_point_hit_count = 0;
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +00004024 expected_step_sequence = "ffghhff";
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004025 f->Call(env->Global(), 0, NULL);
ager@chromium.orgc4c92722009-11-18 14:12:51 +00004026 CHECK_EQ(StrLength(expected_step_sequence),
4027 break_point_hit_count);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004028
4029 // Step through invocation of f + g + h now with break on caught exceptions.
4030 ChangeBreakOnException(true, true);
4031 step_action = StepIn;
4032 break_point_hit_count = 0;
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +00004033 expected_step_sequence = "ffghhhff";
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004034 f->Call(env->Global(), 0, NULL);
ager@chromium.orgc4c92722009-11-18 14:12:51 +00004035 CHECK_EQ(StrLength(expected_step_sequence),
4036 break_point_hit_count);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004037
4038 // Get rid of the debug event listener.
iposva@chromium.org245aa852009-02-10 00:49:54 +00004039 v8::Debug::SetDebugEventListener(NULL);
ager@chromium.org381abbb2009-02-25 13:23:22 +00004040 CheckDebuggerUnloaded();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004041}
4042
4043
4044TEST(DebugBreak) {
4045 v8::HandleScope scope;
4046 DebugLocalContext env;
4047
ager@chromium.org3a37e9b2009-04-27 09:26:21 +00004048 // This test should be run with option --verify-heap. As --verify-heap is
4049 // only available in debug mode only check for it in that case.
4050#ifdef DEBUG
4051 CHECK(v8::internal::FLAG_verify_heap);
4052#endif
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004053
4054 // Register a debug event listener which sets the break flag and counts.
iposva@chromium.org245aa852009-02-10 00:49:54 +00004055 v8::Debug::SetDebugEventListener(DebugEventBreak);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004056
4057 // Create a function for testing stepping.
4058 const char* src = "function f0() {}"
4059 "function f1(x1) {}"
4060 "function f2(x1,x2) {}"
4061 "function f3(x1,x2,x3) {}";
4062 v8::Local<v8::Function> f0 = CompileFunction(&env, src, "f0");
4063 v8::Local<v8::Function> f1 = CompileFunction(&env, src, "f1");
4064 v8::Local<v8::Function> f2 = CompileFunction(&env, src, "f2");
4065 v8::Local<v8::Function> f3 = CompileFunction(&env, src, "f3");
4066
4067 // Call the function to make sure it is compiled.
4068 v8::Handle<v8::Value> argv[] = { v8::Number::New(1),
4069 v8::Number::New(1),
4070 v8::Number::New(1),
4071 v8::Number::New(1) };
4072
4073 // Call all functions to make sure that they are compiled.
4074 f0->Call(env->Global(), 0, NULL);
4075 f1->Call(env->Global(), 0, NULL);
4076 f2->Call(env->Global(), 0, NULL);
4077 f3->Call(env->Global(), 0, NULL);
4078
4079 // Set the debug break flag.
4080 v8::Debug::DebugBreak();
4081
4082 // Call all functions with different argument count.
4083 break_point_hit_count = 0;
4084 for (unsigned int i = 0; i < ARRAY_SIZE(argv); i++) {
4085 f0->Call(env->Global(), i, argv);
4086 f1->Call(env->Global(), i, argv);
4087 f2->Call(env->Global(), i, argv);
4088 f3->Call(env->Global(), i, argv);
4089 }
4090
4091 // One break for each function called.
4092 CHECK_EQ(4 * ARRAY_SIZE(argv), break_point_hit_count);
4093
4094 // Get rid of the debug event listener.
iposva@chromium.org245aa852009-02-10 00:49:54 +00004095 v8::Debug::SetDebugEventListener(NULL);
ager@chromium.org381abbb2009-02-25 13:23:22 +00004096 CheckDebuggerUnloaded();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004097}
4098
4099
4100// Test to ensure that JavaScript code keeps running while the debug break
4101// through the stack limit flag is set but breaks are disabled.
4102TEST(DisableBreak) {
4103 v8::HandleScope scope;
4104 DebugLocalContext env;
4105
4106 // Register a debug event listener which sets the break flag and counts.
iposva@chromium.org245aa852009-02-10 00:49:54 +00004107 v8::Debug::SetDebugEventListener(DebugEventCounter);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004108
4109 // Create a function for testing stepping.
4110 const char* src = "function f() {g()};function g(){i=0; while(i<10){i++}}";
4111 v8::Local<v8::Function> f = CompileFunction(&env, src, "f");
4112
4113 // Set the debug break flag.
4114 v8::Debug::DebugBreak();
4115
4116 // Call all functions with different argument count.
4117 break_point_hit_count = 0;
4118 f->Call(env->Global(), 0, NULL);
4119 CHECK_EQ(1, break_point_hit_count);
4120
4121 {
4122 v8::Debug::DebugBreak();
4123 v8::internal::DisableBreak disable_break(true);
4124 f->Call(env->Global(), 0, NULL);
4125 CHECK_EQ(1, break_point_hit_count);
4126 }
4127
4128 f->Call(env->Global(), 0, NULL);
4129 CHECK_EQ(2, break_point_hit_count);
4130
4131 // Get rid of the debug event listener.
iposva@chromium.org245aa852009-02-10 00:49:54 +00004132 v8::Debug::SetDebugEventListener(NULL);
ager@chromium.org381abbb2009-02-25 13:23:22 +00004133 CheckDebuggerUnloaded();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004134}
4135
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +00004136static const char* kSimpleExtensionSource =
4137 "(function Foo() {"
4138 " return 4;"
4139 "})() ";
4140
4141// http://crbug.com/28933
4142// Test that debug break is disabled when bootstrapper is active.
4143TEST(NoBreakWhenBootstrapping) {
4144 v8::HandleScope scope;
4145
4146 // Register a debug event listener which sets the break flag and counts.
4147 v8::Debug::SetDebugEventListener(DebugEventCounter);
4148
4149 // Set the debug break flag.
4150 v8::Debug::DebugBreak();
4151 break_point_hit_count = 0;
4152 {
4153 // Create a context with an extension to make sure that some JavaScript
4154 // code is executed during bootstrapping.
4155 v8::RegisterExtension(new v8::Extension("simpletest",
4156 kSimpleExtensionSource));
4157 const char* extension_names[] = { "simpletest" };
4158 v8::ExtensionConfiguration extensions(1, extension_names);
4159 v8::Persistent<v8::Context> context = v8::Context::New(&extensions);
4160 context.Dispose();
4161 }
4162 // Check that no DebugBreak events occured during the context creation.
4163 CHECK_EQ(0, break_point_hit_count);
4164
4165 // Get rid of the debug event listener.
4166 v8::Debug::SetDebugEventListener(NULL);
4167 CheckDebuggerUnloaded();
4168}
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004169
4170static v8::Handle<v8::Array> NamedEnum(const v8::AccessorInfo&) {
4171 v8::Handle<v8::Array> result = v8::Array::New(3);
4172 result->Set(v8::Integer::New(0), v8::String::New("a"));
4173 result->Set(v8::Integer::New(1), v8::String::New("b"));
4174 result->Set(v8::Integer::New(2), v8::String::New("c"));
4175 return result;
4176}
4177
4178
4179static v8::Handle<v8::Array> IndexedEnum(const v8::AccessorInfo&) {
4180 v8::Handle<v8::Array> result = v8::Array::New(2);
4181 result->Set(v8::Integer::New(0), v8::Number::New(1));
4182 result->Set(v8::Integer::New(1), v8::Number::New(10));
4183 return result;
4184}
4185
4186
4187static v8::Handle<v8::Value> NamedGetter(v8::Local<v8::String> name,
4188 const v8::AccessorInfo& info) {
4189 v8::String::AsciiValue n(name);
4190 if (strcmp(*n, "a") == 0) {
4191 return v8::String::New("AA");
4192 } else if (strcmp(*n, "b") == 0) {
4193 return v8::String::New("BB");
4194 } else if (strcmp(*n, "c") == 0) {
4195 return v8::String::New("CC");
4196 } else {
4197 return v8::Undefined();
4198 }
4199
4200 return name;
4201}
4202
4203
4204static v8::Handle<v8::Value> IndexedGetter(uint32_t index,
4205 const v8::AccessorInfo& info) {
4206 return v8::Number::New(index + 1);
4207}
4208
4209
4210TEST(InterceptorPropertyMirror) {
4211 // Create a V8 environment with debug access.
4212 v8::HandleScope scope;
4213 DebugLocalContext env;
4214 env.ExposeDebug();
4215
4216 // Create object with named interceptor.
4217 v8::Handle<v8::ObjectTemplate> named = v8::ObjectTemplate::New();
4218 named->SetNamedPropertyHandler(NamedGetter, NULL, NULL, NULL, NamedEnum);
4219 env->Global()->Set(v8::String::New("intercepted_named"),
4220 named->NewInstance());
4221
4222 // Create object with indexed interceptor.
4223 v8::Handle<v8::ObjectTemplate> indexed = v8::ObjectTemplate::New();
4224 indexed->SetIndexedPropertyHandler(IndexedGetter,
4225 NULL,
4226 NULL,
4227 NULL,
4228 IndexedEnum);
4229 env->Global()->Set(v8::String::New("intercepted_indexed"),
4230 indexed->NewInstance());
4231
4232 // Create object with both named and indexed interceptor.
4233 v8::Handle<v8::ObjectTemplate> both = v8::ObjectTemplate::New();
4234 both->SetNamedPropertyHandler(NamedGetter, NULL, NULL, NULL, NamedEnum);
4235 both->SetIndexedPropertyHandler(IndexedGetter, NULL, NULL, NULL, IndexedEnum);
4236 env->Global()->Set(v8::String::New("intercepted_both"), both->NewInstance());
4237
4238 // Get mirrors for the three objects with interceptor.
4239 CompileRun(
4240 "named_mirror = debug.MakeMirror(intercepted_named);"
4241 "indexed_mirror = debug.MakeMirror(intercepted_indexed);"
4242 "both_mirror = debug.MakeMirror(intercepted_both)");
4243 CHECK(CompileRun(
4244 "named_mirror instanceof debug.ObjectMirror")->BooleanValue());
4245 CHECK(CompileRun(
4246 "indexed_mirror instanceof debug.ObjectMirror")->BooleanValue());
4247 CHECK(CompileRun(
4248 "both_mirror instanceof debug.ObjectMirror")->BooleanValue());
4249
4250 // Get the property names from the interceptors
4251 CompileRun(
ager@chromium.org32912102009-01-16 10:38:43 +00004252 "named_names = named_mirror.propertyNames();"
4253 "indexed_names = indexed_mirror.propertyNames();"
4254 "both_names = both_mirror.propertyNames()");
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004255 CHECK_EQ(3, CompileRun("named_names.length")->Int32Value());
4256 CHECK_EQ(2, CompileRun("indexed_names.length")->Int32Value());
4257 CHECK_EQ(5, CompileRun("both_names.length")->Int32Value());
4258
4259 // Check the expected number of properties.
4260 const char* source;
ager@chromium.org32912102009-01-16 10:38:43 +00004261 source = "named_mirror.properties().length";
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004262 CHECK_EQ(3, CompileRun(source)->Int32Value());
4263
ager@chromium.org32912102009-01-16 10:38:43 +00004264 source = "indexed_mirror.properties().length";
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004265 CHECK_EQ(2, CompileRun(source)->Int32Value());
4266
ager@chromium.org32912102009-01-16 10:38:43 +00004267 source = "both_mirror.properties().length";
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004268 CHECK_EQ(5, CompileRun(source)->Int32Value());
4269
ager@chromium.org32912102009-01-16 10:38:43 +00004270 // 1 is PropertyKind.Named;
4271 source = "both_mirror.properties(1).length";
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004272 CHECK_EQ(3, CompileRun(source)->Int32Value());
4273
ager@chromium.org32912102009-01-16 10:38:43 +00004274 // 2 is PropertyKind.Indexed;
4275 source = "both_mirror.properties(2).length";
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004276 CHECK_EQ(2, CompileRun(source)->Int32Value());
4277
ager@chromium.org32912102009-01-16 10:38:43 +00004278 // 3 is PropertyKind.Named | PropertyKind.Indexed;
4279 source = "both_mirror.properties(3).length";
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004280 CHECK_EQ(5, CompileRun(source)->Int32Value());
4281
ager@chromium.org32912102009-01-16 10:38:43 +00004282 // Get the interceptor properties for the object with only named interceptor.
4283 CompileRun("named_values = named_mirror.properties()");
4284
4285 // Check that the properties are interceptor properties.
4286 for (int i = 0; i < 3; i++) {
4287 EmbeddedVector<char, SMALL_STRING_BUFFER_SIZE> buffer;
4288 OS::SNPrintF(buffer,
4289 "named_values[%d] instanceof debug.PropertyMirror", i);
4290 CHECK(CompileRun(buffer.start())->BooleanValue());
4291
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004292 // 5 is PropertyType.Interceptor
ager@chromium.org32912102009-01-16 10:38:43 +00004293 OS::SNPrintF(buffer, "named_values[%d].propertyType()", i);
kmillikin@chromium.orgc53e10d2011-05-18 09:12:58 +00004294 CHECK_EQ(5, CompileRun(buffer.start())->Int32Value());
ager@chromium.org32912102009-01-16 10:38:43 +00004295
4296 OS::SNPrintF(buffer, "named_values[%d].isNative()", i);
4297 CHECK(CompileRun(buffer.start())->BooleanValue());
4298 }
4299
4300 // Get the interceptor properties for the object with only indexed
4301 // interceptor.
4302 CompileRun("indexed_values = indexed_mirror.properties()");
4303
4304 // Check that the properties are interceptor properties.
4305 for (int i = 0; i < 2; i++) {
4306 EmbeddedVector<char, SMALL_STRING_BUFFER_SIZE> buffer;
4307 OS::SNPrintF(buffer,
4308 "indexed_values[%d] instanceof debug.PropertyMirror", i);
4309 CHECK(CompileRun(buffer.start())->BooleanValue());
4310 }
4311
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004312 // Get the interceptor properties for the object with both types of
4313 // interceptors.
ager@chromium.org32912102009-01-16 10:38:43 +00004314 CompileRun("both_values = both_mirror.properties()");
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004315
ager@chromium.org32912102009-01-16 10:38:43 +00004316 // Check that the properties are interceptor properties.
4317 for (int i = 0; i < 5; i++) {
4318 EmbeddedVector<char, SMALL_STRING_BUFFER_SIZE> buffer;
4319 OS::SNPrintF(buffer, "both_values[%d] instanceof debug.PropertyMirror", i);
4320 CHECK(CompileRun(buffer.start())->BooleanValue());
4321 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004322
4323 // Check the property names.
4324 source = "both_values[0].name() == 'a'";
4325 CHECK(CompileRun(source)->BooleanValue());
4326
4327 source = "both_values[1].name() == 'b'";
4328 CHECK(CompileRun(source)->BooleanValue());
4329
4330 source = "both_values[2].name() == 'c'";
4331 CHECK(CompileRun(source)->BooleanValue());
4332
4333 source = "both_values[3].name() == 1";
4334 CHECK(CompileRun(source)->BooleanValue());
4335
4336 source = "both_values[4].name() == 10";
4337 CHECK(CompileRun(source)->BooleanValue());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004338}
4339
4340
ager@chromium.orgddb913d2009-01-27 10:01:48 +00004341TEST(HiddenPrototypePropertyMirror) {
4342 // Create a V8 environment with debug access.
4343 v8::HandleScope scope;
4344 DebugLocalContext env;
4345 env.ExposeDebug();
4346
4347 v8::Handle<v8::FunctionTemplate> t0 = v8::FunctionTemplate::New();
4348 t0->InstanceTemplate()->Set(v8::String::New("x"), v8::Number::New(0));
4349 v8::Handle<v8::FunctionTemplate> t1 = v8::FunctionTemplate::New();
4350 t1->SetHiddenPrototype(true);
4351 t1->InstanceTemplate()->Set(v8::String::New("y"), v8::Number::New(1));
4352 v8::Handle<v8::FunctionTemplate> t2 = v8::FunctionTemplate::New();
4353 t2->SetHiddenPrototype(true);
4354 t2->InstanceTemplate()->Set(v8::String::New("z"), v8::Number::New(2));
4355 v8::Handle<v8::FunctionTemplate> t3 = v8::FunctionTemplate::New();
4356 t3->InstanceTemplate()->Set(v8::String::New("u"), v8::Number::New(3));
4357
4358 // Create object and set them on the global object.
4359 v8::Handle<v8::Object> o0 = t0->GetFunction()->NewInstance();
4360 env->Global()->Set(v8::String::New("o0"), o0);
4361 v8::Handle<v8::Object> o1 = t1->GetFunction()->NewInstance();
4362 env->Global()->Set(v8::String::New("o1"), o1);
4363 v8::Handle<v8::Object> o2 = t2->GetFunction()->NewInstance();
4364 env->Global()->Set(v8::String::New("o2"), o2);
4365 v8::Handle<v8::Object> o3 = t3->GetFunction()->NewInstance();
4366 env->Global()->Set(v8::String::New("o3"), o3);
4367
4368 // Get mirrors for the four objects.
4369 CompileRun(
4370 "o0_mirror = debug.MakeMirror(o0);"
4371 "o1_mirror = debug.MakeMirror(o1);"
4372 "o2_mirror = debug.MakeMirror(o2);"
4373 "o3_mirror = debug.MakeMirror(o3)");
4374 CHECK(CompileRun("o0_mirror instanceof debug.ObjectMirror")->BooleanValue());
4375 CHECK(CompileRun("o1_mirror instanceof debug.ObjectMirror")->BooleanValue());
4376 CHECK(CompileRun("o2_mirror instanceof debug.ObjectMirror")->BooleanValue());
4377 CHECK(CompileRun("o3_mirror instanceof debug.ObjectMirror")->BooleanValue());
4378
4379 // Check that each object has one property.
4380 CHECK_EQ(1, CompileRun(
4381 "o0_mirror.propertyNames().length")->Int32Value());
4382 CHECK_EQ(1, CompileRun(
4383 "o1_mirror.propertyNames().length")->Int32Value());
4384 CHECK_EQ(1, CompileRun(
4385 "o2_mirror.propertyNames().length")->Int32Value());
4386 CHECK_EQ(1, CompileRun(
4387 "o3_mirror.propertyNames().length")->Int32Value());
4388
4389 // Set o1 as prototype for o0. o1 has the hidden prototype flag so all
4390 // properties on o1 should be seen on o0.
4391 o0->Set(v8::String::New("__proto__"), o1);
4392 CHECK_EQ(2, CompileRun(
4393 "o0_mirror.propertyNames().length")->Int32Value());
4394 CHECK_EQ(0, CompileRun(
4395 "o0_mirror.property('x').value().value()")->Int32Value());
4396 CHECK_EQ(1, CompileRun(
4397 "o0_mirror.property('y').value().value()")->Int32Value());
4398
4399 // Set o2 as prototype for o0 (it will end up after o1 as o1 has the hidden
4400 // prototype flag. o2 also has the hidden prototype flag so all properties
4401 // on o2 should be seen on o0 as well as properties on o1.
4402 o0->Set(v8::String::New("__proto__"), o2);
4403 CHECK_EQ(3, CompileRun(
4404 "o0_mirror.propertyNames().length")->Int32Value());
4405 CHECK_EQ(0, CompileRun(
4406 "o0_mirror.property('x').value().value()")->Int32Value());
4407 CHECK_EQ(1, CompileRun(
4408 "o0_mirror.property('y').value().value()")->Int32Value());
4409 CHECK_EQ(2, CompileRun(
4410 "o0_mirror.property('z').value().value()")->Int32Value());
4411
4412 // Set o3 as prototype for o0 (it will end up after o1 and o2 as both o1 and
4413 // o2 has the hidden prototype flag. o3 does not have the hidden prototype
4414 // flag so properties on o3 should not be seen on o0 whereas the properties
4415 // from o1 and o2 should still be seen on o0.
4416 // Final prototype chain: o0 -> o1 -> o2 -> o3
4417 // Hidden prototypes: ^^ ^^
4418 o0->Set(v8::String::New("__proto__"), o3);
4419 CHECK_EQ(3, CompileRun(
4420 "o0_mirror.propertyNames().length")->Int32Value());
4421 CHECK_EQ(1, CompileRun(
4422 "o3_mirror.propertyNames().length")->Int32Value());
4423 CHECK_EQ(0, CompileRun(
4424 "o0_mirror.property('x').value().value()")->Int32Value());
4425 CHECK_EQ(1, CompileRun(
4426 "o0_mirror.property('y').value().value()")->Int32Value());
4427 CHECK_EQ(2, CompileRun(
4428 "o0_mirror.property('z').value().value()")->Int32Value());
4429 CHECK(CompileRun("o0_mirror.property('u').isUndefined()")->BooleanValue());
4430
4431 // The prototype (__proto__) for o0 should be o3 as o1 and o2 are hidden.
4432 CHECK(CompileRun("o0_mirror.protoObject() == o3_mirror")->BooleanValue());
4433}
4434
4435
kasperl@chromium.org71affb52009-05-26 05:44:31 +00004436static v8::Handle<v8::Value> ProtperyXNativeGetter(
4437 v8::Local<v8::String> property, const v8::AccessorInfo& info) {
4438 return v8::Integer::New(10);
4439}
4440
4441
4442TEST(NativeGetterPropertyMirror) {
4443 // Create a V8 environment with debug access.
4444 v8::HandleScope scope;
4445 DebugLocalContext env;
4446 env.ExposeDebug();
4447
4448 v8::Handle<v8::String> name = v8::String::New("x");
4449 // Create object with named accessor.
4450 v8::Handle<v8::ObjectTemplate> named = v8::ObjectTemplate::New();
4451 named->SetAccessor(name, &ProtperyXNativeGetter, NULL,
4452 v8::Handle<v8::Value>(), v8::DEFAULT, v8::None);
4453
4454 // Create object with named property getter.
4455 env->Global()->Set(v8::String::New("instance"), named->NewInstance());
4456 CHECK_EQ(10, CompileRun("instance.x")->Int32Value());
4457
4458 // Get mirror for the object with property getter.
4459 CompileRun("instance_mirror = debug.MakeMirror(instance);");
4460 CHECK(CompileRun(
4461 "instance_mirror instanceof debug.ObjectMirror")->BooleanValue());
4462
4463 CompileRun("named_names = instance_mirror.propertyNames();");
4464 CHECK_EQ(1, CompileRun("named_names.length")->Int32Value());
4465 CHECK(CompileRun("named_names[0] == 'x'")->BooleanValue());
4466 CHECK(CompileRun(
4467 "instance_mirror.property('x').value().isNumber()")->BooleanValue());
4468 CHECK(CompileRun(
4469 "instance_mirror.property('x').value().value() == 10")->BooleanValue());
4470}
4471
4472
4473static v8::Handle<v8::Value> ProtperyXNativeGetterThrowingError(
4474 v8::Local<v8::String> property, const v8::AccessorInfo& info) {
4475 return CompileRun("throw new Error('Error message');");
4476}
4477
4478
4479TEST(NativeGetterThrowingErrorPropertyMirror) {
4480 // Create a V8 environment with debug access.
4481 v8::HandleScope scope;
4482 DebugLocalContext env;
4483 env.ExposeDebug();
4484
4485 v8::Handle<v8::String> name = v8::String::New("x");
4486 // Create object with named accessor.
4487 v8::Handle<v8::ObjectTemplate> named = v8::ObjectTemplate::New();
4488 named->SetAccessor(name, &ProtperyXNativeGetterThrowingError, NULL,
4489 v8::Handle<v8::Value>(), v8::DEFAULT, v8::None);
4490
4491 // Create object with named property getter.
4492 env->Global()->Set(v8::String::New("instance"), named->NewInstance());
4493
4494 // Get mirror for the object with property getter.
4495 CompileRun("instance_mirror = debug.MakeMirror(instance);");
4496 CHECK(CompileRun(
4497 "instance_mirror instanceof debug.ObjectMirror")->BooleanValue());
4498 CompileRun("named_names = instance_mirror.propertyNames();");
4499 CHECK_EQ(1, CompileRun("named_names.length")->Int32Value());
4500 CHECK(CompileRun("named_names[0] == 'x'")->BooleanValue());
4501 CHECK(CompileRun(
4502 "instance_mirror.property('x').value().isError()")->BooleanValue());
4503
4504 // Check that the message is that passed to the Error constructor.
4505 CHECK(CompileRun(
4506 "instance_mirror.property('x').value().message() == 'Error message'")->
4507 BooleanValue());
4508}
4509
4510
ager@chromium.orgc730f772009-11-11 10:11:16 +00004511// Test that hidden properties object is not returned as an unnamed property
4512// among regular properties.
4513// See http://crbug.com/26491
4514TEST(NoHiddenProperties) {
4515 // Create a V8 environment with debug access.
4516 v8::HandleScope scope;
4517 DebugLocalContext env;
4518 env.ExposeDebug();
4519
4520 // Create an object in the global scope.
4521 const char* source = "var obj = {a: 1};";
4522 v8::Script::Compile(v8::String::New(source))->Run();
4523 v8::Local<v8::Object> obj = v8::Local<v8::Object>::Cast(
4524 env->Global()->Get(v8::String::New("obj")));
4525 // Set a hidden property on the object.
4526 obj->SetHiddenValue(v8::String::New("v8::test-debug::a"),
4527 v8::Int32::New(11));
4528
4529 // Get mirror for the object with property getter.
4530 CompileRun("var obj_mirror = debug.MakeMirror(obj);");
4531 CHECK(CompileRun(
4532 "obj_mirror instanceof debug.ObjectMirror")->BooleanValue());
4533 CompileRun("var named_names = obj_mirror.propertyNames();");
4534 // There should be exactly one property. But there is also an unnamed
4535 // property whose value is hidden properties dictionary. The latter
4536 // property should not be in the list of reguar properties.
4537 CHECK_EQ(1, CompileRun("named_names.length")->Int32Value());
4538 CHECK(CompileRun("named_names[0] == 'a'")->BooleanValue());
4539 CHECK(CompileRun(
4540 "obj_mirror.property('a').value().value() == 1")->BooleanValue());
4541
4542 // Object created by t0 will become hidden prototype of object 'obj'.
4543 v8::Handle<v8::FunctionTemplate> t0 = v8::FunctionTemplate::New();
4544 t0->InstanceTemplate()->Set(v8::String::New("b"), v8::Number::New(2));
4545 t0->SetHiddenPrototype(true);
4546 v8::Handle<v8::FunctionTemplate> t1 = v8::FunctionTemplate::New();
4547 t1->InstanceTemplate()->Set(v8::String::New("c"), v8::Number::New(3));
4548
4549 // Create proto objects, add hidden properties to them and set them on
4550 // the global object.
4551 v8::Handle<v8::Object> protoObj = t0->GetFunction()->NewInstance();
4552 protoObj->SetHiddenValue(v8::String::New("v8::test-debug::b"),
4553 v8::Int32::New(12));
4554 env->Global()->Set(v8::String::New("protoObj"), protoObj);
4555 v8::Handle<v8::Object> grandProtoObj = t1->GetFunction()->NewInstance();
4556 grandProtoObj->SetHiddenValue(v8::String::New("v8::test-debug::c"),
4557 v8::Int32::New(13));
4558 env->Global()->Set(v8::String::New("grandProtoObj"), grandProtoObj);
4559
4560 // Setting prototypes: obj->protoObj->grandProtoObj
4561 protoObj->Set(v8::String::New("__proto__"), grandProtoObj);
4562 obj->Set(v8::String::New("__proto__"), protoObj);
4563
4564 // Get mirror for the object with property getter.
4565 CompileRun("var obj_mirror = debug.MakeMirror(obj);");
4566 CHECK(CompileRun(
4567 "obj_mirror instanceof debug.ObjectMirror")->BooleanValue());
4568 CompileRun("var named_names = obj_mirror.propertyNames();");
4569 // There should be exactly two properties - one from the object itself and
4570 // another from its hidden prototype.
4571 CHECK_EQ(2, CompileRun("named_names.length")->Int32Value());
4572 CHECK(CompileRun("named_names.sort(); named_names[0] == 'a' &&"
4573 "named_names[1] == 'b'")->BooleanValue());
4574 CHECK(CompileRun(
4575 "obj_mirror.property('a').value().value() == 1")->BooleanValue());
4576 CHECK(CompileRun(
4577 "obj_mirror.property('b').value().value() == 2")->BooleanValue());
4578}
4579
kasperl@chromium.org71affb52009-05-26 05:44:31 +00004580
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004581// Multithreaded tests of JSON debugger protocol
4582
4583// Support classes
4584
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004585// Provides synchronization between k threads, where k is an input to the
4586// constructor. The Wait() call blocks a thread until it is called for the
4587// k'th time, then all calls return. Each ThreadBarrier object can only
4588// be used once.
4589class ThreadBarrier {
4590 public:
4591 explicit ThreadBarrier(int num_threads);
4592 ~ThreadBarrier();
4593 void Wait();
4594 private:
4595 int num_threads_;
4596 int num_blocked_;
4597 v8::internal::Mutex* lock_;
4598 v8::internal::Semaphore* sem_;
4599 bool invalid_;
4600};
4601
4602ThreadBarrier::ThreadBarrier(int num_threads)
4603 : num_threads_(num_threads), num_blocked_(0) {
4604 lock_ = OS::CreateMutex();
4605 sem_ = OS::CreateSemaphore(0);
4606 invalid_ = false; // A barrier may only be used once. Then it is invalid.
4607}
4608
4609// Do not call, due to race condition with Wait().
4610// Could be resolved with Pthread condition variables.
4611ThreadBarrier::~ThreadBarrier() {
4612 lock_->Lock();
4613 delete lock_;
4614 delete sem_;
4615}
4616
4617void ThreadBarrier::Wait() {
4618 lock_->Lock();
ager@chromium.org3a37e9b2009-04-27 09:26:21 +00004619 CHECK(!invalid_);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004620 if (num_blocked_ == num_threads_ - 1) {
4621 // Signal and unblock all waiting threads.
4622 for (int i = 0; i < num_threads_ - 1; ++i) {
4623 sem_->Signal();
4624 }
4625 invalid_ = true;
4626 printf("BARRIER\n\n");
4627 fflush(stdout);
4628 lock_->Unlock();
4629 } else { // Wait for the semaphore.
4630 ++num_blocked_;
4631 lock_->Unlock(); // Potential race condition with destructor because
4632 sem_->Wait(); // these two lines are not atomic.
4633 }
4634}
4635
4636// A set containing enough barriers and semaphores for any of the tests.
4637class Barriers {
4638 public:
4639 Barriers();
4640 void Initialize();
4641 ThreadBarrier barrier_1;
4642 ThreadBarrier barrier_2;
4643 ThreadBarrier barrier_3;
4644 ThreadBarrier barrier_4;
4645 ThreadBarrier barrier_5;
4646 v8::internal::Semaphore* semaphore_1;
4647 v8::internal::Semaphore* semaphore_2;
4648};
4649
4650Barriers::Barriers() : barrier_1(2), barrier_2(2),
4651 barrier_3(2), barrier_4(2), barrier_5(2) {}
4652
4653void Barriers::Initialize() {
4654 semaphore_1 = OS::CreateSemaphore(0);
4655 semaphore_2 = OS::CreateSemaphore(0);
4656}
4657
4658
ager@chromium.org9258b6b2008-09-11 09:11:10 +00004659// We match parts of the message to decide if it is a break message.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004660bool IsBreakEventMessage(char *message) {
ager@chromium.org9258b6b2008-09-11 09:11:10 +00004661 const char* type_event = "\"type\":\"event\"";
4662 const char* event_break = "\"event\":\"break\"";
4663 // Does the message contain both type:event and event:break?
4664 return strstr(message, type_event) != NULL &&
4665 strstr(message, event_break) != NULL;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004666}
4667
4668
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00004669// We match parts of the message to decide if it is a exception message.
4670bool IsExceptionEventMessage(char *message) {
4671 const char* type_event = "\"type\":\"event\"";
4672 const char* event_exception = "\"event\":\"exception\"";
4673 // Does the message contain both type:event and event:exception?
4674 return strstr(message, type_event) != NULL &&
4675 strstr(message, event_exception) != NULL;
4676}
4677
4678
4679// We match the message wether it is an evaluate response message.
4680bool IsEvaluateResponseMessage(char* message) {
4681 const char* type_response = "\"type\":\"response\"";
4682 const char* command_evaluate = "\"command\":\"evaluate\"";
4683 // Does the message contain both type:response and command:evaluate?
4684 return strstr(message, type_response) != NULL &&
4685 strstr(message, command_evaluate) != NULL;
4686}
4687
4688
ager@chromium.org5c838252010-02-19 08:53:10 +00004689static int StringToInt(const char* s) {
4690 return atoi(s); // NOLINT
4691}
4692
4693
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00004694// We match parts of the message to get evaluate result int value.
4695int GetEvaluateIntResult(char *message) {
4696 const char* value = "\"value\":";
4697 char* pos = strstr(message, value);
4698 if (pos == NULL) {
4699 return -1;
4700 }
4701 int res = -1;
ager@chromium.org5c838252010-02-19 08:53:10 +00004702 res = StringToInt(pos + strlen(value));
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00004703 return res;
4704}
4705
4706
4707// We match parts of the message to get hit breakpoint id.
4708int GetBreakpointIdFromBreakEventMessage(char *message) {
4709 const char* breakpoints = "\"breakpoints\":[";
4710 char* pos = strstr(message, breakpoints);
4711 if (pos == NULL) {
4712 return -1;
4713 }
4714 int res = -1;
ager@chromium.org5c838252010-02-19 08:53:10 +00004715 res = StringToInt(pos + strlen(breakpoints));
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00004716 return res;
4717}
4718
4719
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004720// We match parts of the message to get total frames number.
4721int GetTotalFramesInt(char *message) {
4722 const char* prefix = "\"totalFrames\":";
4723 char* pos = strstr(message, prefix);
4724 if (pos == NULL) {
4725 return -1;
4726 }
4727 pos += strlen(prefix);
ager@chromium.org5c838252010-02-19 08:53:10 +00004728 int res = StringToInt(pos);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004729 return res;
4730}
4731
4732
ager@chromium.org5b2fbee2010-09-08 06:38:15 +00004733// We match parts of the message to get source line.
4734int GetSourceLineFromBreakEventMessage(char *message) {
4735 const char* source_line = "\"sourceLine\":";
4736 char* pos = strstr(message, source_line);
4737 if (pos == NULL) {
4738 return -1;
4739 }
4740 int res = -1;
4741 res = StringToInt(pos + strlen(source_line));
4742 return res;
4743}
4744
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004745/* Test MessageQueues */
4746/* Tests the message queues that hold debugger commands and
4747 * response messages to the debugger. Fills queues and makes
4748 * them grow.
4749 */
4750Barriers message_queue_barriers;
4751
4752// This is the debugger thread, that executes no v8 calls except
4753// placing JSON debugger commands in the queue.
4754class MessageQueueDebuggerThread : public v8::internal::Thread {
4755 public:
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004756 MessageQueueDebuggerThread()
4757 : Thread("MessageQueueDebuggerThread") { }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004758 void Run();
4759};
4760
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004761static void MessageHandler(const uint16_t* message, int length,
4762 v8::Debug::ClientData* client_data) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004763 static char print_buffer[1000];
4764 Utf16ToAscii(message, length, print_buffer);
4765 if (IsBreakEventMessage(print_buffer)) {
4766 // Lets test script wait until break occurs to send commands.
4767 // Signals when a break is reported.
4768 message_queue_barriers.semaphore_2->Signal();
4769 }
ager@chromium.org5ec48922009-05-05 07:25:34 +00004770
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004771 // Allow message handler to block on a semaphore, to test queueing of
4772 // messages while blocked.
4773 message_queue_barriers.semaphore_1->Wait();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004774}
4775
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004776void MessageQueueDebuggerThread::Run() {
4777 const int kBufferSize = 1000;
4778 uint16_t buffer_1[kBufferSize];
4779 uint16_t buffer_2[kBufferSize];
4780 const char* command_1 =
4781 "{\"seq\":117,"
4782 "\"type\":\"request\","
4783 "\"command\":\"evaluate\","
4784 "\"arguments\":{\"expression\":\"1+2\"}}";
4785 const char* command_2 =
4786 "{\"seq\":118,"
4787 "\"type\":\"request\","
4788 "\"command\":\"evaluate\","
4789 "\"arguments\":{\"expression\":\"1+a\"}}";
4790 const char* command_3 =
4791 "{\"seq\":119,"
4792 "\"type\":\"request\","
4793 "\"command\":\"evaluate\","
4794 "\"arguments\":{\"expression\":\"c.d * b\"}}";
4795 const char* command_continue =
4796 "{\"seq\":106,"
4797 "\"type\":\"request\","
4798 "\"command\":\"continue\"}";
4799 const char* command_single_step =
4800 "{\"seq\":107,"
4801 "\"type\":\"request\","
4802 "\"command\":\"continue\","
4803 "\"arguments\":{\"stepaction\":\"next\"}}";
4804
4805 /* Interleaved sequence of actions by the two threads:*/
4806 // Main thread compiles and runs source_1
ager@chromium.org5ec48922009-05-05 07:25:34 +00004807 message_queue_barriers.semaphore_1->Signal();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004808 message_queue_barriers.barrier_1.Wait();
4809 // Post 6 commands, filling the command queue and making it expand.
4810 // These calls return immediately, but the commands stay on the queue
4811 // until the execution of source_2.
4812 // Note: AsciiToUtf16 executes before SendCommand, so command is copied
4813 // to buffer before buffer is sent to SendCommand.
4814 v8::Debug::SendCommand(buffer_1, AsciiToUtf16(command_1, buffer_1));
4815 v8::Debug::SendCommand(buffer_2, AsciiToUtf16(command_2, buffer_2));
4816 v8::Debug::SendCommand(buffer_2, AsciiToUtf16(command_3, buffer_2));
4817 v8::Debug::SendCommand(buffer_2, AsciiToUtf16(command_3, buffer_2));
4818 v8::Debug::SendCommand(buffer_2, AsciiToUtf16(command_3, buffer_2));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004819 message_queue_barriers.barrier_2.Wait();
4820 // Main thread compiles and runs source_2.
ager@chromium.org5ec48922009-05-05 07:25:34 +00004821 // Queued commands are executed at the start of compilation of source_2(
4822 // beforeCompile event).
4823 // Free the message handler to process all the messages from the queue. 7
4824 // messages are expected: 2 afterCompile events and 5 responses.
4825 // All the commands added so far will fail to execute as long as call stack
4826 // is empty on beforeCompile event.
4827 for (int i = 0; i < 6 ; ++i) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004828 message_queue_barriers.semaphore_1->Signal();
4829 }
ager@chromium.org5ec48922009-05-05 07:25:34 +00004830 message_queue_barriers.barrier_3.Wait();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004831 // Main thread compiles and runs source_3.
ager@chromium.org5ec48922009-05-05 07:25:34 +00004832 // Don't stop in the afterCompile handler.
4833 message_queue_barriers.semaphore_1->Signal();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004834 // source_3 includes a debugger statement, which causes a break event.
4835 // Wait on break event from hitting "debugger" statement
4836 message_queue_barriers.semaphore_2->Wait();
4837 // These should execute after the "debugger" statement in source_2
ager@chromium.org5ec48922009-05-05 07:25:34 +00004838 v8::Debug::SendCommand(buffer_1, AsciiToUtf16(command_1, buffer_1));
4839 v8::Debug::SendCommand(buffer_2, AsciiToUtf16(command_2, buffer_2));
4840 v8::Debug::SendCommand(buffer_2, AsciiToUtf16(command_3, buffer_2));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004841 v8::Debug::SendCommand(buffer_2, AsciiToUtf16(command_single_step, buffer_2));
ager@chromium.org5ec48922009-05-05 07:25:34 +00004842 // Run after 2 break events, 4 responses.
4843 for (int i = 0; i < 6 ; ++i) {
4844 message_queue_barriers.semaphore_1->Signal();
4845 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004846 // Wait on break event after a single step executes.
4847 message_queue_barriers.semaphore_2->Wait();
4848 v8::Debug::SendCommand(buffer_1, AsciiToUtf16(command_2, buffer_1));
4849 v8::Debug::SendCommand(buffer_2, AsciiToUtf16(command_continue, buffer_2));
ager@chromium.org5ec48922009-05-05 07:25:34 +00004850 // Run after 2 responses.
4851 for (int i = 0; i < 2 ; ++i) {
4852 message_queue_barriers.semaphore_1->Signal();
4853 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004854 // Main thread continues running source_3 to end, waits for this thread.
4855}
4856
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004857
4858// This thread runs the v8 engine.
4859TEST(MessageQueues) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004860 MessageQueueDebuggerThread message_queue_debugger_thread;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004861
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004862 // Create a V8 environment
4863 v8::HandleScope scope;
4864 DebugLocalContext env;
4865 message_queue_barriers.Initialize();
4866 v8::Debug::SetMessageHandler(MessageHandler);
4867 message_queue_debugger_thread.Start();
4868
4869 const char* source_1 = "a = 3; b = 4; c = new Object(); c.d = 5;";
4870 const char* source_2 = "e = 17;";
4871 const char* source_3 = "a = 4; debugger; a = 5; a = 6; a = 7;";
4872
4873 // See MessageQueueDebuggerThread::Run for interleaved sequence of
4874 // API calls and events in the two threads.
4875 CompileRun(source_1);
4876 message_queue_barriers.barrier_1.Wait();
4877 message_queue_barriers.barrier_2.Wait();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004878 CompileRun(source_2);
4879 message_queue_barriers.barrier_3.Wait();
4880 CompileRun(source_3);
4881 message_queue_debugger_thread.Join();
4882 fflush(stdout);
4883}
4884
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004885
4886class TestClientData : public v8::Debug::ClientData {
4887 public:
4888 TestClientData() {
4889 constructor_call_counter++;
4890 }
4891 virtual ~TestClientData() {
4892 destructor_call_counter++;
4893 }
4894
4895 static void ResetCounters() {
4896 constructor_call_counter = 0;
4897 destructor_call_counter = 0;
4898 }
4899
4900 static int constructor_call_counter;
4901 static int destructor_call_counter;
4902};
4903
4904int TestClientData::constructor_call_counter = 0;
4905int TestClientData::destructor_call_counter = 0;
4906
4907
4908// Tests that MessageQueue doesn't destroy client data when expands and
4909// does destroy when it dies.
4910TEST(MessageQueueExpandAndDestroy) {
4911 TestClientData::ResetCounters();
4912 { // Create a scope for the queue.
ager@chromium.org3a37e9b2009-04-27 09:26:21 +00004913 CommandMessageQueue queue(1);
4914 queue.Put(CommandMessage::New(Vector<uint16_t>::empty(),
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004915 new TestClientData()));
ager@chromium.org3a37e9b2009-04-27 09:26:21 +00004916 queue.Put(CommandMessage::New(Vector<uint16_t>::empty(),
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004917 new TestClientData()));
ager@chromium.org3a37e9b2009-04-27 09:26:21 +00004918 queue.Put(CommandMessage::New(Vector<uint16_t>::empty(),
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004919 new TestClientData()));
ager@chromium.org3a37e9b2009-04-27 09:26:21 +00004920 CHECK_EQ(0, TestClientData::destructor_call_counter);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004921 queue.Get().Dispose();
ager@chromium.org3a37e9b2009-04-27 09:26:21 +00004922 CHECK_EQ(1, TestClientData::destructor_call_counter);
4923 queue.Put(CommandMessage::New(Vector<uint16_t>::empty(),
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004924 new TestClientData()));
ager@chromium.org3a37e9b2009-04-27 09:26:21 +00004925 queue.Put(CommandMessage::New(Vector<uint16_t>::empty(),
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004926 new TestClientData()));
ager@chromium.org3a37e9b2009-04-27 09:26:21 +00004927 queue.Put(CommandMessage::New(Vector<uint16_t>::empty(),
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004928 new TestClientData()));
ager@chromium.org3a37e9b2009-04-27 09:26:21 +00004929 queue.Put(CommandMessage::New(Vector<uint16_t>::empty(),
4930 new TestClientData()));
4931 queue.Put(CommandMessage::New(Vector<uint16_t>::empty(),
4932 new TestClientData()));
4933 CHECK_EQ(1, TestClientData::destructor_call_counter);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004934 queue.Get().Dispose();
ager@chromium.org3a37e9b2009-04-27 09:26:21 +00004935 CHECK_EQ(2, TestClientData::destructor_call_counter);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004936 }
4937 // All the client data should be destroyed when the queue is destroyed.
ager@chromium.org3a37e9b2009-04-27 09:26:21 +00004938 CHECK_EQ(TestClientData::destructor_call_counter,
4939 TestClientData::destructor_call_counter);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004940}
4941
4942
4943static int handled_client_data_instances_count = 0;
4944static void MessageHandlerCountingClientData(
ager@chromium.org5ec48922009-05-05 07:25:34 +00004945 const v8::Debug::Message& message) {
4946 if (message.GetClientData() != NULL) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004947 handled_client_data_instances_count++;
4948 }
4949}
4950
4951
4952// Tests that all client data passed to the debugger are sent to the handler.
4953TEST(SendClientDataToHandler) {
4954 // Create a V8 environment
4955 v8::HandleScope scope;
4956 DebugLocalContext env;
4957 TestClientData::ResetCounters();
4958 handled_client_data_instances_count = 0;
ager@chromium.org5ec48922009-05-05 07:25:34 +00004959 v8::Debug::SetMessageHandler2(MessageHandlerCountingClientData);
4960 const char* source_1 = "a = 3; b = 4; c = new Object(); c.d = 5;";
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004961 const int kBufferSize = 1000;
4962 uint16_t buffer[kBufferSize];
4963 const char* command_1 =
4964 "{\"seq\":117,"
4965 "\"type\":\"request\","
4966 "\"command\":\"evaluate\","
4967 "\"arguments\":{\"expression\":\"1+2\"}}";
4968 const char* command_2 =
4969 "{\"seq\":118,"
4970 "\"type\":\"request\","
4971 "\"command\":\"evaluate\","
4972 "\"arguments\":{\"expression\":\"1+a\"}}";
4973 const char* command_continue =
4974 "{\"seq\":106,"
4975 "\"type\":\"request\","
4976 "\"command\":\"continue\"}";
4977
4978 v8::Debug::SendCommand(buffer, AsciiToUtf16(command_1, buffer),
4979 new TestClientData());
4980 v8::Debug::SendCommand(buffer, AsciiToUtf16(command_2, buffer), NULL);
4981 v8::Debug::SendCommand(buffer, AsciiToUtf16(command_2, buffer),
4982 new TestClientData());
4983 v8::Debug::SendCommand(buffer, AsciiToUtf16(command_2, buffer),
4984 new TestClientData());
ager@chromium.org5ec48922009-05-05 07:25:34 +00004985 // All the messages will be processed on beforeCompile event.
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004986 CompileRun(source_1);
ager@chromium.org5ec48922009-05-05 07:25:34 +00004987 v8::Debug::SendCommand(buffer, AsciiToUtf16(command_continue, buffer));
ager@chromium.org3a37e9b2009-04-27 09:26:21 +00004988 CHECK_EQ(3, TestClientData::constructor_call_counter);
4989 CHECK_EQ(TestClientData::constructor_call_counter,
4990 handled_client_data_instances_count);
4991 CHECK_EQ(TestClientData::constructor_call_counter,
4992 TestClientData::destructor_call_counter);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004993}
4994
4995
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004996/* Test ThreadedDebugging */
4997/* This test interrupts a running infinite loop that is
4998 * occupying the v8 thread by a break command from the
4999 * debugger thread. It then changes the value of a
5000 * global object, to make the loop terminate.
5001 */
5002
5003Barriers threaded_debugging_barriers;
5004
5005class V8Thread : public v8::internal::Thread {
5006 public:
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00005007 V8Thread() : Thread("V8Thread") { }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005008 void Run();
5009};
5010
5011class DebuggerThread : public v8::internal::Thread {
5012 public:
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00005013 DebuggerThread() : Thread("DebuggerThread") { }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005014 void Run();
5015};
5016
5017
kasperl@chromium.orgacae3782009-04-11 09:17:08 +00005018static v8::Handle<v8::Value> ThreadedAtBarrier1(const v8::Arguments& args) {
5019 threaded_debugging_barriers.barrier_1.Wait();
5020 return v8::Undefined();
5021}
5022
5023
ager@chromium.org5ec48922009-05-05 07:25:34 +00005024static void ThreadedMessageHandler(const v8::Debug::Message& message) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005025 static char print_buffer[1000];
ager@chromium.org5ec48922009-05-05 07:25:34 +00005026 v8::String::Value json(message.GetJSON());
5027 Utf16ToAscii(*json, json.length(), print_buffer);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005028 if (IsBreakEventMessage(print_buffer)) {
ager@chromium.org5b2fbee2010-09-08 06:38:15 +00005029 // Check that we are inside the while loop.
5030 int source_line = GetSourceLineFromBreakEventMessage(print_buffer);
5031 CHECK(8 <= source_line && source_line <= 13);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005032 threaded_debugging_barriers.barrier_2.Wait();
5033 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005034}
5035
5036
5037void V8Thread::Run() {
kasperl@chromium.orgacae3782009-04-11 09:17:08 +00005038 const char* source =
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005039 "flag = true;\n"
5040 "function bar( new_value ) {\n"
5041 " flag = new_value;\n"
5042 " return \"Return from bar(\" + new_value + \")\";\n"
5043 "}\n"
5044 "\n"
5045 "function foo() {\n"
5046 " var x = 1;\n"
5047 " while ( flag == true ) {\n"
kasperl@chromium.orgacae3782009-04-11 09:17:08 +00005048 " if ( x == 1 ) {\n"
5049 " ThreadedAtBarrier1();\n"
5050 " }\n"
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005051 " x = x + 1;\n"
5052 " }\n"
5053 "}\n"
kasperl@chromium.orgacae3782009-04-11 09:17:08 +00005054 "\n"
5055 "foo();\n";
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005056
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00005057 v8::V8::Initialize();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005058 v8::HandleScope scope;
5059 DebugLocalContext env;
ager@chromium.org5ec48922009-05-05 07:25:34 +00005060 v8::Debug::SetMessageHandler2(&ThreadedMessageHandler);
kasperl@chromium.orgacae3782009-04-11 09:17:08 +00005061 v8::Handle<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New();
5062 global_template->Set(v8::String::New("ThreadedAtBarrier1"),
5063 v8::FunctionTemplate::New(ThreadedAtBarrier1));
5064 v8::Handle<v8::Context> context = v8::Context::New(NULL, global_template);
5065 v8::Context::Scope context_scope(context);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005066
kasperl@chromium.orgacae3782009-04-11 09:17:08 +00005067 CompileRun(source);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005068}
5069
5070void DebuggerThread::Run() {
5071 const int kBufSize = 1000;
5072 uint16_t buffer[kBufSize];
5073
5074 const char* command_1 = "{\"seq\":102,"
5075 "\"type\":\"request\","
5076 "\"command\":\"evaluate\","
5077 "\"arguments\":{\"expression\":\"bar(false)\"}}";
5078 const char* command_2 = "{\"seq\":103,"
5079 "\"type\":\"request\","
5080 "\"command\":\"continue\"}";
5081
5082 threaded_debugging_barriers.barrier_1.Wait();
5083 v8::Debug::DebugBreak();
5084 threaded_debugging_barriers.barrier_2.Wait();
5085 v8::Debug::SendCommand(buffer, AsciiToUtf16(command_1, buffer));
5086 v8::Debug::SendCommand(buffer, AsciiToUtf16(command_2, buffer));
5087}
5088
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005089
5090TEST(ThreadedDebugging) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00005091 DebuggerThread debugger_thread;
5092 V8Thread v8_thread;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005093
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005094 // Create a V8 environment
5095 threaded_debugging_barriers.Initialize();
5096
5097 v8_thread.Start();
5098 debugger_thread.Start();
5099
5100 v8_thread.Join();
5101 debugger_thread.Join();
5102}
5103
5104/* Test RecursiveBreakpoints */
5105/* In this test, the debugger evaluates a function with a breakpoint, after
5106 * hitting a breakpoint in another function. We do this with both values
5107 * of the flag enabling recursive breakpoints, and verify that the second
5108 * breakpoint is hit when enabled, and missed when disabled.
5109 */
5110
5111class BreakpointsV8Thread : public v8::internal::Thread {
5112 public:
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00005113 BreakpointsV8Thread() : Thread("BreakpointsV8Thread") { }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005114 void Run();
5115};
5116
5117class BreakpointsDebuggerThread : public v8::internal::Thread {
5118 public:
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00005119 explicit BreakpointsDebuggerThread(bool global_evaluate)
5120 : Thread("BreakpointsDebuggerThread"),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005121 global_evaluate_(global_evaluate) {}
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005122 void Run();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005123
5124 private:
5125 bool global_evaluate_;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005126};
5127
5128
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005129Barriers* breakpoints_barriers;
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00005130int break_event_breakpoint_id;
5131int evaluate_int_result;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005132
ager@chromium.org5ec48922009-05-05 07:25:34 +00005133static void BreakpointsMessageHandler(const v8::Debug::Message& message) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005134 static char print_buffer[1000];
ager@chromium.org5ec48922009-05-05 07:25:34 +00005135 v8::String::Value json(message.GetJSON());
5136 Utf16ToAscii(*json, json.length(), print_buffer);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005137
ager@chromium.org9258b6b2008-09-11 09:11:10 +00005138 if (IsBreakEventMessage(print_buffer)) {
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00005139 break_event_breakpoint_id =
5140 GetBreakpointIdFromBreakEventMessage(print_buffer);
5141 breakpoints_barriers->semaphore_1->Signal();
5142 } else if (IsEvaluateResponseMessage(print_buffer)) {
5143 evaluate_int_result = GetEvaluateIntResult(print_buffer);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005144 breakpoints_barriers->semaphore_1->Signal();
5145 }
5146}
5147
5148
5149void BreakpointsV8Thread::Run() {
5150 const char* source_1 = "var y_global = 3;\n"
5151 "function cat( new_value ) {\n"
5152 " var x = new_value;\n"
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00005153 " y_global = y_global + 4;\n"
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005154 " x = 3 * x + 1;\n"
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00005155 " y_global = y_global + 5;\n"
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005156 " return x;\n"
5157 "}\n"
5158 "\n"
5159 "function dog() {\n"
5160 " var x = 1;\n"
5161 " x = y_global;"
5162 " var z = 3;"
5163 " x += 100;\n"
5164 " return x;\n"
5165 "}\n"
5166 "\n";
5167 const char* source_2 = "cat(17);\n"
5168 "cat(19);\n";
5169
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00005170 v8::V8::Initialize();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005171 v8::HandleScope scope;
5172 DebugLocalContext env;
ager@chromium.org5ec48922009-05-05 07:25:34 +00005173 v8::Debug::SetMessageHandler2(&BreakpointsMessageHandler);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005174
5175 CompileRun(source_1);
5176 breakpoints_barriers->barrier_1.Wait();
5177 breakpoints_barriers->barrier_2.Wait();
5178 CompileRun(source_2);
5179}
5180
5181
5182void BreakpointsDebuggerThread::Run() {
5183 const int kBufSize = 1000;
5184 uint16_t buffer[kBufSize];
5185
5186 const char* command_1 = "{\"seq\":101,"
5187 "\"type\":\"request\","
5188 "\"command\":\"setbreakpoint\","
5189 "\"arguments\":{\"type\":\"function\",\"target\":\"cat\",\"line\":3}}";
5190 const char* command_2 = "{\"seq\":102,"
5191 "\"type\":\"request\","
5192 "\"command\":\"setbreakpoint\","
5193 "\"arguments\":{\"type\":\"function\",\"target\":\"dog\",\"line\":3}}";
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005194 const char* command_3;
5195 if (this->global_evaluate_) {
5196 command_3 = "{\"seq\":103,"
5197 "\"type\":\"request\","
5198 "\"command\":\"evaluate\","
5199 "\"arguments\":{\"expression\":\"dog()\",\"disable_break\":false,"
5200 "\"global\":true}}";
5201 } else {
5202 command_3 = "{\"seq\":103,"
5203 "\"type\":\"request\","
5204 "\"command\":\"evaluate\","
5205 "\"arguments\":{\"expression\":\"dog()\",\"disable_break\":false}}";
5206 }
5207 const char* command_4;
5208 if (this->global_evaluate_) {
5209 command_4 = "{\"seq\":104,"
5210 "\"type\":\"request\","
5211 "\"command\":\"evaluate\","
5212 "\"arguments\":{\"expression\":\"100 + 8\",\"disable_break\":true,"
5213 "\"global\":true}}";
5214 } else {
5215 command_4 = "{\"seq\":104,"
5216 "\"type\":\"request\","
5217 "\"command\":\"evaluate\","
5218 "\"arguments\":{\"expression\":\"x + 1\",\"disable_break\":true}}";
5219 }
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00005220 const char* command_5 = "{\"seq\":105,"
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005221 "\"type\":\"request\","
5222 "\"command\":\"continue\"}";
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00005223 const char* command_6 = "{\"seq\":106,"
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005224 "\"type\":\"request\","
5225 "\"command\":\"continue\"}";
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005226 const char* command_7;
5227 if (this->global_evaluate_) {
5228 command_7 = "{\"seq\":107,"
5229 "\"type\":\"request\","
5230 "\"command\":\"evaluate\","
5231 "\"arguments\":{\"expression\":\"dog()\",\"disable_break\":true,"
5232 "\"global\":true}}";
5233 } else {
5234 command_7 = "{\"seq\":107,"
5235 "\"type\":\"request\","
5236 "\"command\":\"evaluate\","
5237 "\"arguments\":{\"expression\":\"dog()\",\"disable_break\":true}}";
5238 }
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00005239 const char* command_8 = "{\"seq\":108,"
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005240 "\"type\":\"request\","
5241 "\"command\":\"continue\"}";
5242
5243
5244 // v8 thread initializes, runs source_1
5245 breakpoints_barriers->barrier_1.Wait();
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00005246 // 1:Set breakpoint in cat() (will get id 1).
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005247 v8::Debug::SendCommand(buffer, AsciiToUtf16(command_1, buffer));
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00005248 // 2:Set breakpoint in dog() (will get id 2).
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005249 v8::Debug::SendCommand(buffer, AsciiToUtf16(command_2, buffer));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005250 breakpoints_barriers->barrier_2.Wait();
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00005251 // V8 thread starts compiling source_2.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005252 // Automatic break happens, to run queued commands
5253 // breakpoints_barriers->semaphore_1->Wait();
5254 // Commands 1 through 3 run, thread continues.
5255 // v8 thread runs source_2 to breakpoint in cat().
5256 // message callback receives break event.
5257 breakpoints_barriers->semaphore_1->Wait();
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00005258 // Must have hit breakpoint #1.
5259 CHECK_EQ(1, break_event_breakpoint_id);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005260 // 4:Evaluate dog() (which has a breakpoint).
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005261 v8::Debug::SendCommand(buffer, AsciiToUtf16(command_3, buffer));
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00005262 // V8 thread hits breakpoint in dog().
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005263 breakpoints_barriers->semaphore_1->Wait(); // wait for break event
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00005264 // Must have hit breakpoint #2.
5265 CHECK_EQ(2, break_event_breakpoint_id);
5266 // 5:Evaluate (x + 1).
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005267 v8::Debug::SendCommand(buffer, AsciiToUtf16(command_4, buffer));
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00005268 // Evaluate (x + 1) finishes.
5269 breakpoints_barriers->semaphore_1->Wait();
5270 // Must have result 108.
5271 CHECK_EQ(108, evaluate_int_result);
5272 // 6:Continue evaluation of dog().
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005273 v8::Debug::SendCommand(buffer, AsciiToUtf16(command_5, buffer));
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00005274 // Evaluate dog() finishes.
5275 breakpoints_barriers->semaphore_1->Wait();
5276 // Must have result 107.
5277 CHECK_EQ(107, evaluate_int_result);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005278 // 7:Continue evaluation of source_2, finish cat(17), hit breakpoint
5279 // in cat(19).
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005280 v8::Debug::SendCommand(buffer, AsciiToUtf16(command_6, buffer));
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00005281 // Message callback gets break event.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005282 breakpoints_barriers->semaphore_1->Wait(); // wait for break event
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00005283 // Must have hit breakpoint #1.
5284 CHECK_EQ(1, break_event_breakpoint_id);
5285 // 8: Evaluate dog() with breaks disabled.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005286 v8::Debug::SendCommand(buffer, AsciiToUtf16(command_7, buffer));
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00005287 // Evaluate dog() finishes.
5288 breakpoints_barriers->semaphore_1->Wait();
5289 // Must have result 116.
5290 CHECK_EQ(116, evaluate_int_result);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005291 // 9: Continue evaluation of source2, reach end.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005292 v8::Debug::SendCommand(buffer, AsciiToUtf16(command_8, buffer));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005293}
5294
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005295void TestRecursiveBreakpointsGeneric(bool global_evaluate) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005296 i::FLAG_debugger_auto_break = true;
5297
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00005298 BreakpointsDebuggerThread breakpoints_debugger_thread(global_evaluate);
5299 BreakpointsV8Thread breakpoints_v8_thread;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005300
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005301 // Create a V8 environment
5302 Barriers stack_allocated_breakpoints_barriers;
5303 stack_allocated_breakpoints_barriers.Initialize();
5304 breakpoints_barriers = &stack_allocated_breakpoints_barriers;
5305
5306 breakpoints_v8_thread.Start();
5307 breakpoints_debugger_thread.Start();
5308
5309 breakpoints_v8_thread.Join();
5310 breakpoints_debugger_thread.Join();
5311}
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00005312
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005313TEST(RecursiveBreakpoints) {
5314 TestRecursiveBreakpointsGeneric(false);
5315}
5316
5317TEST(RecursiveBreakpointsGlobal) {
5318 TestRecursiveBreakpointsGeneric(true);
5319}
5320
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00005321
5322static void DummyDebugEventListener(v8::DebugEvent event,
5323 v8::Handle<v8::Object> exec_state,
5324 v8::Handle<v8::Object> event_data,
5325 v8::Handle<v8::Value> data) {
5326}
5327
5328
iposva@chromium.org245aa852009-02-10 00:49:54 +00005329TEST(SetDebugEventListenerOnUninitializedVM) {
5330 v8::Debug::SetDebugEventListener(DummyDebugEventListener);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00005331}
5332
5333
ager@chromium.org5ec48922009-05-05 07:25:34 +00005334static void DummyMessageHandler(const v8::Debug::Message& message) {
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00005335}
5336
5337
5338TEST(SetMessageHandlerOnUninitializedVM) {
ager@chromium.org5ec48922009-05-05 07:25:34 +00005339 v8::Debug::SetMessageHandler2(DummyMessageHandler);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00005340}
5341
5342
5343TEST(DebugBreakOnUninitializedVM) {
5344 v8::Debug::DebugBreak();
5345}
5346
5347
5348TEST(SendCommandToUninitializedVM) {
5349 const char* dummy_command = "{}";
5350 uint16_t dummy_buffer[80];
5351 int dummy_length = AsciiToUtf16(dummy_command, dummy_buffer);
5352 v8::Debug::SendCommand(dummy_buffer, dummy_length);
5353}
ager@chromium.orga74f0da2008-12-03 16:05:52 +00005354
5355
ager@chromium.orga74f0da2008-12-03 16:05:52 +00005356// Source for a JavaScript function which returns the data parameter of a
5357// function called in the context of the debugger. If no data parameter is
5358// passed it throws an exception.
5359static const char* debugger_call_with_data_source =
5360 "function debugger_call_with_data(exec_state, data) {"
5361 " if (data) return data;"
5362 " throw 'No data!'"
5363 "}";
5364v8::Handle<v8::Function> debugger_call_with_data;
5365
5366
5367// Source for a JavaScript function which returns the data parameter of a
5368// function called in the context of the debugger. If no data parameter is
5369// passed it throws an exception.
5370static const char* debugger_call_with_closure_source =
5371 "var x = 3;"
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00005372 "(function (exec_state) {"
ager@chromium.orga74f0da2008-12-03 16:05:52 +00005373 " if (exec_state.y) return x - 1;"
5374 " exec_state.y = x;"
5375 " return exec_state.y"
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00005376 "})";
ager@chromium.orga74f0da2008-12-03 16:05:52 +00005377v8::Handle<v8::Function> debugger_call_with_closure;
5378
5379// Function to retrieve the number of JavaScript frames by calling a JavaScript
5380// in the debugger.
5381static v8::Handle<v8::Value> CheckFrameCount(const v8::Arguments& args) {
5382 CHECK(v8::Debug::Call(frame_count)->IsNumber());
5383 CHECK_EQ(args[0]->Int32Value(),
5384 v8::Debug::Call(frame_count)->Int32Value());
5385 return v8::Undefined();
5386}
5387
5388
5389// Function to retrieve the source line of the top JavaScript frame by calling a
5390// JavaScript function in the debugger.
5391static v8::Handle<v8::Value> CheckSourceLine(const v8::Arguments& args) {
5392 CHECK(v8::Debug::Call(frame_source_line)->IsNumber());
5393 CHECK_EQ(args[0]->Int32Value(),
5394 v8::Debug::Call(frame_source_line)->Int32Value());
5395 return v8::Undefined();
5396}
5397
5398
5399// Function to test passing an additional parameter to a JavaScript function
5400// called in the debugger. It also tests that functions called in the debugger
5401// can throw exceptions.
5402static v8::Handle<v8::Value> CheckDataParameter(const v8::Arguments& args) {
5403 v8::Handle<v8::String> data = v8::String::New("Test");
5404 CHECK(v8::Debug::Call(debugger_call_with_data, data)->IsString());
5405
5406 CHECK(v8::Debug::Call(debugger_call_with_data).IsEmpty());
5407 CHECK(v8::Debug::Call(debugger_call_with_data).IsEmpty());
5408
5409 v8::TryCatch catcher;
5410 v8::Debug::Call(debugger_call_with_data);
5411 CHECK(catcher.HasCaught());
5412 CHECK(catcher.Exception()->IsString());
5413
5414 return v8::Undefined();
5415}
5416
5417
5418// Function to test using a JavaScript with closure in the debugger.
5419static v8::Handle<v8::Value> CheckClosure(const v8::Arguments& args) {
5420 CHECK(v8::Debug::Call(debugger_call_with_closure)->IsNumber());
5421 CHECK_EQ(3, v8::Debug::Call(debugger_call_with_closure)->Int32Value());
5422 return v8::Undefined();
5423}
5424
5425
5426// Test functions called through the debugger.
5427TEST(CallFunctionInDebugger) {
5428 // Create and enter a context with the functions CheckFrameCount,
5429 // CheckSourceLine and CheckDataParameter installed.
5430 v8::HandleScope scope;
5431 v8::Handle<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New();
5432 global_template->Set(v8::String::New("CheckFrameCount"),
5433 v8::FunctionTemplate::New(CheckFrameCount));
5434 global_template->Set(v8::String::New("CheckSourceLine"),
5435 v8::FunctionTemplate::New(CheckSourceLine));
5436 global_template->Set(v8::String::New("CheckDataParameter"),
5437 v8::FunctionTemplate::New(CheckDataParameter));
5438 global_template->Set(v8::String::New("CheckClosure"),
5439 v8::FunctionTemplate::New(CheckClosure));
5440 v8::Handle<v8::Context> context = v8::Context::New(NULL, global_template);
5441 v8::Context::Scope context_scope(context);
5442
5443 // Compile a function for checking the number of JavaScript frames.
5444 v8::Script::Compile(v8::String::New(frame_count_source))->Run();
5445 frame_count = v8::Local<v8::Function>::Cast(
5446 context->Global()->Get(v8::String::New("frame_count")));
5447
5448 // Compile a function for returning the source line for the top frame.
5449 v8::Script::Compile(v8::String::New(frame_source_line_source))->Run();
5450 frame_source_line = v8::Local<v8::Function>::Cast(
5451 context->Global()->Get(v8::String::New("frame_source_line")));
5452
5453 // Compile a function returning the data parameter.
5454 v8::Script::Compile(v8::String::New(debugger_call_with_data_source))->Run();
5455 debugger_call_with_data = v8::Local<v8::Function>::Cast(
5456 context->Global()->Get(v8::String::New("debugger_call_with_data")));
5457
5458 // Compile a function capturing closure.
5459 debugger_call_with_closure = v8::Local<v8::Function>::Cast(
5460 v8::Script::Compile(
5461 v8::String::New(debugger_call_with_closure_source))->Run());
5462
sgjesse@chromium.orgdf7a2842010-03-25 14:34:15 +00005463 // Calling a function through the debugger returns 0 frames if there are
5464 // no JavaScript frames.
5465 CHECK_EQ(v8::Integer::New(0), v8::Debug::Call(frame_count));
ager@chromium.orga74f0da2008-12-03 16:05:52 +00005466
5467 // Test that the number of frames can be retrieved.
5468 v8::Script::Compile(v8::String::New("CheckFrameCount(1)"))->Run();
5469 v8::Script::Compile(v8::String::New("function f() {"
5470 " CheckFrameCount(2);"
5471 "}; f()"))->Run();
5472
5473 // Test that the source line can be retrieved.
5474 v8::Script::Compile(v8::String::New("CheckSourceLine(0)"))->Run();
5475 v8::Script::Compile(v8::String::New("function f() {\n"
5476 " CheckSourceLine(1)\n"
5477 " CheckSourceLine(2)\n"
5478 " CheckSourceLine(3)\n"
5479 "}; f()"))->Run();
5480
5481 // Test that a parameter can be passed to a function called in the debugger.
5482 v8::Script::Compile(v8::String::New("CheckDataParameter()"))->Run();
5483
5484 // Test that a function with closure can be run in the debugger.
5485 v8::Script::Compile(v8::String::New("CheckClosure()"))->Run();
ager@chromium.org3a6061e2009-03-12 14:24:36 +00005486
5487
5488 // Test that the source line is correct when there is a line offset.
5489 v8::ScriptOrigin origin(v8::String::New("test"),
5490 v8::Integer::New(7));
5491 v8::Script::Compile(v8::String::New("CheckSourceLine(7)"), &origin)->Run();
5492 v8::Script::Compile(v8::String::New("function f() {\n"
5493 " CheckSourceLine(8)\n"
5494 " CheckSourceLine(9)\n"
5495 " CheckSourceLine(10)\n"
5496 "}; f()"), &origin)->Run();
ager@chromium.orga74f0da2008-12-03 16:05:52 +00005497}
ager@chromium.org381abbb2009-02-25 13:23:22 +00005498
5499
sgjesse@chromium.orga9eaf5c2009-06-17 14:04:55 +00005500// Debugger message handler which counts the number of breaks.
5501static void SendContinueCommand();
5502static void MessageHandlerBreakPointHitCount(
5503 const v8::Debug::Message& message) {
5504 if (message.IsEvent() && message.GetEvent() == v8::Break) {
5505 // Count the number of breaks.
5506 break_point_hit_count++;
5507
5508 SendContinueCommand();
5509 }
5510}
5511
5512
ager@chromium.org381abbb2009-02-25 13:23:22 +00005513// Test that clearing the debug event listener actually clears all break points
5514// and related information.
5515TEST(DebuggerUnload) {
ager@chromium.org381abbb2009-02-25 13:23:22 +00005516 DebugLocalContext env;
5517
5518 // Check debugger is unloaded before it is used.
5519 CheckDebuggerUnloaded();
5520
sgjesse@chromium.orga9eaf5c2009-06-17 14:04:55 +00005521 // Set a debug event listener.
5522 break_point_hit_count = 0;
ager@chromium.org381abbb2009-02-25 13:23:22 +00005523 v8::Debug::SetDebugEventListener(DebugEventBreakPointHitCount,
5524 v8::Undefined());
sgjesse@chromium.orga9eaf5c2009-06-17 14:04:55 +00005525 {
5526 v8::HandleScope scope;
5527 // Create a couple of functions for the test.
5528 v8::Local<v8::Function> foo =
5529 CompileFunction(&env, "function foo(){x=1}", "foo");
5530 v8::Local<v8::Function> bar =
5531 CompileFunction(&env, "function bar(){y=2}", "bar");
ager@chromium.org381abbb2009-02-25 13:23:22 +00005532
sgjesse@chromium.orga9eaf5c2009-06-17 14:04:55 +00005533 // Set some break points.
5534 SetBreakPoint(foo, 0);
5535 SetBreakPoint(foo, 4);
5536 SetBreakPoint(bar, 0);
5537 SetBreakPoint(bar, 4);
ager@chromium.org381abbb2009-02-25 13:23:22 +00005538
sgjesse@chromium.orga9eaf5c2009-06-17 14:04:55 +00005539 // Make sure that the break points are there.
5540 break_point_hit_count = 0;
5541 foo->Call(env->Global(), 0, NULL);
5542 CHECK_EQ(2, break_point_hit_count);
5543 bar->Call(env->Global(), 0, NULL);
5544 CHECK_EQ(4, break_point_hit_count);
5545 }
sgjesse@chromium.orgf457d1f2009-06-17 14:18:36 +00005546
sgjesse@chromium.orga9eaf5c2009-06-17 14:04:55 +00005547 // Remove the debug event listener without clearing breakpoints. Do this
5548 // outside a handle scope.
ager@chromium.org381abbb2009-02-25 13:23:22 +00005549 v8::Debug::SetDebugEventListener(NULL);
5550 CheckDebuggerUnloaded(true);
5551
sgjesse@chromium.orga9eaf5c2009-06-17 14:04:55 +00005552 // Now set a debug message handler.
ager@chromium.org381abbb2009-02-25 13:23:22 +00005553 break_point_hit_count = 0;
sgjesse@chromium.orga9eaf5c2009-06-17 14:04:55 +00005554 v8::Debug::SetMessageHandler2(MessageHandlerBreakPointHitCount);
5555 {
5556 v8::HandleScope scope;
ager@chromium.org381abbb2009-02-25 13:23:22 +00005557
sgjesse@chromium.orga9eaf5c2009-06-17 14:04:55 +00005558 // Get the test functions again.
5559 v8::Local<v8::Function> foo =
5560 v8::Local<v8::Function>::Cast(env->Global()->Get(v8::String::New("foo")));
5561 v8::Local<v8::Function> bar =
5562 v8::Local<v8::Function>::Cast(env->Global()->Get(v8::String::New("foo")));
ager@chromium.org381abbb2009-02-25 13:23:22 +00005563
sgjesse@chromium.orga9eaf5c2009-06-17 14:04:55 +00005564 foo->Call(env->Global(), 0, NULL);
5565 CHECK_EQ(0, break_point_hit_count);
5566
5567 // Set break points and run again.
5568 SetBreakPoint(foo, 0);
5569 SetBreakPoint(foo, 4);
5570 foo->Call(env->Global(), 0, NULL);
5571 CHECK_EQ(2, break_point_hit_count);
5572 }
5573
5574 // Remove the debug message handler without clearing breakpoints. Do this
5575 // outside a handle scope.
5576 v8::Debug::SetMessageHandler2(NULL);
ager@chromium.org381abbb2009-02-25 13:23:22 +00005577 CheckDebuggerUnloaded(true);
5578}
5579
5580
kasperl@chromium.org71affb52009-05-26 05:44:31 +00005581// Sends continue command to the debugger.
5582static void SendContinueCommand() {
ager@chromium.org71daaf62009-04-01 07:22:49 +00005583 const int kBufferSize = 1000;
5584 uint16_t buffer[kBufferSize];
5585 const char* command_continue =
5586 "{\"seq\":0,"
5587 "\"type\":\"request\","
5588 "\"command\":\"continue\"}";
5589
5590 v8::Debug::SendCommand(buffer, AsciiToUtf16(command_continue, buffer));
5591}
5592
5593
kasperl@chromium.org71affb52009-05-26 05:44:31 +00005594// Debugger message handler which counts the number of times it is called.
5595static int message_handler_hit_count = 0;
5596static void MessageHandlerHitCount(const v8::Debug::Message& message) {
5597 message_handler_hit_count++;
5598
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00005599 static char print_buffer[1000];
5600 v8::String::Value json(message.GetJSON());
5601 Utf16ToAscii(*json, json.length(), print_buffer);
5602 if (IsExceptionEventMessage(print_buffer)) {
5603 // Send a continue command for exception events.
5604 SendContinueCommand();
5605 }
kasperl@chromium.org71affb52009-05-26 05:44:31 +00005606}
5607
5608
ager@chromium.org71daaf62009-04-01 07:22:49 +00005609// Test clearing the debug message handler.
5610TEST(DebuggerClearMessageHandler) {
5611 v8::HandleScope scope;
5612 DebugLocalContext env;
5613
5614 // Check debugger is unloaded before it is used.
5615 CheckDebuggerUnloaded();
5616
5617 // Set a debug message handler.
ager@chromium.org5ec48922009-05-05 07:25:34 +00005618 v8::Debug::SetMessageHandler2(MessageHandlerHitCount);
ager@chromium.org71daaf62009-04-01 07:22:49 +00005619
5620 // Run code to throw a unhandled exception. This should end up in the message
5621 // handler.
5622 CompileRun("throw 1");
5623
5624 // The message handler should be called.
5625 CHECK_GT(message_handler_hit_count, 0);
5626
5627 // Clear debug message handler.
5628 message_handler_hit_count = 0;
5629 v8::Debug::SetMessageHandler(NULL);
5630
5631 // Run code to throw a unhandled exception. This should end up in the message
5632 // handler.
5633 CompileRun("throw 1");
5634
5635 // The message handler should not be called more.
5636 CHECK_EQ(0, message_handler_hit_count);
5637
5638 CheckDebuggerUnloaded(true);
5639}
5640
5641
5642// Debugger message handler which clears the message handler while active.
ager@chromium.org65dad4b2009-04-23 08:48:43 +00005643static void MessageHandlerClearingMessageHandler(
ager@chromium.org5ec48922009-05-05 07:25:34 +00005644 const v8::Debug::Message& message) {
ager@chromium.org71daaf62009-04-01 07:22:49 +00005645 message_handler_hit_count++;
5646
5647 // Clear debug message handler.
5648 v8::Debug::SetMessageHandler(NULL);
5649}
5650
5651
5652// Test clearing the debug message handler while processing a debug event.
5653TEST(DebuggerClearMessageHandlerWhileActive) {
5654 v8::HandleScope scope;
5655 DebugLocalContext env;
5656
5657 // Check debugger is unloaded before it is used.
5658 CheckDebuggerUnloaded();
5659
5660 // Set a debug message handler.
ager@chromium.org5ec48922009-05-05 07:25:34 +00005661 v8::Debug::SetMessageHandler2(MessageHandlerClearingMessageHandler);
ager@chromium.org71daaf62009-04-01 07:22:49 +00005662
5663 // Run code to throw a unhandled exception. This should end up in the message
5664 // handler.
5665 CompileRun("throw 1");
5666
5667 // The message handler should be called.
5668 CHECK_EQ(1, message_handler_hit_count);
5669
5670 CheckDebuggerUnloaded(true);
5671}
5672
5673
ager@chromium.org65dad4b2009-04-23 08:48:43 +00005674/* Test DebuggerHostDispatch */
5675/* In this test, the debugger waits for a command on a breakpoint
5676 * and is dispatching host commands while in the infinite loop.
5677 */
5678
5679class HostDispatchV8Thread : public v8::internal::Thread {
5680 public:
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00005681 HostDispatchV8Thread() : Thread("HostDispatchV8Thread") { }
ager@chromium.org65dad4b2009-04-23 08:48:43 +00005682 void Run();
5683};
5684
5685class HostDispatchDebuggerThread : public v8::internal::Thread {
5686 public:
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00005687 HostDispatchDebuggerThread() : Thread("HostDispatchDebuggerThread") { }
ager@chromium.org65dad4b2009-04-23 08:48:43 +00005688 void Run();
5689};
5690
5691Barriers* host_dispatch_barriers;
5692
ager@chromium.org5ec48922009-05-05 07:25:34 +00005693static void HostDispatchMessageHandler(const v8::Debug::Message& message) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +00005694 static char print_buffer[1000];
ager@chromium.org5ec48922009-05-05 07:25:34 +00005695 v8::String::Value json(message.GetJSON());
5696 Utf16ToAscii(*json, json.length(), print_buffer);
ager@chromium.org381abbb2009-02-25 13:23:22 +00005697}
5698
5699
ager@chromium.org65dad4b2009-04-23 08:48:43 +00005700static void HostDispatchDispatchHandler() {
5701 host_dispatch_barriers->semaphore_1->Signal();
5702}
5703
5704
5705void HostDispatchV8Thread::Run() {
5706 const char* source_1 = "var y_global = 3;\n"
5707 "function cat( new_value ) {\n"
5708 " var x = new_value;\n"
5709 " y_global = 4;\n"
5710 " x = 3 * x + 1;\n"
5711 " y_global = 5;\n"
5712 " return x;\n"
5713 "}\n"
5714 "\n";
5715 const char* source_2 = "cat(17);\n";
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005716
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00005717 v8::V8::Initialize();
ager@chromium.org381abbb2009-02-25 13:23:22 +00005718 v8::HandleScope scope;
5719 DebugLocalContext env;
5720
ager@chromium.org381abbb2009-02-25 13:23:22 +00005721 // Setup message and host dispatch handlers.
ager@chromium.org5ec48922009-05-05 07:25:34 +00005722 v8::Debug::SetMessageHandler2(HostDispatchMessageHandler);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00005723 v8::Debug::SetHostDispatchHandler(HostDispatchDispatchHandler, 10 /* ms */);
ager@chromium.org381abbb2009-02-25 13:23:22 +00005724
ager@chromium.org65dad4b2009-04-23 08:48:43 +00005725 CompileRun(source_1);
5726 host_dispatch_barriers->barrier_1.Wait();
5727 host_dispatch_barriers->barrier_2.Wait();
5728 CompileRun(source_2);
5729}
sgjesse@chromium.org3afc1582009-04-16 22:31:44 +00005730
ager@chromium.org381abbb2009-02-25 13:23:22 +00005731
ager@chromium.org65dad4b2009-04-23 08:48:43 +00005732void HostDispatchDebuggerThread::Run() {
5733 const int kBufSize = 1000;
5734 uint16_t buffer[kBufSize];
sgjesse@chromium.org3afc1582009-04-16 22:31:44 +00005735
ager@chromium.org65dad4b2009-04-23 08:48:43 +00005736 const char* command_1 = "{\"seq\":101,"
5737 "\"type\":\"request\","
5738 "\"command\":\"setbreakpoint\","
5739 "\"arguments\":{\"type\":\"function\",\"target\":\"cat\",\"line\":3}}";
5740 const char* command_2 = "{\"seq\":102,"
5741 "\"type\":\"request\","
5742 "\"command\":\"continue\"}";
5743
5744 // v8 thread initializes, runs source_1
5745 host_dispatch_barriers->barrier_1.Wait();
5746 // 1: Set breakpoint in cat().
5747 v8::Debug::SendCommand(buffer, AsciiToUtf16(command_1, buffer));
5748
5749 host_dispatch_barriers->barrier_2.Wait();
5750 // v8 thread starts compiling source_2.
5751 // Break happens, to run queued commands and host dispatches.
5752 // Wait for host dispatch to be processed.
5753 host_dispatch_barriers->semaphore_1->Wait();
5754 // 2: Continue evaluation
5755 v8::Debug::SendCommand(buffer, AsciiToUtf16(command_2, buffer));
5756}
5757
ager@chromium.org65dad4b2009-04-23 08:48:43 +00005758
5759TEST(DebuggerHostDispatch) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00005760 HostDispatchDebuggerThread host_dispatch_debugger_thread;
5761 HostDispatchV8Thread host_dispatch_v8_thread;
ager@chromium.org65dad4b2009-04-23 08:48:43 +00005762 i::FLAG_debugger_auto_break = true;
5763
5764 // Create a V8 environment
5765 Barriers stack_allocated_host_dispatch_barriers;
5766 stack_allocated_host_dispatch_barriers.Initialize();
5767 host_dispatch_barriers = &stack_allocated_host_dispatch_barriers;
5768
5769 host_dispatch_v8_thread.Start();
5770 host_dispatch_debugger_thread.Start();
5771
5772 host_dispatch_v8_thread.Join();
5773 host_dispatch_debugger_thread.Join();
ager@chromium.org381abbb2009-02-25 13:23:22 +00005774}
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005775
5776
ager@chromium.orgc4c92722009-11-18 14:12:51 +00005777/* Test DebugMessageDispatch */
5778/* In this test, the V8 thread waits for a message from the debug thread.
5779 * The DebugMessageDispatchHandler is executed from the debugger thread
5780 * which signals the V8 thread to wake up.
5781 */
5782
5783class DebugMessageDispatchV8Thread : public v8::internal::Thread {
5784 public:
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00005785 DebugMessageDispatchV8Thread() : Thread("DebugMessageDispatchV8Thread") { }
ager@chromium.orgc4c92722009-11-18 14:12:51 +00005786 void Run();
5787};
5788
5789class DebugMessageDispatchDebuggerThread : public v8::internal::Thread {
5790 public:
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00005791 DebugMessageDispatchDebuggerThread()
5792 : Thread("DebugMessageDispatchDebuggerThread") { }
ager@chromium.orgc4c92722009-11-18 14:12:51 +00005793 void Run();
5794};
5795
5796Barriers* debug_message_dispatch_barriers;
5797
5798
5799static void DebugMessageHandler() {
5800 debug_message_dispatch_barriers->semaphore_1->Signal();
5801}
5802
5803
5804void DebugMessageDispatchV8Thread::Run() {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00005805 v8::V8::Initialize();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00005806 v8::HandleScope scope;
5807 DebugLocalContext env;
5808
5809 // Setup debug message dispatch handler.
5810 v8::Debug::SetDebugMessageDispatchHandler(DebugMessageHandler);
5811
5812 CompileRun("var y = 1 + 2;\n");
5813 debug_message_dispatch_barriers->barrier_1.Wait();
5814 debug_message_dispatch_barriers->semaphore_1->Wait();
5815 debug_message_dispatch_barriers->barrier_2.Wait();
5816}
5817
5818
5819void DebugMessageDispatchDebuggerThread::Run() {
5820 debug_message_dispatch_barriers->barrier_1.Wait();
5821 SendContinueCommand();
5822 debug_message_dispatch_barriers->barrier_2.Wait();
5823}
5824
ager@chromium.orgc4c92722009-11-18 14:12:51 +00005825
5826TEST(DebuggerDebugMessageDispatch) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00005827 DebugMessageDispatchDebuggerThread debug_message_dispatch_debugger_thread;
5828 DebugMessageDispatchV8Thread debug_message_dispatch_v8_thread;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005829
ager@chromium.orgc4c92722009-11-18 14:12:51 +00005830 i::FLAG_debugger_auto_break = true;
5831
5832 // Create a V8 environment
5833 Barriers stack_allocated_debug_message_dispatch_barriers;
5834 stack_allocated_debug_message_dispatch_barriers.Initialize();
5835 debug_message_dispatch_barriers =
5836 &stack_allocated_debug_message_dispatch_barriers;
5837
5838 debug_message_dispatch_v8_thread.Start();
5839 debug_message_dispatch_debugger_thread.Start();
5840
5841 debug_message_dispatch_v8_thread.Join();
5842 debug_message_dispatch_debugger_thread.Join();
5843}
5844
5845
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005846TEST(DebuggerAgent) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005847 i::Debugger* debugger = i::Isolate::Current()->debugger();
ager@chromium.orga1645e22009-09-09 19:27:10 +00005848 // Make sure these ports is not used by other tests to allow tests to run in
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005849 // parallel.
ager@chromium.orga1645e22009-09-09 19:27:10 +00005850 const int kPort1 = 5858;
5851 const int kPort2 = 5857;
5852 const int kPort3 = 5856;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005853
ager@chromium.orga1645e22009-09-09 19:27:10 +00005854 // Make a string with the port2 number.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005855 const int kPortBufferLen = 6;
ager@chromium.orga1645e22009-09-09 19:27:10 +00005856 char port2_str[kPortBufferLen];
5857 OS::SNPrintF(i::Vector<char>(port2_str, kPortBufferLen), "%d", kPort2);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005858
5859 bool ok;
5860
5861 // Initialize the socket library.
5862 i::Socket::Setup();
5863
5864 // Test starting and stopping the agent without any client connection.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005865 debugger->StartAgent("test", kPort1);
5866 debugger->StopAgent();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005867 // Test starting the agent, connecting a client and shutting down the agent
5868 // with the client connected.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005869 ok = debugger->StartAgent("test", kPort2);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005870 CHECK(ok);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005871 debugger->WaitForAgent();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005872 i::Socket* client = i::OS::CreateSocket();
ager@chromium.orga1645e22009-09-09 19:27:10 +00005873 ok = client->Connect("localhost", port2_str);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005874 CHECK(ok);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00005875 // It is important to wait for a message from the agent. Otherwise,
5876 // we can close the server socket during "accept" syscall, making it failing
5877 // (at least on Linux), and the test will work incorrectly.
5878 char buf;
5879 ok = client->Receive(&buf, 1) == 1;
5880 CHECK(ok);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005881 debugger->StopAgent();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005882 delete client;
5883
5884 // Test starting and stopping the agent with the required port already
5885 // occoupied.
5886 i::Socket* server = i::OS::CreateSocket();
ager@chromium.orga1645e22009-09-09 19:27:10 +00005887 server->Bind(kPort3);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005888
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005889 debugger->StartAgent("test", kPort3);
5890 debugger->StopAgent();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005891
5892 delete server;
5893}
5894
5895
5896class DebuggerAgentProtocolServerThread : public i::Thread {
5897 public:
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00005898 explicit DebuggerAgentProtocolServerThread(int port)
5899 : Thread("DebuggerAgentProtocolServerThread"),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005900 port_(port),
5901 server_(NULL),
5902 client_(NULL),
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005903 listening_(OS::CreateSemaphore(0)) {
5904 }
5905 ~DebuggerAgentProtocolServerThread() {
5906 // Close both sockets.
5907 delete client_;
5908 delete server_;
5909 delete listening_;
5910 }
5911
5912 void Run();
5913 void WaitForListening() { listening_->Wait(); }
5914 char* body() { return *body_; }
5915
5916 private:
5917 int port_;
5918 i::SmartPointer<char> body_;
5919 i::Socket* server_; // Server socket used for bind/accept.
5920 i::Socket* client_; // Single client connection used by the test.
5921 i::Semaphore* listening_; // Signalled when the server is in listen mode.
5922};
5923
5924
5925void DebuggerAgentProtocolServerThread::Run() {
5926 bool ok;
5927
5928 // Create the server socket and bind it to the requested port.
5929 server_ = i::OS::CreateSocket();
5930 CHECK(server_ != NULL);
5931 ok = server_->Bind(port_);
5932 CHECK(ok);
5933
5934 // Listen for new connections.
5935 ok = server_->Listen(1);
5936 CHECK(ok);
5937 listening_->Signal();
5938
5939 // Accept a connection.
5940 client_ = server_->Accept();
5941 CHECK(client_ != NULL);
5942
5943 // Receive a debugger agent protocol message.
5944 i::DebuggerAgentUtil::ReceiveMessage(client_);
5945}
5946
5947
5948TEST(DebuggerAgentProtocolOverflowHeader) {
5949 // Make sure this port is not used by other tests to allow tests to run in
5950 // parallel.
5951 const int kPort = 5860;
5952 static const char* kLocalhost = "localhost";
5953
5954 // Make a string with the port number.
5955 const int kPortBufferLen = 6;
5956 char port_str[kPortBufferLen];
5957 OS::SNPrintF(i::Vector<char>(port_str, kPortBufferLen), "%d", kPort);
5958
5959 // Initialize the socket library.
5960 i::Socket::Setup();
5961
5962 // Create a socket server to receive a debugger agent message.
5963 DebuggerAgentProtocolServerThread* server =
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00005964 new DebuggerAgentProtocolServerThread(kPort);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005965 server->Start();
5966 server->WaitForListening();
5967
5968 // Connect.
5969 i::Socket* client = i::OS::CreateSocket();
5970 CHECK(client != NULL);
5971 bool ok = client->Connect(kLocalhost, port_str);
5972 CHECK(ok);
5973
5974 // Send headers which overflow the receive buffer.
5975 static const int kBufferSize = 1000;
5976 char buffer[kBufferSize];
5977
5978 // Long key and short value: XXXX....XXXX:0\r\n.
5979 for (int i = 0; i < kBufferSize - 4; i++) {
5980 buffer[i] = 'X';
5981 }
5982 buffer[kBufferSize - 4] = ':';
5983 buffer[kBufferSize - 3] = '0';
5984 buffer[kBufferSize - 2] = '\r';
5985 buffer[kBufferSize - 1] = '\n';
5986 client->Send(buffer, kBufferSize);
5987
5988 // Short key and long value: X:XXXX....XXXX\r\n.
5989 buffer[0] = 'X';
5990 buffer[1] = ':';
5991 for (int i = 2; i < kBufferSize - 2; i++) {
5992 buffer[i] = 'X';
5993 }
5994 buffer[kBufferSize - 2] = '\r';
5995 buffer[kBufferSize - 1] = '\n';
5996 client->Send(buffer, kBufferSize);
5997
5998 // Add empty body to request.
5999 const char* content_length_zero_header = "Content-Length:0\r\n";
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006000 client->Send(content_length_zero_header,
6001 StrLength(content_length_zero_header));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006002 client->Send("\r\n", 2);
6003
6004 // Wait until data is received.
6005 server->Join();
6006
6007 // Check for empty body.
6008 CHECK(server->body() == NULL);
6009
6010 // Close the client before the server to avoid TIME_WAIT issues.
6011 client->Shutdown();
6012 delete client;
6013 delete server;
6014}
ager@chromium.org41826e72009-03-30 13:30:57 +00006015
6016
6017// Test for issue http://code.google.com/p/v8/issues/detail?id=289.
6018// Make sure that DebugGetLoadedScripts doesn't return scripts
6019// with disposed external source.
6020class EmptyExternalStringResource : public v8::String::ExternalStringResource {
6021 public:
6022 EmptyExternalStringResource() { empty_[0] = 0; }
6023 virtual ~EmptyExternalStringResource() {}
6024 virtual size_t length() const { return empty_.length(); }
6025 virtual const uint16_t* data() const { return empty_.start(); }
6026 private:
6027 ::v8::internal::EmbeddedVector<uint16_t, 1> empty_;
6028};
6029
6030
6031TEST(DebugGetLoadedScripts) {
6032 v8::HandleScope scope;
6033 DebugLocalContext env;
kasperl@chromium.org71affb52009-05-26 05:44:31 +00006034 env.ExposeDebug();
6035
ager@chromium.org41826e72009-03-30 13:30:57 +00006036 EmptyExternalStringResource source_ext_str;
6037 v8::Local<v8::String> source = v8::String::NewExternal(&source_ext_str);
6038 v8::Handle<v8::Script> evil_script = v8::Script::Compile(source);
6039 Handle<i::ExternalTwoByteString> i_source(
6040 i::ExternalTwoByteString::cast(*v8::Utils::OpenHandle(*source)));
6041 // This situation can happen if source was an external string disposed
6042 // by its owner.
6043 i_source->set_resource(0);
6044
6045 bool allow_natives_syntax = i::FLAG_allow_natives_syntax;
6046 i::FLAG_allow_natives_syntax = true;
6047 CompileRun(
6048 "var scripts = %DebugGetLoadedScripts();"
kasperl@chromium.org71affb52009-05-26 05:44:31 +00006049 "var count = scripts.length;"
6050 "for (var i = 0; i < count; ++i) {"
6051 " scripts[i].line_ends;"
ager@chromium.org41826e72009-03-30 13:30:57 +00006052 "}");
6053 // Must not crash while accessing line_ends.
6054 i::FLAG_allow_natives_syntax = allow_natives_syntax;
kasperl@chromium.org71affb52009-05-26 05:44:31 +00006055
6056 // Some scripts are retrieved - at least the number of native scripts.
6057 CHECK_GT((*env)->Global()->Get(v8::String::New("count"))->Int32Value(), 8);
ager@chromium.org41826e72009-03-30 13:30:57 +00006058}
ager@chromium.org65dad4b2009-04-23 08:48:43 +00006059
6060
6061// Test script break points set on lines.
6062TEST(ScriptNameAndData) {
6063 v8::HandleScope scope;
6064 DebugLocalContext env;
6065 env.ExposeDebug();
6066
6067 // Create functions for retrieving script name and data for the function on
6068 // the top frame when hitting a break point.
6069 frame_script_name = CompileFunction(&env,
6070 frame_script_name_source,
6071 "frame_script_name");
6072 frame_script_data = CompileFunction(&env,
6073 frame_script_data_source,
6074 "frame_script_data");
ager@chromium.org5c838252010-02-19 08:53:10 +00006075 compiled_script_data = CompileFunction(&env,
6076 compiled_script_data_source,
6077 "compiled_script_data");
ager@chromium.org65dad4b2009-04-23 08:48:43 +00006078
6079 v8::Debug::SetDebugEventListener(DebugEventBreakPointHitCount,
6080 v8::Undefined());
6081
6082 // Test function source.
6083 v8::Local<v8::String> script = v8::String::New(
6084 "function f() {\n"
6085 " debugger;\n"
6086 "}\n");
6087
6088 v8::ScriptOrigin origin1 = v8::ScriptOrigin(v8::String::New("name"));
6089 v8::Handle<v8::Script> script1 = v8::Script::Compile(script, &origin1);
6090 script1->SetData(v8::String::New("data"));
6091 script1->Run();
ager@chromium.org65dad4b2009-04-23 08:48:43 +00006092 v8::Local<v8::Function> f;
6093 f = v8::Local<v8::Function>::Cast(env->Global()->Get(v8::String::New("f")));
6094
6095 f->Call(env->Global(), 0, NULL);
6096 CHECK_EQ(1, break_point_hit_count);
6097 CHECK_EQ("name", last_script_name_hit);
6098 CHECK_EQ("data", last_script_data_hit);
6099
kasperl@chromium.org71affb52009-05-26 05:44:31 +00006100 // Compile the same script again without setting data. As the compilation
6101 // cache is disabled when debugging expect the data to be missing.
6102 v8::Script::Compile(script, &origin1)->Run();
6103 f = v8::Local<v8::Function>::Cast(env->Global()->Get(v8::String::New("f")));
6104 f->Call(env->Global(), 0, NULL);
6105 CHECK_EQ(2, break_point_hit_count);
6106 CHECK_EQ("name", last_script_name_hit);
6107 CHECK_EQ("", last_script_data_hit); // Undefined results in empty string.
6108
ager@chromium.org65dad4b2009-04-23 08:48:43 +00006109 v8::Local<v8::String> data_obj_source = v8::String::New(
6110 "({ a: 'abc',\n"
6111 " b: 123,\n"
6112 " toString: function() { return this.a + ' ' + this.b; }\n"
6113 "})\n");
6114 v8::Local<v8::Value> data_obj = v8::Script::Compile(data_obj_source)->Run();
6115 v8::ScriptOrigin origin2 = v8::ScriptOrigin(v8::String::New("new name"));
6116 v8::Handle<v8::Script> script2 = v8::Script::Compile(script, &origin2);
6117 script2->Run();
sgjesse@chromium.org499aaa52009-11-30 08:07:20 +00006118 script2->SetData(data_obj->ToString());
ager@chromium.org65dad4b2009-04-23 08:48:43 +00006119 f = v8::Local<v8::Function>::Cast(env->Global()->Get(v8::String::New("f")));
6120 f->Call(env->Global(), 0, NULL);
kasperl@chromium.org71affb52009-05-26 05:44:31 +00006121 CHECK_EQ(3, break_point_hit_count);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00006122 CHECK_EQ("new name", last_script_name_hit);
6123 CHECK_EQ("abc 123", last_script_data_hit);
ager@chromium.org5c838252010-02-19 08:53:10 +00006124
6125 v8::Handle<v8::Script> script3 =
6126 v8::Script::Compile(script, &origin2, NULL,
6127 v8::String::New("in compile"));
6128 CHECK_EQ("in compile", last_script_data_hit);
6129 script3->Run();
6130 f = v8::Local<v8::Function>::Cast(env->Global()->Get(v8::String::New("f")));
6131 f->Call(env->Global(), 0, NULL);
6132 CHECK_EQ(4, break_point_hit_count);
6133 CHECK_EQ("in compile", last_script_data_hit);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00006134}
ager@chromium.org9085a012009-05-11 19:22:57 +00006135
6136
6137static v8::Persistent<v8::Context> expected_context;
6138static v8::Handle<v8::Value> expected_context_data;
6139
6140
6141// Check that the expected context is the one generating the debug event.
6142static void ContextCheckMessageHandler(const v8::Debug::Message& message) {
6143 CHECK(message.GetEventContext() == expected_context);
6144 CHECK(message.GetEventContext()->GetData()->StrictEquals(
6145 expected_context_data));
6146 message_handler_hit_count++;
6147
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00006148 static char print_buffer[1000];
6149 v8::String::Value json(message.GetJSON());
6150 Utf16ToAscii(*json, json.length(), print_buffer);
6151
ager@chromium.org9085a012009-05-11 19:22:57 +00006152 // Send a continue command for break events.
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00006153 if (IsBreakEventMessage(print_buffer)) {
kasperl@chromium.org71affb52009-05-26 05:44:31 +00006154 SendContinueCommand();
ager@chromium.org9085a012009-05-11 19:22:57 +00006155 }
6156}
6157
6158
6159// Test which creates two contexts and sets different embedder data on each.
6160// Checks that this data is set correctly and that when the debug message
6161// handler is called the expected context is the one active.
6162TEST(ContextData) {
6163 v8::HandleScope scope;
6164
6165 v8::Debug::SetMessageHandler2(ContextCheckMessageHandler);
6166
6167 // Create two contexts.
6168 v8::Persistent<v8::Context> context_1;
6169 v8::Persistent<v8::Context> context_2;
6170 v8::Handle<v8::ObjectTemplate> global_template =
6171 v8::Handle<v8::ObjectTemplate>();
6172 v8::Handle<v8::Value> global_object = v8::Handle<v8::Value>();
6173 context_1 = v8::Context::New(NULL, global_template, global_object);
6174 context_2 = v8::Context::New(NULL, global_template, global_object);
6175
6176 // Default data value is undefined.
6177 CHECK(context_1->GetData()->IsUndefined());
6178 CHECK(context_2->GetData()->IsUndefined());
6179
6180 // Set and check different data values.
sgjesse@chromium.org499aaa52009-11-30 08:07:20 +00006181 v8::Handle<v8::String> data_1 = v8::String::New("1");
6182 v8::Handle<v8::String> data_2 = v8::String::New("2");
ager@chromium.org9085a012009-05-11 19:22:57 +00006183 context_1->SetData(data_1);
6184 context_2->SetData(data_2);
6185 CHECK(context_1->GetData()->StrictEquals(data_1));
6186 CHECK(context_2->GetData()->StrictEquals(data_2));
6187
6188 // Simple test function which causes a break.
6189 const char* source = "function f() { debugger; }";
6190
6191 // Enter and run function in the first context.
6192 {
6193 v8::Context::Scope context_scope(context_1);
6194 expected_context = context_1;
6195 expected_context_data = data_1;
6196 v8::Local<v8::Function> f = CompileFunction(source, "f");
6197 f->Call(context_1->Global(), 0, NULL);
6198 }
6199
6200
6201 // Enter and run function in the second context.
6202 {
6203 v8::Context::Scope context_scope(context_2);
6204 expected_context = context_2;
6205 expected_context_data = data_2;
6206 v8::Local<v8::Function> f = CompileFunction(source, "f");
6207 f->Call(context_2->Global(), 0, NULL);
6208 }
6209
6210 // Two times compile event and two times break event.
6211 CHECK_GT(message_handler_hit_count, 4);
kasperl@chromium.org71affb52009-05-26 05:44:31 +00006212
6213 v8::Debug::SetMessageHandler2(NULL);
6214 CheckDebuggerUnloaded();
6215}
6216
6217
sgjesse@chromium.org755c5b12009-05-29 11:04:38 +00006218// Debug message handler which issues a debug break when it hits a break event.
6219static int message_handler_break_hit_count = 0;
6220static void DebugBreakMessageHandler(const v8::Debug::Message& message) {
6221 // Schedule a debug break for break events.
6222 if (message.IsEvent() && message.GetEvent() == v8::Break) {
6223 message_handler_break_hit_count++;
6224 if (message_handler_break_hit_count == 1) {
6225 v8::Debug::DebugBreak();
6226 }
6227 }
6228
6229 // Issue a continue command if this event will not cause the VM to start
6230 // running.
6231 if (!message.WillStartRunning()) {
6232 SendContinueCommand();
6233 }
6234}
6235
6236
6237// Test that a debug break can be scheduled while in a message handler.
6238TEST(DebugBreakInMessageHandler) {
6239 v8::HandleScope scope;
6240 DebugLocalContext env;
6241
6242 v8::Debug::SetMessageHandler2(DebugBreakMessageHandler);
6243
6244 // Test functions.
kasperl@chromium.orge959c182009-07-27 08:59:04 +00006245 const char* script = "function f() { debugger; g(); } function g() { }";
sgjesse@chromium.org755c5b12009-05-29 11:04:38 +00006246 CompileRun(script);
6247 v8::Local<v8::Function> f =
6248 v8::Local<v8::Function>::Cast(env->Global()->Get(v8::String::New("f")));
6249 v8::Local<v8::Function> g =
6250 v8::Local<v8::Function>::Cast(env->Global()->Get(v8::String::New("g")));
6251
6252 // Call f then g. The debugger statement in f will casue a break which will
6253 // cause another break.
6254 f->Call(env->Global(), 0, NULL);
6255 CHECK_EQ(2, message_handler_break_hit_count);
6256 // Calling g will not cause any additional breaks.
6257 g->Call(env->Global(), 0, NULL);
6258 CHECK_EQ(2, message_handler_break_hit_count);
6259}
6260
6261
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006262#ifndef V8_INTERPRETED_REGEXP
sgjesse@chromium.org755c5b12009-05-29 11:04:38 +00006263// Debug event handler which gets the function on the top frame and schedules a
6264// break a number of times.
6265static void DebugEventDebugBreak(
6266 v8::DebugEvent event,
6267 v8::Handle<v8::Object> exec_state,
6268 v8::Handle<v8::Object> event_data,
6269 v8::Handle<v8::Value> data) {
6270
6271 if (event == v8::Break) {
6272 break_point_hit_count++;
6273
6274 // Get the name of the top frame function.
6275 if (!frame_function_name.IsEmpty()) {
6276 // Get the name of the function.
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006277 const int argc = 2;
6278 v8::Handle<v8::Value> argv[argc] = { exec_state, v8::Integer::New(0) };
sgjesse@chromium.org755c5b12009-05-29 11:04:38 +00006279 v8::Handle<v8::Value> result = frame_function_name->Call(exec_state,
6280 argc, argv);
6281 if (result->IsUndefined()) {
6282 last_function_hit[0] = '\0';
6283 } else {
6284 CHECK(result->IsString());
6285 v8::Handle<v8::String> function_name(result->ToString());
6286 function_name->WriteAscii(last_function_hit);
6287 }
6288 }
6289
6290 // Keep forcing breaks.
6291 if (break_point_hit_count < 20) {
6292 v8::Debug::DebugBreak();
6293 }
6294 }
6295}
6296
6297
6298TEST(RegExpDebugBreak) {
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00006299 // This test only applies to native regexps.
sgjesse@chromium.org755c5b12009-05-29 11:04:38 +00006300 v8::HandleScope scope;
6301 DebugLocalContext env;
6302
sgjesse@chromium.org755c5b12009-05-29 11:04:38 +00006303 // Create a function for checking the function when hitting a break point.
6304 frame_function_name = CompileFunction(&env,
6305 frame_function_name_source,
6306 "frame_function_name");
6307
6308 // Test RegExp which matches white spaces and comments at the begining of a
6309 // source line.
6310 const char* script =
6311 "var sourceLineBeginningSkip = /^(?:[ \\v\\h]*(?:\\/\\*.*?\\*\\/)*)*/;\n"
6312 "function f(s) { return s.match(sourceLineBeginningSkip)[0].length; }";
6313
6314 v8::Local<v8::Function> f = CompileFunction(script, "f");
6315 const int argc = 1;
6316 v8::Handle<v8::Value> argv[argc] = { v8::String::New(" /* xxx */ a=0;") };
6317 v8::Local<v8::Value> result = f->Call(env->Global(), argc, argv);
6318 CHECK_EQ(12, result->Int32Value());
6319
6320 v8::Debug::SetDebugEventListener(DebugEventDebugBreak);
6321 v8::Debug::DebugBreak();
6322 result = f->Call(env->Global(), argc, argv);
6323
kasperl@chromium.orge959c182009-07-27 08:59:04 +00006324 // Check that there was only one break event. Matching RegExp should not
6325 // cause Break events.
6326 CHECK_EQ(1, break_point_hit_count);
6327 CHECK_EQ("f", last_function_hit);
sgjesse@chromium.org755c5b12009-05-29 11:04:38 +00006328}
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006329#endif // V8_INTERPRETED_REGEXP
sgjesse@chromium.org755c5b12009-05-29 11:04:38 +00006330
6331
kasperl@chromium.org71affb52009-05-26 05:44:31 +00006332// Common part of EvalContextData and NestedBreakEventContextData tests.
6333static void ExecuteScriptForContextCheck() {
6334 // Create a context.
6335 v8::Persistent<v8::Context> context_1;
6336 v8::Handle<v8::ObjectTemplate> global_template =
6337 v8::Handle<v8::ObjectTemplate>();
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00006338 context_1 = v8::Context::New(NULL, global_template);
kasperl@chromium.org71affb52009-05-26 05:44:31 +00006339
6340 // Default data value is undefined.
6341 CHECK(context_1->GetData()->IsUndefined());
6342
6343 // Set and check a data value.
sgjesse@chromium.org499aaa52009-11-30 08:07:20 +00006344 v8::Handle<v8::String> data_1 = v8::String::New("1");
kasperl@chromium.org71affb52009-05-26 05:44:31 +00006345 context_1->SetData(data_1);
6346 CHECK(context_1->GetData()->StrictEquals(data_1));
6347
6348 // Simple test function with eval that causes a break.
6349 const char* source = "function f() { eval('debugger;'); }";
6350
6351 // Enter and run function in the context.
6352 {
6353 v8::Context::Scope context_scope(context_1);
6354 expected_context = context_1;
6355 expected_context_data = data_1;
6356 v8::Local<v8::Function> f = CompileFunction(source, "f");
6357 f->Call(context_1->Global(), 0, NULL);
6358 }
6359}
6360
6361
6362// Test which creates a context and sets embedder data on it. Checks that this
6363// data is set correctly and that when the debug message handler is called for
6364// break event in an eval statement the expected context is the one returned by
6365// Message.GetEventContext.
6366TEST(EvalContextData) {
6367 v8::HandleScope scope;
6368 v8::Debug::SetMessageHandler2(ContextCheckMessageHandler);
6369
6370 ExecuteScriptForContextCheck();
6371
6372 // One time compile event and one time break event.
6373 CHECK_GT(message_handler_hit_count, 2);
6374 v8::Debug::SetMessageHandler2(NULL);
6375 CheckDebuggerUnloaded();
6376}
6377
6378
6379static bool sent_eval = false;
6380static int break_count = 0;
6381static int continue_command_send_count = 0;
6382// Check that the expected context is the one generating the debug event
6383// including the case of nested break event.
6384static void DebugEvalContextCheckMessageHandler(
6385 const v8::Debug::Message& message) {
6386 CHECK(message.GetEventContext() == expected_context);
6387 CHECK(message.GetEventContext()->GetData()->StrictEquals(
6388 expected_context_data));
6389 message_handler_hit_count++;
6390
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00006391 static char print_buffer[1000];
6392 v8::String::Value json(message.GetJSON());
6393 Utf16ToAscii(*json, json.length(), print_buffer);
6394
6395 if (IsBreakEventMessage(print_buffer)) {
kasperl@chromium.org71affb52009-05-26 05:44:31 +00006396 break_count++;
6397 if (!sent_eval) {
6398 sent_eval = true;
6399
6400 const int kBufferSize = 1000;
6401 uint16_t buffer[kBufferSize];
6402 const char* eval_command =
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00006403 "{\"seq\":0,"
6404 "\"type\":\"request\","
6405 "\"command\":\"evaluate\","
6406 "\"arguments\":{\"expression\":\"debugger;\","
6407 "\"global\":true,\"disable_break\":false}}";
kasperl@chromium.org71affb52009-05-26 05:44:31 +00006408
6409 // Send evaluate command.
6410 v8::Debug::SendCommand(buffer, AsciiToUtf16(eval_command, buffer));
6411 return;
6412 } else {
6413 // It's a break event caused by the evaluation request above.
6414 SendContinueCommand();
6415 continue_command_send_count++;
6416 }
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00006417 } else if (IsEvaluateResponseMessage(print_buffer) &&
6418 continue_command_send_count < 2) {
kasperl@chromium.org71affb52009-05-26 05:44:31 +00006419 // Response to the evaluation request. We're still on the breakpoint so
6420 // send continue.
6421 SendContinueCommand();
6422 continue_command_send_count++;
6423 }
6424}
6425
6426
6427// Tests that context returned for break event is correct when the event occurs
6428// in 'evaluate' debugger request.
6429TEST(NestedBreakEventContextData) {
6430 v8::HandleScope scope;
6431 break_count = 0;
6432 message_handler_hit_count = 0;
6433 v8::Debug::SetMessageHandler2(DebugEvalContextCheckMessageHandler);
6434
6435 ExecuteScriptForContextCheck();
6436
6437 // One time compile event and two times break event.
6438 CHECK_GT(message_handler_hit_count, 3);
6439
6440 // One break from the source and another from the evaluate request.
6441 CHECK_EQ(break_count, 2);
6442 v8::Debug::SetMessageHandler2(NULL);
6443 CheckDebuggerUnloaded();
6444}
6445
6446
6447// Debug event listener which counts the script collected events.
6448int script_collected_count = 0;
6449static void DebugEventScriptCollectedEvent(v8::DebugEvent event,
6450 v8::Handle<v8::Object> exec_state,
6451 v8::Handle<v8::Object> event_data,
6452 v8::Handle<v8::Value> data) {
6453 // Count the number of breaks.
6454 if (event == v8::ScriptCollected) {
6455 script_collected_count++;
6456 }
6457}
6458
6459
6460// Test that scripts collected are reported through the debug event listener.
6461TEST(ScriptCollectedEvent) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006462 v8::internal::Debug* debug = v8::internal::Isolate::Current()->debug();
kasperl@chromium.org71affb52009-05-26 05:44:31 +00006463 break_point_hit_count = 0;
6464 script_collected_count = 0;
6465 v8::HandleScope scope;
6466 DebugLocalContext env;
6467
6468 // Request the loaded scripts to initialize the debugger script cache.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006469 debug->GetLoadedScripts();
kasperl@chromium.org71affb52009-05-26 05:44:31 +00006470
6471 // Do garbage collection to ensure that only the script in this test will be
6472 // collected afterwards.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006473 HEAP->CollectAllGarbage(false);
kasperl@chromium.org71affb52009-05-26 05:44:31 +00006474
6475 script_collected_count = 0;
6476 v8::Debug::SetDebugEventListener(DebugEventScriptCollectedEvent,
6477 v8::Undefined());
6478 {
6479 v8::Script::Compile(v8::String::New("eval('a=1')"))->Run();
6480 v8::Script::Compile(v8::String::New("eval('a=2')"))->Run();
6481 }
6482
6483 // Do garbage collection to collect the script above which is no longer
6484 // referenced.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006485 HEAP->CollectAllGarbage(false);
kasperl@chromium.org71affb52009-05-26 05:44:31 +00006486
6487 CHECK_EQ(2, script_collected_count);
6488
6489 v8::Debug::SetDebugEventListener(NULL);
6490 CheckDebuggerUnloaded();
6491}
6492
6493
6494// Debug event listener which counts the script collected events.
6495int script_collected_message_count = 0;
6496static void ScriptCollectedMessageHandler(const v8::Debug::Message& message) {
6497 // Count the number of scripts collected.
6498 if (message.IsEvent() && message.GetEvent() == v8::ScriptCollected) {
6499 script_collected_message_count++;
6500 v8::Handle<v8::Context> context = message.GetEventContext();
6501 CHECK(context.IsEmpty());
6502 }
6503}
6504
6505
6506// Test that GetEventContext doesn't fail and return empty handle for
6507// ScriptCollected events.
6508TEST(ScriptCollectedEventContext) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006509 v8::internal::Debug* debug = v8::internal::Isolate::Current()->debug();
kasperl@chromium.org71affb52009-05-26 05:44:31 +00006510 script_collected_message_count = 0;
6511 v8::HandleScope scope;
6512
6513 { // Scope for the DebugLocalContext.
6514 DebugLocalContext env;
6515
6516 // Request the loaded scripts to initialize the debugger script cache.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006517 debug->GetLoadedScripts();
kasperl@chromium.org71affb52009-05-26 05:44:31 +00006518
6519 // Do garbage collection to ensure that only the script in this test will be
6520 // collected afterwards.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006521 HEAP->CollectAllGarbage(false);
kasperl@chromium.org71affb52009-05-26 05:44:31 +00006522
6523 v8::Debug::SetMessageHandler2(ScriptCollectedMessageHandler);
6524 {
6525 v8::Script::Compile(v8::String::New("eval('a=1')"))->Run();
6526 v8::Script::Compile(v8::String::New("eval('a=2')"))->Run();
6527 }
6528 }
6529
6530 // Do garbage collection to collect the script above which is no longer
6531 // referenced.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006532 HEAP->CollectAllGarbage(false);
kasperl@chromium.org71affb52009-05-26 05:44:31 +00006533
6534 CHECK_EQ(2, script_collected_message_count);
6535
6536 v8::Debug::SetMessageHandler2(NULL);
6537}
6538
6539
6540// Debug event listener which counts the after compile events.
6541int after_compile_message_count = 0;
6542static void AfterCompileMessageHandler(const v8::Debug::Message& message) {
6543 // Count the number of scripts collected.
6544 if (message.IsEvent()) {
6545 if (message.GetEvent() == v8::AfterCompile) {
6546 after_compile_message_count++;
6547 } else if (message.GetEvent() == v8::Break) {
6548 SendContinueCommand();
6549 }
6550 }
6551}
6552
6553
6554// Tests that after compile event is sent as many times as there are scripts
6555// compiled.
6556TEST(AfterCompileMessageWhenMessageHandlerIsReset) {
6557 v8::HandleScope scope;
6558 DebugLocalContext env;
6559 after_compile_message_count = 0;
6560 const char* script = "var a=1";
6561
6562 v8::Debug::SetMessageHandler2(AfterCompileMessageHandler);
6563 v8::Script::Compile(v8::String::New(script))->Run();
6564 v8::Debug::SetMessageHandler2(NULL);
6565
6566 v8::Debug::SetMessageHandler2(AfterCompileMessageHandler);
6567 v8::Debug::DebugBreak();
6568 v8::Script::Compile(v8::String::New(script))->Run();
6569
6570 // Setting listener to NULL should cause debugger unload.
6571 v8::Debug::SetMessageHandler2(NULL);
6572 CheckDebuggerUnloaded();
6573
6574 // Compilation cache should be disabled when debugger is active.
6575 CHECK_EQ(2, after_compile_message_count);
6576}
6577
6578
6579// Tests that break event is sent when message handler is reset.
6580TEST(BreakMessageWhenMessageHandlerIsReset) {
6581 v8::HandleScope scope;
6582 DebugLocalContext env;
6583 after_compile_message_count = 0;
6584 const char* script = "function f() {};";
6585
6586 v8::Debug::SetMessageHandler2(AfterCompileMessageHandler);
6587 v8::Script::Compile(v8::String::New(script))->Run();
6588 v8::Debug::SetMessageHandler2(NULL);
6589
6590 v8::Debug::SetMessageHandler2(AfterCompileMessageHandler);
6591 v8::Debug::DebugBreak();
6592 v8::Local<v8::Function> f =
6593 v8::Local<v8::Function>::Cast(env->Global()->Get(v8::String::New("f")));
6594 f->Call(env->Global(), 0, NULL);
6595
6596 // Setting message handler to NULL should cause debugger unload.
6597 v8::Debug::SetMessageHandler2(NULL);
6598 CheckDebuggerUnloaded();
6599
6600 // Compilation cache should be disabled when debugger is active.
6601 CHECK_EQ(1, after_compile_message_count);
6602}
6603
6604
6605static int exception_event_count = 0;
6606static void ExceptionMessageHandler(const v8::Debug::Message& message) {
6607 if (message.IsEvent() && message.GetEvent() == v8::Exception) {
6608 exception_event_count++;
6609 SendContinueCommand();
6610 }
6611}
6612
6613
6614// Tests that exception event is sent when message handler is reset.
6615TEST(ExceptionMessageWhenMessageHandlerIsReset) {
6616 v8::HandleScope scope;
6617 DebugLocalContext env;
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00006618
6619 // For this test, we want to break on uncaught exceptions:
6620 ChangeBreakOnException(false, true);
6621
kasperl@chromium.org71affb52009-05-26 05:44:31 +00006622 exception_event_count = 0;
6623 const char* script = "function f() {throw new Error()};";
6624
6625 v8::Debug::SetMessageHandler2(AfterCompileMessageHandler);
6626 v8::Script::Compile(v8::String::New(script))->Run();
6627 v8::Debug::SetMessageHandler2(NULL);
6628
6629 v8::Debug::SetMessageHandler2(ExceptionMessageHandler);
6630 v8::Local<v8::Function> f =
6631 v8::Local<v8::Function>::Cast(env->Global()->Get(v8::String::New("f")));
6632 f->Call(env->Global(), 0, NULL);
6633
6634 // Setting message handler to NULL should cause debugger unload.
6635 v8::Debug::SetMessageHandler2(NULL);
6636 CheckDebuggerUnloaded();
6637
6638 CHECK_EQ(1, exception_event_count);
ager@chromium.org9085a012009-05-11 19:22:57 +00006639}
ager@chromium.org5aa501c2009-06-23 07:57:28 +00006640
6641
6642// Tests after compile event is sent when there are some provisional
6643// breakpoints out of the scripts lines range.
6644TEST(ProvisionalBreakpointOnLineOutOfRange) {
6645 v8::HandleScope scope;
6646 DebugLocalContext env;
6647 env.ExposeDebug();
6648 const char* script = "function f() {};";
6649 const char* resource_name = "test_resource";
6650
6651 // Set a couple of provisional breakpoint on lines out of the script lines
6652 // range.
6653 int sbp1 = SetScriptBreakPointByNameFromJS(resource_name, 3,
6654 -1 /* no column */);
6655 int sbp2 = SetScriptBreakPointByNameFromJS(resource_name, 5, 5);
6656
6657 after_compile_message_count = 0;
6658 v8::Debug::SetMessageHandler2(AfterCompileMessageHandler);
6659
6660 v8::ScriptOrigin origin(
6661 v8::String::New(resource_name),
6662 v8::Integer::New(10),
6663 v8::Integer::New(1));
6664 // Compile a script whose first line number is greater than the breakpoints'
6665 // lines.
6666 v8::Script::Compile(v8::String::New(script), &origin)->Run();
6667
6668 // If the script is compiled successfully there is exactly one after compile
6669 // event. In case of an exception in debugger code after compile event is not
6670 // sent.
6671 CHECK_EQ(1, after_compile_message_count);
6672
6673 ClearBreakPointFromJS(sbp1);
6674 ClearBreakPointFromJS(sbp2);
6675 v8::Debug::SetMessageHandler2(NULL);
6676}
kasperl@chromium.orge959c182009-07-27 08:59:04 +00006677
6678
6679static void BreakMessageHandler(const v8::Debug::Message& message) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006680 i::Isolate* isolate = i::Isolate::Current();
kasperl@chromium.orge959c182009-07-27 08:59:04 +00006681 if (message.IsEvent() && message.GetEvent() == v8::Break) {
6682 // Count the number of breaks.
6683 break_point_hit_count++;
6684
6685 v8::HandleScope scope;
6686 v8::Handle<v8::String> json = message.GetJSON();
6687
6688 SendContinueCommand();
6689 } else if (message.IsEvent() && message.GetEvent() == v8::AfterCompile) {
6690 v8::HandleScope scope;
6691
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006692 bool is_debug_break = isolate->stack_guard()->IsDebugBreak();
kasperl@chromium.orge959c182009-07-27 08:59:04 +00006693 // Force DebugBreak flag while serializer is working.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006694 isolate->stack_guard()->DebugBreak();
kasperl@chromium.orge959c182009-07-27 08:59:04 +00006695
6696 // Force serialization to trigger some internal JS execution.
6697 v8::Handle<v8::String> json = message.GetJSON();
6698
6699 // Restore previous state.
6700 if (is_debug_break) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006701 isolate->stack_guard()->DebugBreak();
kasperl@chromium.orge959c182009-07-27 08:59:04 +00006702 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006703 isolate->stack_guard()->Continue(i::DEBUGBREAK);
kasperl@chromium.orge959c182009-07-27 08:59:04 +00006704 }
6705 }
6706}
6707
6708
6709// Test that if DebugBreak is forced it is ignored when code from
6710// debug-delay.js is executed.
6711TEST(NoDebugBreakInAfterCompileMessageHandler) {
6712 v8::HandleScope scope;
6713 DebugLocalContext env;
6714
6715 // Register a debug event listener which sets the break flag and counts.
6716 v8::Debug::SetMessageHandler2(BreakMessageHandler);
6717
6718 // Set the debug break flag.
6719 v8::Debug::DebugBreak();
6720
6721 // Create a function for testing stepping.
6722 const char* src = "function f() { eval('var x = 10;'); } ";
6723 v8::Local<v8::Function> f = CompileFunction(&env, src, "f");
6724
6725 // There should be only one break event.
6726 CHECK_EQ(1, break_point_hit_count);
6727
6728 // Set the debug break flag again.
6729 v8::Debug::DebugBreak();
6730 f->Call(env->Global(), 0, NULL);
6731 // There should be one more break event when the script is evaluated in 'f'.
6732 CHECK_EQ(2, break_point_hit_count);
6733
6734 // Get rid of the debug message handler.
6735 v8::Debug::SetMessageHandler2(NULL);
6736 CheckDebuggerUnloaded();
6737}
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00006738
6739
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00006740static int counting_message_handler_counter;
6741
6742static void CountingMessageHandler(const v8::Debug::Message& message) {
6743 counting_message_handler_counter++;
6744}
6745
6746// Test that debug messages get processed when ProcessDebugMessages is called.
6747TEST(ProcessDebugMessages) {
6748 v8::HandleScope scope;
6749 DebugLocalContext env;
6750
6751 counting_message_handler_counter = 0;
6752
6753 v8::Debug::SetMessageHandler2(CountingMessageHandler);
6754
6755 const int kBufferSize = 1000;
6756 uint16_t buffer[kBufferSize];
6757 const char* scripts_command =
6758 "{\"seq\":0,"
6759 "\"type\":\"request\","
6760 "\"command\":\"scripts\"}";
6761
6762 // Send scripts command.
6763 v8::Debug::SendCommand(buffer, AsciiToUtf16(scripts_command, buffer));
6764
6765 CHECK_EQ(0, counting_message_handler_counter);
6766 v8::Debug::ProcessDebugMessages();
6767 // At least one message should come
6768 CHECK_GE(counting_message_handler_counter, 1);
6769
6770 counting_message_handler_counter = 0;
6771
6772 v8::Debug::SendCommand(buffer, AsciiToUtf16(scripts_command, buffer));
6773 v8::Debug::SendCommand(buffer, AsciiToUtf16(scripts_command, buffer));
6774 CHECK_EQ(0, counting_message_handler_counter);
6775 v8::Debug::ProcessDebugMessages();
6776 // At least two messages should come
6777 CHECK_GE(counting_message_handler_counter, 2);
6778
6779 // Get rid of the debug message handler.
6780 v8::Debug::SetMessageHandler2(NULL);
6781 CheckDebuggerUnloaded();
6782}
6783
6784
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006785struct BacktraceData {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00006786 static int frame_counter;
6787 static void MessageHandler(const v8::Debug::Message& message) {
6788 char print_buffer[1000];
6789 v8::String::Value json(message.GetJSON());
6790 Utf16ToAscii(*json, json.length(), print_buffer, 1000);
6791
6792 if (strstr(print_buffer, "backtrace") == NULL) {
6793 return;
6794 }
6795 frame_counter = GetTotalFramesInt(print_buffer);
6796 }
6797};
6798
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006799int BacktraceData::frame_counter;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00006800
6801
6802// Test that debug messages get processed when ProcessDebugMessages is called.
6803TEST(Backtrace) {
6804 v8::HandleScope scope;
6805 DebugLocalContext env;
6806
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006807 v8::Debug::SetMessageHandler2(BacktraceData::MessageHandler);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00006808
6809 const int kBufferSize = 1000;
6810 uint16_t buffer[kBufferSize];
6811 const char* scripts_command =
6812 "{\"seq\":0,"
6813 "\"type\":\"request\","
6814 "\"command\":\"backtrace\"}";
6815
6816 // Check backtrace from ProcessDebugMessages.
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006817 BacktraceData::frame_counter = -10;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00006818 v8::Debug::SendCommand(buffer, AsciiToUtf16(scripts_command, buffer));
6819 v8::Debug::ProcessDebugMessages();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006820 CHECK_EQ(BacktraceData::frame_counter, 0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00006821
6822 v8::Handle<v8::String> void0 = v8::String::New("void(0)");
6823 v8::Handle<v8::Script> script = v8::Script::Compile(void0, void0);
6824
6825 // Check backtrace from "void(0)" script.
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006826 BacktraceData::frame_counter = -10;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00006827 v8::Debug::SendCommand(buffer, AsciiToUtf16(scripts_command, buffer));
6828 script->Run();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006829 CHECK_EQ(BacktraceData::frame_counter, 1);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00006830
6831 // Get rid of the debug message handler.
6832 v8::Debug::SetMessageHandler2(NULL);
6833 CheckDebuggerUnloaded();
6834}
6835
6836
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00006837TEST(GetMirror) {
6838 v8::HandleScope scope;
6839 DebugLocalContext env;
6840 v8::Handle<v8::Value> obj = v8::Debug::GetMirror(v8::String::New("hodja"));
6841 v8::Handle<v8::Function> run_test = v8::Handle<v8::Function>::Cast(
6842 v8::Script::New(
6843 v8::String::New(
6844 "function runTest(mirror) {"
6845 " return mirror.isString() && (mirror.length() == 5);"
6846 "}"
6847 ""
6848 "runTest;"))->Run());
6849 v8::Handle<v8::Value> result = run_test->Call(env->Global(), 1, &obj);
6850 CHECK(result->IsTrue());
6851}
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006852
6853
6854// Test that the debug break flag works with function.apply.
6855TEST(DebugBreakFunctionApply) {
6856 v8::HandleScope scope;
6857 DebugLocalContext env;
6858
6859 // Create a function for testing breaking in apply.
6860 v8::Local<v8::Function> foo = CompileFunction(
6861 &env,
6862 "function baz(x) { }"
6863 "function bar(x) { baz(); }"
6864 "function foo(){ bar.apply(this, [1]); }",
6865 "foo");
6866
6867 // Register a debug event listener which steps and counts.
6868 v8::Debug::SetDebugEventListener(DebugEventBreakMax);
6869
6870 // Set the debug break flag before calling the code using function.apply.
6871 v8::Debug::DebugBreak();
6872
6873 // Limit the number of debug breaks. This is a regression test for issue 493
6874 // where this test would enter an infinite loop.
6875 break_point_hit_count = 0;
6876 max_break_point_hit_count = 10000; // 10000 => infinite loop.
6877 foo->Call(env->Global(), 0, NULL);
6878
6879 // When keeping the debug break several break will happen.
6880 CHECK_EQ(3, break_point_hit_count);
6881
6882 v8::Debug::SetDebugEventListener(NULL);
6883 CheckDebuggerUnloaded();
6884}
6885
6886
6887v8::Handle<v8::Context> debugee_context;
6888v8::Handle<v8::Context> debugger_context;
6889
6890
6891// Property getter that checks that current and calling contexts
6892// are both the debugee contexts.
6893static v8::Handle<v8::Value> NamedGetterWithCallingContextCheck(
6894 v8::Local<v8::String> name,
6895 const v8::AccessorInfo& info) {
6896 CHECK_EQ(0, strcmp(*v8::String::AsciiValue(name), "a"));
6897 v8::Handle<v8::Context> current = v8::Context::GetCurrent();
6898 CHECK(current == debugee_context);
6899 CHECK(current != debugger_context);
6900 v8::Handle<v8::Context> calling = v8::Context::GetCalling();
6901 CHECK(calling == debugee_context);
6902 CHECK(calling != debugger_context);
6903 return v8::Int32::New(1);
6904}
6905
6906
6907// Debug event listener that checks if the first argument of a function is
6908// an object with property 'a' == 1. If the property has custom accessor
6909// this handler will eventually invoke it.
6910static void DebugEventGetAtgumentPropertyValue(
6911 v8::DebugEvent event,
6912 v8::Handle<v8::Object> exec_state,
6913 v8::Handle<v8::Object> event_data,
6914 v8::Handle<v8::Value> data) {
6915 if (event == v8::Break) {
6916 break_point_hit_count++;
6917 CHECK(debugger_context == v8::Context::GetCurrent());
6918 v8::Handle<v8::Function> func(v8::Function::Cast(*CompileRun(
6919 "(function(exec_state) {\n"
6920 " return (exec_state.frame(0).argumentValue(0).property('a').\n"
6921 " value().value() == 1);\n"
6922 "})")));
6923 const int argc = 1;
6924 v8::Handle<v8::Value> argv[argc] = { exec_state };
6925 v8::Handle<v8::Value> result = func->Call(exec_state, argc, argv);
6926 CHECK(result->IsTrue());
6927 }
6928}
6929
6930
6931TEST(CallingContextIsNotDebugContext) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006932 v8::internal::Debug* debug = v8::internal::Isolate::Current()->debug();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006933 // Create and enter a debugee context.
6934 v8::HandleScope scope;
6935 DebugLocalContext env;
6936 env.ExposeDebug();
6937
6938 // Save handles to the debugger and debugee contexts to be used in
6939 // NamedGetterWithCallingContextCheck.
6940 debugee_context = v8::Local<v8::Context>(*env);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006941 debugger_context = v8::Utils::ToLocal(debug->debug_context());
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006942
6943 // Create object with 'a' property accessor.
6944 v8::Handle<v8::ObjectTemplate> named = v8::ObjectTemplate::New();
6945 named->SetAccessor(v8::String::New("a"),
6946 NamedGetterWithCallingContextCheck);
6947 env->Global()->Set(v8::String::New("obj"),
6948 named->NewInstance());
6949
6950 // Register the debug event listener
6951 v8::Debug::SetDebugEventListener(DebugEventGetAtgumentPropertyValue);
6952
6953 // Create a function that invokes debugger.
6954 v8::Local<v8::Function> foo = CompileFunction(
6955 &env,
6956 "function bar(x) { debugger; }"
6957 "function foo(){ bar(obj); }",
6958 "foo");
6959
6960 break_point_hit_count = 0;
6961 foo->Call(env->Global(), 0, NULL);
6962 CHECK_EQ(1, break_point_hit_count);
6963
6964 v8::Debug::SetDebugEventListener(NULL);
6965 debugee_context = v8::Handle<v8::Context>();
6966 debugger_context = v8::Handle<v8::Context>();
6967 CheckDebuggerUnloaded();
6968}
lrn@chromium.orgc34f5802010-04-28 12:53:43 +00006969
6970
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00006971TEST(DebugContextIsPreservedBetweenAccesses) {
6972 v8::HandleScope scope;
6973 v8::Local<v8::Context> context1 = v8::Debug::GetDebugContext();
6974 v8::Local<v8::Context> context2 = v8::Debug::GetDebugContext();
6975 CHECK_EQ(*context1, *context2);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00006976}
6977
6978
6979static v8::Handle<v8::Value> expected_callback_data;
6980static void DebugEventContextChecker(const v8::Debug::EventDetails& details) {
6981 CHECK(details.GetEventContext() == expected_context);
6982 CHECK_EQ(expected_callback_data, details.GetCallbackData());
6983}
6984
6985// Check that event details contain context where debug event occured.
6986TEST(DebugEventContext) {
6987 v8::HandleScope scope;
6988 expected_callback_data = v8::Int32::New(2010);
6989 v8::Debug::SetDebugEventListener2(DebugEventContextChecker,
6990 expected_callback_data);
6991 expected_context = v8::Context::New();
6992 v8::Context::Scope context_scope(expected_context);
6993 v8::Script::Compile(v8::String::New("(function(){debugger;})();"))->Run();
6994 expected_context.Dispose();
6995 expected_context.Clear();
6996 v8::Debug::SetDebugEventListener(NULL);
6997 expected_context_data = v8::Handle<v8::Value>();
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00006998 CheckDebuggerUnloaded();
6999}
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00007000
mikhail.naganov@gmail.com22762872010-07-14 09:29:05 +00007001
7002static void* expected_break_data;
7003static bool was_debug_break_called;
7004static bool was_debug_event_called;
7005static void DebugEventBreakDataChecker(const v8::Debug::EventDetails& details) {
7006 if (details.GetEvent() == v8::BreakForCommand) {
7007 CHECK_EQ(expected_break_data, details.GetClientData());
7008 was_debug_event_called = true;
7009 } else if (details.GetEvent() == v8::Break) {
7010 was_debug_break_called = true;
7011 }
7012}
7013
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007014
mikhail.naganov@gmail.com22762872010-07-14 09:29:05 +00007015// Check that event details contain context where debug event occured.
7016TEST(DebugEventBreakData) {
7017 v8::HandleScope scope;
7018 DebugLocalContext env;
7019 v8::Debug::SetDebugEventListener2(DebugEventBreakDataChecker);
7020
7021 TestClientData::constructor_call_counter = 0;
7022 TestClientData::destructor_call_counter = 0;
7023
7024 expected_break_data = NULL;
7025 was_debug_event_called = false;
7026 was_debug_break_called = false;
7027 v8::Debug::DebugBreakForCommand();
7028 v8::Script::Compile(v8::String::New("(function(x){return x;})(1);"))->Run();
7029 CHECK(was_debug_event_called);
7030 CHECK(!was_debug_break_called);
7031
7032 TestClientData* data1 = new TestClientData();
7033 expected_break_data = data1;
7034 was_debug_event_called = false;
7035 was_debug_break_called = false;
7036 v8::Debug::DebugBreakForCommand(data1);
7037 v8::Script::Compile(v8::String::New("(function(x){return x+1;})(1);"))->Run();
7038 CHECK(was_debug_event_called);
7039 CHECK(!was_debug_break_called);
7040
7041 expected_break_data = NULL;
7042 was_debug_event_called = false;
7043 was_debug_break_called = false;
7044 v8::Debug::DebugBreak();
7045 v8::Script::Compile(v8::String::New("(function(x){return x+2;})(1);"))->Run();
7046 CHECK(!was_debug_event_called);
7047 CHECK(was_debug_break_called);
7048
7049 TestClientData* data2 = new TestClientData();
7050 expected_break_data = data2;
7051 was_debug_event_called = false;
7052 was_debug_break_called = false;
7053 v8::Debug::DebugBreak();
7054 v8::Debug::DebugBreakForCommand(data2);
7055 v8::Script::Compile(v8::String::New("(function(x){return x+3;})(1);"))->Run();
7056 CHECK(was_debug_event_called);
7057 CHECK(was_debug_break_called);
7058
7059 CHECK_EQ(2, TestClientData::constructor_call_counter);
7060 CHECK_EQ(TestClientData::constructor_call_counter,
7061 TestClientData::destructor_call_counter);
7062
7063 v8::Debug::SetDebugEventListener(NULL);
7064 CheckDebuggerUnloaded();
7065}
7066
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007067static bool debug_event_break_deoptimize_done = false;
7068
7069static void DebugEventBreakDeoptimize(v8::DebugEvent event,
7070 v8::Handle<v8::Object> exec_state,
7071 v8::Handle<v8::Object> event_data,
7072 v8::Handle<v8::Value> data) {
7073 if (event == v8::Break) {
7074 if (!frame_function_name.IsEmpty()) {
7075 // Get the name of the function.
7076 const int argc = 2;
7077 v8::Handle<v8::Value> argv[argc] = { exec_state, v8::Integer::New(0) };
7078 v8::Handle<v8::Value> result =
7079 frame_function_name->Call(exec_state, argc, argv);
7080 if (!result->IsUndefined()) {
7081 char fn[80];
7082 CHECK(result->IsString());
7083 v8::Handle<v8::String> function_name(result->ToString());
7084 function_name->WriteAscii(fn);
7085 if (strcmp(fn, "bar") == 0) {
7086 i::Deoptimizer::DeoptimizeAll();
7087 debug_event_break_deoptimize_done = true;
7088 }
7089 }
7090 }
7091
7092 v8::Debug::DebugBreak();
7093 }
7094}
7095
7096
7097// Test deoptimization when execution is broken using the debug break stack
7098// check interrupt.
7099TEST(DeoptimizeDuringDebugBreak) {
7100 v8::HandleScope scope;
7101 DebugLocalContext env;
7102 env.ExposeDebug();
7103
7104 // Create a function for checking the function when hitting a break point.
7105 frame_function_name = CompileFunction(&env,
7106 frame_function_name_source,
7107 "frame_function_name");
7108
7109
7110 // Set a debug event listener which will keep interrupting execution until
7111 // debug break. When inside function bar it will deoptimize all functions.
7112 // This tests lazy deoptimization bailout for the stack check, as the first
7113 // time in function bar when using debug break and no break points will be at
7114 // the initial stack check.
7115 v8::Debug::SetDebugEventListener(DebugEventBreakDeoptimize,
7116 v8::Undefined());
7117
7118 // Compile and run function bar which will optimize it for some flag settings.
7119 v8::Script::Compile(v8::String::New("function bar(){}; bar()"))->Run();
7120
7121 // Set debug break and call bar again.
7122 v8::Debug::DebugBreak();
7123 v8::Script::Compile(v8::String::New("bar()"))->Run();
7124
7125 CHECK(debug_event_break_deoptimize_done);
7126
7127 v8::Debug::SetDebugEventListener(NULL);
7128}
7129
7130
7131static void DebugEventBreakWithOptimizedStack(v8::DebugEvent event,
7132 v8::Handle<v8::Object> exec_state,
7133 v8::Handle<v8::Object> event_data,
7134 v8::Handle<v8::Value> data) {
7135 if (event == v8::Break) {
7136 if (!frame_function_name.IsEmpty()) {
7137 for (int i = 0; i < 2; i++) {
7138 const int argc = 2;
7139 v8::Handle<v8::Value> argv[argc] = { exec_state, v8::Integer::New(i) };
7140 // Get the name of the function in frame i.
7141 v8::Handle<v8::Value> result =
7142 frame_function_name->Call(exec_state, argc, argv);
7143 CHECK(result->IsString());
7144 v8::Handle<v8::String> function_name(result->ToString());
7145 CHECK(function_name->Equals(v8::String::New("loop")));
7146 // Get the name of the first argument in frame i.
7147 result = frame_argument_name->Call(exec_state, argc, argv);
7148 CHECK(result->IsString());
7149 v8::Handle<v8::String> argument_name(result->ToString());
7150 CHECK(argument_name->Equals(v8::String::New("count")));
7151 // Get the value of the first argument in frame i. If the
7152 // funtion is optimized the value will be undefined, otherwise
7153 // the value will be '1 - i'.
7154 //
7155 // TODO(3141533): We should be able to get the real value for
7156 // optimized frames.
7157 result = frame_argument_value->Call(exec_state, argc, argv);
7158 CHECK(result->IsUndefined() || (result->Int32Value() == 1 - i));
7159 // Get the name of the first local variable.
7160 result = frame_local_name->Call(exec_state, argc, argv);
7161 CHECK(result->IsString());
7162 v8::Handle<v8::String> local_name(result->ToString());
7163 CHECK(local_name->Equals(v8::String::New("local")));
7164 // Get the value of the first local variable. If the function
7165 // is optimized the value will be undefined, otherwise it will
7166 // be 42.
7167 //
7168 // TODO(3141533): We should be able to get the real value for
7169 // optimized frames.
7170 result = frame_local_value->Call(exec_state, argc, argv);
7171 CHECK(result->IsUndefined() || (result->Int32Value() == 42));
7172 }
7173 }
7174 }
7175}
7176
7177
7178static v8::Handle<v8::Value> ScheduleBreak(const v8::Arguments& args) {
7179 v8::Debug::SetDebugEventListener(DebugEventBreakWithOptimizedStack,
7180 v8::Undefined());
7181 v8::Debug::DebugBreak();
7182 return v8::Undefined();
7183}
7184
7185
7186TEST(DebugBreakStackInspection) {
7187 v8::HandleScope scope;
7188 DebugLocalContext env;
7189
7190 frame_function_name =
7191 CompileFunction(&env, frame_function_name_source, "frame_function_name");
7192 frame_argument_name =
7193 CompileFunction(&env, frame_argument_name_source, "frame_argument_name");
7194 frame_argument_value = CompileFunction(&env,
7195 frame_argument_value_source,
7196 "frame_argument_value");
7197 frame_local_name =
7198 CompileFunction(&env, frame_local_name_source, "frame_local_name");
7199 frame_local_value =
7200 CompileFunction(&env, frame_local_value_source, "frame_local_value");
7201
7202 v8::Handle<v8::FunctionTemplate> schedule_break_template =
7203 v8::FunctionTemplate::New(ScheduleBreak);
7204 v8::Handle<v8::Function> schedule_break =
7205 schedule_break_template->GetFunction();
7206 env->Global()->Set(v8_str("scheduleBreak"), schedule_break);
7207
7208 const char* src =
7209 "function loop(count) {"
7210 " var local = 42;"
7211 " if (count < 1) { scheduleBreak(); loop(count + 1); }"
7212 "}"
7213 "loop(0);";
7214 v8::Script::Compile(v8::String::New(src))->Run();
7215}
7216
whesse@chromium.orgf0ac72d2010-11-08 12:47:26 +00007217
7218// Test that setting the terminate execution flag during debug break processing.
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00007219static void TestDebugBreakInLoop(const char* loop_head,
7220 const char** loop_bodies,
7221 const char* loop_tail) {
7222 // Receive 100 breaks for each test and then terminate JavaScript execution.
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00007223 static const int kBreaksPerTest = 100;
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00007224
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00007225 for (int i = 0; i < 1 && loop_bodies[i] != NULL; i++) {
7226 // Perform a lazy deoptimization after various numbers of breaks
7227 // have been hit.
7228 for (int j = 0; j < 10; j++) {
7229 break_point_hit_count_deoptimize = j;
7230 if (j == 10) {
7231 break_point_hit_count_deoptimize = kBreaksPerTest;
7232 }
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00007233
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00007234 break_point_hit_count = 0;
7235 max_break_point_hit_count = kBreaksPerTest;
7236 terminate_after_max_break_point_hit = true;
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00007237
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00007238 EmbeddedVector<char, 1024> buffer;
7239 OS::SNPrintF(buffer,
7240 "function f() {%s%s%s}",
7241 loop_head, loop_bodies[i], loop_tail);
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00007242
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00007243 // Function with infinite loop.
7244 CompileRun(buffer.start());
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00007245
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00007246 // Set the debug break to enter the debugger as soon as possible.
7247 v8::Debug::DebugBreak();
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00007248
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00007249 // Call function with infinite loop.
7250 CompileRun("f();");
7251 CHECK_EQ(kBreaksPerTest, break_point_hit_count);
7252
7253 CHECK(!v8::V8::IsExecutionTerminating());
7254 }
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00007255 }
7256}
7257
7258
whesse@chromium.orgf0ac72d2010-11-08 12:47:26 +00007259TEST(DebugBreakLoop) {
7260 v8::HandleScope scope;
7261 DebugLocalContext env;
7262
whesse@chromium.orgf0ac72d2010-11-08 12:47:26 +00007263 // Register a debug event listener which sets the break flag and counts.
7264 v8::Debug::SetDebugEventListener(DebugEventBreakMax);
7265
jkummerow@chromium.orgddda9e82011-07-06 11:27:02 +00007266 // Create a function for getting the frame count when hitting the break.
7267 frame_count = CompileFunction(&env, frame_count_source, "frame_count");
7268
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00007269 CompileRun("var a = 1;");
7270 CompileRun("function g() { }");
7271 CompileRun("function h() { }");
whesse@chromium.orgf0ac72d2010-11-08 12:47:26 +00007272
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00007273 const char* loop_bodies[] = {
7274 "",
7275 "g()",
7276 "if (a == 0) { g() }",
7277 "if (a == 1) { g() }",
7278 "if (a == 0) { g() } else { h() }",
7279 "if (a == 0) { continue }",
7280 "if (a == 1) { continue }",
7281 "switch (a) { case 1: g(); }",
7282 "switch (a) { case 1: continue; }",
7283 "switch (a) { case 1: g(); break; default: h() }",
7284 "switch (a) { case 1: continue; break; default: h() }",
7285 NULL
7286 };
whesse@chromium.orgf0ac72d2010-11-08 12:47:26 +00007287
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00007288 TestDebugBreakInLoop("while (true) {", loop_bodies, "}");
7289 TestDebugBreakInLoop("while (a == 1) {", loop_bodies, "}");
7290
7291 TestDebugBreakInLoop("do {", loop_bodies, "} while (true)");
7292 TestDebugBreakInLoop("do {", loop_bodies, "} while (a == 1)");
7293
7294 TestDebugBreakInLoop("for (;;) {", loop_bodies, "}");
7295 TestDebugBreakInLoop("for (;a == 1;) {", loop_bodies, "}");
whesse@chromium.orgf0ac72d2010-11-08 12:47:26 +00007296
7297 // Get rid of the debug event listener.
7298 v8::Debug::SetDebugEventListener(NULL);
7299 CheckDebuggerUnloaded();
7300}
7301
7302
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00007303#endif // ENABLE_DEBUGGER_SUPPORT