blob: 0455790e04408e784928a014c92744b37ba514d8 [file] [log] [blame]
Steve Blocka7e24c12009-10-30 11:49:00 +00001// Copyright 2007-2008 the V8 project authors. All rights reserved.
2// Redistribution and use in source and binary forms, with or without
3// modification, are permitted provided that the following conditions are
4// met:
5//
6// * Redistributions of source code must retain the above copyright
7// notice, this list of conditions and the following disclaimer.
8// * Redistributions in binary form must reproduce the above
9// copyright notice, this list of conditions and the following
10// disclaimer in the documentation and/or other materials provided
11// with the distribution.
12// * Neither the name of Google Inc. nor the names of its
13// contributors may be used to endorse or promote products derived
14// from this software without specific prior written permission.
15//
16// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27
Kristian Monsen9dcf7e22010-06-28 14:14:28 +010028#ifdef ENABLE_DEBUGGER_SUPPORT
Steve Blocka7e24c12009-10-30 11:49:00 +000029
Kristian Monsen9dcf7e22010-06-28 14:14:28 +010030#include <stdlib.h>
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +010031
Steve Blocka7e24c12009-10-30 11:49:00 +000032#include "v8.h"
33
34#include "api.h"
35#include "compilation-cache.h"
36#include "debug.h"
37#include "platform.h"
38#include "stub-cache.h"
39#include "cctest.h"
40
41
42using ::v8::internal::EmbeddedVector;
43using ::v8::internal::Object;
44using ::v8::internal::OS;
45using ::v8::internal::Handle;
46using ::v8::internal::Heap;
47using ::v8::internal::JSGlobalProxy;
48using ::v8::internal::Code;
49using ::v8::internal::Debug;
50using ::v8::internal::Debugger;
51using ::v8::internal::CommandMessage;
52using ::v8::internal::CommandMessageQueue;
53using ::v8::internal::StepAction;
54using ::v8::internal::StepIn; // From StepAction enum
55using ::v8::internal::StepNext; // From StepAction enum
56using ::v8::internal::StepOut; // From StepAction enum
57using ::v8::internal::Vector;
Steve Blockd0582a62009-12-15 09:54:21 +000058using ::v8::internal::StrLength;
Steve Blocka7e24c12009-10-30 11:49:00 +000059
60// Size of temp buffer for formatting small strings.
61#define SMALL_STRING_BUFFER_SIZE 80
62
63// --- A d d i t i o n a l C h e c k H e l p e r s
64
65
66// Helper function used by the CHECK_EQ function when given Address
67// arguments. Should not be called directly.
68static inline void CheckEqualsHelper(const char* file, int line,
69 const char* expected_source,
70 ::v8::internal::Address expected,
71 const char* value_source,
72 ::v8::internal::Address value) {
73 if (expected != value) {
74 V8_Fatal(file, line, "CHECK_EQ(%s, %s) failed\n# "
75 "Expected: %i\n# Found: %i",
76 expected_source, value_source, expected, value);
77 }
78}
79
80
81// Helper function used by the CHECK_NE function when given Address
82// arguments. Should not be called directly.
83static inline void CheckNonEqualsHelper(const char* file, int line,
84 const char* unexpected_source,
85 ::v8::internal::Address unexpected,
86 const char* value_source,
87 ::v8::internal::Address value) {
88 if (unexpected == value) {
89 V8_Fatal(file, line, "CHECK_NE(%s, %s) failed\n# Value: %i",
90 unexpected_source, value_source, value);
91 }
92}
93
94
95// Helper function used by the CHECK function when given code
96// arguments. Should not be called directly.
97static inline void CheckEqualsHelper(const char* file, int line,
98 const char* expected_source,
99 const Code* expected,
100 const char* value_source,
101 const Code* value) {
102 if (expected != value) {
103 V8_Fatal(file, line, "CHECK_EQ(%s, %s) failed\n# "
104 "Expected: %p\n# Found: %p",
105 expected_source, value_source, expected, value);
106 }
107}
108
109
110static inline void CheckNonEqualsHelper(const char* file, int line,
111 const char* expected_source,
112 const Code* expected,
113 const char* value_source,
114 const Code* value) {
115 if (expected == value) {
116 V8_Fatal(file, line, "CHECK_NE(%s, %s) failed\n# Value: %p",
117 expected_source, value_source, value);
118 }
119}
120
121
122// --- H e l p e r C l a s s e s
123
124
125// Helper class for creating a V8 enviromnent for running tests
126class DebugLocalContext {
127 public:
128 inline DebugLocalContext(
129 v8::ExtensionConfiguration* extensions = 0,
130 v8::Handle<v8::ObjectTemplate> global_template =
131 v8::Handle<v8::ObjectTemplate>(),
132 v8::Handle<v8::Value> global_object = v8::Handle<v8::Value>())
133 : context_(v8::Context::New(extensions, global_template, global_object)) {
134 context_->Enter();
135 }
136 inline ~DebugLocalContext() {
137 context_->Exit();
138 context_.Dispose();
139 }
140 inline v8::Context* operator->() { return *context_; }
141 inline v8::Context* operator*() { return *context_; }
142 inline bool IsReady() { return !context_.IsEmpty(); }
143 void ExposeDebug() {
144 // Expose the debug context global object in the global object for testing.
145 Debug::Load();
146 Debug::debug_context()->set_security_token(
147 v8::Utils::OpenHandle(*context_)->security_token());
148
149 Handle<JSGlobalProxy> global(Handle<JSGlobalProxy>::cast(
150 v8::Utils::OpenHandle(*context_->Global())));
151 Handle<v8::internal::String> debug_string =
152 v8::internal::Factory::LookupAsciiSymbol("debug");
153 SetProperty(global, debug_string,
154 Handle<Object>(Debug::debug_context()->global_proxy()), DONT_ENUM);
155 }
156 private:
157 v8::Persistent<v8::Context> context_;
158};
159
160
161// --- H e l p e r F u n c t i o n s
162
163
164// Compile and run the supplied source and return the fequested function.
165static v8::Local<v8::Function> CompileFunction(DebugLocalContext* env,
166 const char* source,
167 const char* function_name) {
168 v8::Script::Compile(v8::String::New(source))->Run();
169 return v8::Local<v8::Function>::Cast(
170 (*env)->Global()->Get(v8::String::New(function_name)));
171}
172
173
174// Compile and run the supplied source and return the requested function.
175static v8::Local<v8::Function> CompileFunction(const char* source,
176 const char* function_name) {
177 v8::Script::Compile(v8::String::New(source))->Run();
178 return v8::Local<v8::Function>::Cast(
179 v8::Context::GetCurrent()->Global()->Get(v8::String::New(function_name)));
180}
181
182
Steve Blocka7e24c12009-10-30 11:49:00 +0000183// Is there any debug info for the function?
184static bool HasDebugInfo(v8::Handle<v8::Function> fun) {
185 Handle<v8::internal::JSFunction> f = v8::Utils::OpenHandle(*fun);
186 Handle<v8::internal::SharedFunctionInfo> shared(f->shared());
187 return Debug::HasDebugInfo(shared);
188}
189
190
191// Set a break point in a function and return the associated break point
192// number.
193static int SetBreakPoint(Handle<v8::internal::JSFunction> fun, int position) {
194 static int break_point = 0;
195 Handle<v8::internal::SharedFunctionInfo> shared(fun->shared());
196 Debug::SetBreakPoint(
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100197 shared,
198 Handle<Object>(v8::internal::Smi::FromInt(++break_point)),
199 &position);
Steve Blocka7e24c12009-10-30 11:49:00 +0000200 return break_point;
201}
202
203
204// Set a break point in a function and return the associated break point
205// number.
206static int SetBreakPoint(v8::Handle<v8::Function> fun, int position) {
207 return SetBreakPoint(v8::Utils::OpenHandle(*fun), position);
208}
209
210
211// Set a break point in a function using the Debug object and return the
212// associated break point number.
213static int SetBreakPointFromJS(const char* function_name,
214 int line, int position) {
215 EmbeddedVector<char, SMALL_STRING_BUFFER_SIZE> buffer;
216 OS::SNPrintF(buffer,
217 "debug.Debug.setBreakPoint(%s,%d,%d)",
218 function_name, line, position);
219 buffer[SMALL_STRING_BUFFER_SIZE - 1] = '\0';
220 v8::Handle<v8::String> str = v8::String::New(buffer.start());
221 return v8::Script::Compile(str)->Run()->Int32Value();
222}
223
224
225// Set a break point in a script identified by id using the global Debug object.
226static int SetScriptBreakPointByIdFromJS(int script_id, int line, int column) {
227 EmbeddedVector<char, SMALL_STRING_BUFFER_SIZE> buffer;
228 if (column >= 0) {
229 // Column specified set script break point on precise location.
230 OS::SNPrintF(buffer,
231 "debug.Debug.setScriptBreakPointById(%d,%d,%d)",
232 script_id, line, column);
233 } else {
234 // Column not specified set script break point on line.
235 OS::SNPrintF(buffer,
236 "debug.Debug.setScriptBreakPointById(%d,%d)",
237 script_id, line);
238 }
239 buffer[SMALL_STRING_BUFFER_SIZE - 1] = '\0';
240 {
241 v8::TryCatch try_catch;
242 v8::Handle<v8::String> str = v8::String::New(buffer.start());
243 v8::Handle<v8::Value> value = v8::Script::Compile(str)->Run();
244 CHECK(!try_catch.HasCaught());
245 return value->Int32Value();
246 }
247}
248
249
250// Set a break point in a script identified by name using the global Debug
251// object.
252static int SetScriptBreakPointByNameFromJS(const char* script_name,
253 int line, int column) {
254 EmbeddedVector<char, SMALL_STRING_BUFFER_SIZE> buffer;
255 if (column >= 0) {
256 // Column specified set script break point on precise location.
257 OS::SNPrintF(buffer,
258 "debug.Debug.setScriptBreakPointByName(\"%s\",%d,%d)",
259 script_name, line, column);
260 } else {
261 // Column not specified set script break point on line.
262 OS::SNPrintF(buffer,
263 "debug.Debug.setScriptBreakPointByName(\"%s\",%d)",
264 script_name, line);
265 }
266 buffer[SMALL_STRING_BUFFER_SIZE - 1] = '\0';
267 {
268 v8::TryCatch try_catch;
269 v8::Handle<v8::String> str = v8::String::New(buffer.start());
270 v8::Handle<v8::Value> value = v8::Script::Compile(str)->Run();
271 CHECK(!try_catch.HasCaught());
272 return value->Int32Value();
273 }
274}
275
276
277// Clear a break point.
278static void ClearBreakPoint(int break_point) {
279 Debug::ClearBreakPoint(
280 Handle<Object>(v8::internal::Smi::FromInt(break_point)));
281}
282
283
284// Clear a break point using the global Debug object.
285static void ClearBreakPointFromJS(int break_point_number) {
286 EmbeddedVector<char, SMALL_STRING_BUFFER_SIZE> buffer;
287 OS::SNPrintF(buffer,
288 "debug.Debug.clearBreakPoint(%d)",
289 break_point_number);
290 buffer[SMALL_STRING_BUFFER_SIZE - 1] = '\0';
291 v8::Script::Compile(v8::String::New(buffer.start()))->Run();
292}
293
294
295static void EnableScriptBreakPointFromJS(int break_point_number) {
296 EmbeddedVector<char, SMALL_STRING_BUFFER_SIZE> buffer;
297 OS::SNPrintF(buffer,
298 "debug.Debug.enableScriptBreakPoint(%d)",
299 break_point_number);
300 buffer[SMALL_STRING_BUFFER_SIZE - 1] = '\0';
301 v8::Script::Compile(v8::String::New(buffer.start()))->Run();
302}
303
304
305static void DisableScriptBreakPointFromJS(int break_point_number) {
306 EmbeddedVector<char, SMALL_STRING_BUFFER_SIZE> buffer;
307 OS::SNPrintF(buffer,
308 "debug.Debug.disableScriptBreakPoint(%d)",
309 break_point_number);
310 buffer[SMALL_STRING_BUFFER_SIZE - 1] = '\0';
311 v8::Script::Compile(v8::String::New(buffer.start()))->Run();
312}
313
314
315static void ChangeScriptBreakPointConditionFromJS(int break_point_number,
316 const char* condition) {
317 EmbeddedVector<char, SMALL_STRING_BUFFER_SIZE> buffer;
318 OS::SNPrintF(buffer,
319 "debug.Debug.changeScriptBreakPointCondition(%d, \"%s\")",
320 break_point_number, condition);
321 buffer[SMALL_STRING_BUFFER_SIZE - 1] = '\0';
322 v8::Script::Compile(v8::String::New(buffer.start()))->Run();
323}
324
325
326static void ChangeScriptBreakPointIgnoreCountFromJS(int break_point_number,
327 int ignoreCount) {
328 EmbeddedVector<char, SMALL_STRING_BUFFER_SIZE> buffer;
329 OS::SNPrintF(buffer,
330 "debug.Debug.changeScriptBreakPointIgnoreCount(%d, %d)",
331 break_point_number, ignoreCount);
332 buffer[SMALL_STRING_BUFFER_SIZE - 1] = '\0';
333 v8::Script::Compile(v8::String::New(buffer.start()))->Run();
334}
335
336
337// Change break on exception.
338static void ChangeBreakOnException(bool caught, bool uncaught) {
339 Debug::ChangeBreakOnException(v8::internal::BreakException, caught);
340 Debug::ChangeBreakOnException(v8::internal::BreakUncaughtException, uncaught);
341}
342
343
344// Change break on exception using the global Debug object.
345static void ChangeBreakOnExceptionFromJS(bool caught, bool uncaught) {
346 if (caught) {
347 v8::Script::Compile(
348 v8::String::New("debug.Debug.setBreakOnException()"))->Run();
349 } else {
350 v8::Script::Compile(
351 v8::String::New("debug.Debug.clearBreakOnException()"))->Run();
352 }
353 if (uncaught) {
354 v8::Script::Compile(
355 v8::String::New("debug.Debug.setBreakOnUncaughtException()"))->Run();
356 } else {
357 v8::Script::Compile(
358 v8::String::New("debug.Debug.clearBreakOnUncaughtException()"))->Run();
359 }
360}
361
362
363// Prepare to step to next break location.
364static void PrepareStep(StepAction step_action) {
365 Debug::PrepareStep(step_action, 1);
366}
367
368
369// This function is in namespace v8::internal to be friend with class
370// v8::internal::Debug.
371namespace v8 {
372namespace internal {
373
374// Collect the currently debugged functions.
375Handle<FixedArray> GetDebuggedFunctions() {
376 v8::internal::DebugInfoListNode* node = Debug::debug_info_list_;
377
378 // Find the number of debugged functions.
379 int count = 0;
380 while (node) {
381 count++;
382 node = node->next();
383 }
384
385 // Allocate array for the debugged functions
386 Handle<FixedArray> debugged_functions =
387 v8::internal::Factory::NewFixedArray(count);
388
389 // Run through the debug info objects and collect all functions.
390 count = 0;
391 while (node) {
392 debugged_functions->set(count++, *node->debug_info());
393 node = node->next();
394 }
395
396 return debugged_functions;
397}
398
399
400static Handle<Code> ComputeCallDebugBreak(int argc) {
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100401 CALL_HEAP_FUNCTION(
402 v8::internal::StubCache::ComputeCallDebugBreak(argc, Code::CALL_IC),
403 Code);
Steve Blocka7e24c12009-10-30 11:49:00 +0000404}
405
406
407// Check that the debugger has been fully unloaded.
408void CheckDebuggerUnloaded(bool check_functions) {
409 // Check that the debugger context is cleared and that there is no debug
410 // information stored for the debugger.
411 CHECK(Debug::debug_context().is_null());
412 CHECK_EQ(NULL, Debug::debug_info_list_);
413
414 // Collect garbage to ensure weak handles are cleared.
415 Heap::CollectAllGarbage(false);
416 Heap::CollectAllGarbage(false);
417
418 // Iterate the head and check that there are no debugger related objects left.
419 HeapIterator iterator;
Leon Clarked91b9f72010-01-27 17:25:45 +0000420 for (HeapObject* obj = iterator.next(); obj != NULL; obj = iterator.next()) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000421 CHECK(!obj->IsDebugInfo());
422 CHECK(!obj->IsBreakPointInfo());
423
424 // If deep check of functions is requested check that no debug break code
425 // is left in all functions.
426 if (check_functions) {
427 if (obj->IsJSFunction()) {
428 JSFunction* fun = JSFunction::cast(obj);
429 for (RelocIterator it(fun->shared()->code()); !it.done(); it.next()) {
430 RelocInfo::Mode rmode = it.rinfo()->rmode();
431 if (RelocInfo::IsCodeTarget(rmode)) {
432 CHECK(!Debug::IsDebugBreak(it.rinfo()->target_address()));
433 } else if (RelocInfo::IsJSReturn(rmode)) {
434 CHECK(!Debug::IsDebugBreakAtReturn(it.rinfo()));
435 }
436 }
437 }
438 }
439 }
440}
441
442
Steve Block6ded16b2010-05-10 14:33:55 +0100443void ForceUnloadDebugger() {
444 Debugger::never_unload_debugger_ = false;
445 Debugger::UnloadDebugger();
446}
447
448
Steve Blocka7e24c12009-10-30 11:49:00 +0000449} } // namespace v8::internal
450
451
452// Check that the debugger has been fully unloaded.
453static void CheckDebuggerUnloaded(bool check_functions = false) {
Leon Clarkee46be812010-01-19 14:06:41 +0000454 // Let debugger to unload itself synchronously
455 v8::Debug::ProcessDebugMessages();
456
Steve Blocka7e24c12009-10-30 11:49:00 +0000457 v8::internal::CheckDebuggerUnloaded(check_functions);
458}
459
460
461// Inherit from BreakLocationIterator to get access to protected parts for
462// testing.
463class TestBreakLocationIterator: public v8::internal::BreakLocationIterator {
464 public:
465 explicit TestBreakLocationIterator(Handle<v8::internal::DebugInfo> debug_info)
466 : BreakLocationIterator(debug_info, v8::internal::SOURCE_BREAK_LOCATIONS) {}
467 v8::internal::RelocIterator* it() { return reloc_iterator_; }
468 v8::internal::RelocIterator* it_original() {
469 return reloc_iterator_original_;
470 }
471};
472
473
474// Compile a function, set a break point and check that the call at the break
475// location in the code is the expected debug_break function.
476void CheckDebugBreakFunction(DebugLocalContext* env,
477 const char* source, const char* name,
478 int position, v8::internal::RelocInfo::Mode mode,
479 Code* debug_break) {
480 // Create function and set the break point.
481 Handle<v8::internal::JSFunction> fun = v8::Utils::OpenHandle(
482 *CompileFunction(env, source, name));
483 int bp = SetBreakPoint(fun, position);
484
485 // Check that the debug break function is as expected.
486 Handle<v8::internal::SharedFunctionInfo> shared(fun->shared());
487 CHECK(Debug::HasDebugInfo(shared));
488 TestBreakLocationIterator it1(Debug::GetDebugInfo(shared));
489 it1.FindBreakLocationFromPosition(position);
490 CHECK_EQ(mode, it1.it()->rinfo()->rmode());
491 if (mode != v8::internal::RelocInfo::JS_RETURN) {
492 CHECK_EQ(debug_break,
493 Code::GetCodeFromTargetAddress(it1.it()->rinfo()->target_address()));
494 } else {
495 CHECK(Debug::IsDebugBreakAtReturn(it1.it()->rinfo()));
496 }
497
498 // Clear the break point and check that the debug break function is no longer
499 // there
500 ClearBreakPoint(bp);
501 CHECK(!Debug::HasDebugInfo(shared));
502 CHECK(Debug::EnsureDebugInfo(shared));
503 TestBreakLocationIterator it2(Debug::GetDebugInfo(shared));
504 it2.FindBreakLocationFromPosition(position);
505 CHECK_EQ(mode, it2.it()->rinfo()->rmode());
506 if (mode == v8::internal::RelocInfo::JS_RETURN) {
507 CHECK(!Debug::IsDebugBreakAtReturn(it2.it()->rinfo()));
508 }
509}
510
511
512// --- D e b u g E v e n t H a n d l e r s
513// ---
514// --- The different tests uses a number of debug event handlers.
515// ---
516
517
518// Source for The JavaScript function which picks out the function name of the
519// top frame.
520const char* frame_function_name_source =
521 "function frame_function_name(exec_state) {"
522 " return exec_state.frame(0).func().name();"
523 "}";
524v8::Local<v8::Function> frame_function_name;
525
526
527// Source for The JavaScript function which picks out the source line for the
528// top frame.
529const char* frame_source_line_source =
530 "function frame_source_line(exec_state) {"
531 " return exec_state.frame(0).sourceLine();"
532 "}";
533v8::Local<v8::Function> frame_source_line;
534
535
536// Source for The JavaScript function which picks out the source column for the
537// top frame.
538const char* frame_source_column_source =
539 "function frame_source_column(exec_state) {"
540 " return exec_state.frame(0).sourceColumn();"
541 "}";
542v8::Local<v8::Function> frame_source_column;
543
544
545// Source for The JavaScript function which picks out the script name for the
546// top frame.
547const char* frame_script_name_source =
548 "function frame_script_name(exec_state) {"
549 " return exec_state.frame(0).func().script().name();"
550 "}";
551v8::Local<v8::Function> frame_script_name;
552
553
554// Source for The JavaScript function which picks out the script data for the
555// top frame.
556const char* frame_script_data_source =
557 "function frame_script_data(exec_state) {"
558 " return exec_state.frame(0).func().script().data();"
559 "}";
560v8::Local<v8::Function> frame_script_data;
561
562
Andrei Popescu402d9372010-02-26 13:31:12 +0000563// Source for The JavaScript function which picks out the script data from
564// AfterCompile event
565const char* compiled_script_data_source =
566 "function compiled_script_data(event_data) {"
567 " return event_data.script().data();"
568 "}";
569v8::Local<v8::Function> compiled_script_data;
570
571
Steve Blocka7e24c12009-10-30 11:49:00 +0000572// Source for The JavaScript function which returns the number of frames.
573static const char* frame_count_source =
574 "function frame_count(exec_state) {"
575 " return exec_state.frameCount();"
576 "}";
577v8::Handle<v8::Function> frame_count;
578
579
580// Global variable to store the last function hit - used by some tests.
581char last_function_hit[80];
582
583// Global variable to store the name and data for last script hit - used by some
584// tests.
585char last_script_name_hit[80];
586char last_script_data_hit[80];
587
588// Global variables to store the last source position - used by some tests.
589int last_source_line = -1;
590int last_source_column = -1;
591
592// Debug event handler which counts the break points which have been hit.
593int break_point_hit_count = 0;
594static void DebugEventBreakPointHitCount(v8::DebugEvent event,
595 v8::Handle<v8::Object> exec_state,
596 v8::Handle<v8::Object> event_data,
597 v8::Handle<v8::Value> data) {
598 // When hitting a debug event listener there must be a break set.
599 CHECK_NE(v8::internal::Debug::break_id(), 0);
600
601 // Count the number of breaks.
602 if (event == v8::Break) {
603 break_point_hit_count++;
604 if (!frame_function_name.IsEmpty()) {
605 // Get the name of the function.
606 const int argc = 1;
607 v8::Handle<v8::Value> argv[argc] = { exec_state };
608 v8::Handle<v8::Value> result = frame_function_name->Call(exec_state,
609 argc, argv);
610 if (result->IsUndefined()) {
611 last_function_hit[0] = '\0';
612 } else {
613 CHECK(result->IsString());
614 v8::Handle<v8::String> function_name(result->ToString());
615 function_name->WriteAscii(last_function_hit);
616 }
617 }
618
619 if (!frame_source_line.IsEmpty()) {
620 // Get the source line.
621 const int argc = 1;
622 v8::Handle<v8::Value> argv[argc] = { exec_state };
623 v8::Handle<v8::Value> result = frame_source_line->Call(exec_state,
624 argc, argv);
625 CHECK(result->IsNumber());
626 last_source_line = result->Int32Value();
627 }
628
629 if (!frame_source_column.IsEmpty()) {
630 // Get the source column.
631 const int argc = 1;
632 v8::Handle<v8::Value> argv[argc] = { exec_state };
633 v8::Handle<v8::Value> result = frame_source_column->Call(exec_state,
634 argc, argv);
635 CHECK(result->IsNumber());
636 last_source_column = result->Int32Value();
637 }
638
639 if (!frame_script_name.IsEmpty()) {
640 // Get the script name of the function script.
641 const int argc = 1;
642 v8::Handle<v8::Value> argv[argc] = { exec_state };
643 v8::Handle<v8::Value> result = frame_script_name->Call(exec_state,
644 argc, argv);
645 if (result->IsUndefined()) {
646 last_script_name_hit[0] = '\0';
647 } else {
648 CHECK(result->IsString());
649 v8::Handle<v8::String> script_name(result->ToString());
650 script_name->WriteAscii(last_script_name_hit);
651 }
652 }
653
654 if (!frame_script_data.IsEmpty()) {
655 // Get the script data of the function script.
656 const int argc = 1;
657 v8::Handle<v8::Value> argv[argc] = { exec_state };
658 v8::Handle<v8::Value> result = frame_script_data->Call(exec_state,
659 argc, argv);
660 if (result->IsUndefined()) {
661 last_script_data_hit[0] = '\0';
662 } else {
663 result = result->ToString();
664 CHECK(result->IsString());
665 v8::Handle<v8::String> script_data(result->ToString());
666 script_data->WriteAscii(last_script_data_hit);
667 }
668 }
Andrei Popescu402d9372010-02-26 13:31:12 +0000669 } else if (event == v8::AfterCompile && !compiled_script_data.IsEmpty()) {
670 const int argc = 1;
671 v8::Handle<v8::Value> argv[argc] = { event_data };
672 v8::Handle<v8::Value> result = compiled_script_data->Call(exec_state,
673 argc, argv);
674 if (result->IsUndefined()) {
675 last_script_data_hit[0] = '\0';
676 } else {
677 result = result->ToString();
678 CHECK(result->IsString());
679 v8::Handle<v8::String> script_data(result->ToString());
680 script_data->WriteAscii(last_script_data_hit);
681 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000682 }
683}
684
685
686// Debug event handler which counts a number of events and collects the stack
687// height if there is a function compiled for that.
688int exception_hit_count = 0;
689int uncaught_exception_hit_count = 0;
690int last_js_stack_height = -1;
691
692static void DebugEventCounterClear() {
693 break_point_hit_count = 0;
694 exception_hit_count = 0;
695 uncaught_exception_hit_count = 0;
696}
697
698static void DebugEventCounter(v8::DebugEvent event,
699 v8::Handle<v8::Object> exec_state,
700 v8::Handle<v8::Object> event_data,
701 v8::Handle<v8::Value> data) {
702 // When hitting a debug event listener there must be a break set.
703 CHECK_NE(v8::internal::Debug::break_id(), 0);
704
705 // Count the number of breaks.
706 if (event == v8::Break) {
707 break_point_hit_count++;
708 } else if (event == v8::Exception) {
709 exception_hit_count++;
710
711 // Check whether the exception was uncaught.
712 v8::Local<v8::String> fun_name = v8::String::New("uncaught");
713 v8::Local<v8::Function> fun =
714 v8::Function::Cast(*event_data->Get(fun_name));
715 v8::Local<v8::Value> result = *fun->Call(event_data, 0, NULL);
716 if (result->IsTrue()) {
717 uncaught_exception_hit_count++;
718 }
719 }
720
721 // Collect the JavsScript stack height if the function frame_count is
722 // compiled.
723 if (!frame_count.IsEmpty()) {
724 static const int kArgc = 1;
725 v8::Handle<v8::Value> argv[kArgc] = { exec_state };
726 // Using exec_state as receiver is just to have a receiver.
727 v8::Handle<v8::Value> result = frame_count->Call(exec_state, kArgc, argv);
728 last_js_stack_height = result->Int32Value();
729 }
730}
731
732
733// Debug event handler which evaluates a number of expressions when a break
734// point is hit. Each evaluated expression is compared with an expected value.
735// For this debug event handler to work the following two global varaibles
736// must be initialized.
737// checks: An array of expressions and expected results
738// evaluate_check_function: A JavaScript function (see below)
739
740// Structure for holding checks to do.
741struct EvaluateCheck {
742 const char* expr; // An expression to evaluate when a break point is hit.
743 v8::Handle<v8::Value> expected; // The expected result.
744};
745// Array of checks to do.
746struct EvaluateCheck* checks = NULL;
747// Source for The JavaScript function which can do the evaluation when a break
748// point is hit.
749const char* evaluate_check_source =
750 "function evaluate_check(exec_state, expr, expected) {"
751 " return exec_state.frame(0).evaluate(expr).value() === expected;"
752 "}";
753v8::Local<v8::Function> evaluate_check_function;
754
755// The actual debug event described by the longer comment above.
756static void DebugEventEvaluate(v8::DebugEvent event,
757 v8::Handle<v8::Object> exec_state,
758 v8::Handle<v8::Object> event_data,
759 v8::Handle<v8::Value> data) {
760 // When hitting a debug event listener there must be a break set.
761 CHECK_NE(v8::internal::Debug::break_id(), 0);
762
763 if (event == v8::Break) {
764 for (int i = 0; checks[i].expr != NULL; i++) {
765 const int argc = 3;
766 v8::Handle<v8::Value> argv[argc] = { exec_state,
767 v8::String::New(checks[i].expr),
768 checks[i].expected };
769 v8::Handle<v8::Value> result =
770 evaluate_check_function->Call(exec_state, argc, argv);
771 if (!result->IsTrue()) {
772 v8::String::AsciiValue ascii(checks[i].expected->ToString());
773 V8_Fatal(__FILE__, __LINE__, "%s != %s", checks[i].expr, *ascii);
774 }
775 }
776 }
777}
778
779
780// This debug event listener removes a breakpoint in a function
781int debug_event_remove_break_point = 0;
782static void DebugEventRemoveBreakPoint(v8::DebugEvent event,
783 v8::Handle<v8::Object> exec_state,
784 v8::Handle<v8::Object> event_data,
785 v8::Handle<v8::Value> data) {
786 // When hitting a debug event listener there must be a break set.
787 CHECK_NE(v8::internal::Debug::break_id(), 0);
788
789 if (event == v8::Break) {
790 break_point_hit_count++;
791 v8::Handle<v8::Function> fun = v8::Handle<v8::Function>::Cast(data);
792 ClearBreakPoint(debug_event_remove_break_point);
793 }
794}
795
796
797// Debug event handler which counts break points hit and performs a step
798// afterwards.
799StepAction step_action = StepIn; // Step action to perform when stepping.
800static void DebugEventStep(v8::DebugEvent event,
801 v8::Handle<v8::Object> exec_state,
802 v8::Handle<v8::Object> event_data,
803 v8::Handle<v8::Value> data) {
804 // When hitting a debug event listener there must be a break set.
805 CHECK_NE(v8::internal::Debug::break_id(), 0);
806
807 if (event == v8::Break) {
808 break_point_hit_count++;
809 PrepareStep(step_action);
810 }
811}
812
813
814// Debug event handler which counts break points hit and performs a step
815// afterwards. For each call the expected function is checked.
816// For this debug event handler to work the following two global varaibles
817// must be initialized.
818// expected_step_sequence: An array of the expected function call sequence.
819// frame_function_name: A JavaScript function (see below).
820
821// String containing the expected function call sequence. Note: this only works
822// if functions have name length of one.
823const char* expected_step_sequence = NULL;
824
825// The actual debug event described by the longer comment above.
826static void DebugEventStepSequence(v8::DebugEvent event,
827 v8::Handle<v8::Object> exec_state,
828 v8::Handle<v8::Object> event_data,
829 v8::Handle<v8::Value> data) {
830 // When hitting a debug event listener there must be a break set.
831 CHECK_NE(v8::internal::Debug::break_id(), 0);
832
833 if (event == v8::Break || event == v8::Exception) {
834 // Check that the current function is the expected.
835 CHECK(break_point_hit_count <
Steve Blockd0582a62009-12-15 09:54:21 +0000836 StrLength(expected_step_sequence));
Steve Blocka7e24c12009-10-30 11:49:00 +0000837 const int argc = 1;
838 v8::Handle<v8::Value> argv[argc] = { exec_state };
839 v8::Handle<v8::Value> result = frame_function_name->Call(exec_state,
840 argc, argv);
841 CHECK(result->IsString());
842 v8::String::AsciiValue function_name(result->ToString());
Steve Blockd0582a62009-12-15 09:54:21 +0000843 CHECK_EQ(1, StrLength(*function_name));
Steve Blocka7e24c12009-10-30 11:49:00 +0000844 CHECK_EQ((*function_name)[0],
845 expected_step_sequence[break_point_hit_count]);
846
847 // Perform step.
848 break_point_hit_count++;
849 PrepareStep(step_action);
850 }
851}
852
853
854// Debug event handler which performs a garbage collection.
855static void DebugEventBreakPointCollectGarbage(
856 v8::DebugEvent event,
857 v8::Handle<v8::Object> exec_state,
858 v8::Handle<v8::Object> event_data,
859 v8::Handle<v8::Value> data) {
860 // When hitting a debug event listener there must be a break set.
861 CHECK_NE(v8::internal::Debug::break_id(), 0);
862
863 // Perform a garbage collection when break point is hit and continue. Based
864 // on the number of break points hit either scavenge or mark compact
865 // collector is used.
866 if (event == v8::Break) {
867 break_point_hit_count++;
868 if (break_point_hit_count % 2 == 0) {
869 // Scavenge.
870 Heap::CollectGarbage(0, v8::internal::NEW_SPACE);
871 } else {
872 // Mark sweep (and perhaps compact).
873 Heap::CollectAllGarbage(false);
874 }
875 }
876}
877
878
879// Debug event handler which re-issues a debug break and calls the garbage
880// collector to have the heap verified.
881static void DebugEventBreak(v8::DebugEvent event,
882 v8::Handle<v8::Object> exec_state,
883 v8::Handle<v8::Object> event_data,
884 v8::Handle<v8::Value> data) {
885 // When hitting a debug event listener there must be a break set.
886 CHECK_NE(v8::internal::Debug::break_id(), 0);
887
888 if (event == v8::Break) {
889 // Count the number of breaks.
890 break_point_hit_count++;
891
892 // Run the garbage collector to enforce heap verification if option
893 // --verify-heap is set.
894 Heap::CollectGarbage(0, v8::internal::NEW_SPACE);
895
896 // Set the break flag again to come back here as soon as possible.
897 v8::Debug::DebugBreak();
898 }
899}
900
901
Steve Blockd0582a62009-12-15 09:54:21 +0000902// Debug event handler which re-issues a debug break until a limit has been
903// reached.
904int max_break_point_hit_count = 0;
905static void DebugEventBreakMax(v8::DebugEvent event,
906 v8::Handle<v8::Object> exec_state,
907 v8::Handle<v8::Object> event_data,
908 v8::Handle<v8::Value> data) {
909 // When hitting a debug event listener there must be a break set.
910 CHECK_NE(v8::internal::Debug::break_id(), 0);
911
912 if (event == v8::Break && break_point_hit_count < max_break_point_hit_count) {
913 // Count the number of breaks.
914 break_point_hit_count++;
915
916 // Set the break flag again to come back here as soon as possible.
917 v8::Debug::DebugBreak();
918 }
919}
920
921
Steve Blocka7e24c12009-10-30 11:49:00 +0000922// --- M e s s a g e C a l l b a c k
923
924
925// Message callback which counts the number of messages.
926int message_callback_count = 0;
927
928static void MessageCallbackCountClear() {
929 message_callback_count = 0;
930}
931
932static void MessageCallbackCount(v8::Handle<v8::Message> message,
933 v8::Handle<v8::Value> data) {
934 message_callback_count++;
935}
936
937
938// --- T h e A c t u a l T e s t s
939
940
941// Test that the debug break function is the expected one for different kinds
942// of break locations.
943TEST(DebugStub) {
944 using ::v8::internal::Builtins;
945 v8::HandleScope scope;
946 DebugLocalContext env;
947
948 CheckDebugBreakFunction(&env,
949 "function f1(){}", "f1",
950 0,
951 v8::internal::RelocInfo::JS_RETURN,
952 NULL);
953 CheckDebugBreakFunction(&env,
954 "function f2(){x=1;}", "f2",
955 0,
956 v8::internal::RelocInfo::CODE_TARGET,
957 Builtins::builtin(Builtins::StoreIC_DebugBreak));
958 CheckDebugBreakFunction(&env,
959 "function f3(){var a=x;}", "f3",
960 0,
961 v8::internal::RelocInfo::CODE_TARGET_CONTEXT,
962 Builtins::builtin(Builtins::LoadIC_DebugBreak));
963
964// TODO(1240753): Make the test architecture independent or split
965// parts of the debugger into architecture dependent files. This
966// part currently disabled as it is not portable between IA32/ARM.
967// Currently on ICs for keyed store/load on ARM.
968#if !defined (__arm__) && !defined(__thumb__)
969 CheckDebugBreakFunction(
970 &env,
971 "function f4(){var index='propertyName'; var a={}; a[index] = 'x';}",
972 "f4",
973 0,
974 v8::internal::RelocInfo::CODE_TARGET,
975 Builtins::builtin(Builtins::KeyedStoreIC_DebugBreak));
976 CheckDebugBreakFunction(
977 &env,
978 "function f5(){var index='propertyName'; var a={}; return a[index];}",
979 "f5",
980 0,
981 v8::internal::RelocInfo::CODE_TARGET,
982 Builtins::builtin(Builtins::KeyedLoadIC_DebugBreak));
983#endif
984
985 // Check the debug break code stubs for call ICs with different number of
986 // parameters.
987 Handle<Code> debug_break_0 = v8::internal::ComputeCallDebugBreak(0);
988 Handle<Code> debug_break_1 = v8::internal::ComputeCallDebugBreak(1);
989 Handle<Code> debug_break_4 = v8::internal::ComputeCallDebugBreak(4);
990
991 CheckDebugBreakFunction(&env,
992 "function f4_0(){x();}", "f4_0",
993 0,
994 v8::internal::RelocInfo::CODE_TARGET_CONTEXT,
995 *debug_break_0);
996
997 CheckDebugBreakFunction(&env,
998 "function f4_1(){x(1);}", "f4_1",
999 0,
1000 v8::internal::RelocInfo::CODE_TARGET_CONTEXT,
1001 *debug_break_1);
1002
1003 CheckDebugBreakFunction(&env,
1004 "function f4_4(){x(1,2,3,4);}", "f4_4",
1005 0,
1006 v8::internal::RelocInfo::CODE_TARGET_CONTEXT,
1007 *debug_break_4);
1008}
1009
1010
1011// Test that the debug info in the VM is in sync with the functions being
1012// debugged.
1013TEST(DebugInfo) {
1014 v8::HandleScope scope;
1015 DebugLocalContext env;
1016 // Create a couple of functions for the test.
1017 v8::Local<v8::Function> foo =
1018 CompileFunction(&env, "function foo(){}", "foo");
1019 v8::Local<v8::Function> bar =
1020 CompileFunction(&env, "function bar(){}", "bar");
1021 // Initially no functions are debugged.
1022 CHECK_EQ(0, v8::internal::GetDebuggedFunctions()->length());
1023 CHECK(!HasDebugInfo(foo));
1024 CHECK(!HasDebugInfo(bar));
1025 // One function (foo) is debugged.
1026 int bp1 = SetBreakPoint(foo, 0);
1027 CHECK_EQ(1, v8::internal::GetDebuggedFunctions()->length());
1028 CHECK(HasDebugInfo(foo));
1029 CHECK(!HasDebugInfo(bar));
1030 // Two functions are debugged.
1031 int bp2 = SetBreakPoint(bar, 0);
1032 CHECK_EQ(2, v8::internal::GetDebuggedFunctions()->length());
1033 CHECK(HasDebugInfo(foo));
1034 CHECK(HasDebugInfo(bar));
1035 // One function (bar) is debugged.
1036 ClearBreakPoint(bp1);
1037 CHECK_EQ(1, v8::internal::GetDebuggedFunctions()->length());
1038 CHECK(!HasDebugInfo(foo));
1039 CHECK(HasDebugInfo(bar));
1040 // No functions are debugged.
1041 ClearBreakPoint(bp2);
1042 CHECK_EQ(0, v8::internal::GetDebuggedFunctions()->length());
1043 CHECK(!HasDebugInfo(foo));
1044 CHECK(!HasDebugInfo(bar));
1045}
1046
1047
1048// Test that a break point can be set at an IC store location.
1049TEST(BreakPointICStore) {
1050 break_point_hit_count = 0;
1051 v8::HandleScope scope;
1052 DebugLocalContext env;
1053
1054 v8::Debug::SetDebugEventListener(DebugEventBreakPointHitCount,
1055 v8::Undefined());
1056 v8::Script::Compile(v8::String::New("function foo(){bar=0;}"))->Run();
1057 v8::Local<v8::Function> foo =
1058 v8::Local<v8::Function>::Cast(env->Global()->Get(v8::String::New("foo")));
1059
1060 // Run without breakpoints.
1061 foo->Call(env->Global(), 0, NULL);
1062 CHECK_EQ(0, break_point_hit_count);
1063
1064 // Run with breakpoint
1065 int bp = SetBreakPoint(foo, 0);
1066 foo->Call(env->Global(), 0, NULL);
1067 CHECK_EQ(1, break_point_hit_count);
1068 foo->Call(env->Global(), 0, NULL);
1069 CHECK_EQ(2, break_point_hit_count);
1070
1071 // Run without breakpoints.
1072 ClearBreakPoint(bp);
1073 foo->Call(env->Global(), 0, NULL);
1074 CHECK_EQ(2, break_point_hit_count);
1075
1076 v8::Debug::SetDebugEventListener(NULL);
1077 CheckDebuggerUnloaded();
1078}
1079
1080
1081// Test that a break point can be set at an IC load location.
1082TEST(BreakPointICLoad) {
1083 break_point_hit_count = 0;
1084 v8::HandleScope scope;
1085 DebugLocalContext env;
1086 v8::Debug::SetDebugEventListener(DebugEventBreakPointHitCount,
1087 v8::Undefined());
1088 v8::Script::Compile(v8::String::New("bar=1"))->Run();
1089 v8::Script::Compile(v8::String::New("function foo(){var x=bar;}"))->Run();
1090 v8::Local<v8::Function> foo =
1091 v8::Local<v8::Function>::Cast(env->Global()->Get(v8::String::New("foo")));
1092
1093 // Run without breakpoints.
1094 foo->Call(env->Global(), 0, NULL);
1095 CHECK_EQ(0, break_point_hit_count);
1096
1097 // Run with breakpoint
1098 int bp = SetBreakPoint(foo, 0);
1099 foo->Call(env->Global(), 0, NULL);
1100 CHECK_EQ(1, break_point_hit_count);
1101 foo->Call(env->Global(), 0, NULL);
1102 CHECK_EQ(2, break_point_hit_count);
1103
1104 // Run without breakpoints.
1105 ClearBreakPoint(bp);
1106 foo->Call(env->Global(), 0, NULL);
1107 CHECK_EQ(2, break_point_hit_count);
1108
1109 v8::Debug::SetDebugEventListener(NULL);
1110 CheckDebuggerUnloaded();
1111}
1112
1113
1114// Test that a break point can be set at an IC call location.
1115TEST(BreakPointICCall) {
1116 break_point_hit_count = 0;
1117 v8::HandleScope scope;
1118 DebugLocalContext env;
1119 v8::Debug::SetDebugEventListener(DebugEventBreakPointHitCount,
1120 v8::Undefined());
1121 v8::Script::Compile(v8::String::New("function bar(){}"))->Run();
1122 v8::Script::Compile(v8::String::New("function foo(){bar();}"))->Run();
1123 v8::Local<v8::Function> foo =
1124 v8::Local<v8::Function>::Cast(env->Global()->Get(v8::String::New("foo")));
1125
1126 // Run without breakpoints.
1127 foo->Call(env->Global(), 0, NULL);
1128 CHECK_EQ(0, break_point_hit_count);
1129
1130 // Run with breakpoint
1131 int bp = SetBreakPoint(foo, 0);
1132 foo->Call(env->Global(), 0, NULL);
1133 CHECK_EQ(1, break_point_hit_count);
1134 foo->Call(env->Global(), 0, NULL);
1135 CHECK_EQ(2, break_point_hit_count);
1136
1137 // Run without breakpoints.
1138 ClearBreakPoint(bp);
1139 foo->Call(env->Global(), 0, NULL);
1140 CHECK_EQ(2, break_point_hit_count);
1141
1142 v8::Debug::SetDebugEventListener(NULL);
1143 CheckDebuggerUnloaded();
1144}
1145
1146
1147// Test that a break point can be set at a return store location.
1148TEST(BreakPointReturn) {
1149 break_point_hit_count = 0;
1150 v8::HandleScope scope;
1151 DebugLocalContext env;
1152
1153 // Create a functions for checking the source line and column when hitting
1154 // a break point.
1155 frame_source_line = CompileFunction(&env,
1156 frame_source_line_source,
1157 "frame_source_line");
1158 frame_source_column = CompileFunction(&env,
1159 frame_source_column_source,
1160 "frame_source_column");
1161
1162
1163 v8::Debug::SetDebugEventListener(DebugEventBreakPointHitCount,
1164 v8::Undefined());
1165 v8::Script::Compile(v8::String::New("function foo(){}"))->Run();
1166 v8::Local<v8::Function> foo =
1167 v8::Local<v8::Function>::Cast(env->Global()->Get(v8::String::New("foo")));
1168
1169 // Run without breakpoints.
1170 foo->Call(env->Global(), 0, NULL);
1171 CHECK_EQ(0, break_point_hit_count);
1172
1173 // Run with breakpoint
1174 int bp = SetBreakPoint(foo, 0);
1175 foo->Call(env->Global(), 0, NULL);
1176 CHECK_EQ(1, break_point_hit_count);
1177 CHECK_EQ(0, last_source_line);
Ben Murdochbb769b22010-08-11 14:56:33 +01001178 CHECK_EQ(15, last_source_column);
Steve Blocka7e24c12009-10-30 11:49:00 +00001179 foo->Call(env->Global(), 0, NULL);
1180 CHECK_EQ(2, break_point_hit_count);
1181 CHECK_EQ(0, last_source_line);
Ben Murdochbb769b22010-08-11 14:56:33 +01001182 CHECK_EQ(15, last_source_column);
Steve Blocka7e24c12009-10-30 11:49:00 +00001183
1184 // Run without breakpoints.
1185 ClearBreakPoint(bp);
1186 foo->Call(env->Global(), 0, NULL);
1187 CHECK_EQ(2, break_point_hit_count);
1188
1189 v8::Debug::SetDebugEventListener(NULL);
1190 CheckDebuggerUnloaded();
1191}
1192
1193
1194static void CallWithBreakPoints(v8::Local<v8::Object> recv,
1195 v8::Local<v8::Function> f,
1196 int break_point_count,
1197 int call_count) {
1198 break_point_hit_count = 0;
1199 for (int i = 0; i < call_count; i++) {
1200 f->Call(recv, 0, NULL);
1201 CHECK_EQ((i + 1) * break_point_count, break_point_hit_count);
1202 }
1203}
1204
1205// Test GC during break point processing.
1206TEST(GCDuringBreakPointProcessing) {
1207 break_point_hit_count = 0;
1208 v8::HandleScope scope;
1209 DebugLocalContext env;
1210
1211 v8::Debug::SetDebugEventListener(DebugEventBreakPointCollectGarbage,
1212 v8::Undefined());
1213 v8::Local<v8::Function> foo;
1214
1215 // Test IC store break point with garbage collection.
1216 foo = CompileFunction(&env, "function foo(){bar=0;}", "foo");
1217 SetBreakPoint(foo, 0);
1218 CallWithBreakPoints(env->Global(), foo, 1, 10);
1219
1220 // Test IC load break point with garbage collection.
1221 foo = CompileFunction(&env, "bar=1;function foo(){var x=bar;}", "foo");
1222 SetBreakPoint(foo, 0);
1223 CallWithBreakPoints(env->Global(), foo, 1, 10);
1224
1225 // Test IC call break point with garbage collection.
1226 foo = CompileFunction(&env, "function bar(){};function foo(){bar();}", "foo");
1227 SetBreakPoint(foo, 0);
1228 CallWithBreakPoints(env->Global(), foo, 1, 10);
1229
1230 // Test return break point with garbage collection.
1231 foo = CompileFunction(&env, "function foo(){}", "foo");
1232 SetBreakPoint(foo, 0);
1233 CallWithBreakPoints(env->Global(), foo, 1, 25);
1234
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001235 // Test debug break slot break point with garbage collection.
1236 foo = CompileFunction(&env, "function foo(){var a;}", "foo");
1237 SetBreakPoint(foo, 0);
1238 CallWithBreakPoints(env->Global(), foo, 1, 25);
1239
Steve Blocka7e24c12009-10-30 11:49:00 +00001240 v8::Debug::SetDebugEventListener(NULL);
1241 CheckDebuggerUnloaded();
1242}
1243
1244
1245// Call the function three times with different garbage collections in between
1246// and make sure that the break point survives.
Ben Murdochbb769b22010-08-11 14:56:33 +01001247static void CallAndGC(v8::Local<v8::Object> recv,
1248 v8::Local<v8::Function> f,
1249 bool force_compaction) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001250 break_point_hit_count = 0;
1251
1252 for (int i = 0; i < 3; i++) {
1253 // Call function.
1254 f->Call(recv, 0, NULL);
1255 CHECK_EQ(1 + i * 3, break_point_hit_count);
1256
1257 // Scavenge and call function.
1258 Heap::CollectGarbage(0, v8::internal::NEW_SPACE);
1259 f->Call(recv, 0, NULL);
1260 CHECK_EQ(2 + i * 3, break_point_hit_count);
1261
1262 // Mark sweep (and perhaps compact) and call function.
Ben Murdochbb769b22010-08-11 14:56:33 +01001263 Heap::CollectAllGarbage(force_compaction);
Steve Blocka7e24c12009-10-30 11:49:00 +00001264 f->Call(recv, 0, NULL);
1265 CHECK_EQ(3 + i * 3, break_point_hit_count);
1266 }
1267}
1268
1269
Ben Murdochbb769b22010-08-11 14:56:33 +01001270static void TestBreakPointSurviveGC(bool force_compaction) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001271 break_point_hit_count = 0;
1272 v8::HandleScope scope;
1273 DebugLocalContext env;
1274
1275 v8::Debug::SetDebugEventListener(DebugEventBreakPointHitCount,
1276 v8::Undefined());
1277 v8::Local<v8::Function> foo;
1278
1279 // Test IC store break point with garbage collection.
Ben Murdochbb769b22010-08-11 14:56:33 +01001280 {
1281 v8::Local<v8::Function> bar =
1282 CompileFunction(&env, "function foo(){}", "foo");
1283 foo = CompileFunction(&env, "function foo(){bar=0;}", "foo");
1284 SetBreakPoint(foo, 0);
1285 }
1286 CallAndGC(env->Global(), foo, force_compaction);
Steve Blocka7e24c12009-10-30 11:49:00 +00001287
1288 // Test IC load break point with garbage collection.
Ben Murdochbb769b22010-08-11 14:56:33 +01001289 {
1290 v8::Local<v8::Function> bar =
1291 CompileFunction(&env, "function foo(){}", "foo");
1292 foo = CompileFunction(&env, "bar=1;function foo(){var x=bar;}", "foo");
1293 SetBreakPoint(foo, 0);
1294 }
1295 CallAndGC(env->Global(), foo, force_compaction);
Steve Blocka7e24c12009-10-30 11:49:00 +00001296
1297 // Test IC call break point with garbage collection.
Ben Murdochbb769b22010-08-11 14:56:33 +01001298 {
1299 v8::Local<v8::Function> bar =
1300 CompileFunction(&env, "function foo(){}", "foo");
1301 foo = CompileFunction(&env,
1302 "function bar(){};function foo(){bar();}",
1303 "foo");
1304 SetBreakPoint(foo, 0);
1305 }
1306 CallAndGC(env->Global(), foo, force_compaction);
Steve Blocka7e24c12009-10-30 11:49:00 +00001307
1308 // Test return break point with garbage collection.
Ben Murdochbb769b22010-08-11 14:56:33 +01001309 {
1310 v8::Local<v8::Function> bar =
1311 CompileFunction(&env, "function foo(){}", "foo");
1312 foo = CompileFunction(&env, "function foo(){}", "foo");
1313 SetBreakPoint(foo, 0);
1314 }
1315 CallAndGC(env->Global(), foo, force_compaction);
1316
1317 // Test non IC break point with garbage collection.
1318 {
1319 v8::Local<v8::Function> bar =
1320 CompileFunction(&env, "function foo(){}", "foo");
1321 foo = CompileFunction(&env, "function foo(){var bar=0;}", "foo");
1322 SetBreakPoint(foo, 0);
1323 }
1324 CallAndGC(env->Global(), foo, force_compaction);
1325
Steve Blocka7e24c12009-10-30 11:49:00 +00001326
1327 v8::Debug::SetDebugEventListener(NULL);
1328 CheckDebuggerUnloaded();
1329}
1330
1331
Ben Murdochbb769b22010-08-11 14:56:33 +01001332// Test that a break point can be set at a return store location.
1333TEST(BreakPointSurviveGC) {
1334 TestBreakPointSurviveGC(false);
1335 TestBreakPointSurviveGC(true);
1336}
1337
1338
Steve Blocka7e24c12009-10-30 11:49:00 +00001339// Test that break points can be set using the global Debug object.
1340TEST(BreakPointThroughJavaScript) {
1341 break_point_hit_count = 0;
1342 v8::HandleScope scope;
1343 DebugLocalContext env;
1344 env.ExposeDebug();
1345
1346 v8::Debug::SetDebugEventListener(DebugEventBreakPointHitCount,
1347 v8::Undefined());
1348 v8::Script::Compile(v8::String::New("function bar(){}"))->Run();
1349 v8::Script::Compile(v8::String::New("function foo(){bar();bar();}"))->Run();
1350 // 012345678901234567890
1351 // 1 2
1352 // Break points are set at position 3 and 9
1353 v8::Local<v8::Script> foo = v8::Script::Compile(v8::String::New("foo()"));
1354
1355 // Run without breakpoints.
1356 foo->Run();
1357 CHECK_EQ(0, break_point_hit_count);
1358
1359 // Run with one breakpoint
1360 int bp1 = SetBreakPointFromJS("foo", 0, 3);
1361 foo->Run();
1362 CHECK_EQ(1, break_point_hit_count);
1363 foo->Run();
1364 CHECK_EQ(2, break_point_hit_count);
1365
1366 // Run with two breakpoints
1367 int bp2 = SetBreakPointFromJS("foo", 0, 9);
1368 foo->Run();
1369 CHECK_EQ(4, break_point_hit_count);
1370 foo->Run();
1371 CHECK_EQ(6, break_point_hit_count);
1372
1373 // Run with one breakpoint
1374 ClearBreakPointFromJS(bp2);
1375 foo->Run();
1376 CHECK_EQ(7, break_point_hit_count);
1377 foo->Run();
1378 CHECK_EQ(8, break_point_hit_count);
1379
1380 // Run without breakpoints.
1381 ClearBreakPointFromJS(bp1);
1382 foo->Run();
1383 CHECK_EQ(8, break_point_hit_count);
1384
1385 v8::Debug::SetDebugEventListener(NULL);
1386 CheckDebuggerUnloaded();
1387
1388 // Make sure that the break point numbers are consecutive.
1389 CHECK_EQ(1, bp1);
1390 CHECK_EQ(2, bp2);
1391}
1392
1393
1394// Test that break points on scripts identified by name can be set using the
1395// global Debug object.
1396TEST(ScriptBreakPointByNameThroughJavaScript) {
1397 break_point_hit_count = 0;
1398 v8::HandleScope scope;
1399 DebugLocalContext env;
1400 env.ExposeDebug();
1401
1402 v8::Debug::SetDebugEventListener(DebugEventBreakPointHitCount,
1403 v8::Undefined());
1404
1405 v8::Local<v8::String> script = v8::String::New(
1406 "function f() {\n"
1407 " function h() {\n"
1408 " a = 0; // line 2\n"
1409 " }\n"
1410 " b = 1; // line 4\n"
1411 " return h();\n"
1412 "}\n"
1413 "\n"
1414 "function g() {\n"
1415 " function h() {\n"
1416 " a = 0;\n"
1417 " }\n"
1418 " b = 2; // line 12\n"
1419 " h();\n"
1420 " b = 3; // line 14\n"
1421 " f(); // line 15\n"
1422 "}");
1423
1424 // Compile the script and get the two functions.
1425 v8::ScriptOrigin origin =
1426 v8::ScriptOrigin(v8::String::New("test"));
1427 v8::Script::Compile(script, &origin)->Run();
1428 v8::Local<v8::Function> f =
1429 v8::Local<v8::Function>::Cast(env->Global()->Get(v8::String::New("f")));
1430 v8::Local<v8::Function> g =
1431 v8::Local<v8::Function>::Cast(env->Global()->Get(v8::String::New("g")));
1432
1433 // Call f and g without break points.
1434 break_point_hit_count = 0;
1435 f->Call(env->Global(), 0, NULL);
1436 CHECK_EQ(0, break_point_hit_count);
1437 g->Call(env->Global(), 0, NULL);
1438 CHECK_EQ(0, break_point_hit_count);
1439
1440 // Call f and g with break point on line 12.
1441 int sbp1 = SetScriptBreakPointByNameFromJS("test", 12, 0);
1442 break_point_hit_count = 0;
1443 f->Call(env->Global(), 0, NULL);
1444 CHECK_EQ(0, break_point_hit_count);
1445 g->Call(env->Global(), 0, NULL);
1446 CHECK_EQ(1, break_point_hit_count);
1447
1448 // Remove the break point again.
1449 break_point_hit_count = 0;
1450 ClearBreakPointFromJS(sbp1);
1451 f->Call(env->Global(), 0, NULL);
1452 CHECK_EQ(0, break_point_hit_count);
1453 g->Call(env->Global(), 0, NULL);
1454 CHECK_EQ(0, break_point_hit_count);
1455
1456 // Call f and g with break point on line 2.
1457 int sbp2 = SetScriptBreakPointByNameFromJS("test", 2, 0);
1458 break_point_hit_count = 0;
1459 f->Call(env->Global(), 0, NULL);
1460 CHECK_EQ(1, break_point_hit_count);
1461 g->Call(env->Global(), 0, NULL);
1462 CHECK_EQ(2, break_point_hit_count);
1463
1464 // Call f and g with break point on line 2, 4, 12, 14 and 15.
1465 int sbp3 = SetScriptBreakPointByNameFromJS("test", 4, 0);
1466 int sbp4 = SetScriptBreakPointByNameFromJS("test", 12, 0);
1467 int sbp5 = SetScriptBreakPointByNameFromJS("test", 14, 0);
1468 int sbp6 = SetScriptBreakPointByNameFromJS("test", 15, 0);
1469 break_point_hit_count = 0;
1470 f->Call(env->Global(), 0, NULL);
1471 CHECK_EQ(2, break_point_hit_count);
1472 g->Call(env->Global(), 0, NULL);
1473 CHECK_EQ(7, break_point_hit_count);
1474
1475 // Remove all the break points again.
1476 break_point_hit_count = 0;
1477 ClearBreakPointFromJS(sbp2);
1478 ClearBreakPointFromJS(sbp3);
1479 ClearBreakPointFromJS(sbp4);
1480 ClearBreakPointFromJS(sbp5);
1481 ClearBreakPointFromJS(sbp6);
1482 f->Call(env->Global(), 0, NULL);
1483 CHECK_EQ(0, break_point_hit_count);
1484 g->Call(env->Global(), 0, NULL);
1485 CHECK_EQ(0, break_point_hit_count);
1486
1487 v8::Debug::SetDebugEventListener(NULL);
1488 CheckDebuggerUnloaded();
1489
1490 // Make sure that the break point numbers are consecutive.
1491 CHECK_EQ(1, sbp1);
1492 CHECK_EQ(2, sbp2);
1493 CHECK_EQ(3, sbp3);
1494 CHECK_EQ(4, sbp4);
1495 CHECK_EQ(5, sbp5);
1496 CHECK_EQ(6, sbp6);
1497}
1498
1499
1500TEST(ScriptBreakPointByIdThroughJavaScript) {
1501 break_point_hit_count = 0;
1502 v8::HandleScope scope;
1503 DebugLocalContext env;
1504 env.ExposeDebug();
1505
1506 v8::Debug::SetDebugEventListener(DebugEventBreakPointHitCount,
1507 v8::Undefined());
1508
1509 v8::Local<v8::String> source = v8::String::New(
1510 "function f() {\n"
1511 " function h() {\n"
1512 " a = 0; // line 2\n"
1513 " }\n"
1514 " b = 1; // line 4\n"
1515 " return h();\n"
1516 "}\n"
1517 "\n"
1518 "function g() {\n"
1519 " function h() {\n"
1520 " a = 0;\n"
1521 " }\n"
1522 " b = 2; // line 12\n"
1523 " h();\n"
1524 " b = 3; // line 14\n"
1525 " f(); // line 15\n"
1526 "}");
1527
1528 // Compile the script and get the two functions.
1529 v8::ScriptOrigin origin =
1530 v8::ScriptOrigin(v8::String::New("test"));
1531 v8::Local<v8::Script> script = v8::Script::Compile(source, &origin);
1532 script->Run();
1533 v8::Local<v8::Function> f =
1534 v8::Local<v8::Function>::Cast(env->Global()->Get(v8::String::New("f")));
1535 v8::Local<v8::Function> g =
1536 v8::Local<v8::Function>::Cast(env->Global()->Get(v8::String::New("g")));
1537
1538 // Get the script id knowing that internally it is a 32 integer.
1539 uint32_t script_id = script->Id()->Uint32Value();
1540
1541 // Call f and g without break points.
1542 break_point_hit_count = 0;
1543 f->Call(env->Global(), 0, NULL);
1544 CHECK_EQ(0, break_point_hit_count);
1545 g->Call(env->Global(), 0, NULL);
1546 CHECK_EQ(0, break_point_hit_count);
1547
1548 // Call f and g with break point on line 12.
1549 int sbp1 = SetScriptBreakPointByIdFromJS(script_id, 12, 0);
1550 break_point_hit_count = 0;
1551 f->Call(env->Global(), 0, NULL);
1552 CHECK_EQ(0, break_point_hit_count);
1553 g->Call(env->Global(), 0, NULL);
1554 CHECK_EQ(1, break_point_hit_count);
1555
1556 // Remove the break point again.
1557 break_point_hit_count = 0;
1558 ClearBreakPointFromJS(sbp1);
1559 f->Call(env->Global(), 0, NULL);
1560 CHECK_EQ(0, break_point_hit_count);
1561 g->Call(env->Global(), 0, NULL);
1562 CHECK_EQ(0, break_point_hit_count);
1563
1564 // Call f and g with break point on line 2.
1565 int sbp2 = SetScriptBreakPointByIdFromJS(script_id, 2, 0);
1566 break_point_hit_count = 0;
1567 f->Call(env->Global(), 0, NULL);
1568 CHECK_EQ(1, break_point_hit_count);
1569 g->Call(env->Global(), 0, NULL);
1570 CHECK_EQ(2, break_point_hit_count);
1571
1572 // Call f and g with break point on line 2, 4, 12, 14 and 15.
1573 int sbp3 = SetScriptBreakPointByIdFromJS(script_id, 4, 0);
1574 int sbp4 = SetScriptBreakPointByIdFromJS(script_id, 12, 0);
1575 int sbp5 = SetScriptBreakPointByIdFromJS(script_id, 14, 0);
1576 int sbp6 = SetScriptBreakPointByIdFromJS(script_id, 15, 0);
1577 break_point_hit_count = 0;
1578 f->Call(env->Global(), 0, NULL);
1579 CHECK_EQ(2, break_point_hit_count);
1580 g->Call(env->Global(), 0, NULL);
1581 CHECK_EQ(7, break_point_hit_count);
1582
1583 // Remove all the break points again.
1584 break_point_hit_count = 0;
1585 ClearBreakPointFromJS(sbp2);
1586 ClearBreakPointFromJS(sbp3);
1587 ClearBreakPointFromJS(sbp4);
1588 ClearBreakPointFromJS(sbp5);
1589 ClearBreakPointFromJS(sbp6);
1590 f->Call(env->Global(), 0, NULL);
1591 CHECK_EQ(0, break_point_hit_count);
1592 g->Call(env->Global(), 0, NULL);
1593 CHECK_EQ(0, break_point_hit_count);
1594
1595 v8::Debug::SetDebugEventListener(NULL);
1596 CheckDebuggerUnloaded();
1597
1598 // Make sure that the break point numbers are consecutive.
1599 CHECK_EQ(1, sbp1);
1600 CHECK_EQ(2, sbp2);
1601 CHECK_EQ(3, sbp3);
1602 CHECK_EQ(4, sbp4);
1603 CHECK_EQ(5, sbp5);
1604 CHECK_EQ(6, sbp6);
1605}
1606
1607
1608// Test conditional script break points.
1609TEST(EnableDisableScriptBreakPoint) {
1610 break_point_hit_count = 0;
1611 v8::HandleScope scope;
1612 DebugLocalContext env;
1613 env.ExposeDebug();
1614
1615 v8::Debug::SetDebugEventListener(DebugEventBreakPointHitCount,
1616 v8::Undefined());
1617
1618 v8::Local<v8::String> script = v8::String::New(
1619 "function f() {\n"
1620 " a = 0; // line 1\n"
1621 "};");
1622
1623 // Compile the script and get function f.
1624 v8::ScriptOrigin origin =
1625 v8::ScriptOrigin(v8::String::New("test"));
1626 v8::Script::Compile(script, &origin)->Run();
1627 v8::Local<v8::Function> f =
1628 v8::Local<v8::Function>::Cast(env->Global()->Get(v8::String::New("f")));
1629
1630 // Set script break point on line 1 (in function f).
1631 int sbp = SetScriptBreakPointByNameFromJS("test", 1, 0);
1632
1633 // Call f while enabeling and disabling the script break point.
1634 break_point_hit_count = 0;
1635 f->Call(env->Global(), 0, NULL);
1636 CHECK_EQ(1, break_point_hit_count);
1637
1638 DisableScriptBreakPointFromJS(sbp);
1639 f->Call(env->Global(), 0, NULL);
1640 CHECK_EQ(1, break_point_hit_count);
1641
1642 EnableScriptBreakPointFromJS(sbp);
1643 f->Call(env->Global(), 0, NULL);
1644 CHECK_EQ(2, break_point_hit_count);
1645
1646 DisableScriptBreakPointFromJS(sbp);
1647 f->Call(env->Global(), 0, NULL);
1648 CHECK_EQ(2, break_point_hit_count);
1649
1650 // Reload the script and get f again checking that the disabeling survives.
1651 v8::Script::Compile(script, &origin)->Run();
1652 f = v8::Local<v8::Function>::Cast(env->Global()->Get(v8::String::New("f")));
1653 f->Call(env->Global(), 0, NULL);
1654 CHECK_EQ(2, break_point_hit_count);
1655
1656 EnableScriptBreakPointFromJS(sbp);
1657 f->Call(env->Global(), 0, NULL);
1658 CHECK_EQ(3, break_point_hit_count);
1659
1660 v8::Debug::SetDebugEventListener(NULL);
1661 CheckDebuggerUnloaded();
1662}
1663
1664
1665// Test conditional script break points.
1666TEST(ConditionalScriptBreakPoint) {
1667 break_point_hit_count = 0;
1668 v8::HandleScope scope;
1669 DebugLocalContext env;
1670 env.ExposeDebug();
1671
1672 v8::Debug::SetDebugEventListener(DebugEventBreakPointHitCount,
1673 v8::Undefined());
1674
1675 v8::Local<v8::String> script = v8::String::New(
1676 "count = 0;\n"
1677 "function f() {\n"
1678 " g(count++); // line 2\n"
1679 "};\n"
1680 "function g(x) {\n"
1681 " var a=x; // line 5\n"
1682 "};");
1683
1684 // Compile the script and get function f.
1685 v8::ScriptOrigin origin =
1686 v8::ScriptOrigin(v8::String::New("test"));
1687 v8::Script::Compile(script, &origin)->Run();
1688 v8::Local<v8::Function> f =
1689 v8::Local<v8::Function>::Cast(env->Global()->Get(v8::String::New("f")));
1690
1691 // Set script break point on line 5 (in function g).
1692 int sbp1 = SetScriptBreakPointByNameFromJS("test", 5, 0);
1693
1694 // Call f with different conditions on the script break point.
1695 break_point_hit_count = 0;
1696 ChangeScriptBreakPointConditionFromJS(sbp1, "false");
1697 f->Call(env->Global(), 0, NULL);
1698 CHECK_EQ(0, break_point_hit_count);
1699
1700 ChangeScriptBreakPointConditionFromJS(sbp1, "true");
1701 break_point_hit_count = 0;
1702 f->Call(env->Global(), 0, NULL);
1703 CHECK_EQ(1, break_point_hit_count);
1704
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001705 ChangeScriptBreakPointConditionFromJS(sbp1, "x % 2 == 0");
Steve Blocka7e24c12009-10-30 11:49:00 +00001706 break_point_hit_count = 0;
1707 for (int i = 0; i < 10; i++) {
1708 f->Call(env->Global(), 0, NULL);
1709 }
1710 CHECK_EQ(5, break_point_hit_count);
1711
1712 // Reload the script and get f again checking that the condition survives.
1713 v8::Script::Compile(script, &origin)->Run();
1714 f = v8::Local<v8::Function>::Cast(env->Global()->Get(v8::String::New("f")));
1715
1716 break_point_hit_count = 0;
1717 for (int i = 0; i < 10; i++) {
1718 f->Call(env->Global(), 0, NULL);
1719 }
1720 CHECK_EQ(5, break_point_hit_count);
1721
1722 v8::Debug::SetDebugEventListener(NULL);
1723 CheckDebuggerUnloaded();
1724}
1725
1726
1727// Test ignore count on script break points.
1728TEST(ScriptBreakPointIgnoreCount) {
1729 break_point_hit_count = 0;
1730 v8::HandleScope scope;
1731 DebugLocalContext env;
1732 env.ExposeDebug();
1733
1734 v8::Debug::SetDebugEventListener(DebugEventBreakPointHitCount,
1735 v8::Undefined());
1736
1737 v8::Local<v8::String> script = v8::String::New(
1738 "function f() {\n"
1739 " a = 0; // line 1\n"
1740 "};");
1741
1742 // Compile the script and get function f.
1743 v8::ScriptOrigin origin =
1744 v8::ScriptOrigin(v8::String::New("test"));
1745 v8::Script::Compile(script, &origin)->Run();
1746 v8::Local<v8::Function> f =
1747 v8::Local<v8::Function>::Cast(env->Global()->Get(v8::String::New("f")));
1748
1749 // Set script break point on line 1 (in function f).
1750 int sbp = SetScriptBreakPointByNameFromJS("test", 1, 0);
1751
1752 // Call f with different ignores on the script break point.
1753 break_point_hit_count = 0;
1754 ChangeScriptBreakPointIgnoreCountFromJS(sbp, 1);
1755 f->Call(env->Global(), 0, NULL);
1756 CHECK_EQ(0, break_point_hit_count);
1757 f->Call(env->Global(), 0, NULL);
1758 CHECK_EQ(1, break_point_hit_count);
1759
1760 ChangeScriptBreakPointIgnoreCountFromJS(sbp, 5);
1761 break_point_hit_count = 0;
1762 for (int i = 0; i < 10; i++) {
1763 f->Call(env->Global(), 0, NULL);
1764 }
1765 CHECK_EQ(5, break_point_hit_count);
1766
1767 // Reload the script and get f again checking that the ignore survives.
1768 v8::Script::Compile(script, &origin)->Run();
1769 f = v8::Local<v8::Function>::Cast(env->Global()->Get(v8::String::New("f")));
1770
1771 break_point_hit_count = 0;
1772 for (int i = 0; i < 10; i++) {
1773 f->Call(env->Global(), 0, NULL);
1774 }
1775 CHECK_EQ(5, break_point_hit_count);
1776
1777 v8::Debug::SetDebugEventListener(NULL);
1778 CheckDebuggerUnloaded();
1779}
1780
1781
1782// Test that script break points survive when a script is reloaded.
1783TEST(ScriptBreakPointReload) {
1784 break_point_hit_count = 0;
1785 v8::HandleScope scope;
1786 DebugLocalContext env;
1787 env.ExposeDebug();
1788
1789 v8::Debug::SetDebugEventListener(DebugEventBreakPointHitCount,
1790 v8::Undefined());
1791
1792 v8::Local<v8::Function> f;
1793 v8::Local<v8::String> script = v8::String::New(
1794 "function f() {\n"
1795 " function h() {\n"
1796 " a = 0; // line 2\n"
1797 " }\n"
1798 " b = 1; // line 4\n"
1799 " return h();\n"
1800 "}");
1801
1802 v8::ScriptOrigin origin_1 = v8::ScriptOrigin(v8::String::New("1"));
1803 v8::ScriptOrigin origin_2 = v8::ScriptOrigin(v8::String::New("2"));
1804
1805 // Set a script break point before the script is loaded.
1806 SetScriptBreakPointByNameFromJS("1", 2, 0);
1807
1808 // Compile the script and get the function.
1809 v8::Script::Compile(script, &origin_1)->Run();
1810 f = v8::Local<v8::Function>::Cast(env->Global()->Get(v8::String::New("f")));
1811
1812 // Call f and check that the script break point is active.
1813 break_point_hit_count = 0;
1814 f->Call(env->Global(), 0, NULL);
1815 CHECK_EQ(1, break_point_hit_count);
1816
1817 // Compile the script again with a different script data and get the
1818 // function.
1819 v8::Script::Compile(script, &origin_2)->Run();
1820 f = v8::Local<v8::Function>::Cast(env->Global()->Get(v8::String::New("f")));
1821
1822 // Call f and check that no break points are set.
1823 break_point_hit_count = 0;
1824 f->Call(env->Global(), 0, NULL);
1825 CHECK_EQ(0, break_point_hit_count);
1826
1827 // Compile the script again and get the function.
1828 v8::Script::Compile(script, &origin_1)->Run();
1829 f = v8::Local<v8::Function>::Cast(env->Global()->Get(v8::String::New("f")));
1830
1831 // Call f and check that the script break point is active.
1832 break_point_hit_count = 0;
1833 f->Call(env->Global(), 0, NULL);
1834 CHECK_EQ(1, break_point_hit_count);
1835
1836 v8::Debug::SetDebugEventListener(NULL);
1837 CheckDebuggerUnloaded();
1838}
1839
1840
1841// Test when several scripts has the same script data
1842TEST(ScriptBreakPointMultiple) {
1843 break_point_hit_count = 0;
1844 v8::HandleScope scope;
1845 DebugLocalContext env;
1846 env.ExposeDebug();
1847
1848 v8::Debug::SetDebugEventListener(DebugEventBreakPointHitCount,
1849 v8::Undefined());
1850
1851 v8::Local<v8::Function> f;
1852 v8::Local<v8::String> script_f = v8::String::New(
1853 "function f() {\n"
1854 " a = 0; // line 1\n"
1855 "}");
1856
1857 v8::Local<v8::Function> g;
1858 v8::Local<v8::String> script_g = v8::String::New(
1859 "function g() {\n"
1860 " b = 0; // line 1\n"
1861 "}");
1862
1863 v8::ScriptOrigin origin =
1864 v8::ScriptOrigin(v8::String::New("test"));
1865
1866 // Set a script break point before the scripts are loaded.
1867 int sbp = SetScriptBreakPointByNameFromJS("test", 1, 0);
1868
1869 // Compile the scripts with same script data and get the functions.
1870 v8::Script::Compile(script_f, &origin)->Run();
1871 f = v8::Local<v8::Function>::Cast(env->Global()->Get(v8::String::New("f")));
1872 v8::Script::Compile(script_g, &origin)->Run();
1873 g = v8::Local<v8::Function>::Cast(env->Global()->Get(v8::String::New("g")));
1874
1875 // Call f and g and check that the script break point is active.
1876 break_point_hit_count = 0;
1877 f->Call(env->Global(), 0, NULL);
1878 CHECK_EQ(1, break_point_hit_count);
1879 g->Call(env->Global(), 0, NULL);
1880 CHECK_EQ(2, break_point_hit_count);
1881
1882 // Clear the script break point.
1883 ClearBreakPointFromJS(sbp);
1884
1885 // Call f and g and check that the script break point is no longer active.
1886 break_point_hit_count = 0;
1887 f->Call(env->Global(), 0, NULL);
1888 CHECK_EQ(0, break_point_hit_count);
1889 g->Call(env->Global(), 0, NULL);
1890 CHECK_EQ(0, break_point_hit_count);
1891
1892 // Set script break point with the scripts loaded.
1893 sbp = SetScriptBreakPointByNameFromJS("test", 1, 0);
1894
1895 // Call f and g and check that the script break point is active.
1896 break_point_hit_count = 0;
1897 f->Call(env->Global(), 0, NULL);
1898 CHECK_EQ(1, break_point_hit_count);
1899 g->Call(env->Global(), 0, NULL);
1900 CHECK_EQ(2, break_point_hit_count);
1901
1902 v8::Debug::SetDebugEventListener(NULL);
1903 CheckDebuggerUnloaded();
1904}
1905
1906
1907// Test the script origin which has both name and line offset.
1908TEST(ScriptBreakPointLineOffset) {
1909 break_point_hit_count = 0;
1910 v8::HandleScope scope;
1911 DebugLocalContext env;
1912 env.ExposeDebug();
1913
1914 v8::Debug::SetDebugEventListener(DebugEventBreakPointHitCount,
1915 v8::Undefined());
1916
1917 v8::Local<v8::Function> f;
1918 v8::Local<v8::String> script = v8::String::New(
1919 "function f() {\n"
1920 " a = 0; // line 8 as this script has line offset 7\n"
1921 " b = 0; // line 9 as this script has line offset 7\n"
1922 "}");
1923
1924 // Create script origin both name and line offset.
1925 v8::ScriptOrigin origin(v8::String::New("test.html"),
1926 v8::Integer::New(7));
1927
1928 // Set two script break points before the script is loaded.
1929 int sbp1 = SetScriptBreakPointByNameFromJS("test.html", 8, 0);
1930 int sbp2 = SetScriptBreakPointByNameFromJS("test.html", 9, 0);
1931
1932 // Compile the script and get the function.
1933 v8::Script::Compile(script, &origin)->Run();
1934 f = v8::Local<v8::Function>::Cast(env->Global()->Get(v8::String::New("f")));
1935
1936 // Call f and check that the script break point is active.
1937 break_point_hit_count = 0;
1938 f->Call(env->Global(), 0, NULL);
1939 CHECK_EQ(2, break_point_hit_count);
1940
1941 // Clear the script break points.
1942 ClearBreakPointFromJS(sbp1);
1943 ClearBreakPointFromJS(sbp2);
1944
1945 // Call f and check that no script break points are active.
1946 break_point_hit_count = 0;
1947 f->Call(env->Global(), 0, NULL);
1948 CHECK_EQ(0, break_point_hit_count);
1949
1950 // Set a script break point with the script loaded.
1951 sbp1 = SetScriptBreakPointByNameFromJS("test.html", 9, 0);
1952
1953 // Call f and check that the script break point is active.
1954 break_point_hit_count = 0;
1955 f->Call(env->Global(), 0, NULL);
1956 CHECK_EQ(1, break_point_hit_count);
1957
1958 v8::Debug::SetDebugEventListener(NULL);
1959 CheckDebuggerUnloaded();
1960}
1961
1962
1963// Test script break points set on lines.
1964TEST(ScriptBreakPointLine) {
1965 v8::HandleScope scope;
1966 DebugLocalContext env;
1967 env.ExposeDebug();
1968
1969 // Create a function for checking the function when hitting a break point.
1970 frame_function_name = CompileFunction(&env,
1971 frame_function_name_source,
1972 "frame_function_name");
1973
1974 v8::Debug::SetDebugEventListener(DebugEventBreakPointHitCount,
1975 v8::Undefined());
1976
1977 v8::Local<v8::Function> f;
1978 v8::Local<v8::Function> g;
1979 v8::Local<v8::String> script = v8::String::New(
1980 "a = 0 // line 0\n"
1981 "function f() {\n"
1982 " a = 1; // line 2\n"
1983 "}\n"
1984 " a = 2; // line 4\n"
1985 " /* xx */ function g() { // line 5\n"
1986 " function h() { // line 6\n"
1987 " a = 3; // line 7\n"
1988 " }\n"
1989 " h(); // line 9\n"
1990 " a = 4; // line 10\n"
1991 " }\n"
1992 " a=5; // line 12");
1993
1994 // Set a couple script break point before the script is loaded.
1995 int sbp1 = SetScriptBreakPointByNameFromJS("test.html", 0, -1);
1996 int sbp2 = SetScriptBreakPointByNameFromJS("test.html", 1, -1);
1997 int sbp3 = SetScriptBreakPointByNameFromJS("test.html", 5, -1);
1998
1999 // Compile the script and get the function.
2000 break_point_hit_count = 0;
2001 v8::ScriptOrigin origin(v8::String::New("test.html"), v8::Integer::New(0));
2002 v8::Script::Compile(script, &origin)->Run();
2003 f = v8::Local<v8::Function>::Cast(env->Global()->Get(v8::String::New("f")));
2004 g = v8::Local<v8::Function>::Cast(env->Global()->Get(v8::String::New("g")));
2005
2006 // Chesk that a break point was hit when the script was run.
2007 CHECK_EQ(1, break_point_hit_count);
Steve Blockd0582a62009-12-15 09:54:21 +00002008 CHECK_EQ(0, StrLength(last_function_hit));
Steve Blocka7e24c12009-10-30 11:49:00 +00002009
2010 // Call f and check that the script break point.
2011 f->Call(env->Global(), 0, NULL);
2012 CHECK_EQ(2, break_point_hit_count);
2013 CHECK_EQ("f", last_function_hit);
2014
2015 // Call g and check that the script break point.
2016 g->Call(env->Global(), 0, NULL);
2017 CHECK_EQ(3, break_point_hit_count);
2018 CHECK_EQ("g", last_function_hit);
2019
2020 // Clear the script break point on g and set one on h.
2021 ClearBreakPointFromJS(sbp3);
2022 int sbp4 = SetScriptBreakPointByNameFromJS("test.html", 6, -1);
2023
2024 // Call g and check that the script break point in h is hit.
2025 g->Call(env->Global(), 0, NULL);
2026 CHECK_EQ(4, break_point_hit_count);
2027 CHECK_EQ("h", last_function_hit);
2028
2029 // Clear break points in f and h. Set a new one in the script between
2030 // functions f and g and test that there is no break points in f and g any
2031 // more.
2032 ClearBreakPointFromJS(sbp2);
2033 ClearBreakPointFromJS(sbp4);
2034 int sbp5 = SetScriptBreakPointByNameFromJS("test.html", 4, -1);
2035 break_point_hit_count = 0;
2036 f->Call(env->Global(), 0, NULL);
2037 g->Call(env->Global(), 0, NULL);
2038 CHECK_EQ(0, break_point_hit_count);
2039
2040 // Reload the script which should hit two break points.
2041 break_point_hit_count = 0;
2042 v8::Script::Compile(script, &origin)->Run();
2043 CHECK_EQ(2, break_point_hit_count);
Steve Blockd0582a62009-12-15 09:54:21 +00002044 CHECK_EQ(0, StrLength(last_function_hit));
Steve Blocka7e24c12009-10-30 11:49:00 +00002045
2046 // Set a break point in the code after the last function decleration.
2047 int sbp6 = SetScriptBreakPointByNameFromJS("test.html", 12, -1);
2048
2049 // Reload the script which should hit three break points.
2050 break_point_hit_count = 0;
2051 v8::Script::Compile(script, &origin)->Run();
2052 CHECK_EQ(3, break_point_hit_count);
Steve Blockd0582a62009-12-15 09:54:21 +00002053 CHECK_EQ(0, StrLength(last_function_hit));
Steve Blocka7e24c12009-10-30 11:49:00 +00002054
2055 // Clear the last break points, and reload the script which should not hit any
2056 // break points.
2057 ClearBreakPointFromJS(sbp1);
2058 ClearBreakPointFromJS(sbp5);
2059 ClearBreakPointFromJS(sbp6);
2060 break_point_hit_count = 0;
2061 v8::Script::Compile(script, &origin)->Run();
2062 CHECK_EQ(0, break_point_hit_count);
2063
2064 v8::Debug::SetDebugEventListener(NULL);
2065 CheckDebuggerUnloaded();
2066}
2067
2068
Kristian Monsen9dcf7e22010-06-28 14:14:28 +01002069// Test top level script break points set on lines.
2070TEST(ScriptBreakPointLineTopLevel) {
2071 v8::HandleScope scope;
2072 DebugLocalContext env;
2073 env.ExposeDebug();
2074
2075 v8::Debug::SetDebugEventListener(DebugEventBreakPointHitCount,
2076 v8::Undefined());
2077
2078 v8::Local<v8::String> script = v8::String::New(
2079 "function f() {\n"
2080 " a = 1; // line 1\n"
2081 "}\n"
2082 "a = 2; // line 3\n");
2083 v8::Local<v8::Function> f;
2084 {
2085 v8::HandleScope scope;
2086 v8::Script::Compile(script, v8::String::New("test.html"))->Run();
2087 }
2088 f = v8::Local<v8::Function>::Cast(env->Global()->Get(v8::String::New("f")));
2089
2090 Heap::CollectAllGarbage(false);
2091
2092 SetScriptBreakPointByNameFromJS("test.html", 3, -1);
2093
2094 // Call f and check that there was no break points.
2095 break_point_hit_count = 0;
2096 f->Call(env->Global(), 0, NULL);
2097 CHECK_EQ(0, break_point_hit_count);
2098
2099 // Recompile and run script and check that break point was hit.
2100 break_point_hit_count = 0;
2101 v8::Script::Compile(script, v8::String::New("test.html"))->Run();
2102 CHECK_EQ(1, break_point_hit_count);
2103
2104 // Call f and check that there are still no break points.
2105 break_point_hit_count = 0;
2106 f = v8::Local<v8::Function>::Cast(env->Global()->Get(v8::String::New("f")));
2107 CHECK_EQ(0, break_point_hit_count);
2108
2109 v8::Debug::SetDebugEventListener(NULL);
2110 CheckDebuggerUnloaded();
2111}
2112
2113
Steve Block8defd9f2010-07-08 12:39:36 +01002114// Test that it is possible to add and remove break points in a top level
2115// function which has no references but has not been collected yet.
2116TEST(ScriptBreakPointTopLevelCrash) {
2117 v8::HandleScope scope;
2118 DebugLocalContext env;
2119 env.ExposeDebug();
2120
2121 v8::Debug::SetDebugEventListener(DebugEventBreakPointHitCount,
2122 v8::Undefined());
2123
2124 v8::Local<v8::String> script_source = v8::String::New(
2125 "function f() {\n"
2126 " return 0;\n"
2127 "}\n"
2128 "f()");
2129
2130 int sbp1 = SetScriptBreakPointByNameFromJS("test.html", 3, -1);
2131 {
2132 v8::HandleScope scope;
2133 break_point_hit_count = 0;
2134 v8::Script::Compile(script_source, v8::String::New("test.html"))->Run();
2135 CHECK_EQ(1, break_point_hit_count);
2136 }
2137
2138 int sbp2 = SetScriptBreakPointByNameFromJS("test.html", 3, -1);
2139 ClearBreakPointFromJS(sbp1);
2140 ClearBreakPointFromJS(sbp2);
2141
2142 v8::Debug::SetDebugEventListener(NULL);
2143 CheckDebuggerUnloaded();
2144}
2145
2146
Steve Blocka7e24c12009-10-30 11:49:00 +00002147// Test that it is possible to remove the last break point for a function
2148// inside the break handling of that break point.
2149TEST(RemoveBreakPointInBreak) {
2150 v8::HandleScope scope;
2151 DebugLocalContext env;
2152
2153 v8::Local<v8::Function> foo =
2154 CompileFunction(&env, "function foo(){a=1;}", "foo");
2155 debug_event_remove_break_point = SetBreakPoint(foo, 0);
2156
2157 // Register the debug event listener pasing the function
2158 v8::Debug::SetDebugEventListener(DebugEventRemoveBreakPoint, foo);
2159
2160 break_point_hit_count = 0;
2161 foo->Call(env->Global(), 0, NULL);
2162 CHECK_EQ(1, break_point_hit_count);
2163
2164 break_point_hit_count = 0;
2165 foo->Call(env->Global(), 0, NULL);
2166 CHECK_EQ(0, break_point_hit_count);
2167
2168 v8::Debug::SetDebugEventListener(NULL);
2169 CheckDebuggerUnloaded();
2170}
2171
2172
2173// Test that the debugger statement causes a break.
2174TEST(DebuggerStatement) {
2175 break_point_hit_count = 0;
2176 v8::HandleScope scope;
2177 DebugLocalContext env;
2178 v8::Debug::SetDebugEventListener(DebugEventBreakPointHitCount,
2179 v8::Undefined());
2180 v8::Script::Compile(v8::String::New("function bar(){debugger}"))->Run();
2181 v8::Script::Compile(v8::String::New(
2182 "function foo(){debugger;debugger;}"))->Run();
2183 v8::Local<v8::Function> foo =
2184 v8::Local<v8::Function>::Cast(env->Global()->Get(v8::String::New("foo")));
2185 v8::Local<v8::Function> bar =
2186 v8::Local<v8::Function>::Cast(env->Global()->Get(v8::String::New("bar")));
2187
2188 // Run function with debugger statement
2189 bar->Call(env->Global(), 0, NULL);
2190 CHECK_EQ(1, break_point_hit_count);
2191
2192 // Run function with two debugger statement
2193 foo->Call(env->Global(), 0, NULL);
2194 CHECK_EQ(3, break_point_hit_count);
2195
2196 v8::Debug::SetDebugEventListener(NULL);
2197 CheckDebuggerUnloaded();
2198}
2199
2200
Steve Block8defd9f2010-07-08 12:39:36 +01002201// Test setting a breakpoint on the debugger statement.
Leon Clarke4515c472010-02-03 11:58:03 +00002202TEST(DebuggerStatementBreakpoint) {
2203 break_point_hit_count = 0;
2204 v8::HandleScope scope;
2205 DebugLocalContext env;
2206 v8::Debug::SetDebugEventListener(DebugEventBreakPointHitCount,
2207 v8::Undefined());
2208 v8::Script::Compile(v8::String::New("function foo(){debugger;}"))->Run();
2209 v8::Local<v8::Function> foo =
2210 v8::Local<v8::Function>::Cast(env->Global()->Get(v8::String::New("foo")));
2211
2212 // The debugger statement triggers breakpint hit
2213 foo->Call(env->Global(), 0, NULL);
2214 CHECK_EQ(1, break_point_hit_count);
2215
2216 int bp = SetBreakPoint(foo, 0);
2217
2218 // Set breakpoint does not duplicate hits
2219 foo->Call(env->Global(), 0, NULL);
2220 CHECK_EQ(2, break_point_hit_count);
2221
2222 ClearBreakPoint(bp);
2223 v8::Debug::SetDebugEventListener(NULL);
2224 CheckDebuggerUnloaded();
2225}
2226
2227
Steve Blocka7e24c12009-10-30 11:49:00 +00002228// Thest that the evaluation of expressions when a break point is hit generates
2229// the correct results.
2230TEST(DebugEvaluate) {
2231 v8::HandleScope scope;
2232 DebugLocalContext env;
2233 env.ExposeDebug();
2234
2235 // Create a function for checking the evaluation when hitting a break point.
2236 evaluate_check_function = CompileFunction(&env,
2237 evaluate_check_source,
2238 "evaluate_check");
2239 // Register the debug event listener
2240 v8::Debug::SetDebugEventListener(DebugEventEvaluate);
2241
2242 // Different expected vaules of x and a when in a break point (u = undefined,
2243 // d = Hello, world!).
2244 struct EvaluateCheck checks_uu[] = {
2245 {"x", v8::Undefined()},
2246 {"a", v8::Undefined()},
2247 {NULL, v8::Handle<v8::Value>()}
2248 };
2249 struct EvaluateCheck checks_hu[] = {
2250 {"x", v8::String::New("Hello, world!")},
2251 {"a", v8::Undefined()},
2252 {NULL, v8::Handle<v8::Value>()}
2253 };
2254 struct EvaluateCheck checks_hh[] = {
2255 {"x", v8::String::New("Hello, world!")},
2256 {"a", v8::String::New("Hello, world!")},
2257 {NULL, v8::Handle<v8::Value>()}
2258 };
2259
2260 // Simple test function. The "y=0" is in the function foo to provide a break
2261 // location. For "y=0" the "y" is at position 15 in the barbar function
2262 // therefore setting breakpoint at position 15 will break at "y=0" and
2263 // setting it higher will break after.
2264 v8::Local<v8::Function> foo = CompileFunction(&env,
2265 "function foo(x) {"
2266 " var a;"
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01002267 " y=0;" // To ensure break location 1.
Steve Blocka7e24c12009-10-30 11:49:00 +00002268 " a=x;"
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01002269 " y=0;" // To ensure break location 2.
Steve Blocka7e24c12009-10-30 11:49:00 +00002270 "}",
2271 "foo");
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01002272 const int foo_break_position_1 = 15;
2273 const int foo_break_position_2 = 29;
Steve Blocka7e24c12009-10-30 11:49:00 +00002274
2275 // Arguments with one parameter "Hello, world!"
2276 v8::Handle<v8::Value> argv_foo[1] = { v8::String::New("Hello, world!") };
2277
2278 // Call foo with breakpoint set before a=x and undefined as parameter.
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01002279 int bp = SetBreakPoint(foo, foo_break_position_1);
Steve Blocka7e24c12009-10-30 11:49:00 +00002280 checks = checks_uu;
2281 foo->Call(env->Global(), 0, NULL);
2282
2283 // Call foo with breakpoint set before a=x and parameter "Hello, world!".
2284 checks = checks_hu;
2285 foo->Call(env->Global(), 1, argv_foo);
2286
2287 // Call foo with breakpoint set after a=x and parameter "Hello, world!".
2288 ClearBreakPoint(bp);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01002289 SetBreakPoint(foo, foo_break_position_2);
Steve Blocka7e24c12009-10-30 11:49:00 +00002290 checks = checks_hh;
2291 foo->Call(env->Global(), 1, argv_foo);
2292
2293 // Test function with an inner function. The "y=0" is in function barbar
2294 // to provide a break location. For "y=0" the "y" is at position 8 in the
2295 // barbar function therefore setting breakpoint at position 8 will break at
2296 // "y=0" and setting it higher will break after.
2297 v8::Local<v8::Function> bar = CompileFunction(&env,
2298 "y = 0;"
2299 "x = 'Goodbye, world!';"
2300 "function bar(x, b) {"
2301 " var a;"
2302 " function barbar() {"
2303 " y=0; /* To ensure break location.*/"
2304 " a=x;"
2305 " };"
2306 " debug.Debug.clearAllBreakPoints();"
2307 " barbar();"
2308 " y=0;a=x;"
2309 "}",
2310 "bar");
2311 const int barbar_break_position = 8;
2312
2313 // Call bar setting breakpoint before a=x in barbar and undefined as
2314 // parameter.
2315 checks = checks_uu;
2316 v8::Handle<v8::Value> argv_bar_1[2] = {
2317 v8::Undefined(),
2318 v8::Number::New(barbar_break_position)
2319 };
2320 bar->Call(env->Global(), 2, argv_bar_1);
2321
2322 // Call bar setting breakpoint before a=x in barbar and parameter
2323 // "Hello, world!".
2324 checks = checks_hu;
2325 v8::Handle<v8::Value> argv_bar_2[2] = {
2326 v8::String::New("Hello, world!"),
2327 v8::Number::New(barbar_break_position)
2328 };
2329 bar->Call(env->Global(), 2, argv_bar_2);
2330
2331 // Call bar setting breakpoint after a=x in barbar and parameter
2332 // "Hello, world!".
2333 checks = checks_hh;
2334 v8::Handle<v8::Value> argv_bar_3[2] = {
2335 v8::String::New("Hello, world!"),
2336 v8::Number::New(barbar_break_position + 1)
2337 };
2338 bar->Call(env->Global(), 2, argv_bar_3);
2339
2340 v8::Debug::SetDebugEventListener(NULL);
2341 CheckDebuggerUnloaded();
2342}
2343
Leon Clarkee46be812010-01-19 14:06:41 +00002344// Copies a C string to a 16-bit string. Does not check for buffer overflow.
2345// Does not use the V8 engine to convert strings, so it can be used
2346// in any thread. Returns the length of the string.
2347int AsciiToUtf16(const char* input_buffer, uint16_t* output_buffer) {
2348 int i;
2349 for (i = 0; input_buffer[i] != '\0'; ++i) {
2350 // ASCII does not use chars > 127, but be careful anyway.
2351 output_buffer[i] = static_cast<unsigned char>(input_buffer[i]);
2352 }
2353 output_buffer[i] = 0;
2354 return i;
2355}
2356
2357// Copies a 16-bit string to a C string by dropping the high byte of
2358// each character. Does not check for buffer overflow.
2359// Can be used in any thread. Requires string length as an input.
2360int Utf16ToAscii(const uint16_t* input_buffer, int length,
2361 char* output_buffer, int output_len = -1) {
2362 if (output_len >= 0) {
2363 if (length > output_len - 1) {
2364 length = output_len - 1;
2365 }
2366 }
2367
2368 for (int i = 0; i < length; ++i) {
2369 output_buffer[i] = static_cast<char>(input_buffer[i]);
2370 }
2371 output_buffer[length] = '\0';
2372 return length;
2373}
2374
2375
2376// We match parts of the message to get evaluate result int value.
2377bool GetEvaluateStringResult(char *message, char* buffer, int buffer_size) {
Leon Clarked91b9f72010-01-27 17:25:45 +00002378 if (strstr(message, "\"command\":\"evaluate\"") == NULL) {
2379 return false;
2380 }
2381 const char* prefix = "\"text\":\"";
2382 char* pos1 = strstr(message, prefix);
2383 if (pos1 == NULL) {
2384 return false;
2385 }
2386 pos1 += strlen(prefix);
2387 char* pos2 = strchr(pos1, '"');
2388 if (pos2 == NULL) {
Leon Clarkee46be812010-01-19 14:06:41 +00002389 return false;
2390 }
2391 Vector<char> buf(buffer, buffer_size);
Leon Clarked91b9f72010-01-27 17:25:45 +00002392 int len = static_cast<int>(pos2 - pos1);
2393 if (len > buffer_size - 1) {
2394 len = buffer_size - 1;
2395 }
2396 OS::StrNCpy(buf, pos1, len);
Leon Clarkee46be812010-01-19 14:06:41 +00002397 buffer[buffer_size - 1] = '\0';
2398 return true;
2399}
2400
2401
2402struct EvaluateResult {
2403 static const int kBufferSize = 20;
2404 char buffer[kBufferSize];
2405};
2406
2407struct DebugProcessDebugMessagesData {
2408 static const int kArraySize = 5;
2409 int counter;
2410 EvaluateResult results[kArraySize];
2411
2412 void reset() {
2413 counter = 0;
2414 }
2415 EvaluateResult* current() {
2416 return &results[counter % kArraySize];
2417 }
2418 void next() {
2419 counter++;
2420 }
2421};
2422
2423DebugProcessDebugMessagesData process_debug_messages_data;
2424
2425static void DebugProcessDebugMessagesHandler(
2426 const uint16_t* message,
2427 int length,
2428 v8::Debug::ClientData* client_data) {
2429
2430 const int kBufferSize = 100000;
2431 char print_buffer[kBufferSize];
2432 Utf16ToAscii(message, length, print_buffer, kBufferSize);
2433
2434 EvaluateResult* array_item = process_debug_messages_data.current();
2435
2436 bool res = GetEvaluateStringResult(print_buffer,
2437 array_item->buffer,
2438 EvaluateResult::kBufferSize);
2439 if (res) {
2440 process_debug_messages_data.next();
2441 }
2442}
2443
2444// Test that the evaluation of expressions works even from ProcessDebugMessages
2445// i.e. with empty stack.
2446TEST(DebugEvaluateWithoutStack) {
2447 v8::Debug::SetMessageHandler(DebugProcessDebugMessagesHandler);
2448
2449 v8::HandleScope scope;
2450 DebugLocalContext env;
2451
2452 const char* source =
2453 "var v1 = 'Pinguin';\n function getAnimal() { return 'Capy' + 'bara'; }";
2454
2455 v8::Script::Compile(v8::String::New(source))->Run();
2456
2457 v8::Debug::ProcessDebugMessages();
2458
2459 const int kBufferSize = 1000;
2460 uint16_t buffer[kBufferSize];
2461
2462 const char* command_111 = "{\"seq\":111,"
2463 "\"type\":\"request\","
2464 "\"command\":\"evaluate\","
2465 "\"arguments\":{"
2466 " \"global\":true,"
2467 " \"expression\":\"v1\",\"disable_break\":true"
2468 "}}";
2469
2470 v8::Debug::SendCommand(buffer, AsciiToUtf16(command_111, buffer));
2471
2472 const char* command_112 = "{\"seq\":112,"
2473 "\"type\":\"request\","
2474 "\"command\":\"evaluate\","
2475 "\"arguments\":{"
2476 " \"global\":true,"
2477 " \"expression\":\"getAnimal()\",\"disable_break\":true"
2478 "}}";
2479
2480 v8::Debug::SendCommand(buffer, AsciiToUtf16(command_112, buffer));
2481
2482 const char* command_113 = "{\"seq\":113,"
2483 "\"type\":\"request\","
2484 "\"command\":\"evaluate\","
2485 "\"arguments\":{"
2486 " \"global\":true,"
2487 " \"expression\":\"239 + 566\",\"disable_break\":true"
2488 "}}";
2489
2490 v8::Debug::SendCommand(buffer, AsciiToUtf16(command_113, buffer));
2491
2492 v8::Debug::ProcessDebugMessages();
2493
2494 CHECK_EQ(3, process_debug_messages_data.counter);
2495
Leon Clarked91b9f72010-01-27 17:25:45 +00002496 CHECK_EQ(strcmp("Pinguin", process_debug_messages_data.results[0].buffer), 0);
2497 CHECK_EQ(strcmp("Capybara", process_debug_messages_data.results[1].buffer),
2498 0);
2499 CHECK_EQ(strcmp("805", process_debug_messages_data.results[2].buffer), 0);
Leon Clarkee46be812010-01-19 14:06:41 +00002500
2501 v8::Debug::SetMessageHandler(NULL);
2502 v8::Debug::SetDebugEventListener(NULL);
2503 CheckDebuggerUnloaded();
2504}
2505
Steve Blocka7e24c12009-10-30 11:49:00 +00002506
2507// Simple test of the stepping mechanism using only store ICs.
2508TEST(DebugStepLinear) {
2509 v8::HandleScope scope;
2510 DebugLocalContext env;
2511
2512 // Create a function for testing stepping.
2513 v8::Local<v8::Function> foo = CompileFunction(&env,
2514 "function foo(){a=1;b=1;c=1;}",
2515 "foo");
2516 SetBreakPoint(foo, 3);
2517
2518 // Register a debug event listener which steps and counts.
2519 v8::Debug::SetDebugEventListener(DebugEventStep);
2520
2521 step_action = StepIn;
2522 break_point_hit_count = 0;
2523 foo->Call(env->Global(), 0, NULL);
2524
2525 // With stepping all break locations are hit.
2526 CHECK_EQ(4, break_point_hit_count);
2527
2528 v8::Debug::SetDebugEventListener(NULL);
2529 CheckDebuggerUnloaded();
2530
2531 // Register a debug event listener which just counts.
2532 v8::Debug::SetDebugEventListener(DebugEventBreakPointHitCount);
2533
2534 SetBreakPoint(foo, 3);
2535 break_point_hit_count = 0;
2536 foo->Call(env->Global(), 0, NULL);
2537
2538 // Without stepping only active break points are hit.
2539 CHECK_EQ(1, break_point_hit_count);
2540
2541 v8::Debug::SetDebugEventListener(NULL);
2542 CheckDebuggerUnloaded();
2543}
2544
2545
2546// Test of the stepping mechanism for keyed load in a loop.
2547TEST(DebugStepKeyedLoadLoop) {
2548 v8::HandleScope scope;
2549 DebugLocalContext env;
2550
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01002551 // Register a debug event listener which steps and counts.
2552 v8::Debug::SetDebugEventListener(DebugEventStep);
2553
Steve Blocka7e24c12009-10-30 11:49:00 +00002554 // Create a function for testing stepping of keyed load. The statement 'y=1'
2555 // is there to have more than one breakable statement in the loop, TODO(315).
2556 v8::Local<v8::Function> foo = CompileFunction(
2557 &env,
2558 "function foo(a) {\n"
2559 " var x;\n"
2560 " var len = a.length;\n"
2561 " for (var i = 0; i < len; i++) {\n"
2562 " y = 1;\n"
2563 " x = a[i];\n"
2564 " }\n"
2565 "}\n",
2566 "foo");
2567
2568 // Create array [0,1,2,3,4,5,6,7,8,9]
2569 v8::Local<v8::Array> a = v8::Array::New(10);
2570 for (int i = 0; i < 10; i++) {
2571 a->Set(v8::Number::New(i), v8::Number::New(i));
2572 }
2573
2574 // Call function without any break points to ensure inlining is in place.
2575 const int kArgc = 1;
2576 v8::Handle<v8::Value> args[kArgc] = { a };
2577 foo->Call(env->Global(), kArgc, args);
2578
Steve Blocka7e24c12009-10-30 11:49:00 +00002579 // Setup break point and step through the function.
2580 SetBreakPoint(foo, 3);
2581 step_action = StepNext;
2582 break_point_hit_count = 0;
2583 foo->Call(env->Global(), kArgc, args);
2584
2585 // With stepping all break locations are hit.
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01002586 CHECK_EQ(33, break_point_hit_count);
Steve Blocka7e24c12009-10-30 11:49:00 +00002587
2588 v8::Debug::SetDebugEventListener(NULL);
2589 CheckDebuggerUnloaded();
2590}
2591
2592
2593// Test of the stepping mechanism for keyed store in a loop.
2594TEST(DebugStepKeyedStoreLoop) {
2595 v8::HandleScope scope;
2596 DebugLocalContext env;
2597
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01002598 // Register a debug event listener which steps and counts.
2599 v8::Debug::SetDebugEventListener(DebugEventStep);
2600
Steve Blocka7e24c12009-10-30 11:49:00 +00002601 // Create a function for testing stepping of keyed store. The statement 'y=1'
2602 // is there to have more than one breakable statement in the loop, TODO(315).
2603 v8::Local<v8::Function> foo = CompileFunction(
2604 &env,
2605 "function foo(a) {\n"
2606 " var len = a.length;\n"
2607 " for (var i = 0; i < len; i++) {\n"
2608 " y = 1;\n"
2609 " a[i] = 42;\n"
2610 " }\n"
2611 "}\n",
2612 "foo");
2613
2614 // Create array [0,1,2,3,4,5,6,7,8,9]
2615 v8::Local<v8::Array> a = v8::Array::New(10);
2616 for (int i = 0; i < 10; i++) {
2617 a->Set(v8::Number::New(i), v8::Number::New(i));
2618 }
2619
2620 // Call function without any break points to ensure inlining is in place.
2621 const int kArgc = 1;
2622 v8::Handle<v8::Value> args[kArgc] = { a };
2623 foo->Call(env->Global(), kArgc, args);
2624
Steve Blocka7e24c12009-10-30 11:49:00 +00002625 // Setup break point and step through the function.
2626 SetBreakPoint(foo, 3);
2627 step_action = StepNext;
2628 break_point_hit_count = 0;
2629 foo->Call(env->Global(), kArgc, args);
2630
2631 // With stepping all break locations are hit.
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01002632 CHECK_EQ(32, break_point_hit_count);
Steve Blocka7e24c12009-10-30 11:49:00 +00002633
2634 v8::Debug::SetDebugEventListener(NULL);
2635 CheckDebuggerUnloaded();
2636}
2637
2638
Kristian Monsen25f61362010-05-21 11:50:48 +01002639// Test of the stepping mechanism for named load in a loop.
2640TEST(DebugStepNamedLoadLoop) {
2641 v8::HandleScope scope;
2642 DebugLocalContext env;
2643
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01002644 // Register a debug event listener which steps and counts.
2645 v8::Debug::SetDebugEventListener(DebugEventStep);
2646
Kristian Monsen25f61362010-05-21 11:50:48 +01002647 // Create a function for testing stepping of named load.
2648 v8::Local<v8::Function> foo = CompileFunction(
2649 &env,
2650 "function foo() {\n"
2651 " var a = [];\n"
2652 " var s = \"\";\n"
2653 " for (var i = 0; i < 10; i++) {\n"
2654 " var v = new V(i, i + 1);\n"
2655 " v.y;\n"
2656 " a.length;\n" // Special case: array length.
2657 " s.length;\n" // Special case: string length.
2658 " }\n"
2659 "}\n"
2660 "function V(x, y) {\n"
2661 " this.x = x;\n"
2662 " this.y = y;\n"
2663 "}\n",
2664 "foo");
2665
2666 // Call function without any break points to ensure inlining is in place.
2667 foo->Call(env->Global(), 0, NULL);
2668
Kristian Monsen25f61362010-05-21 11:50:48 +01002669 // Setup break point and step through the function.
2670 SetBreakPoint(foo, 4);
2671 step_action = StepNext;
2672 break_point_hit_count = 0;
2673 foo->Call(env->Global(), 0, NULL);
2674
2675 // With stepping all break locations are hit.
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01002676 CHECK_EQ(53, break_point_hit_count);
Kristian Monsen25f61362010-05-21 11:50:48 +01002677
2678 v8::Debug::SetDebugEventListener(NULL);
2679 CheckDebuggerUnloaded();
2680}
2681
2682
Steve Blocka7e24c12009-10-30 11:49:00 +00002683// Test the stepping mechanism with different ICs.
2684TEST(DebugStepLinearMixedICs) {
2685 v8::HandleScope scope;
2686 DebugLocalContext env;
2687
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01002688 // Register a debug event listener which steps and counts.
2689 v8::Debug::SetDebugEventListener(DebugEventStep);
2690
Steve Blocka7e24c12009-10-30 11:49:00 +00002691 // Create a function for testing stepping.
2692 v8::Local<v8::Function> foo = CompileFunction(&env,
2693 "function bar() {};"
2694 "function foo() {"
2695 " var x;"
2696 " var index='name';"
2697 " var y = {};"
2698 " a=1;b=2;x=a;y[index]=3;x=y[index];bar();}", "foo");
2699 SetBreakPoint(foo, 0);
2700
Steve Blocka7e24c12009-10-30 11:49:00 +00002701 step_action = StepIn;
2702 break_point_hit_count = 0;
2703 foo->Call(env->Global(), 0, NULL);
2704
2705 // With stepping all break locations are hit.
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01002706 CHECK_EQ(11, break_point_hit_count);
Steve Blocka7e24c12009-10-30 11:49:00 +00002707
2708 v8::Debug::SetDebugEventListener(NULL);
2709 CheckDebuggerUnloaded();
2710
2711 // Register a debug event listener which just counts.
2712 v8::Debug::SetDebugEventListener(DebugEventBreakPointHitCount);
2713
2714 SetBreakPoint(foo, 0);
2715 break_point_hit_count = 0;
2716 foo->Call(env->Global(), 0, NULL);
2717
2718 // Without stepping only active break points are hit.
2719 CHECK_EQ(1, break_point_hit_count);
2720
2721 v8::Debug::SetDebugEventListener(NULL);
2722 CheckDebuggerUnloaded();
2723}
2724
2725
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01002726TEST(DebugStepDeclarations) {
2727 v8::HandleScope scope;
2728 DebugLocalContext env;
2729
2730 // Register a debug event listener which steps and counts.
2731 v8::Debug::SetDebugEventListener(DebugEventStep);
2732
2733 // Create a function for testing stepping.
2734 const char* src = "function foo() { "
2735 " var a;"
2736 " var b = 1;"
2737 " var c = foo;"
2738 " var d = Math.floor;"
2739 " var e = b + d(1.2);"
2740 "}";
2741 v8::Local<v8::Function> foo = CompileFunction(&env, src, "foo");
2742 SetBreakPoint(foo, 0);
2743
2744 // Stepping through the declarations.
2745 step_action = StepIn;
2746 break_point_hit_count = 0;
2747 foo->Call(env->Global(), 0, NULL);
2748 CHECK_EQ(6, break_point_hit_count);
2749
2750 // Get rid of the debug event listener.
2751 v8::Debug::SetDebugEventListener(NULL);
2752 CheckDebuggerUnloaded();
2753}
2754
2755
2756TEST(DebugStepLocals) {
2757 v8::HandleScope scope;
2758 DebugLocalContext env;
2759
2760 // Register a debug event listener which steps and counts.
2761 v8::Debug::SetDebugEventListener(DebugEventStep);
2762
2763 // Create a function for testing stepping.
2764 const char* src = "function foo() { "
2765 " var a,b;"
2766 " a = 1;"
2767 " b = a + 2;"
2768 " b = 1 + 2 + 3;"
2769 " a = Math.floor(b);"
2770 "}";
2771 v8::Local<v8::Function> foo = CompileFunction(&env, src, "foo");
2772 SetBreakPoint(foo, 0);
2773
2774 // Stepping through the declarations.
2775 step_action = StepIn;
2776 break_point_hit_count = 0;
2777 foo->Call(env->Global(), 0, NULL);
2778 CHECK_EQ(6, break_point_hit_count);
2779
2780 // Get rid of the debug event listener.
2781 v8::Debug::SetDebugEventListener(NULL);
2782 CheckDebuggerUnloaded();
2783}
2784
2785
Steve Blocka7e24c12009-10-30 11:49:00 +00002786TEST(DebugStepIf) {
2787 v8::HandleScope scope;
2788 DebugLocalContext env;
2789
2790 // Register a debug event listener which steps and counts.
2791 v8::Debug::SetDebugEventListener(DebugEventStep);
2792
2793 // Create a function for testing stepping.
2794 const int argc = 1;
2795 const char* src = "function foo(x) { "
2796 " a = 1;"
2797 " if (x) {"
2798 " b = 1;"
2799 " } else {"
2800 " c = 1;"
2801 " d = 1;"
2802 " }"
2803 "}";
2804 v8::Local<v8::Function> foo = CompileFunction(&env, src, "foo");
2805 SetBreakPoint(foo, 0);
2806
2807 // Stepping through the true part.
2808 step_action = StepIn;
2809 break_point_hit_count = 0;
2810 v8::Handle<v8::Value> argv_true[argc] = { v8::True() };
2811 foo->Call(env->Global(), argc, argv_true);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01002812 CHECK_EQ(4, break_point_hit_count);
Steve Blocka7e24c12009-10-30 11:49:00 +00002813
2814 // Stepping through the false part.
2815 step_action = StepIn;
2816 break_point_hit_count = 0;
2817 v8::Handle<v8::Value> argv_false[argc] = { v8::False() };
2818 foo->Call(env->Global(), argc, argv_false);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01002819 CHECK_EQ(5, break_point_hit_count);
Steve Blocka7e24c12009-10-30 11:49:00 +00002820
2821 // Get rid of the debug event listener.
2822 v8::Debug::SetDebugEventListener(NULL);
2823 CheckDebuggerUnloaded();
2824}
2825
2826
2827TEST(DebugStepSwitch) {
2828 v8::HandleScope scope;
2829 DebugLocalContext env;
2830
2831 // Register a debug event listener which steps and counts.
2832 v8::Debug::SetDebugEventListener(DebugEventStep);
2833
2834 // Create a function for testing stepping.
2835 const int argc = 1;
2836 const char* src = "function foo(x) { "
2837 " a = 1;"
2838 " switch (x) {"
2839 " case 1:"
2840 " b = 1;"
2841 " case 2:"
2842 " c = 1;"
2843 " break;"
2844 " case 3:"
2845 " d = 1;"
2846 " e = 1;"
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01002847 " f = 1;"
Steve Blocka7e24c12009-10-30 11:49:00 +00002848 " break;"
2849 " }"
2850 "}";
2851 v8::Local<v8::Function> foo = CompileFunction(&env, src, "foo");
2852 SetBreakPoint(foo, 0);
2853
2854 // One case with fall-through.
2855 step_action = StepIn;
2856 break_point_hit_count = 0;
2857 v8::Handle<v8::Value> argv_1[argc] = { v8::Number::New(1) };
2858 foo->Call(env->Global(), argc, argv_1);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01002859 CHECK_EQ(6, break_point_hit_count);
Steve Blocka7e24c12009-10-30 11:49:00 +00002860
2861 // Another case.
2862 step_action = StepIn;
2863 break_point_hit_count = 0;
2864 v8::Handle<v8::Value> argv_2[argc] = { v8::Number::New(2) };
2865 foo->Call(env->Global(), argc, argv_2);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01002866 CHECK_EQ(5, break_point_hit_count);
Steve Blocka7e24c12009-10-30 11:49:00 +00002867
2868 // Last case.
2869 step_action = StepIn;
2870 break_point_hit_count = 0;
2871 v8::Handle<v8::Value> argv_3[argc] = { v8::Number::New(3) };
2872 foo->Call(env->Global(), argc, argv_3);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01002873 CHECK_EQ(7, break_point_hit_count);
2874
2875 // Get rid of the debug event listener.
2876 v8::Debug::SetDebugEventListener(NULL);
2877 CheckDebuggerUnloaded();
2878}
2879
2880
2881TEST(DebugStepWhile) {
2882 v8::HandleScope scope;
2883 DebugLocalContext env;
2884
2885 // Register a debug event listener which steps and counts.
2886 v8::Debug::SetDebugEventListener(DebugEventStep);
2887
2888 // Create a function for testing stepping.
2889 const int argc = 1;
2890 const char* src = "function foo(x) { "
2891 " var a = 0;"
2892 " while (a < x) {"
2893 " a++;"
2894 " }"
2895 "}";
2896 v8::Local<v8::Function> foo = CompileFunction(&env, src, "foo");
2897 SetBreakPoint(foo, 8); // "var a = 0;"
2898
2899 // Looping 10 times.
2900 step_action = StepIn;
2901 break_point_hit_count = 0;
2902 v8::Handle<v8::Value> argv_10[argc] = { v8::Number::New(10) };
2903 foo->Call(env->Global(), argc, argv_10);
2904 CHECK_EQ(23, break_point_hit_count);
2905
2906 // Looping 100 times.
2907 step_action = StepIn;
2908 break_point_hit_count = 0;
2909 v8::Handle<v8::Value> argv_100[argc] = { v8::Number::New(100) };
2910 foo->Call(env->Global(), argc, argv_100);
2911 CHECK_EQ(203, break_point_hit_count);
2912
2913 // Get rid of the debug event listener.
2914 v8::Debug::SetDebugEventListener(NULL);
2915 CheckDebuggerUnloaded();
2916}
2917
2918
2919TEST(DebugStepDoWhile) {
2920 v8::HandleScope scope;
2921 DebugLocalContext env;
2922
2923 // Register a debug event listener which steps and counts.
2924 v8::Debug::SetDebugEventListener(DebugEventStep);
2925
2926 // Create a function for testing stepping.
2927 const int argc = 1;
2928 const char* src = "function foo(x) { "
2929 " var a = 0;"
2930 " do {"
2931 " a++;"
2932 " } while (a < x)"
2933 "}";
2934 v8::Local<v8::Function> foo = CompileFunction(&env, src, "foo");
2935 SetBreakPoint(foo, 8); // "var a = 0;"
2936
2937 // Looping 10 times.
2938 step_action = StepIn;
2939 break_point_hit_count = 0;
2940 v8::Handle<v8::Value> argv_10[argc] = { v8::Number::New(10) };
2941 foo->Call(env->Global(), argc, argv_10);
2942 CHECK_EQ(22, break_point_hit_count);
2943
2944 // Looping 100 times.
2945 step_action = StepIn;
2946 break_point_hit_count = 0;
2947 v8::Handle<v8::Value> argv_100[argc] = { v8::Number::New(100) };
2948 foo->Call(env->Global(), argc, argv_100);
2949 CHECK_EQ(202, break_point_hit_count);
Steve Blocka7e24c12009-10-30 11:49:00 +00002950
2951 // Get rid of the debug event listener.
2952 v8::Debug::SetDebugEventListener(NULL);
2953 CheckDebuggerUnloaded();
2954}
2955
2956
2957TEST(DebugStepFor) {
2958 v8::HandleScope scope;
2959 DebugLocalContext env;
2960
2961 // Register a debug event listener which steps and counts.
2962 v8::Debug::SetDebugEventListener(DebugEventStep);
2963
2964 // Create a function for testing stepping.
2965 const int argc = 1;
2966 const char* src = "function foo(x) { "
2967 " a = 1;"
2968 " for (i = 0; i < x; i++) {"
2969 " b = 1;"
2970 " }"
2971 "}";
2972 v8::Local<v8::Function> foo = CompileFunction(&env, src, "foo");
2973 SetBreakPoint(foo, 8); // "a = 1;"
2974
2975 // Looping 10 times.
2976 step_action = StepIn;
2977 break_point_hit_count = 0;
2978 v8::Handle<v8::Value> argv_10[argc] = { v8::Number::New(10) };
2979 foo->Call(env->Global(), argc, argv_10);
2980 CHECK_EQ(23, break_point_hit_count);
2981
2982 // Looping 100 times.
2983 step_action = StepIn;
2984 break_point_hit_count = 0;
2985 v8::Handle<v8::Value> argv_100[argc] = { v8::Number::New(100) };
2986 foo->Call(env->Global(), argc, argv_100);
2987 CHECK_EQ(203, break_point_hit_count);
2988
2989 // Get rid of the debug event listener.
2990 v8::Debug::SetDebugEventListener(NULL);
2991 CheckDebuggerUnloaded();
2992}
2993
2994
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01002995TEST(DebugStepForContinue) {
2996 v8::HandleScope scope;
2997 DebugLocalContext env;
2998
2999 // Register a debug event listener which steps and counts.
3000 v8::Debug::SetDebugEventListener(DebugEventStep);
3001
3002 // Create a function for testing stepping.
3003 const int argc = 1;
3004 const char* src = "function foo(x) { "
3005 " var a = 0;"
3006 " var b = 0;"
3007 " var c = 0;"
3008 " for (var i = 0; i < x; i++) {"
3009 " a++;"
3010 " if (a % 2 == 0) continue;"
3011 " b++;"
3012 " c++;"
3013 " }"
3014 " return b;"
3015 "}";
3016 v8::Local<v8::Function> foo = CompileFunction(&env, src, "foo");
3017 v8::Handle<v8::Value> result;
3018 SetBreakPoint(foo, 8); // "var a = 0;"
3019
3020 // Each loop generates 4 or 5 steps depending on whether a is equal.
3021
3022 // Looping 10 times.
3023 step_action = StepIn;
3024 break_point_hit_count = 0;
3025 v8::Handle<v8::Value> argv_10[argc] = { v8::Number::New(10) };
3026 result = foo->Call(env->Global(), argc, argv_10);
3027 CHECK_EQ(5, result->Int32Value());
3028 CHECK_EQ(50, break_point_hit_count);
3029
3030 // Looping 100 times.
3031 step_action = StepIn;
3032 break_point_hit_count = 0;
3033 v8::Handle<v8::Value> argv_100[argc] = { v8::Number::New(100) };
3034 result = foo->Call(env->Global(), argc, argv_100);
3035 CHECK_EQ(50, result->Int32Value());
3036 CHECK_EQ(455, break_point_hit_count);
3037
3038 // Get rid of the debug event listener.
3039 v8::Debug::SetDebugEventListener(NULL);
3040 CheckDebuggerUnloaded();
3041}
3042
3043
3044TEST(DebugStepForBreak) {
3045 v8::HandleScope scope;
3046 DebugLocalContext env;
3047
3048 // Register a debug event listener which steps and counts.
3049 v8::Debug::SetDebugEventListener(DebugEventStep);
3050
3051 // Create a function for testing stepping.
3052 const int argc = 1;
3053 const char* src = "function foo(x) { "
3054 " var a = 0;"
3055 " var b = 0;"
3056 " var c = 0;"
3057 " for (var i = 0; i < 1000; i++) {"
3058 " a++;"
3059 " if (a == x) break;"
3060 " b++;"
3061 " c++;"
3062 " }"
3063 " return b;"
3064 "}";
3065 v8::Local<v8::Function> foo = CompileFunction(&env, src, "foo");
3066 v8::Handle<v8::Value> result;
3067 SetBreakPoint(foo, 8); // "var a = 0;"
3068
3069 // Each loop generates 5 steps except for the last (when break is executed)
3070 // which only generates 4.
3071
3072 // Looping 10 times.
3073 step_action = StepIn;
3074 break_point_hit_count = 0;
3075 v8::Handle<v8::Value> argv_10[argc] = { v8::Number::New(10) };
3076 result = foo->Call(env->Global(), argc, argv_10);
3077 CHECK_EQ(9, result->Int32Value());
3078 CHECK_EQ(53, break_point_hit_count);
3079
3080 // Looping 100 times.
3081 step_action = StepIn;
3082 break_point_hit_count = 0;
3083 v8::Handle<v8::Value> argv_100[argc] = { v8::Number::New(100) };
3084 result = foo->Call(env->Global(), argc, argv_100);
3085 CHECK_EQ(99, result->Int32Value());
3086 CHECK_EQ(503, break_point_hit_count);
3087
3088 // Get rid of the debug event listener.
3089 v8::Debug::SetDebugEventListener(NULL);
3090 CheckDebuggerUnloaded();
3091}
3092
3093
3094TEST(DebugStepForIn) {
3095 v8::HandleScope scope;
3096 DebugLocalContext env;
3097
3098 // Register a debug event listener which steps and counts.
3099 v8::Debug::SetDebugEventListener(DebugEventStep);
3100
3101 v8::Local<v8::Function> foo;
3102 const char* src_1 = "function foo() { "
3103 " var a = [1, 2];"
3104 " for (x in a) {"
3105 " b = 0;"
3106 " }"
3107 "}";
3108 foo = CompileFunction(&env, src_1, "foo");
3109 SetBreakPoint(foo, 0); // "var a = ..."
3110
3111 step_action = StepIn;
3112 break_point_hit_count = 0;
3113 foo->Call(env->Global(), 0, NULL);
3114 CHECK_EQ(6, break_point_hit_count);
3115
3116 const char* src_2 = "function foo() { "
3117 " var a = {a:[1, 2, 3]};"
3118 " for (x in a.a) {"
3119 " b = 0;"
3120 " }"
3121 "}";
3122 foo = CompileFunction(&env, src_2, "foo");
3123 SetBreakPoint(foo, 0); // "var a = ..."
3124
3125 step_action = StepIn;
3126 break_point_hit_count = 0;
3127 foo->Call(env->Global(), 0, NULL);
3128 CHECK_EQ(8, break_point_hit_count);
3129
3130 // Get rid of the debug event listener.
3131 v8::Debug::SetDebugEventListener(NULL);
3132 CheckDebuggerUnloaded();
3133}
3134
3135
3136TEST(DebugStepWith) {
3137 v8::HandleScope scope;
3138 DebugLocalContext env;
3139
3140 // Register a debug event listener which steps and counts.
3141 v8::Debug::SetDebugEventListener(DebugEventStep);
3142
3143 // Create a function for testing stepping.
3144 const char* src = "function foo(x) { "
3145 " var a = {};"
3146 " with (a) {}"
3147 " with (b) {}"
3148 "}";
3149 env->Global()->Set(v8::String::New("b"), v8::Object::New());
3150 v8::Local<v8::Function> foo = CompileFunction(&env, src, "foo");
3151 v8::Handle<v8::Value> result;
3152 SetBreakPoint(foo, 8); // "var a = {};"
3153
3154 step_action = StepIn;
3155 break_point_hit_count = 0;
3156 foo->Call(env->Global(), 0, NULL);
3157 CHECK_EQ(4, break_point_hit_count);
3158
3159 // Get rid of the debug event listener.
3160 v8::Debug::SetDebugEventListener(NULL);
3161 CheckDebuggerUnloaded();
3162}
3163
3164
3165TEST(DebugConditional) {
3166 v8::HandleScope scope;
3167 DebugLocalContext env;
3168
3169 // Register a debug event listener which steps and counts.
3170 v8::Debug::SetDebugEventListener(DebugEventStep);
3171
3172 // Create a function for testing stepping.
3173 const char* src = "function foo(x) { "
3174 " var a;"
3175 " a = x ? 1 : 2;"
3176 " return a;"
3177 "}";
3178 v8::Local<v8::Function> foo = CompileFunction(&env, src, "foo");
3179 SetBreakPoint(foo, 0); // "var a;"
3180
3181 step_action = StepIn;
3182 break_point_hit_count = 0;
3183 foo->Call(env->Global(), 0, NULL);
3184 CHECK_EQ(5, break_point_hit_count);
3185
3186 step_action = StepIn;
3187 break_point_hit_count = 0;
3188 const int argc = 1;
3189 v8::Handle<v8::Value> argv_true[argc] = { v8::True() };
3190 foo->Call(env->Global(), argc, argv_true);
3191 CHECK_EQ(5, break_point_hit_count);
3192
3193 // Get rid of the debug event listener.
3194 v8::Debug::SetDebugEventListener(NULL);
3195 CheckDebuggerUnloaded();
3196}
3197
3198
Steve Blocka7e24c12009-10-30 11:49:00 +00003199TEST(StepInOutSimple) {
3200 v8::HandleScope scope;
3201 DebugLocalContext env;
3202
3203 // Create a function for checking the function when hitting a break point.
3204 frame_function_name = CompileFunction(&env,
3205 frame_function_name_source,
3206 "frame_function_name");
3207
3208 // Register a debug event listener which steps and counts.
3209 v8::Debug::SetDebugEventListener(DebugEventStepSequence);
3210
3211 // Create functions for testing stepping.
3212 const char* src = "function a() {b();c();}; "
3213 "function b() {c();}; "
3214 "function c() {}; ";
3215 v8::Local<v8::Function> a = CompileFunction(&env, src, "a");
3216 SetBreakPoint(a, 0);
3217
3218 // Step through invocation of a with step in.
3219 step_action = StepIn;
3220 break_point_hit_count = 0;
3221 expected_step_sequence = "abcbaca";
3222 a->Call(env->Global(), 0, NULL);
Steve Blockd0582a62009-12-15 09:54:21 +00003223 CHECK_EQ(StrLength(expected_step_sequence),
3224 break_point_hit_count);
Steve Blocka7e24c12009-10-30 11:49:00 +00003225
3226 // Step through invocation of a with step next.
3227 step_action = StepNext;
3228 break_point_hit_count = 0;
3229 expected_step_sequence = "aaa";
3230 a->Call(env->Global(), 0, NULL);
Steve Blockd0582a62009-12-15 09:54:21 +00003231 CHECK_EQ(StrLength(expected_step_sequence),
3232 break_point_hit_count);
Steve Blocka7e24c12009-10-30 11:49:00 +00003233
3234 // Step through invocation of a with step out.
3235 step_action = StepOut;
3236 break_point_hit_count = 0;
3237 expected_step_sequence = "a";
3238 a->Call(env->Global(), 0, NULL);
Steve Blockd0582a62009-12-15 09:54:21 +00003239 CHECK_EQ(StrLength(expected_step_sequence),
3240 break_point_hit_count);
Steve Blocka7e24c12009-10-30 11:49:00 +00003241
3242 // Get rid of the debug event listener.
3243 v8::Debug::SetDebugEventListener(NULL);
3244 CheckDebuggerUnloaded();
3245}
3246
3247
3248TEST(StepInOutTree) {
3249 v8::HandleScope scope;
3250 DebugLocalContext env;
3251
3252 // Create a function for checking the function when hitting a break point.
3253 frame_function_name = CompileFunction(&env,
3254 frame_function_name_source,
3255 "frame_function_name");
3256
3257 // Register a debug event listener which steps and counts.
3258 v8::Debug::SetDebugEventListener(DebugEventStepSequence);
3259
3260 // Create functions for testing stepping.
3261 const char* src = "function a() {b(c(d()),d());c(d());d()}; "
3262 "function b(x,y) {c();}; "
3263 "function c(x) {}; "
3264 "function d() {}; ";
3265 v8::Local<v8::Function> a = CompileFunction(&env, src, "a");
3266 SetBreakPoint(a, 0);
3267
3268 // Step through invocation of a with step in.
3269 step_action = StepIn;
3270 break_point_hit_count = 0;
3271 expected_step_sequence = "adacadabcbadacada";
3272 a->Call(env->Global(), 0, NULL);
Steve Blockd0582a62009-12-15 09:54:21 +00003273 CHECK_EQ(StrLength(expected_step_sequence),
3274 break_point_hit_count);
Steve Blocka7e24c12009-10-30 11:49:00 +00003275
3276 // Step through invocation of a with step next.
3277 step_action = StepNext;
3278 break_point_hit_count = 0;
3279 expected_step_sequence = "aaaa";
3280 a->Call(env->Global(), 0, NULL);
Steve Blockd0582a62009-12-15 09:54:21 +00003281 CHECK_EQ(StrLength(expected_step_sequence),
3282 break_point_hit_count);
Steve Blocka7e24c12009-10-30 11:49:00 +00003283
3284 // Step through invocation of a with step out.
3285 step_action = StepOut;
3286 break_point_hit_count = 0;
3287 expected_step_sequence = "a";
3288 a->Call(env->Global(), 0, NULL);
Steve Blockd0582a62009-12-15 09:54:21 +00003289 CHECK_EQ(StrLength(expected_step_sequence),
3290 break_point_hit_count);
Steve Blocka7e24c12009-10-30 11:49:00 +00003291
3292 // Get rid of the debug event listener.
3293 v8::Debug::SetDebugEventListener(NULL);
3294 CheckDebuggerUnloaded(true);
3295}
3296
3297
3298TEST(StepInOutBranch) {
3299 v8::HandleScope scope;
3300 DebugLocalContext env;
3301
3302 // Create a function for checking the function when hitting a break point.
3303 frame_function_name = CompileFunction(&env,
3304 frame_function_name_source,
3305 "frame_function_name");
3306
3307 // Register a debug event listener which steps and counts.
3308 v8::Debug::SetDebugEventListener(DebugEventStepSequence);
3309
3310 // Create functions for testing stepping.
3311 const char* src = "function a() {b(false);c();}; "
3312 "function b(x) {if(x){c();};}; "
3313 "function c() {}; ";
3314 v8::Local<v8::Function> a = CompileFunction(&env, src, "a");
3315 SetBreakPoint(a, 0);
3316
3317 // Step through invocation of a.
3318 step_action = StepIn;
3319 break_point_hit_count = 0;
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01003320 expected_step_sequence = "abbaca";
Steve Blocka7e24c12009-10-30 11:49:00 +00003321 a->Call(env->Global(), 0, NULL);
Steve Blockd0582a62009-12-15 09:54:21 +00003322 CHECK_EQ(StrLength(expected_step_sequence),
3323 break_point_hit_count);
Steve Blocka7e24c12009-10-30 11:49:00 +00003324
3325 // Get rid of the debug event listener.
3326 v8::Debug::SetDebugEventListener(NULL);
3327 CheckDebuggerUnloaded();
3328}
3329
3330
3331// Test that step in does not step into native functions.
3332TEST(DebugStepNatives) {
3333 v8::HandleScope scope;
3334 DebugLocalContext env;
3335
3336 // Create a function for testing stepping.
3337 v8::Local<v8::Function> foo = CompileFunction(
3338 &env,
3339 "function foo(){debugger;Math.sin(1);}",
3340 "foo");
3341
3342 // Register a debug event listener which steps and counts.
3343 v8::Debug::SetDebugEventListener(DebugEventStep);
3344
3345 step_action = StepIn;
3346 break_point_hit_count = 0;
3347 foo->Call(env->Global(), 0, NULL);
3348
3349 // With stepping all break locations are hit.
3350 CHECK_EQ(3, break_point_hit_count);
3351
3352 v8::Debug::SetDebugEventListener(NULL);
3353 CheckDebuggerUnloaded();
3354
3355 // Register a debug event listener which just counts.
3356 v8::Debug::SetDebugEventListener(DebugEventBreakPointHitCount);
3357
3358 break_point_hit_count = 0;
3359 foo->Call(env->Global(), 0, NULL);
3360
3361 // Without stepping only active break points are hit.
3362 CHECK_EQ(1, break_point_hit_count);
3363
3364 v8::Debug::SetDebugEventListener(NULL);
3365 CheckDebuggerUnloaded();
3366}
3367
3368
3369// Test that step in works with function.apply.
3370TEST(DebugStepFunctionApply) {
3371 v8::HandleScope scope;
3372 DebugLocalContext env;
3373
3374 // Create a function for testing stepping.
3375 v8::Local<v8::Function> foo = CompileFunction(
3376 &env,
3377 "function bar(x, y, z) { if (x == 1) { a = y; b = z; } }"
3378 "function foo(){ debugger; bar.apply(this, [1,2,3]); }",
3379 "foo");
3380
3381 // Register a debug event listener which steps and counts.
3382 v8::Debug::SetDebugEventListener(DebugEventStep);
3383
3384 step_action = StepIn;
3385 break_point_hit_count = 0;
3386 foo->Call(env->Global(), 0, NULL);
3387
3388 // With stepping all break locations are hit.
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01003389 CHECK_EQ(7, break_point_hit_count);
Steve Blocka7e24c12009-10-30 11:49:00 +00003390
3391 v8::Debug::SetDebugEventListener(NULL);
3392 CheckDebuggerUnloaded();
3393
3394 // Register a debug event listener which just counts.
3395 v8::Debug::SetDebugEventListener(DebugEventBreakPointHitCount);
3396
3397 break_point_hit_count = 0;
3398 foo->Call(env->Global(), 0, NULL);
3399
3400 // Without stepping only the debugger statement is hit.
3401 CHECK_EQ(1, break_point_hit_count);
3402
3403 v8::Debug::SetDebugEventListener(NULL);
3404 CheckDebuggerUnloaded();
3405}
3406
3407
3408// Test that step in works with function.call.
3409TEST(DebugStepFunctionCall) {
3410 v8::HandleScope scope;
3411 DebugLocalContext env;
3412
3413 // Create a function for testing stepping.
3414 v8::Local<v8::Function> foo = CompileFunction(
3415 &env,
3416 "function bar(x, y, z) { if (x == 1) { a = y; b = z; } }"
3417 "function foo(a){ debugger;"
3418 " if (a) {"
3419 " bar.call(this, 1, 2, 3);"
3420 " } else {"
3421 " bar.call(this, 0);"
3422 " }"
3423 "}",
3424 "foo");
3425
3426 // Register a debug event listener which steps and counts.
3427 v8::Debug::SetDebugEventListener(DebugEventStep);
3428 step_action = StepIn;
3429
3430 // Check stepping where the if condition in bar is false.
3431 break_point_hit_count = 0;
3432 foo->Call(env->Global(), 0, NULL);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01003433 CHECK_EQ(6, break_point_hit_count);
Steve Blocka7e24c12009-10-30 11:49:00 +00003434
3435 // Check stepping where the if condition in bar is true.
3436 break_point_hit_count = 0;
3437 const int argc = 1;
3438 v8::Handle<v8::Value> argv[argc] = { v8::True() };
3439 foo->Call(env->Global(), argc, argv);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01003440 CHECK_EQ(8, break_point_hit_count);
Steve Blocka7e24c12009-10-30 11:49:00 +00003441
3442 v8::Debug::SetDebugEventListener(NULL);
3443 CheckDebuggerUnloaded();
3444
3445 // Register a debug event listener which just counts.
3446 v8::Debug::SetDebugEventListener(DebugEventBreakPointHitCount);
3447
3448 break_point_hit_count = 0;
3449 foo->Call(env->Global(), 0, NULL);
3450
3451 // Without stepping only the debugger statement is hit.
3452 CHECK_EQ(1, break_point_hit_count);
3453
3454 v8::Debug::SetDebugEventListener(NULL);
3455 CheckDebuggerUnloaded();
3456}
3457
3458
Steve Blockd0582a62009-12-15 09:54:21 +00003459// Tests that breakpoint will be hit if it's set in script.
3460TEST(PauseInScript) {
3461 v8::HandleScope scope;
3462 DebugLocalContext env;
3463 env.ExposeDebug();
3464
3465 // Register a debug event listener which counts.
3466 v8::Debug::SetDebugEventListener(DebugEventCounter);
3467
3468 // Create a script that returns a function.
3469 const char* src = "(function (evt) {})";
3470 const char* script_name = "StepInHandlerTest";
3471
3472 // Set breakpoint in the script.
3473 SetScriptBreakPointByNameFromJS(script_name, 0, -1);
3474 break_point_hit_count = 0;
3475
3476 v8::ScriptOrigin origin(v8::String::New(script_name), v8::Integer::New(0));
3477 v8::Handle<v8::Script> script = v8::Script::Compile(v8::String::New(src),
3478 &origin);
3479 v8::Local<v8::Value> r = script->Run();
3480
3481 CHECK(r->IsFunction());
3482 CHECK_EQ(1, break_point_hit_count);
3483
3484 // Get rid of the debug event listener.
3485 v8::Debug::SetDebugEventListener(NULL);
3486 CheckDebuggerUnloaded();
3487}
3488
3489
Steve Blocka7e24c12009-10-30 11:49:00 +00003490// Test break on exceptions. For each exception break combination the number
3491// of debug event exception callbacks and message callbacks are collected. The
3492// number of debug event exception callbacks are used to check that the
3493// debugger is called correctly and the number of message callbacks is used to
3494// check that uncaught exceptions are still returned even if there is a break
3495// for them.
3496TEST(BreakOnException) {
3497 v8::HandleScope scope;
3498 DebugLocalContext env;
3499 env.ExposeDebug();
3500
3501 v8::internal::Top::TraceException(false);
3502
3503 // Create functions for testing break on exception.
3504 v8::Local<v8::Function> throws =
3505 CompileFunction(&env, "function throws(){throw 1;}", "throws");
3506 v8::Local<v8::Function> caught =
3507 CompileFunction(&env,
3508 "function caught(){try {throws();} catch(e) {};}",
3509 "caught");
3510 v8::Local<v8::Function> notCaught =
3511 CompileFunction(&env, "function notCaught(){throws();}", "notCaught");
3512
3513 v8::V8::AddMessageListener(MessageCallbackCount);
3514 v8::Debug::SetDebugEventListener(DebugEventCounter);
3515
3516 // Initial state should be break on uncaught exception.
3517 DebugEventCounterClear();
3518 MessageCallbackCountClear();
3519 caught->Call(env->Global(), 0, NULL);
3520 CHECK_EQ(0, exception_hit_count);
3521 CHECK_EQ(0, uncaught_exception_hit_count);
3522 CHECK_EQ(0, message_callback_count);
3523 notCaught->Call(env->Global(), 0, NULL);
3524 CHECK_EQ(1, exception_hit_count);
3525 CHECK_EQ(1, uncaught_exception_hit_count);
3526 CHECK_EQ(1, message_callback_count);
3527
3528 // No break on exception
3529 DebugEventCounterClear();
3530 MessageCallbackCountClear();
3531 ChangeBreakOnException(false, false);
3532 caught->Call(env->Global(), 0, NULL);
3533 CHECK_EQ(0, exception_hit_count);
3534 CHECK_EQ(0, uncaught_exception_hit_count);
3535 CHECK_EQ(0, message_callback_count);
3536 notCaught->Call(env->Global(), 0, NULL);
3537 CHECK_EQ(0, exception_hit_count);
3538 CHECK_EQ(0, uncaught_exception_hit_count);
3539 CHECK_EQ(1, message_callback_count);
3540
3541 // Break on uncaught exception
3542 DebugEventCounterClear();
3543 MessageCallbackCountClear();
3544 ChangeBreakOnException(false, true);
3545 caught->Call(env->Global(), 0, NULL);
3546 CHECK_EQ(0, exception_hit_count);
3547 CHECK_EQ(0, uncaught_exception_hit_count);
3548 CHECK_EQ(0, message_callback_count);
3549 notCaught->Call(env->Global(), 0, NULL);
3550 CHECK_EQ(1, exception_hit_count);
3551 CHECK_EQ(1, uncaught_exception_hit_count);
3552 CHECK_EQ(1, message_callback_count);
3553
3554 // Break on exception and uncaught exception
3555 DebugEventCounterClear();
3556 MessageCallbackCountClear();
3557 ChangeBreakOnException(true, true);
3558 caught->Call(env->Global(), 0, NULL);
3559 CHECK_EQ(1, exception_hit_count);
3560 CHECK_EQ(0, uncaught_exception_hit_count);
3561 CHECK_EQ(0, message_callback_count);
3562 notCaught->Call(env->Global(), 0, NULL);
3563 CHECK_EQ(2, exception_hit_count);
3564 CHECK_EQ(1, uncaught_exception_hit_count);
3565 CHECK_EQ(1, message_callback_count);
3566
3567 // Break on exception
3568 DebugEventCounterClear();
3569 MessageCallbackCountClear();
3570 ChangeBreakOnException(true, false);
3571 caught->Call(env->Global(), 0, NULL);
3572 CHECK_EQ(1, exception_hit_count);
3573 CHECK_EQ(0, uncaught_exception_hit_count);
3574 CHECK_EQ(0, message_callback_count);
3575 notCaught->Call(env->Global(), 0, NULL);
3576 CHECK_EQ(2, exception_hit_count);
3577 CHECK_EQ(1, uncaught_exception_hit_count);
3578 CHECK_EQ(1, message_callback_count);
3579
3580 // No break on exception using JavaScript
3581 DebugEventCounterClear();
3582 MessageCallbackCountClear();
3583 ChangeBreakOnExceptionFromJS(false, false);
3584 caught->Call(env->Global(), 0, NULL);
3585 CHECK_EQ(0, exception_hit_count);
3586 CHECK_EQ(0, uncaught_exception_hit_count);
3587 CHECK_EQ(0, message_callback_count);
3588 notCaught->Call(env->Global(), 0, NULL);
3589 CHECK_EQ(0, exception_hit_count);
3590 CHECK_EQ(0, uncaught_exception_hit_count);
3591 CHECK_EQ(1, message_callback_count);
3592
3593 // Break on uncaught exception using JavaScript
3594 DebugEventCounterClear();
3595 MessageCallbackCountClear();
3596 ChangeBreakOnExceptionFromJS(false, true);
3597 caught->Call(env->Global(), 0, NULL);
3598 CHECK_EQ(0, exception_hit_count);
3599 CHECK_EQ(0, uncaught_exception_hit_count);
3600 CHECK_EQ(0, message_callback_count);
3601 notCaught->Call(env->Global(), 0, NULL);
3602 CHECK_EQ(1, exception_hit_count);
3603 CHECK_EQ(1, uncaught_exception_hit_count);
3604 CHECK_EQ(1, message_callback_count);
3605
3606 // Break on exception and uncaught exception using JavaScript
3607 DebugEventCounterClear();
3608 MessageCallbackCountClear();
3609 ChangeBreakOnExceptionFromJS(true, true);
3610 caught->Call(env->Global(), 0, NULL);
3611 CHECK_EQ(1, exception_hit_count);
3612 CHECK_EQ(0, message_callback_count);
3613 CHECK_EQ(0, uncaught_exception_hit_count);
3614 notCaught->Call(env->Global(), 0, NULL);
3615 CHECK_EQ(2, exception_hit_count);
3616 CHECK_EQ(1, uncaught_exception_hit_count);
3617 CHECK_EQ(1, message_callback_count);
3618
3619 // Break on exception using JavaScript
3620 DebugEventCounterClear();
3621 MessageCallbackCountClear();
3622 ChangeBreakOnExceptionFromJS(true, false);
3623 caught->Call(env->Global(), 0, NULL);
3624 CHECK_EQ(1, exception_hit_count);
3625 CHECK_EQ(0, uncaught_exception_hit_count);
3626 CHECK_EQ(0, message_callback_count);
3627 notCaught->Call(env->Global(), 0, NULL);
3628 CHECK_EQ(2, exception_hit_count);
3629 CHECK_EQ(1, uncaught_exception_hit_count);
3630 CHECK_EQ(1, message_callback_count);
3631
3632 v8::Debug::SetDebugEventListener(NULL);
3633 CheckDebuggerUnloaded();
3634 v8::V8::RemoveMessageListeners(MessageCallbackCount);
3635}
3636
3637
3638// Test break on exception from compiler errors. When compiling using
3639// v8::Script::Compile there is no JavaScript stack whereas when compiling using
3640// eval there are JavaScript frames.
3641TEST(BreakOnCompileException) {
3642 v8::HandleScope scope;
3643 DebugLocalContext env;
3644
3645 v8::internal::Top::TraceException(false);
3646
3647 // Create a function for checking the function when hitting a break point.
3648 frame_count = CompileFunction(&env, frame_count_source, "frame_count");
3649
3650 v8::V8::AddMessageListener(MessageCallbackCount);
3651 v8::Debug::SetDebugEventListener(DebugEventCounter);
3652
3653 DebugEventCounterClear();
3654 MessageCallbackCountClear();
3655
3656 // Check initial state.
3657 CHECK_EQ(0, exception_hit_count);
3658 CHECK_EQ(0, uncaught_exception_hit_count);
3659 CHECK_EQ(0, message_callback_count);
3660 CHECK_EQ(-1, last_js_stack_height);
3661
3662 // Throws SyntaxError: Unexpected end of input
3663 v8::Script::Compile(v8::String::New("+++"));
3664 CHECK_EQ(1, exception_hit_count);
3665 CHECK_EQ(1, uncaught_exception_hit_count);
3666 CHECK_EQ(1, message_callback_count);
3667 CHECK_EQ(0, last_js_stack_height); // No JavaScript stack.
3668
3669 // Throws SyntaxError: Unexpected identifier
3670 v8::Script::Compile(v8::String::New("x x"));
3671 CHECK_EQ(2, exception_hit_count);
3672 CHECK_EQ(2, uncaught_exception_hit_count);
3673 CHECK_EQ(2, message_callback_count);
3674 CHECK_EQ(0, last_js_stack_height); // No JavaScript stack.
3675
3676 // Throws SyntaxError: Unexpected end of input
3677 v8::Script::Compile(v8::String::New("eval('+++')"))->Run();
3678 CHECK_EQ(3, exception_hit_count);
3679 CHECK_EQ(3, uncaught_exception_hit_count);
3680 CHECK_EQ(3, message_callback_count);
3681 CHECK_EQ(1, last_js_stack_height);
3682
3683 // Throws SyntaxError: Unexpected identifier
3684 v8::Script::Compile(v8::String::New("eval('x x')"))->Run();
3685 CHECK_EQ(4, exception_hit_count);
3686 CHECK_EQ(4, uncaught_exception_hit_count);
3687 CHECK_EQ(4, message_callback_count);
3688 CHECK_EQ(1, last_js_stack_height);
3689}
3690
3691
3692TEST(StepWithException) {
3693 v8::HandleScope scope;
3694 DebugLocalContext env;
3695
3696 // Create a function for checking the function when hitting a break point.
3697 frame_function_name = CompileFunction(&env,
3698 frame_function_name_source,
3699 "frame_function_name");
3700
3701 // Register a debug event listener which steps and counts.
3702 v8::Debug::SetDebugEventListener(DebugEventStepSequence);
3703
3704 // Create functions for testing stepping.
3705 const char* src = "function a() { n(); }; "
3706 "function b() { c(); }; "
3707 "function c() { n(); }; "
3708 "function d() { x = 1; try { e(); } catch(x) { x = 2; } }; "
3709 "function e() { n(); }; "
3710 "function f() { x = 1; try { g(); } catch(x) { x = 2; } }; "
3711 "function g() { h(); }; "
3712 "function h() { x = 1; throw 1; }; ";
3713
3714 // Step through invocation of a.
3715 v8::Local<v8::Function> a = CompileFunction(&env, src, "a");
3716 SetBreakPoint(a, 0);
3717 step_action = StepIn;
3718 break_point_hit_count = 0;
3719 expected_step_sequence = "aa";
3720 a->Call(env->Global(), 0, NULL);
Steve Blockd0582a62009-12-15 09:54:21 +00003721 CHECK_EQ(StrLength(expected_step_sequence),
3722 break_point_hit_count);
Steve Blocka7e24c12009-10-30 11:49:00 +00003723
3724 // Step through invocation of b + c.
3725 v8::Local<v8::Function> b = CompileFunction(&env, src, "b");
3726 SetBreakPoint(b, 0);
3727 step_action = StepIn;
3728 break_point_hit_count = 0;
3729 expected_step_sequence = "bcc";
3730 b->Call(env->Global(), 0, NULL);
Steve Blockd0582a62009-12-15 09:54:21 +00003731 CHECK_EQ(StrLength(expected_step_sequence),
3732 break_point_hit_count);
Steve Blocka7e24c12009-10-30 11:49:00 +00003733 // Step through invocation of d + e.
3734 v8::Local<v8::Function> d = CompileFunction(&env, src, "d");
3735 SetBreakPoint(d, 0);
3736 ChangeBreakOnException(false, true);
3737 step_action = StepIn;
3738 break_point_hit_count = 0;
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01003739 expected_step_sequence = "ddedd";
Steve Blocka7e24c12009-10-30 11:49:00 +00003740 d->Call(env->Global(), 0, NULL);
Steve Blockd0582a62009-12-15 09:54:21 +00003741 CHECK_EQ(StrLength(expected_step_sequence),
3742 break_point_hit_count);
Steve Blocka7e24c12009-10-30 11:49:00 +00003743
3744 // Step through invocation of d + e now with break on caught exceptions.
3745 ChangeBreakOnException(true, true);
3746 step_action = StepIn;
3747 break_point_hit_count = 0;
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01003748 expected_step_sequence = "ddeedd";
Steve Blocka7e24c12009-10-30 11:49:00 +00003749 d->Call(env->Global(), 0, NULL);
Steve Blockd0582a62009-12-15 09:54:21 +00003750 CHECK_EQ(StrLength(expected_step_sequence),
3751 break_point_hit_count);
Steve Blocka7e24c12009-10-30 11:49:00 +00003752
3753 // Step through invocation of f + g + h.
3754 v8::Local<v8::Function> f = CompileFunction(&env, src, "f");
3755 SetBreakPoint(f, 0);
3756 ChangeBreakOnException(false, true);
3757 step_action = StepIn;
3758 break_point_hit_count = 0;
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01003759 expected_step_sequence = "ffghhff";
Steve Blocka7e24c12009-10-30 11:49:00 +00003760 f->Call(env->Global(), 0, NULL);
Steve Blockd0582a62009-12-15 09:54:21 +00003761 CHECK_EQ(StrLength(expected_step_sequence),
3762 break_point_hit_count);
Steve Blocka7e24c12009-10-30 11:49:00 +00003763
3764 // Step through invocation of f + g + h now with break on caught exceptions.
3765 ChangeBreakOnException(true, true);
3766 step_action = StepIn;
3767 break_point_hit_count = 0;
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01003768 expected_step_sequence = "ffghhhff";
Steve Blocka7e24c12009-10-30 11:49:00 +00003769 f->Call(env->Global(), 0, NULL);
Steve Blockd0582a62009-12-15 09:54:21 +00003770 CHECK_EQ(StrLength(expected_step_sequence),
3771 break_point_hit_count);
Steve Blocka7e24c12009-10-30 11:49:00 +00003772
3773 // Get rid of the debug event listener.
3774 v8::Debug::SetDebugEventListener(NULL);
3775 CheckDebuggerUnloaded();
3776}
3777
3778
3779TEST(DebugBreak) {
3780 v8::HandleScope scope;
3781 DebugLocalContext env;
3782
3783 // This test should be run with option --verify-heap. As --verify-heap is
3784 // only available in debug mode only check for it in that case.
3785#ifdef DEBUG
3786 CHECK(v8::internal::FLAG_verify_heap);
3787#endif
3788
3789 // Register a debug event listener which sets the break flag and counts.
3790 v8::Debug::SetDebugEventListener(DebugEventBreak);
3791
3792 // Create a function for testing stepping.
3793 const char* src = "function f0() {}"
3794 "function f1(x1) {}"
3795 "function f2(x1,x2) {}"
3796 "function f3(x1,x2,x3) {}";
3797 v8::Local<v8::Function> f0 = CompileFunction(&env, src, "f0");
3798 v8::Local<v8::Function> f1 = CompileFunction(&env, src, "f1");
3799 v8::Local<v8::Function> f2 = CompileFunction(&env, src, "f2");
3800 v8::Local<v8::Function> f3 = CompileFunction(&env, src, "f3");
3801
3802 // Call the function to make sure it is compiled.
3803 v8::Handle<v8::Value> argv[] = { v8::Number::New(1),
3804 v8::Number::New(1),
3805 v8::Number::New(1),
3806 v8::Number::New(1) };
3807
3808 // Call all functions to make sure that they are compiled.
3809 f0->Call(env->Global(), 0, NULL);
3810 f1->Call(env->Global(), 0, NULL);
3811 f2->Call(env->Global(), 0, NULL);
3812 f3->Call(env->Global(), 0, NULL);
3813
3814 // Set the debug break flag.
3815 v8::Debug::DebugBreak();
3816
3817 // Call all functions with different argument count.
3818 break_point_hit_count = 0;
3819 for (unsigned int i = 0; i < ARRAY_SIZE(argv); i++) {
3820 f0->Call(env->Global(), i, argv);
3821 f1->Call(env->Global(), i, argv);
3822 f2->Call(env->Global(), i, argv);
3823 f3->Call(env->Global(), i, argv);
3824 }
3825
3826 // One break for each function called.
3827 CHECK_EQ(4 * ARRAY_SIZE(argv), break_point_hit_count);
3828
3829 // Get rid of the debug event listener.
3830 v8::Debug::SetDebugEventListener(NULL);
3831 CheckDebuggerUnloaded();
3832}
3833
3834
3835// Test to ensure that JavaScript code keeps running while the debug break
3836// through the stack limit flag is set but breaks are disabled.
3837TEST(DisableBreak) {
3838 v8::HandleScope scope;
3839 DebugLocalContext env;
3840
3841 // Register a debug event listener which sets the break flag and counts.
3842 v8::Debug::SetDebugEventListener(DebugEventCounter);
3843
3844 // Create a function for testing stepping.
3845 const char* src = "function f() {g()};function g(){i=0; while(i<10){i++}}";
3846 v8::Local<v8::Function> f = CompileFunction(&env, src, "f");
3847
3848 // Set the debug break flag.
3849 v8::Debug::DebugBreak();
3850
3851 // Call all functions with different argument count.
3852 break_point_hit_count = 0;
3853 f->Call(env->Global(), 0, NULL);
3854 CHECK_EQ(1, break_point_hit_count);
3855
3856 {
3857 v8::Debug::DebugBreak();
3858 v8::internal::DisableBreak disable_break(true);
3859 f->Call(env->Global(), 0, NULL);
3860 CHECK_EQ(1, break_point_hit_count);
3861 }
3862
3863 f->Call(env->Global(), 0, NULL);
3864 CHECK_EQ(2, break_point_hit_count);
3865
3866 // Get rid of the debug event listener.
3867 v8::Debug::SetDebugEventListener(NULL);
3868 CheckDebuggerUnloaded();
3869}
3870
Leon Clarkee46be812010-01-19 14:06:41 +00003871static const char* kSimpleExtensionSource =
3872 "(function Foo() {"
3873 " return 4;"
3874 "})() ";
3875
3876// http://crbug.com/28933
3877// Test that debug break is disabled when bootstrapper is active.
3878TEST(NoBreakWhenBootstrapping) {
3879 v8::HandleScope scope;
3880
3881 // Register a debug event listener which sets the break flag and counts.
3882 v8::Debug::SetDebugEventListener(DebugEventCounter);
3883
3884 // Set the debug break flag.
3885 v8::Debug::DebugBreak();
3886 break_point_hit_count = 0;
3887 {
3888 // Create a context with an extension to make sure that some JavaScript
3889 // code is executed during bootstrapping.
3890 v8::RegisterExtension(new v8::Extension("simpletest",
3891 kSimpleExtensionSource));
3892 const char* extension_names[] = { "simpletest" };
3893 v8::ExtensionConfiguration extensions(1, extension_names);
3894 v8::Persistent<v8::Context> context = v8::Context::New(&extensions);
3895 context.Dispose();
3896 }
3897 // Check that no DebugBreak events occured during the context creation.
3898 CHECK_EQ(0, break_point_hit_count);
3899
3900 // Get rid of the debug event listener.
3901 v8::Debug::SetDebugEventListener(NULL);
3902 CheckDebuggerUnloaded();
3903}
Steve Blocka7e24c12009-10-30 11:49:00 +00003904
3905static v8::Handle<v8::Array> NamedEnum(const v8::AccessorInfo&) {
3906 v8::Handle<v8::Array> result = v8::Array::New(3);
3907 result->Set(v8::Integer::New(0), v8::String::New("a"));
3908 result->Set(v8::Integer::New(1), v8::String::New("b"));
3909 result->Set(v8::Integer::New(2), v8::String::New("c"));
3910 return result;
3911}
3912
3913
3914static v8::Handle<v8::Array> IndexedEnum(const v8::AccessorInfo&) {
3915 v8::Handle<v8::Array> result = v8::Array::New(2);
3916 result->Set(v8::Integer::New(0), v8::Number::New(1));
3917 result->Set(v8::Integer::New(1), v8::Number::New(10));
3918 return result;
3919}
3920
3921
3922static v8::Handle<v8::Value> NamedGetter(v8::Local<v8::String> name,
3923 const v8::AccessorInfo& info) {
3924 v8::String::AsciiValue n(name);
3925 if (strcmp(*n, "a") == 0) {
3926 return v8::String::New("AA");
3927 } else if (strcmp(*n, "b") == 0) {
3928 return v8::String::New("BB");
3929 } else if (strcmp(*n, "c") == 0) {
3930 return v8::String::New("CC");
3931 } else {
3932 return v8::Undefined();
3933 }
3934
3935 return name;
3936}
3937
3938
3939static v8::Handle<v8::Value> IndexedGetter(uint32_t index,
3940 const v8::AccessorInfo& info) {
3941 return v8::Number::New(index + 1);
3942}
3943
3944
3945TEST(InterceptorPropertyMirror) {
3946 // Create a V8 environment with debug access.
3947 v8::HandleScope scope;
3948 DebugLocalContext env;
3949 env.ExposeDebug();
3950
3951 // Create object with named interceptor.
3952 v8::Handle<v8::ObjectTemplate> named = v8::ObjectTemplate::New();
3953 named->SetNamedPropertyHandler(NamedGetter, NULL, NULL, NULL, NamedEnum);
3954 env->Global()->Set(v8::String::New("intercepted_named"),
3955 named->NewInstance());
3956
3957 // Create object with indexed interceptor.
3958 v8::Handle<v8::ObjectTemplate> indexed = v8::ObjectTemplate::New();
3959 indexed->SetIndexedPropertyHandler(IndexedGetter,
3960 NULL,
3961 NULL,
3962 NULL,
3963 IndexedEnum);
3964 env->Global()->Set(v8::String::New("intercepted_indexed"),
3965 indexed->NewInstance());
3966
3967 // Create object with both named and indexed interceptor.
3968 v8::Handle<v8::ObjectTemplate> both = v8::ObjectTemplate::New();
3969 both->SetNamedPropertyHandler(NamedGetter, NULL, NULL, NULL, NamedEnum);
3970 both->SetIndexedPropertyHandler(IndexedGetter, NULL, NULL, NULL, IndexedEnum);
3971 env->Global()->Set(v8::String::New("intercepted_both"), both->NewInstance());
3972
3973 // Get mirrors for the three objects with interceptor.
3974 CompileRun(
3975 "named_mirror = debug.MakeMirror(intercepted_named);"
3976 "indexed_mirror = debug.MakeMirror(intercepted_indexed);"
3977 "both_mirror = debug.MakeMirror(intercepted_both)");
3978 CHECK(CompileRun(
3979 "named_mirror instanceof debug.ObjectMirror")->BooleanValue());
3980 CHECK(CompileRun(
3981 "indexed_mirror instanceof debug.ObjectMirror")->BooleanValue());
3982 CHECK(CompileRun(
3983 "both_mirror instanceof debug.ObjectMirror")->BooleanValue());
3984
3985 // Get the property names from the interceptors
3986 CompileRun(
3987 "named_names = named_mirror.propertyNames();"
3988 "indexed_names = indexed_mirror.propertyNames();"
3989 "both_names = both_mirror.propertyNames()");
3990 CHECK_EQ(3, CompileRun("named_names.length")->Int32Value());
3991 CHECK_EQ(2, CompileRun("indexed_names.length")->Int32Value());
3992 CHECK_EQ(5, CompileRun("both_names.length")->Int32Value());
3993
3994 // Check the expected number of properties.
3995 const char* source;
3996 source = "named_mirror.properties().length";
3997 CHECK_EQ(3, CompileRun(source)->Int32Value());
3998
3999 source = "indexed_mirror.properties().length";
4000 CHECK_EQ(2, CompileRun(source)->Int32Value());
4001
4002 source = "both_mirror.properties().length";
4003 CHECK_EQ(5, CompileRun(source)->Int32Value());
4004
4005 // 1 is PropertyKind.Named;
4006 source = "both_mirror.properties(1).length";
4007 CHECK_EQ(3, CompileRun(source)->Int32Value());
4008
4009 // 2 is PropertyKind.Indexed;
4010 source = "both_mirror.properties(2).length";
4011 CHECK_EQ(2, CompileRun(source)->Int32Value());
4012
4013 // 3 is PropertyKind.Named | PropertyKind.Indexed;
4014 source = "both_mirror.properties(3).length";
4015 CHECK_EQ(5, CompileRun(source)->Int32Value());
4016
4017 // Get the interceptor properties for the object with only named interceptor.
4018 CompileRun("named_values = named_mirror.properties()");
4019
4020 // Check that the properties are interceptor properties.
4021 for (int i = 0; i < 3; i++) {
4022 EmbeddedVector<char, SMALL_STRING_BUFFER_SIZE> buffer;
4023 OS::SNPrintF(buffer,
4024 "named_values[%d] instanceof debug.PropertyMirror", i);
4025 CHECK(CompileRun(buffer.start())->BooleanValue());
4026
4027 // 4 is PropertyType.Interceptor
4028 OS::SNPrintF(buffer, "named_values[%d].propertyType()", i);
4029 CHECK_EQ(4, CompileRun(buffer.start())->Int32Value());
4030
4031 OS::SNPrintF(buffer, "named_values[%d].isNative()", i);
4032 CHECK(CompileRun(buffer.start())->BooleanValue());
4033 }
4034
4035 // Get the interceptor properties for the object with only indexed
4036 // interceptor.
4037 CompileRun("indexed_values = indexed_mirror.properties()");
4038
4039 // Check that the properties are interceptor properties.
4040 for (int i = 0; i < 2; i++) {
4041 EmbeddedVector<char, SMALL_STRING_BUFFER_SIZE> buffer;
4042 OS::SNPrintF(buffer,
4043 "indexed_values[%d] instanceof debug.PropertyMirror", i);
4044 CHECK(CompileRun(buffer.start())->BooleanValue());
4045 }
4046
4047 // Get the interceptor properties for the object with both types of
4048 // interceptors.
4049 CompileRun("both_values = both_mirror.properties()");
4050
4051 // Check that the properties are interceptor properties.
4052 for (int i = 0; i < 5; i++) {
4053 EmbeddedVector<char, SMALL_STRING_BUFFER_SIZE> buffer;
4054 OS::SNPrintF(buffer, "both_values[%d] instanceof debug.PropertyMirror", i);
4055 CHECK(CompileRun(buffer.start())->BooleanValue());
4056 }
4057
4058 // Check the property names.
4059 source = "both_values[0].name() == 'a'";
4060 CHECK(CompileRun(source)->BooleanValue());
4061
4062 source = "both_values[1].name() == 'b'";
4063 CHECK(CompileRun(source)->BooleanValue());
4064
4065 source = "both_values[2].name() == 'c'";
4066 CHECK(CompileRun(source)->BooleanValue());
4067
4068 source = "both_values[3].name() == 1";
4069 CHECK(CompileRun(source)->BooleanValue());
4070
4071 source = "both_values[4].name() == 10";
4072 CHECK(CompileRun(source)->BooleanValue());
4073}
4074
4075
4076TEST(HiddenPrototypePropertyMirror) {
4077 // Create a V8 environment with debug access.
4078 v8::HandleScope scope;
4079 DebugLocalContext env;
4080 env.ExposeDebug();
4081
4082 v8::Handle<v8::FunctionTemplate> t0 = v8::FunctionTemplate::New();
4083 t0->InstanceTemplate()->Set(v8::String::New("x"), v8::Number::New(0));
4084 v8::Handle<v8::FunctionTemplate> t1 = v8::FunctionTemplate::New();
4085 t1->SetHiddenPrototype(true);
4086 t1->InstanceTemplate()->Set(v8::String::New("y"), v8::Number::New(1));
4087 v8::Handle<v8::FunctionTemplate> t2 = v8::FunctionTemplate::New();
4088 t2->SetHiddenPrototype(true);
4089 t2->InstanceTemplate()->Set(v8::String::New("z"), v8::Number::New(2));
4090 v8::Handle<v8::FunctionTemplate> t3 = v8::FunctionTemplate::New();
4091 t3->InstanceTemplate()->Set(v8::String::New("u"), v8::Number::New(3));
4092
4093 // Create object and set them on the global object.
4094 v8::Handle<v8::Object> o0 = t0->GetFunction()->NewInstance();
4095 env->Global()->Set(v8::String::New("o0"), o0);
4096 v8::Handle<v8::Object> o1 = t1->GetFunction()->NewInstance();
4097 env->Global()->Set(v8::String::New("o1"), o1);
4098 v8::Handle<v8::Object> o2 = t2->GetFunction()->NewInstance();
4099 env->Global()->Set(v8::String::New("o2"), o2);
4100 v8::Handle<v8::Object> o3 = t3->GetFunction()->NewInstance();
4101 env->Global()->Set(v8::String::New("o3"), o3);
4102
4103 // Get mirrors for the four objects.
4104 CompileRun(
4105 "o0_mirror = debug.MakeMirror(o0);"
4106 "o1_mirror = debug.MakeMirror(o1);"
4107 "o2_mirror = debug.MakeMirror(o2);"
4108 "o3_mirror = debug.MakeMirror(o3)");
4109 CHECK(CompileRun("o0_mirror instanceof debug.ObjectMirror")->BooleanValue());
4110 CHECK(CompileRun("o1_mirror instanceof debug.ObjectMirror")->BooleanValue());
4111 CHECK(CompileRun("o2_mirror instanceof debug.ObjectMirror")->BooleanValue());
4112 CHECK(CompileRun("o3_mirror instanceof debug.ObjectMirror")->BooleanValue());
4113
4114 // Check that each object has one property.
4115 CHECK_EQ(1, CompileRun(
4116 "o0_mirror.propertyNames().length")->Int32Value());
4117 CHECK_EQ(1, CompileRun(
4118 "o1_mirror.propertyNames().length")->Int32Value());
4119 CHECK_EQ(1, CompileRun(
4120 "o2_mirror.propertyNames().length")->Int32Value());
4121 CHECK_EQ(1, CompileRun(
4122 "o3_mirror.propertyNames().length")->Int32Value());
4123
4124 // Set o1 as prototype for o0. o1 has the hidden prototype flag so all
4125 // properties on o1 should be seen on o0.
4126 o0->Set(v8::String::New("__proto__"), o1);
4127 CHECK_EQ(2, CompileRun(
4128 "o0_mirror.propertyNames().length")->Int32Value());
4129 CHECK_EQ(0, CompileRun(
4130 "o0_mirror.property('x').value().value()")->Int32Value());
4131 CHECK_EQ(1, CompileRun(
4132 "o0_mirror.property('y').value().value()")->Int32Value());
4133
4134 // Set o2 as prototype for o0 (it will end up after o1 as o1 has the hidden
4135 // prototype flag. o2 also has the hidden prototype flag so all properties
4136 // on o2 should be seen on o0 as well as properties on o1.
4137 o0->Set(v8::String::New("__proto__"), o2);
4138 CHECK_EQ(3, CompileRun(
4139 "o0_mirror.propertyNames().length")->Int32Value());
4140 CHECK_EQ(0, CompileRun(
4141 "o0_mirror.property('x').value().value()")->Int32Value());
4142 CHECK_EQ(1, CompileRun(
4143 "o0_mirror.property('y').value().value()")->Int32Value());
4144 CHECK_EQ(2, CompileRun(
4145 "o0_mirror.property('z').value().value()")->Int32Value());
4146
4147 // Set o3 as prototype for o0 (it will end up after o1 and o2 as both o1 and
4148 // o2 has the hidden prototype flag. o3 does not have the hidden prototype
4149 // flag so properties on o3 should not be seen on o0 whereas the properties
4150 // from o1 and o2 should still be seen on o0.
4151 // Final prototype chain: o0 -> o1 -> o2 -> o3
4152 // Hidden prototypes: ^^ ^^
4153 o0->Set(v8::String::New("__proto__"), o3);
4154 CHECK_EQ(3, CompileRun(
4155 "o0_mirror.propertyNames().length")->Int32Value());
4156 CHECK_EQ(1, CompileRun(
4157 "o3_mirror.propertyNames().length")->Int32Value());
4158 CHECK_EQ(0, CompileRun(
4159 "o0_mirror.property('x').value().value()")->Int32Value());
4160 CHECK_EQ(1, CompileRun(
4161 "o0_mirror.property('y').value().value()")->Int32Value());
4162 CHECK_EQ(2, CompileRun(
4163 "o0_mirror.property('z').value().value()")->Int32Value());
4164 CHECK(CompileRun("o0_mirror.property('u').isUndefined()")->BooleanValue());
4165
4166 // The prototype (__proto__) for o0 should be o3 as o1 and o2 are hidden.
4167 CHECK(CompileRun("o0_mirror.protoObject() == o3_mirror")->BooleanValue());
4168}
4169
4170
4171static v8::Handle<v8::Value> ProtperyXNativeGetter(
4172 v8::Local<v8::String> property, const v8::AccessorInfo& info) {
4173 return v8::Integer::New(10);
4174}
4175
4176
4177TEST(NativeGetterPropertyMirror) {
4178 // Create a V8 environment with debug access.
4179 v8::HandleScope scope;
4180 DebugLocalContext env;
4181 env.ExposeDebug();
4182
4183 v8::Handle<v8::String> name = v8::String::New("x");
4184 // Create object with named accessor.
4185 v8::Handle<v8::ObjectTemplate> named = v8::ObjectTemplate::New();
4186 named->SetAccessor(name, &ProtperyXNativeGetter, NULL,
4187 v8::Handle<v8::Value>(), v8::DEFAULT, v8::None);
4188
4189 // Create object with named property getter.
4190 env->Global()->Set(v8::String::New("instance"), named->NewInstance());
4191 CHECK_EQ(10, CompileRun("instance.x")->Int32Value());
4192
4193 // Get mirror for the object with property getter.
4194 CompileRun("instance_mirror = debug.MakeMirror(instance);");
4195 CHECK(CompileRun(
4196 "instance_mirror instanceof debug.ObjectMirror")->BooleanValue());
4197
4198 CompileRun("named_names = instance_mirror.propertyNames();");
4199 CHECK_EQ(1, CompileRun("named_names.length")->Int32Value());
4200 CHECK(CompileRun("named_names[0] == 'x'")->BooleanValue());
4201 CHECK(CompileRun(
4202 "instance_mirror.property('x').value().isNumber()")->BooleanValue());
4203 CHECK(CompileRun(
4204 "instance_mirror.property('x').value().value() == 10")->BooleanValue());
4205}
4206
4207
4208static v8::Handle<v8::Value> ProtperyXNativeGetterThrowingError(
4209 v8::Local<v8::String> property, const v8::AccessorInfo& info) {
4210 return CompileRun("throw new Error('Error message');");
4211}
4212
4213
4214TEST(NativeGetterThrowingErrorPropertyMirror) {
4215 // Create a V8 environment with debug access.
4216 v8::HandleScope scope;
4217 DebugLocalContext env;
4218 env.ExposeDebug();
4219
4220 v8::Handle<v8::String> name = v8::String::New("x");
4221 // Create object with named accessor.
4222 v8::Handle<v8::ObjectTemplate> named = v8::ObjectTemplate::New();
4223 named->SetAccessor(name, &ProtperyXNativeGetterThrowingError, NULL,
4224 v8::Handle<v8::Value>(), v8::DEFAULT, v8::None);
4225
4226 // Create object with named property getter.
4227 env->Global()->Set(v8::String::New("instance"), named->NewInstance());
4228
4229 // Get mirror for the object with property getter.
4230 CompileRun("instance_mirror = debug.MakeMirror(instance);");
4231 CHECK(CompileRun(
4232 "instance_mirror instanceof debug.ObjectMirror")->BooleanValue());
4233 CompileRun("named_names = instance_mirror.propertyNames();");
4234 CHECK_EQ(1, CompileRun("named_names.length")->Int32Value());
4235 CHECK(CompileRun("named_names[0] == 'x'")->BooleanValue());
4236 CHECK(CompileRun(
4237 "instance_mirror.property('x').value().isError()")->BooleanValue());
4238
4239 // Check that the message is that passed to the Error constructor.
4240 CHECK(CompileRun(
4241 "instance_mirror.property('x').value().message() == 'Error message'")->
4242 BooleanValue());
4243}
4244
4245
Steve Blockd0582a62009-12-15 09:54:21 +00004246// Test that hidden properties object is not returned as an unnamed property
4247// among regular properties.
4248// See http://crbug.com/26491
4249TEST(NoHiddenProperties) {
4250 // Create a V8 environment with debug access.
4251 v8::HandleScope scope;
4252 DebugLocalContext env;
4253 env.ExposeDebug();
4254
4255 // Create an object in the global scope.
4256 const char* source = "var obj = {a: 1};";
4257 v8::Script::Compile(v8::String::New(source))->Run();
4258 v8::Local<v8::Object> obj = v8::Local<v8::Object>::Cast(
4259 env->Global()->Get(v8::String::New("obj")));
4260 // Set a hidden property on the object.
4261 obj->SetHiddenValue(v8::String::New("v8::test-debug::a"),
4262 v8::Int32::New(11));
4263
4264 // Get mirror for the object with property getter.
4265 CompileRun("var obj_mirror = debug.MakeMirror(obj);");
4266 CHECK(CompileRun(
4267 "obj_mirror instanceof debug.ObjectMirror")->BooleanValue());
4268 CompileRun("var named_names = obj_mirror.propertyNames();");
4269 // There should be exactly one property. But there is also an unnamed
4270 // property whose value is hidden properties dictionary. The latter
4271 // property should not be in the list of reguar properties.
4272 CHECK_EQ(1, CompileRun("named_names.length")->Int32Value());
4273 CHECK(CompileRun("named_names[0] == 'a'")->BooleanValue());
4274 CHECK(CompileRun(
4275 "obj_mirror.property('a').value().value() == 1")->BooleanValue());
4276
4277 // Object created by t0 will become hidden prototype of object 'obj'.
4278 v8::Handle<v8::FunctionTemplate> t0 = v8::FunctionTemplate::New();
4279 t0->InstanceTemplate()->Set(v8::String::New("b"), v8::Number::New(2));
4280 t0->SetHiddenPrototype(true);
4281 v8::Handle<v8::FunctionTemplate> t1 = v8::FunctionTemplate::New();
4282 t1->InstanceTemplate()->Set(v8::String::New("c"), v8::Number::New(3));
4283
4284 // Create proto objects, add hidden properties to them and set them on
4285 // the global object.
4286 v8::Handle<v8::Object> protoObj = t0->GetFunction()->NewInstance();
4287 protoObj->SetHiddenValue(v8::String::New("v8::test-debug::b"),
4288 v8::Int32::New(12));
4289 env->Global()->Set(v8::String::New("protoObj"), protoObj);
4290 v8::Handle<v8::Object> grandProtoObj = t1->GetFunction()->NewInstance();
4291 grandProtoObj->SetHiddenValue(v8::String::New("v8::test-debug::c"),
4292 v8::Int32::New(13));
4293 env->Global()->Set(v8::String::New("grandProtoObj"), grandProtoObj);
4294
4295 // Setting prototypes: obj->protoObj->grandProtoObj
4296 protoObj->Set(v8::String::New("__proto__"), grandProtoObj);
4297 obj->Set(v8::String::New("__proto__"), protoObj);
4298
4299 // Get mirror for the object with property getter.
4300 CompileRun("var obj_mirror = debug.MakeMirror(obj);");
4301 CHECK(CompileRun(
4302 "obj_mirror instanceof debug.ObjectMirror")->BooleanValue());
4303 CompileRun("var named_names = obj_mirror.propertyNames();");
4304 // There should be exactly two properties - one from the object itself and
4305 // another from its hidden prototype.
4306 CHECK_EQ(2, CompileRun("named_names.length")->Int32Value());
4307 CHECK(CompileRun("named_names.sort(); named_names[0] == 'a' &&"
4308 "named_names[1] == 'b'")->BooleanValue());
4309 CHECK(CompileRun(
4310 "obj_mirror.property('a').value().value() == 1")->BooleanValue());
4311 CHECK(CompileRun(
4312 "obj_mirror.property('b').value().value() == 2")->BooleanValue());
4313}
4314
Steve Blocka7e24c12009-10-30 11:49:00 +00004315
4316// Multithreaded tests of JSON debugger protocol
4317
4318// Support classes
4319
Steve Blocka7e24c12009-10-30 11:49:00 +00004320// Provides synchronization between k threads, where k is an input to the
4321// constructor. The Wait() call blocks a thread until it is called for the
4322// k'th time, then all calls return. Each ThreadBarrier object can only
4323// be used once.
4324class ThreadBarrier {
4325 public:
4326 explicit ThreadBarrier(int num_threads);
4327 ~ThreadBarrier();
4328 void Wait();
4329 private:
4330 int num_threads_;
4331 int num_blocked_;
4332 v8::internal::Mutex* lock_;
4333 v8::internal::Semaphore* sem_;
4334 bool invalid_;
4335};
4336
4337ThreadBarrier::ThreadBarrier(int num_threads)
4338 : num_threads_(num_threads), num_blocked_(0) {
4339 lock_ = OS::CreateMutex();
4340 sem_ = OS::CreateSemaphore(0);
4341 invalid_ = false; // A barrier may only be used once. Then it is invalid.
4342}
4343
4344// Do not call, due to race condition with Wait().
4345// Could be resolved with Pthread condition variables.
4346ThreadBarrier::~ThreadBarrier() {
4347 lock_->Lock();
4348 delete lock_;
4349 delete sem_;
4350}
4351
4352void ThreadBarrier::Wait() {
4353 lock_->Lock();
4354 CHECK(!invalid_);
4355 if (num_blocked_ == num_threads_ - 1) {
4356 // Signal and unblock all waiting threads.
4357 for (int i = 0; i < num_threads_ - 1; ++i) {
4358 sem_->Signal();
4359 }
4360 invalid_ = true;
4361 printf("BARRIER\n\n");
4362 fflush(stdout);
4363 lock_->Unlock();
4364 } else { // Wait for the semaphore.
4365 ++num_blocked_;
4366 lock_->Unlock(); // Potential race condition with destructor because
4367 sem_->Wait(); // these two lines are not atomic.
4368 }
4369}
4370
4371// A set containing enough barriers and semaphores for any of the tests.
4372class Barriers {
4373 public:
4374 Barriers();
4375 void Initialize();
4376 ThreadBarrier barrier_1;
4377 ThreadBarrier barrier_2;
4378 ThreadBarrier barrier_3;
4379 ThreadBarrier barrier_4;
4380 ThreadBarrier barrier_5;
4381 v8::internal::Semaphore* semaphore_1;
4382 v8::internal::Semaphore* semaphore_2;
4383};
4384
4385Barriers::Barriers() : barrier_1(2), barrier_2(2),
4386 barrier_3(2), barrier_4(2), barrier_5(2) {}
4387
4388void Barriers::Initialize() {
4389 semaphore_1 = OS::CreateSemaphore(0);
4390 semaphore_2 = OS::CreateSemaphore(0);
4391}
4392
4393
4394// We match parts of the message to decide if it is a break message.
4395bool IsBreakEventMessage(char *message) {
4396 const char* type_event = "\"type\":\"event\"";
4397 const char* event_break = "\"event\":\"break\"";
4398 // Does the message contain both type:event and event:break?
4399 return strstr(message, type_event) != NULL &&
4400 strstr(message, event_break) != NULL;
4401}
4402
4403
Steve Block3ce2e202009-11-05 08:53:23 +00004404// We match parts of the message to decide if it is a exception message.
4405bool IsExceptionEventMessage(char *message) {
4406 const char* type_event = "\"type\":\"event\"";
4407 const char* event_exception = "\"event\":\"exception\"";
4408 // Does the message contain both type:event and event:exception?
4409 return strstr(message, type_event) != NULL &&
4410 strstr(message, event_exception) != NULL;
4411}
4412
4413
4414// We match the message wether it is an evaluate response message.
4415bool IsEvaluateResponseMessage(char* message) {
4416 const char* type_response = "\"type\":\"response\"";
4417 const char* command_evaluate = "\"command\":\"evaluate\"";
4418 // Does the message contain both type:response and command:evaluate?
4419 return strstr(message, type_response) != NULL &&
4420 strstr(message, command_evaluate) != NULL;
4421}
4422
4423
Andrei Popescu402d9372010-02-26 13:31:12 +00004424static int StringToInt(const char* s) {
4425 return atoi(s); // NOLINT
4426}
4427
4428
Steve Block3ce2e202009-11-05 08:53:23 +00004429// We match parts of the message to get evaluate result int value.
4430int GetEvaluateIntResult(char *message) {
4431 const char* value = "\"value\":";
4432 char* pos = strstr(message, value);
4433 if (pos == NULL) {
4434 return -1;
4435 }
4436 int res = -1;
Andrei Popescu402d9372010-02-26 13:31:12 +00004437 res = StringToInt(pos + strlen(value));
Steve Block3ce2e202009-11-05 08:53:23 +00004438 return res;
4439}
4440
4441
4442// We match parts of the message to get hit breakpoint id.
4443int GetBreakpointIdFromBreakEventMessage(char *message) {
4444 const char* breakpoints = "\"breakpoints\":[";
4445 char* pos = strstr(message, breakpoints);
4446 if (pos == NULL) {
4447 return -1;
4448 }
4449 int res = -1;
Andrei Popescu402d9372010-02-26 13:31:12 +00004450 res = StringToInt(pos + strlen(breakpoints));
Steve Block3ce2e202009-11-05 08:53:23 +00004451 return res;
4452}
4453
4454
Leon Clarked91b9f72010-01-27 17:25:45 +00004455// We match parts of the message to get total frames number.
4456int GetTotalFramesInt(char *message) {
4457 const char* prefix = "\"totalFrames\":";
4458 char* pos = strstr(message, prefix);
4459 if (pos == NULL) {
4460 return -1;
4461 }
4462 pos += strlen(prefix);
Andrei Popescu402d9372010-02-26 13:31:12 +00004463 int res = StringToInt(pos);
Leon Clarked91b9f72010-01-27 17:25:45 +00004464 return res;
4465}
4466
4467
Steve Blocka7e24c12009-10-30 11:49:00 +00004468/* Test MessageQueues */
4469/* Tests the message queues that hold debugger commands and
4470 * response messages to the debugger. Fills queues and makes
4471 * them grow.
4472 */
4473Barriers message_queue_barriers;
4474
4475// This is the debugger thread, that executes no v8 calls except
4476// placing JSON debugger commands in the queue.
4477class MessageQueueDebuggerThread : public v8::internal::Thread {
4478 public:
4479 void Run();
4480};
4481
4482static void MessageHandler(const uint16_t* message, int length,
4483 v8::Debug::ClientData* client_data) {
4484 static char print_buffer[1000];
4485 Utf16ToAscii(message, length, print_buffer);
4486 if (IsBreakEventMessage(print_buffer)) {
4487 // Lets test script wait until break occurs to send commands.
4488 // Signals when a break is reported.
4489 message_queue_barriers.semaphore_2->Signal();
4490 }
4491
4492 // Allow message handler to block on a semaphore, to test queueing of
4493 // messages while blocked.
4494 message_queue_barriers.semaphore_1->Wait();
Steve Blocka7e24c12009-10-30 11:49:00 +00004495}
4496
4497void MessageQueueDebuggerThread::Run() {
4498 const int kBufferSize = 1000;
4499 uint16_t buffer_1[kBufferSize];
4500 uint16_t buffer_2[kBufferSize];
4501 const char* command_1 =
4502 "{\"seq\":117,"
4503 "\"type\":\"request\","
4504 "\"command\":\"evaluate\","
4505 "\"arguments\":{\"expression\":\"1+2\"}}";
4506 const char* command_2 =
4507 "{\"seq\":118,"
4508 "\"type\":\"request\","
4509 "\"command\":\"evaluate\","
4510 "\"arguments\":{\"expression\":\"1+a\"}}";
4511 const char* command_3 =
4512 "{\"seq\":119,"
4513 "\"type\":\"request\","
4514 "\"command\":\"evaluate\","
4515 "\"arguments\":{\"expression\":\"c.d * b\"}}";
4516 const char* command_continue =
4517 "{\"seq\":106,"
4518 "\"type\":\"request\","
4519 "\"command\":\"continue\"}";
4520 const char* command_single_step =
4521 "{\"seq\":107,"
4522 "\"type\":\"request\","
4523 "\"command\":\"continue\","
4524 "\"arguments\":{\"stepaction\":\"next\"}}";
4525
4526 /* Interleaved sequence of actions by the two threads:*/
4527 // Main thread compiles and runs source_1
4528 message_queue_barriers.semaphore_1->Signal();
4529 message_queue_barriers.barrier_1.Wait();
4530 // Post 6 commands, filling the command queue and making it expand.
4531 // These calls return immediately, but the commands stay on the queue
4532 // until the execution of source_2.
4533 // Note: AsciiToUtf16 executes before SendCommand, so command is copied
4534 // to buffer before buffer is sent to SendCommand.
4535 v8::Debug::SendCommand(buffer_1, AsciiToUtf16(command_1, buffer_1));
4536 v8::Debug::SendCommand(buffer_2, AsciiToUtf16(command_2, buffer_2));
4537 v8::Debug::SendCommand(buffer_2, AsciiToUtf16(command_3, buffer_2));
4538 v8::Debug::SendCommand(buffer_2, AsciiToUtf16(command_3, buffer_2));
4539 v8::Debug::SendCommand(buffer_2, AsciiToUtf16(command_3, buffer_2));
4540 message_queue_barriers.barrier_2.Wait();
4541 // Main thread compiles and runs source_2.
4542 // Queued commands are executed at the start of compilation of source_2(
4543 // beforeCompile event).
4544 // Free the message handler to process all the messages from the queue. 7
4545 // messages are expected: 2 afterCompile events and 5 responses.
4546 // All the commands added so far will fail to execute as long as call stack
4547 // is empty on beforeCompile event.
4548 for (int i = 0; i < 6 ; ++i) {
4549 message_queue_barriers.semaphore_1->Signal();
4550 }
4551 message_queue_barriers.barrier_3.Wait();
4552 // Main thread compiles and runs source_3.
4553 // Don't stop in the afterCompile handler.
4554 message_queue_barriers.semaphore_1->Signal();
4555 // source_3 includes a debugger statement, which causes a break event.
4556 // Wait on break event from hitting "debugger" statement
4557 message_queue_barriers.semaphore_2->Wait();
4558 // These should execute after the "debugger" statement in source_2
4559 v8::Debug::SendCommand(buffer_1, AsciiToUtf16(command_1, buffer_1));
4560 v8::Debug::SendCommand(buffer_2, AsciiToUtf16(command_2, buffer_2));
4561 v8::Debug::SendCommand(buffer_2, AsciiToUtf16(command_3, buffer_2));
4562 v8::Debug::SendCommand(buffer_2, AsciiToUtf16(command_single_step, buffer_2));
4563 // Run after 2 break events, 4 responses.
4564 for (int i = 0; i < 6 ; ++i) {
4565 message_queue_barriers.semaphore_1->Signal();
4566 }
4567 // Wait on break event after a single step executes.
4568 message_queue_barriers.semaphore_2->Wait();
4569 v8::Debug::SendCommand(buffer_1, AsciiToUtf16(command_2, buffer_1));
4570 v8::Debug::SendCommand(buffer_2, AsciiToUtf16(command_continue, buffer_2));
4571 // Run after 2 responses.
4572 for (int i = 0; i < 2 ; ++i) {
4573 message_queue_barriers.semaphore_1->Signal();
4574 }
4575 // Main thread continues running source_3 to end, waits for this thread.
4576}
4577
4578MessageQueueDebuggerThread message_queue_debugger_thread;
4579
4580// This thread runs the v8 engine.
4581TEST(MessageQueues) {
4582 // Create a V8 environment
4583 v8::HandleScope scope;
4584 DebugLocalContext env;
4585 message_queue_barriers.Initialize();
4586 v8::Debug::SetMessageHandler(MessageHandler);
4587 message_queue_debugger_thread.Start();
4588
4589 const char* source_1 = "a = 3; b = 4; c = new Object(); c.d = 5;";
4590 const char* source_2 = "e = 17;";
4591 const char* source_3 = "a = 4; debugger; a = 5; a = 6; a = 7;";
4592
4593 // See MessageQueueDebuggerThread::Run for interleaved sequence of
4594 // API calls and events in the two threads.
4595 CompileRun(source_1);
4596 message_queue_barriers.barrier_1.Wait();
4597 message_queue_barriers.barrier_2.Wait();
4598 CompileRun(source_2);
4599 message_queue_barriers.barrier_3.Wait();
4600 CompileRun(source_3);
4601 message_queue_debugger_thread.Join();
4602 fflush(stdout);
4603}
4604
4605
4606class TestClientData : public v8::Debug::ClientData {
4607 public:
4608 TestClientData() {
4609 constructor_call_counter++;
4610 }
4611 virtual ~TestClientData() {
4612 destructor_call_counter++;
4613 }
4614
4615 static void ResetCounters() {
4616 constructor_call_counter = 0;
4617 destructor_call_counter = 0;
4618 }
4619
4620 static int constructor_call_counter;
4621 static int destructor_call_counter;
4622};
4623
4624int TestClientData::constructor_call_counter = 0;
4625int TestClientData::destructor_call_counter = 0;
4626
4627
4628// Tests that MessageQueue doesn't destroy client data when expands and
4629// does destroy when it dies.
4630TEST(MessageQueueExpandAndDestroy) {
4631 TestClientData::ResetCounters();
4632 { // Create a scope for the queue.
4633 CommandMessageQueue queue(1);
4634 queue.Put(CommandMessage::New(Vector<uint16_t>::empty(),
4635 new TestClientData()));
4636 queue.Put(CommandMessage::New(Vector<uint16_t>::empty(),
4637 new TestClientData()));
4638 queue.Put(CommandMessage::New(Vector<uint16_t>::empty(),
4639 new TestClientData()));
4640 CHECK_EQ(0, TestClientData::destructor_call_counter);
4641 queue.Get().Dispose();
4642 CHECK_EQ(1, TestClientData::destructor_call_counter);
4643 queue.Put(CommandMessage::New(Vector<uint16_t>::empty(),
4644 new TestClientData()));
4645 queue.Put(CommandMessage::New(Vector<uint16_t>::empty(),
4646 new TestClientData()));
4647 queue.Put(CommandMessage::New(Vector<uint16_t>::empty(),
4648 new TestClientData()));
4649 queue.Put(CommandMessage::New(Vector<uint16_t>::empty(),
4650 new TestClientData()));
4651 queue.Put(CommandMessage::New(Vector<uint16_t>::empty(),
4652 new TestClientData()));
4653 CHECK_EQ(1, TestClientData::destructor_call_counter);
4654 queue.Get().Dispose();
4655 CHECK_EQ(2, TestClientData::destructor_call_counter);
4656 }
4657 // All the client data should be destroyed when the queue is destroyed.
4658 CHECK_EQ(TestClientData::destructor_call_counter,
4659 TestClientData::destructor_call_counter);
4660}
4661
4662
4663static int handled_client_data_instances_count = 0;
4664static void MessageHandlerCountingClientData(
4665 const v8::Debug::Message& message) {
4666 if (message.GetClientData() != NULL) {
4667 handled_client_data_instances_count++;
4668 }
4669}
4670
4671
4672// Tests that all client data passed to the debugger are sent to the handler.
4673TEST(SendClientDataToHandler) {
4674 // Create a V8 environment
4675 v8::HandleScope scope;
4676 DebugLocalContext env;
4677 TestClientData::ResetCounters();
4678 handled_client_data_instances_count = 0;
4679 v8::Debug::SetMessageHandler2(MessageHandlerCountingClientData);
4680 const char* source_1 = "a = 3; b = 4; c = new Object(); c.d = 5;";
4681 const int kBufferSize = 1000;
4682 uint16_t buffer[kBufferSize];
4683 const char* command_1 =
4684 "{\"seq\":117,"
4685 "\"type\":\"request\","
4686 "\"command\":\"evaluate\","
4687 "\"arguments\":{\"expression\":\"1+2\"}}";
4688 const char* command_2 =
4689 "{\"seq\":118,"
4690 "\"type\":\"request\","
4691 "\"command\":\"evaluate\","
4692 "\"arguments\":{\"expression\":\"1+a\"}}";
4693 const char* command_continue =
4694 "{\"seq\":106,"
4695 "\"type\":\"request\","
4696 "\"command\":\"continue\"}";
4697
4698 v8::Debug::SendCommand(buffer, AsciiToUtf16(command_1, buffer),
4699 new TestClientData());
4700 v8::Debug::SendCommand(buffer, AsciiToUtf16(command_2, buffer), NULL);
4701 v8::Debug::SendCommand(buffer, AsciiToUtf16(command_2, buffer),
4702 new TestClientData());
4703 v8::Debug::SendCommand(buffer, AsciiToUtf16(command_2, buffer),
4704 new TestClientData());
4705 // All the messages will be processed on beforeCompile event.
4706 CompileRun(source_1);
4707 v8::Debug::SendCommand(buffer, AsciiToUtf16(command_continue, buffer));
4708 CHECK_EQ(3, TestClientData::constructor_call_counter);
4709 CHECK_EQ(TestClientData::constructor_call_counter,
4710 handled_client_data_instances_count);
4711 CHECK_EQ(TestClientData::constructor_call_counter,
4712 TestClientData::destructor_call_counter);
4713}
4714
4715
4716/* Test ThreadedDebugging */
4717/* This test interrupts a running infinite loop that is
4718 * occupying the v8 thread by a break command from the
4719 * debugger thread. It then changes the value of a
4720 * global object, to make the loop terminate.
4721 */
4722
4723Barriers threaded_debugging_barriers;
4724
4725class V8Thread : public v8::internal::Thread {
4726 public:
4727 void Run();
4728};
4729
4730class DebuggerThread : public v8::internal::Thread {
4731 public:
4732 void Run();
4733};
4734
4735
4736static v8::Handle<v8::Value> ThreadedAtBarrier1(const v8::Arguments& args) {
4737 threaded_debugging_barriers.barrier_1.Wait();
4738 return v8::Undefined();
4739}
4740
4741
4742static void ThreadedMessageHandler(const v8::Debug::Message& message) {
4743 static char print_buffer[1000];
4744 v8::String::Value json(message.GetJSON());
4745 Utf16ToAscii(*json, json.length(), print_buffer);
4746 if (IsBreakEventMessage(print_buffer)) {
4747 threaded_debugging_barriers.barrier_2.Wait();
4748 }
Steve Blocka7e24c12009-10-30 11:49:00 +00004749}
4750
4751
4752void V8Thread::Run() {
4753 const char* source =
4754 "flag = true;\n"
4755 "function bar( new_value ) {\n"
4756 " flag = new_value;\n"
4757 " return \"Return from bar(\" + new_value + \")\";\n"
4758 "}\n"
4759 "\n"
4760 "function foo() {\n"
4761 " var x = 1;\n"
4762 " while ( flag == true ) {\n"
4763 " if ( x == 1 ) {\n"
4764 " ThreadedAtBarrier1();\n"
4765 " }\n"
4766 " x = x + 1;\n"
4767 " }\n"
4768 "}\n"
4769 "\n"
4770 "foo();\n";
4771
4772 v8::HandleScope scope;
4773 DebugLocalContext env;
4774 v8::Debug::SetMessageHandler2(&ThreadedMessageHandler);
4775 v8::Handle<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New();
4776 global_template->Set(v8::String::New("ThreadedAtBarrier1"),
4777 v8::FunctionTemplate::New(ThreadedAtBarrier1));
4778 v8::Handle<v8::Context> context = v8::Context::New(NULL, global_template);
4779 v8::Context::Scope context_scope(context);
4780
4781 CompileRun(source);
4782}
4783
4784void DebuggerThread::Run() {
4785 const int kBufSize = 1000;
4786 uint16_t buffer[kBufSize];
4787
4788 const char* command_1 = "{\"seq\":102,"
4789 "\"type\":\"request\","
4790 "\"command\":\"evaluate\","
4791 "\"arguments\":{\"expression\":\"bar(false)\"}}";
4792 const char* command_2 = "{\"seq\":103,"
4793 "\"type\":\"request\","
4794 "\"command\":\"continue\"}";
4795
4796 threaded_debugging_barriers.barrier_1.Wait();
4797 v8::Debug::DebugBreak();
4798 threaded_debugging_barriers.barrier_2.Wait();
4799 v8::Debug::SendCommand(buffer, AsciiToUtf16(command_1, buffer));
4800 v8::Debug::SendCommand(buffer, AsciiToUtf16(command_2, buffer));
4801}
4802
4803DebuggerThread debugger_thread;
4804V8Thread v8_thread;
4805
4806TEST(ThreadedDebugging) {
4807 // Create a V8 environment
4808 threaded_debugging_barriers.Initialize();
4809
4810 v8_thread.Start();
4811 debugger_thread.Start();
4812
4813 v8_thread.Join();
4814 debugger_thread.Join();
4815}
4816
4817/* Test RecursiveBreakpoints */
4818/* In this test, the debugger evaluates a function with a breakpoint, after
4819 * hitting a breakpoint in another function. We do this with both values
4820 * of the flag enabling recursive breakpoints, and verify that the second
4821 * breakpoint is hit when enabled, and missed when disabled.
4822 */
4823
4824class BreakpointsV8Thread : public v8::internal::Thread {
4825 public:
4826 void Run();
4827};
4828
4829class BreakpointsDebuggerThread : public v8::internal::Thread {
4830 public:
Leon Clarked91b9f72010-01-27 17:25:45 +00004831 explicit BreakpointsDebuggerThread(bool global_evaluate)
4832 : global_evaluate_(global_evaluate) {}
Steve Blocka7e24c12009-10-30 11:49:00 +00004833 void Run();
Leon Clarked91b9f72010-01-27 17:25:45 +00004834
4835 private:
4836 bool global_evaluate_;
Steve Blocka7e24c12009-10-30 11:49:00 +00004837};
4838
4839
4840Barriers* breakpoints_barriers;
Steve Block3ce2e202009-11-05 08:53:23 +00004841int break_event_breakpoint_id;
4842int evaluate_int_result;
Steve Blocka7e24c12009-10-30 11:49:00 +00004843
4844static void BreakpointsMessageHandler(const v8::Debug::Message& message) {
4845 static char print_buffer[1000];
4846 v8::String::Value json(message.GetJSON());
4847 Utf16ToAscii(*json, json.length(), print_buffer);
Steve Blocka7e24c12009-10-30 11:49:00 +00004848
Steve Blocka7e24c12009-10-30 11:49:00 +00004849 if (IsBreakEventMessage(print_buffer)) {
Steve Block3ce2e202009-11-05 08:53:23 +00004850 break_event_breakpoint_id =
4851 GetBreakpointIdFromBreakEventMessage(print_buffer);
4852 breakpoints_barriers->semaphore_1->Signal();
4853 } else if (IsEvaluateResponseMessage(print_buffer)) {
4854 evaluate_int_result = GetEvaluateIntResult(print_buffer);
Steve Blocka7e24c12009-10-30 11:49:00 +00004855 breakpoints_barriers->semaphore_1->Signal();
4856 }
4857}
4858
4859
4860void BreakpointsV8Thread::Run() {
4861 const char* source_1 = "var y_global = 3;\n"
4862 "function cat( new_value ) {\n"
4863 " var x = new_value;\n"
Steve Block3ce2e202009-11-05 08:53:23 +00004864 " y_global = y_global + 4;\n"
Steve Blocka7e24c12009-10-30 11:49:00 +00004865 " x = 3 * x + 1;\n"
Steve Block3ce2e202009-11-05 08:53:23 +00004866 " y_global = y_global + 5;\n"
Steve Blocka7e24c12009-10-30 11:49:00 +00004867 " return x;\n"
4868 "}\n"
4869 "\n"
4870 "function dog() {\n"
4871 " var x = 1;\n"
4872 " x = y_global;"
4873 " var z = 3;"
4874 " x += 100;\n"
4875 " return x;\n"
4876 "}\n"
4877 "\n";
4878 const char* source_2 = "cat(17);\n"
4879 "cat(19);\n";
4880
4881 v8::HandleScope scope;
4882 DebugLocalContext env;
4883 v8::Debug::SetMessageHandler2(&BreakpointsMessageHandler);
4884
4885 CompileRun(source_1);
4886 breakpoints_barriers->barrier_1.Wait();
4887 breakpoints_barriers->barrier_2.Wait();
4888 CompileRun(source_2);
4889}
4890
4891
4892void BreakpointsDebuggerThread::Run() {
4893 const int kBufSize = 1000;
4894 uint16_t buffer[kBufSize];
4895
4896 const char* command_1 = "{\"seq\":101,"
4897 "\"type\":\"request\","
4898 "\"command\":\"setbreakpoint\","
4899 "\"arguments\":{\"type\":\"function\",\"target\":\"cat\",\"line\":3}}";
4900 const char* command_2 = "{\"seq\":102,"
4901 "\"type\":\"request\","
4902 "\"command\":\"setbreakpoint\","
4903 "\"arguments\":{\"type\":\"function\",\"target\":\"dog\",\"line\":3}}";
Leon Clarked91b9f72010-01-27 17:25:45 +00004904 const char* command_3;
4905 if (this->global_evaluate_) {
4906 command_3 = "{\"seq\":103,"
4907 "\"type\":\"request\","
4908 "\"command\":\"evaluate\","
4909 "\"arguments\":{\"expression\":\"dog()\",\"disable_break\":false,"
4910 "\"global\":true}}";
4911 } else {
4912 command_3 = "{\"seq\":103,"
4913 "\"type\":\"request\","
4914 "\"command\":\"evaluate\","
4915 "\"arguments\":{\"expression\":\"dog()\",\"disable_break\":false}}";
4916 }
4917 const char* command_4;
4918 if (this->global_evaluate_) {
4919 command_4 = "{\"seq\":104,"
4920 "\"type\":\"request\","
4921 "\"command\":\"evaluate\","
4922 "\"arguments\":{\"expression\":\"100 + 8\",\"disable_break\":true,"
4923 "\"global\":true}}";
4924 } else {
4925 command_4 = "{\"seq\":104,"
4926 "\"type\":\"request\","
4927 "\"command\":\"evaluate\","
4928 "\"arguments\":{\"expression\":\"x + 1\",\"disable_break\":true}}";
4929 }
Steve Block3ce2e202009-11-05 08:53:23 +00004930 const char* command_5 = "{\"seq\":105,"
Steve Blocka7e24c12009-10-30 11:49:00 +00004931 "\"type\":\"request\","
4932 "\"command\":\"continue\"}";
Steve Block3ce2e202009-11-05 08:53:23 +00004933 const char* command_6 = "{\"seq\":106,"
Steve Blocka7e24c12009-10-30 11:49:00 +00004934 "\"type\":\"request\","
4935 "\"command\":\"continue\"}";
Leon Clarked91b9f72010-01-27 17:25:45 +00004936 const char* command_7;
4937 if (this->global_evaluate_) {
4938 command_7 = "{\"seq\":107,"
4939 "\"type\":\"request\","
4940 "\"command\":\"evaluate\","
4941 "\"arguments\":{\"expression\":\"dog()\",\"disable_break\":true,"
4942 "\"global\":true}}";
4943 } else {
4944 command_7 = "{\"seq\":107,"
4945 "\"type\":\"request\","
4946 "\"command\":\"evaluate\","
4947 "\"arguments\":{\"expression\":\"dog()\",\"disable_break\":true}}";
4948 }
Steve Block3ce2e202009-11-05 08:53:23 +00004949 const char* command_8 = "{\"seq\":108,"
Steve Blocka7e24c12009-10-30 11:49:00 +00004950 "\"type\":\"request\","
4951 "\"command\":\"continue\"}";
4952
4953
4954 // v8 thread initializes, runs source_1
4955 breakpoints_barriers->barrier_1.Wait();
Steve Block3ce2e202009-11-05 08:53:23 +00004956 // 1:Set breakpoint in cat() (will get id 1).
Steve Blocka7e24c12009-10-30 11:49:00 +00004957 v8::Debug::SendCommand(buffer, AsciiToUtf16(command_1, buffer));
Steve Block3ce2e202009-11-05 08:53:23 +00004958 // 2:Set breakpoint in dog() (will get id 2).
Steve Blocka7e24c12009-10-30 11:49:00 +00004959 v8::Debug::SendCommand(buffer, AsciiToUtf16(command_2, buffer));
4960 breakpoints_barriers->barrier_2.Wait();
Steve Block3ce2e202009-11-05 08:53:23 +00004961 // V8 thread starts compiling source_2.
Steve Blocka7e24c12009-10-30 11:49:00 +00004962 // Automatic break happens, to run queued commands
4963 // breakpoints_barriers->semaphore_1->Wait();
4964 // Commands 1 through 3 run, thread continues.
4965 // v8 thread runs source_2 to breakpoint in cat().
4966 // message callback receives break event.
4967 breakpoints_barriers->semaphore_1->Wait();
Steve Block3ce2e202009-11-05 08:53:23 +00004968 // Must have hit breakpoint #1.
4969 CHECK_EQ(1, break_event_breakpoint_id);
Steve Blocka7e24c12009-10-30 11:49:00 +00004970 // 4:Evaluate dog() (which has a breakpoint).
4971 v8::Debug::SendCommand(buffer, AsciiToUtf16(command_3, buffer));
Steve Block3ce2e202009-11-05 08:53:23 +00004972 // V8 thread hits breakpoint in dog().
Steve Blocka7e24c12009-10-30 11:49:00 +00004973 breakpoints_barriers->semaphore_1->Wait(); // wait for break event
Steve Block3ce2e202009-11-05 08:53:23 +00004974 // Must have hit breakpoint #2.
4975 CHECK_EQ(2, break_event_breakpoint_id);
4976 // 5:Evaluate (x + 1).
Steve Blocka7e24c12009-10-30 11:49:00 +00004977 v8::Debug::SendCommand(buffer, AsciiToUtf16(command_4, buffer));
Steve Block3ce2e202009-11-05 08:53:23 +00004978 // Evaluate (x + 1) finishes.
4979 breakpoints_barriers->semaphore_1->Wait();
4980 // Must have result 108.
4981 CHECK_EQ(108, evaluate_int_result);
4982 // 6:Continue evaluation of dog().
Steve Blocka7e24c12009-10-30 11:49:00 +00004983 v8::Debug::SendCommand(buffer, AsciiToUtf16(command_5, buffer));
Steve Block3ce2e202009-11-05 08:53:23 +00004984 // Evaluate dog() finishes.
4985 breakpoints_barriers->semaphore_1->Wait();
4986 // Must have result 107.
4987 CHECK_EQ(107, evaluate_int_result);
Steve Blocka7e24c12009-10-30 11:49:00 +00004988 // 7:Continue evaluation of source_2, finish cat(17), hit breakpoint
4989 // in cat(19).
4990 v8::Debug::SendCommand(buffer, AsciiToUtf16(command_6, buffer));
Steve Block3ce2e202009-11-05 08:53:23 +00004991 // Message callback gets break event.
Steve Blocka7e24c12009-10-30 11:49:00 +00004992 breakpoints_barriers->semaphore_1->Wait(); // wait for break event
Steve Block3ce2e202009-11-05 08:53:23 +00004993 // Must have hit breakpoint #1.
4994 CHECK_EQ(1, break_event_breakpoint_id);
4995 // 8: Evaluate dog() with breaks disabled.
Steve Blocka7e24c12009-10-30 11:49:00 +00004996 v8::Debug::SendCommand(buffer, AsciiToUtf16(command_7, buffer));
Steve Block3ce2e202009-11-05 08:53:23 +00004997 // Evaluate dog() finishes.
4998 breakpoints_barriers->semaphore_1->Wait();
4999 // Must have result 116.
5000 CHECK_EQ(116, evaluate_int_result);
Steve Blocka7e24c12009-10-30 11:49:00 +00005001 // 9: Continue evaluation of source2, reach end.
5002 v8::Debug::SendCommand(buffer, AsciiToUtf16(command_8, buffer));
5003}
5004
Leon Clarked91b9f72010-01-27 17:25:45 +00005005void TestRecursiveBreakpointsGeneric(bool global_evaluate) {
Leon Clarkeeab96aa2010-01-27 16:31:12 +00005006 i::FLAG_debugger_auto_break = true;
Leon Clarke888f6722010-01-27 15:57:47 +00005007
Leon Clarked91b9f72010-01-27 17:25:45 +00005008 BreakpointsDebuggerThread breakpoints_debugger_thread(global_evaluate);
5009 BreakpointsV8Thread breakpoints_v8_thread;
5010
Steve Blocka7e24c12009-10-30 11:49:00 +00005011 // Create a V8 environment
5012 Barriers stack_allocated_breakpoints_barriers;
5013 stack_allocated_breakpoints_barriers.Initialize();
5014 breakpoints_barriers = &stack_allocated_breakpoints_barriers;
5015
5016 breakpoints_v8_thread.Start();
5017 breakpoints_debugger_thread.Start();
5018
5019 breakpoints_v8_thread.Join();
5020 breakpoints_debugger_thread.Join();
5021}
5022
Leon Clarked91b9f72010-01-27 17:25:45 +00005023TEST(RecursiveBreakpoints) {
5024 TestRecursiveBreakpointsGeneric(false);
5025}
5026
5027TEST(RecursiveBreakpointsGlobal) {
5028 TestRecursiveBreakpointsGeneric(true);
5029}
5030
Steve Blocka7e24c12009-10-30 11:49:00 +00005031
5032static void DummyDebugEventListener(v8::DebugEvent event,
5033 v8::Handle<v8::Object> exec_state,
5034 v8::Handle<v8::Object> event_data,
5035 v8::Handle<v8::Value> data) {
5036}
5037
5038
5039TEST(SetDebugEventListenerOnUninitializedVM) {
5040 v8::Debug::SetDebugEventListener(DummyDebugEventListener);
5041}
5042
5043
5044static void DummyMessageHandler(const v8::Debug::Message& message) {
5045}
5046
5047
5048TEST(SetMessageHandlerOnUninitializedVM) {
5049 v8::Debug::SetMessageHandler2(DummyMessageHandler);
5050}
5051
5052
5053TEST(DebugBreakOnUninitializedVM) {
5054 v8::Debug::DebugBreak();
5055}
5056
5057
5058TEST(SendCommandToUninitializedVM) {
5059 const char* dummy_command = "{}";
5060 uint16_t dummy_buffer[80];
5061 int dummy_length = AsciiToUtf16(dummy_command, dummy_buffer);
5062 v8::Debug::SendCommand(dummy_buffer, dummy_length);
5063}
5064
5065
5066// Source for a JavaScript function which returns the data parameter of a
5067// function called in the context of the debugger. If no data parameter is
5068// passed it throws an exception.
5069static const char* debugger_call_with_data_source =
5070 "function debugger_call_with_data(exec_state, data) {"
5071 " if (data) return data;"
5072 " throw 'No data!'"
5073 "}";
5074v8::Handle<v8::Function> debugger_call_with_data;
5075
5076
5077// Source for a JavaScript function which returns the data parameter of a
5078// function called in the context of the debugger. If no data parameter is
5079// passed it throws an exception.
5080static const char* debugger_call_with_closure_source =
5081 "var x = 3;"
5082 "(function (exec_state) {"
5083 " if (exec_state.y) return x - 1;"
5084 " exec_state.y = x;"
5085 " return exec_state.y"
5086 "})";
5087v8::Handle<v8::Function> debugger_call_with_closure;
5088
5089// Function to retrieve the number of JavaScript frames by calling a JavaScript
5090// in the debugger.
5091static v8::Handle<v8::Value> CheckFrameCount(const v8::Arguments& args) {
5092 CHECK(v8::Debug::Call(frame_count)->IsNumber());
5093 CHECK_EQ(args[0]->Int32Value(),
5094 v8::Debug::Call(frame_count)->Int32Value());
5095 return v8::Undefined();
5096}
5097
5098
5099// Function to retrieve the source line of the top JavaScript frame by calling a
5100// JavaScript function in the debugger.
5101static v8::Handle<v8::Value> CheckSourceLine(const v8::Arguments& args) {
5102 CHECK(v8::Debug::Call(frame_source_line)->IsNumber());
5103 CHECK_EQ(args[0]->Int32Value(),
5104 v8::Debug::Call(frame_source_line)->Int32Value());
5105 return v8::Undefined();
5106}
5107
5108
5109// Function to test passing an additional parameter to a JavaScript function
5110// called in the debugger. It also tests that functions called in the debugger
5111// can throw exceptions.
5112static v8::Handle<v8::Value> CheckDataParameter(const v8::Arguments& args) {
5113 v8::Handle<v8::String> data = v8::String::New("Test");
5114 CHECK(v8::Debug::Call(debugger_call_with_data, data)->IsString());
5115
5116 CHECK(v8::Debug::Call(debugger_call_with_data).IsEmpty());
5117 CHECK(v8::Debug::Call(debugger_call_with_data).IsEmpty());
5118
5119 v8::TryCatch catcher;
5120 v8::Debug::Call(debugger_call_with_data);
5121 CHECK(catcher.HasCaught());
5122 CHECK(catcher.Exception()->IsString());
5123
5124 return v8::Undefined();
5125}
5126
5127
5128// Function to test using a JavaScript with closure in the debugger.
5129static v8::Handle<v8::Value> CheckClosure(const v8::Arguments& args) {
5130 CHECK(v8::Debug::Call(debugger_call_with_closure)->IsNumber());
5131 CHECK_EQ(3, v8::Debug::Call(debugger_call_with_closure)->Int32Value());
5132 return v8::Undefined();
5133}
5134
5135
5136// Test functions called through the debugger.
5137TEST(CallFunctionInDebugger) {
5138 // Create and enter a context with the functions CheckFrameCount,
5139 // CheckSourceLine and CheckDataParameter installed.
5140 v8::HandleScope scope;
5141 v8::Handle<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New();
5142 global_template->Set(v8::String::New("CheckFrameCount"),
5143 v8::FunctionTemplate::New(CheckFrameCount));
5144 global_template->Set(v8::String::New("CheckSourceLine"),
5145 v8::FunctionTemplate::New(CheckSourceLine));
5146 global_template->Set(v8::String::New("CheckDataParameter"),
5147 v8::FunctionTemplate::New(CheckDataParameter));
5148 global_template->Set(v8::String::New("CheckClosure"),
5149 v8::FunctionTemplate::New(CheckClosure));
5150 v8::Handle<v8::Context> context = v8::Context::New(NULL, global_template);
5151 v8::Context::Scope context_scope(context);
5152
5153 // Compile a function for checking the number of JavaScript frames.
5154 v8::Script::Compile(v8::String::New(frame_count_source))->Run();
5155 frame_count = v8::Local<v8::Function>::Cast(
5156 context->Global()->Get(v8::String::New("frame_count")));
5157
5158 // Compile a function for returning the source line for the top frame.
5159 v8::Script::Compile(v8::String::New(frame_source_line_source))->Run();
5160 frame_source_line = v8::Local<v8::Function>::Cast(
5161 context->Global()->Get(v8::String::New("frame_source_line")));
5162
5163 // Compile a function returning the data parameter.
5164 v8::Script::Compile(v8::String::New(debugger_call_with_data_source))->Run();
5165 debugger_call_with_data = v8::Local<v8::Function>::Cast(
5166 context->Global()->Get(v8::String::New("debugger_call_with_data")));
5167
5168 // Compile a function capturing closure.
5169 debugger_call_with_closure = v8::Local<v8::Function>::Cast(
5170 v8::Script::Compile(
5171 v8::String::New(debugger_call_with_closure_source))->Run());
5172
Steve Block6ded16b2010-05-10 14:33:55 +01005173 // Calling a function through the debugger returns 0 frames if there are
5174 // no JavaScript frames.
5175 CHECK_EQ(v8::Integer::New(0), v8::Debug::Call(frame_count));
Steve Blocka7e24c12009-10-30 11:49:00 +00005176
5177 // Test that the number of frames can be retrieved.
5178 v8::Script::Compile(v8::String::New("CheckFrameCount(1)"))->Run();
5179 v8::Script::Compile(v8::String::New("function f() {"
5180 " CheckFrameCount(2);"
5181 "}; f()"))->Run();
5182
5183 // Test that the source line can be retrieved.
5184 v8::Script::Compile(v8::String::New("CheckSourceLine(0)"))->Run();
5185 v8::Script::Compile(v8::String::New("function f() {\n"
5186 " CheckSourceLine(1)\n"
5187 " CheckSourceLine(2)\n"
5188 " CheckSourceLine(3)\n"
5189 "}; f()"))->Run();
5190
5191 // Test that a parameter can be passed to a function called in the debugger.
5192 v8::Script::Compile(v8::String::New("CheckDataParameter()"))->Run();
5193
5194 // Test that a function with closure can be run in the debugger.
5195 v8::Script::Compile(v8::String::New("CheckClosure()"))->Run();
5196
5197
5198 // Test that the source line is correct when there is a line offset.
5199 v8::ScriptOrigin origin(v8::String::New("test"),
5200 v8::Integer::New(7));
5201 v8::Script::Compile(v8::String::New("CheckSourceLine(7)"), &origin)->Run();
5202 v8::Script::Compile(v8::String::New("function f() {\n"
5203 " CheckSourceLine(8)\n"
5204 " CheckSourceLine(9)\n"
5205 " CheckSourceLine(10)\n"
5206 "}; f()"), &origin)->Run();
5207}
5208
5209
5210// Debugger message handler which counts the number of breaks.
5211static void SendContinueCommand();
5212static void MessageHandlerBreakPointHitCount(
5213 const v8::Debug::Message& message) {
5214 if (message.IsEvent() && message.GetEvent() == v8::Break) {
5215 // Count the number of breaks.
5216 break_point_hit_count++;
5217
5218 SendContinueCommand();
5219 }
5220}
5221
5222
5223// Test that clearing the debug event listener actually clears all break points
5224// and related information.
5225TEST(DebuggerUnload) {
5226 DebugLocalContext env;
5227
5228 // Check debugger is unloaded before it is used.
5229 CheckDebuggerUnloaded();
5230
5231 // Set a debug event listener.
5232 break_point_hit_count = 0;
5233 v8::Debug::SetDebugEventListener(DebugEventBreakPointHitCount,
5234 v8::Undefined());
5235 {
5236 v8::HandleScope scope;
5237 // Create a couple of functions for the test.
5238 v8::Local<v8::Function> foo =
5239 CompileFunction(&env, "function foo(){x=1}", "foo");
5240 v8::Local<v8::Function> bar =
5241 CompileFunction(&env, "function bar(){y=2}", "bar");
5242
5243 // Set some break points.
5244 SetBreakPoint(foo, 0);
5245 SetBreakPoint(foo, 4);
5246 SetBreakPoint(bar, 0);
5247 SetBreakPoint(bar, 4);
5248
5249 // Make sure that the break points are there.
5250 break_point_hit_count = 0;
5251 foo->Call(env->Global(), 0, NULL);
5252 CHECK_EQ(2, break_point_hit_count);
5253 bar->Call(env->Global(), 0, NULL);
5254 CHECK_EQ(4, break_point_hit_count);
5255 }
5256
5257 // Remove the debug event listener without clearing breakpoints. Do this
5258 // outside a handle scope.
5259 v8::Debug::SetDebugEventListener(NULL);
5260 CheckDebuggerUnloaded(true);
5261
5262 // Now set a debug message handler.
5263 break_point_hit_count = 0;
5264 v8::Debug::SetMessageHandler2(MessageHandlerBreakPointHitCount);
5265 {
5266 v8::HandleScope scope;
5267
5268 // Get the test functions again.
5269 v8::Local<v8::Function> foo =
5270 v8::Local<v8::Function>::Cast(env->Global()->Get(v8::String::New("foo")));
5271 v8::Local<v8::Function> bar =
5272 v8::Local<v8::Function>::Cast(env->Global()->Get(v8::String::New("foo")));
5273
5274 foo->Call(env->Global(), 0, NULL);
5275 CHECK_EQ(0, break_point_hit_count);
5276
5277 // Set break points and run again.
5278 SetBreakPoint(foo, 0);
5279 SetBreakPoint(foo, 4);
5280 foo->Call(env->Global(), 0, NULL);
5281 CHECK_EQ(2, break_point_hit_count);
5282 }
5283
5284 // Remove the debug message handler without clearing breakpoints. Do this
5285 // outside a handle scope.
5286 v8::Debug::SetMessageHandler2(NULL);
5287 CheckDebuggerUnloaded(true);
5288}
5289
5290
5291// Sends continue command to the debugger.
5292static void SendContinueCommand() {
5293 const int kBufferSize = 1000;
5294 uint16_t buffer[kBufferSize];
5295 const char* command_continue =
5296 "{\"seq\":0,"
5297 "\"type\":\"request\","
5298 "\"command\":\"continue\"}";
5299
5300 v8::Debug::SendCommand(buffer, AsciiToUtf16(command_continue, buffer));
5301}
5302
5303
5304// Debugger message handler which counts the number of times it is called.
5305static int message_handler_hit_count = 0;
5306static void MessageHandlerHitCount(const v8::Debug::Message& message) {
5307 message_handler_hit_count++;
5308
Steve Block3ce2e202009-11-05 08:53:23 +00005309 static char print_buffer[1000];
5310 v8::String::Value json(message.GetJSON());
5311 Utf16ToAscii(*json, json.length(), print_buffer);
5312 if (IsExceptionEventMessage(print_buffer)) {
5313 // Send a continue command for exception events.
5314 SendContinueCommand();
5315 }
Steve Blocka7e24c12009-10-30 11:49:00 +00005316}
5317
5318
5319// Test clearing the debug message handler.
5320TEST(DebuggerClearMessageHandler) {
5321 v8::HandleScope scope;
5322 DebugLocalContext env;
5323
5324 // Check debugger is unloaded before it is used.
5325 CheckDebuggerUnloaded();
5326
5327 // Set a debug message handler.
5328 v8::Debug::SetMessageHandler2(MessageHandlerHitCount);
5329
5330 // Run code to throw a unhandled exception. This should end up in the message
5331 // handler.
5332 CompileRun("throw 1");
5333
5334 // The message handler should be called.
5335 CHECK_GT(message_handler_hit_count, 0);
5336
5337 // Clear debug message handler.
5338 message_handler_hit_count = 0;
5339 v8::Debug::SetMessageHandler(NULL);
5340
5341 // Run code to throw a unhandled exception. This should end up in the message
5342 // handler.
5343 CompileRun("throw 1");
5344
5345 // The message handler should not be called more.
5346 CHECK_EQ(0, message_handler_hit_count);
5347
5348 CheckDebuggerUnloaded(true);
5349}
5350
5351
5352// Debugger message handler which clears the message handler while active.
5353static void MessageHandlerClearingMessageHandler(
5354 const v8::Debug::Message& message) {
5355 message_handler_hit_count++;
5356
5357 // Clear debug message handler.
5358 v8::Debug::SetMessageHandler(NULL);
5359}
5360
5361
5362// Test clearing the debug message handler while processing a debug event.
5363TEST(DebuggerClearMessageHandlerWhileActive) {
5364 v8::HandleScope scope;
5365 DebugLocalContext env;
5366
5367 // Check debugger is unloaded before it is used.
5368 CheckDebuggerUnloaded();
5369
5370 // Set a debug message handler.
5371 v8::Debug::SetMessageHandler2(MessageHandlerClearingMessageHandler);
5372
5373 // Run code to throw a unhandled exception. This should end up in the message
5374 // handler.
5375 CompileRun("throw 1");
5376
5377 // The message handler should be called.
5378 CHECK_EQ(1, message_handler_hit_count);
5379
5380 CheckDebuggerUnloaded(true);
5381}
5382
5383
5384/* Test DebuggerHostDispatch */
5385/* In this test, the debugger waits for a command on a breakpoint
5386 * and is dispatching host commands while in the infinite loop.
5387 */
5388
5389class HostDispatchV8Thread : public v8::internal::Thread {
5390 public:
5391 void Run();
5392};
5393
5394class HostDispatchDebuggerThread : public v8::internal::Thread {
5395 public:
5396 void Run();
5397};
5398
5399Barriers* host_dispatch_barriers;
5400
5401static void HostDispatchMessageHandler(const v8::Debug::Message& message) {
5402 static char print_buffer[1000];
5403 v8::String::Value json(message.GetJSON());
5404 Utf16ToAscii(*json, json.length(), print_buffer);
Steve Blocka7e24c12009-10-30 11:49:00 +00005405}
5406
5407
5408static void HostDispatchDispatchHandler() {
5409 host_dispatch_barriers->semaphore_1->Signal();
5410}
5411
5412
5413void HostDispatchV8Thread::Run() {
5414 const char* source_1 = "var y_global = 3;\n"
5415 "function cat( new_value ) {\n"
5416 " var x = new_value;\n"
5417 " y_global = 4;\n"
5418 " x = 3 * x + 1;\n"
5419 " y_global = 5;\n"
5420 " return x;\n"
5421 "}\n"
5422 "\n";
5423 const char* source_2 = "cat(17);\n";
5424
5425 v8::HandleScope scope;
5426 DebugLocalContext env;
5427
5428 // Setup message and host dispatch handlers.
5429 v8::Debug::SetMessageHandler2(HostDispatchMessageHandler);
5430 v8::Debug::SetHostDispatchHandler(HostDispatchDispatchHandler, 10 /* ms */);
5431
5432 CompileRun(source_1);
5433 host_dispatch_barriers->barrier_1.Wait();
5434 host_dispatch_barriers->barrier_2.Wait();
5435 CompileRun(source_2);
5436}
5437
5438
5439void HostDispatchDebuggerThread::Run() {
5440 const int kBufSize = 1000;
5441 uint16_t buffer[kBufSize];
5442
5443 const char* command_1 = "{\"seq\":101,"
5444 "\"type\":\"request\","
5445 "\"command\":\"setbreakpoint\","
5446 "\"arguments\":{\"type\":\"function\",\"target\":\"cat\",\"line\":3}}";
5447 const char* command_2 = "{\"seq\":102,"
5448 "\"type\":\"request\","
5449 "\"command\":\"continue\"}";
5450
5451 // v8 thread initializes, runs source_1
5452 host_dispatch_barriers->barrier_1.Wait();
5453 // 1: Set breakpoint in cat().
5454 v8::Debug::SendCommand(buffer, AsciiToUtf16(command_1, buffer));
5455
5456 host_dispatch_barriers->barrier_2.Wait();
5457 // v8 thread starts compiling source_2.
5458 // Break happens, to run queued commands and host dispatches.
5459 // Wait for host dispatch to be processed.
5460 host_dispatch_barriers->semaphore_1->Wait();
5461 // 2: Continue evaluation
5462 v8::Debug::SendCommand(buffer, AsciiToUtf16(command_2, buffer));
5463}
5464
5465HostDispatchDebuggerThread host_dispatch_debugger_thread;
5466HostDispatchV8Thread host_dispatch_v8_thread;
5467
5468
5469TEST(DebuggerHostDispatch) {
5470 i::FLAG_debugger_auto_break = true;
5471
5472 // Create a V8 environment
5473 Barriers stack_allocated_host_dispatch_barriers;
5474 stack_allocated_host_dispatch_barriers.Initialize();
5475 host_dispatch_barriers = &stack_allocated_host_dispatch_barriers;
5476
5477 host_dispatch_v8_thread.Start();
5478 host_dispatch_debugger_thread.Start();
5479
5480 host_dispatch_v8_thread.Join();
5481 host_dispatch_debugger_thread.Join();
5482}
5483
5484
Steve Blockd0582a62009-12-15 09:54:21 +00005485/* Test DebugMessageDispatch */
5486/* In this test, the V8 thread waits for a message from the debug thread.
5487 * The DebugMessageDispatchHandler is executed from the debugger thread
5488 * which signals the V8 thread to wake up.
5489 */
5490
5491class DebugMessageDispatchV8Thread : public v8::internal::Thread {
5492 public:
5493 void Run();
5494};
5495
5496class DebugMessageDispatchDebuggerThread : public v8::internal::Thread {
5497 public:
5498 void Run();
5499};
5500
5501Barriers* debug_message_dispatch_barriers;
5502
5503
5504static void DebugMessageHandler() {
5505 debug_message_dispatch_barriers->semaphore_1->Signal();
5506}
5507
5508
5509void DebugMessageDispatchV8Thread::Run() {
5510 v8::HandleScope scope;
5511 DebugLocalContext env;
5512
5513 // Setup debug message dispatch handler.
5514 v8::Debug::SetDebugMessageDispatchHandler(DebugMessageHandler);
5515
5516 CompileRun("var y = 1 + 2;\n");
5517 debug_message_dispatch_barriers->barrier_1.Wait();
5518 debug_message_dispatch_barriers->semaphore_1->Wait();
5519 debug_message_dispatch_barriers->barrier_2.Wait();
5520}
5521
5522
5523void DebugMessageDispatchDebuggerThread::Run() {
5524 debug_message_dispatch_barriers->barrier_1.Wait();
5525 SendContinueCommand();
5526 debug_message_dispatch_barriers->barrier_2.Wait();
5527}
5528
5529DebugMessageDispatchDebuggerThread debug_message_dispatch_debugger_thread;
5530DebugMessageDispatchV8Thread debug_message_dispatch_v8_thread;
5531
5532
5533TEST(DebuggerDebugMessageDispatch) {
5534 i::FLAG_debugger_auto_break = true;
5535
5536 // Create a V8 environment
5537 Barriers stack_allocated_debug_message_dispatch_barriers;
5538 stack_allocated_debug_message_dispatch_barriers.Initialize();
5539 debug_message_dispatch_barriers =
5540 &stack_allocated_debug_message_dispatch_barriers;
5541
5542 debug_message_dispatch_v8_thread.Start();
5543 debug_message_dispatch_debugger_thread.Start();
5544
5545 debug_message_dispatch_v8_thread.Join();
5546 debug_message_dispatch_debugger_thread.Join();
5547}
5548
5549
Steve Blocka7e24c12009-10-30 11:49:00 +00005550TEST(DebuggerAgent) {
5551 // Make sure these ports is not used by other tests to allow tests to run in
5552 // parallel.
5553 const int kPort1 = 5858;
5554 const int kPort2 = 5857;
5555 const int kPort3 = 5856;
5556
5557 // Make a string with the port2 number.
5558 const int kPortBufferLen = 6;
5559 char port2_str[kPortBufferLen];
5560 OS::SNPrintF(i::Vector<char>(port2_str, kPortBufferLen), "%d", kPort2);
5561
5562 bool ok;
5563
5564 // Initialize the socket library.
5565 i::Socket::Setup();
5566
5567 // Test starting and stopping the agent without any client connection.
5568 i::Debugger::StartAgent("test", kPort1);
5569 i::Debugger::StopAgent();
5570
5571 // Test starting the agent, connecting a client and shutting down the agent
5572 // with the client connected.
5573 ok = i::Debugger::StartAgent("test", kPort2);
5574 CHECK(ok);
5575 i::Debugger::WaitForAgent();
5576 i::Socket* client = i::OS::CreateSocket();
5577 ok = client->Connect("localhost", port2_str);
5578 CHECK(ok);
5579 i::Debugger::StopAgent();
5580 delete client;
5581
5582 // Test starting and stopping the agent with the required port already
5583 // occoupied.
5584 i::Socket* server = i::OS::CreateSocket();
5585 server->Bind(kPort3);
5586
5587 i::Debugger::StartAgent("test", kPort3);
5588 i::Debugger::StopAgent();
5589
5590 delete server;
5591}
5592
5593
5594class DebuggerAgentProtocolServerThread : public i::Thread {
5595 public:
5596 explicit DebuggerAgentProtocolServerThread(int port)
5597 : port_(port), server_(NULL), client_(NULL),
5598 listening_(OS::CreateSemaphore(0)) {
5599 }
5600 ~DebuggerAgentProtocolServerThread() {
5601 // Close both sockets.
5602 delete client_;
5603 delete server_;
5604 delete listening_;
5605 }
5606
5607 void Run();
5608 void WaitForListening() { listening_->Wait(); }
5609 char* body() { return *body_; }
5610
5611 private:
5612 int port_;
5613 i::SmartPointer<char> body_;
5614 i::Socket* server_; // Server socket used for bind/accept.
5615 i::Socket* client_; // Single client connection used by the test.
5616 i::Semaphore* listening_; // Signalled when the server is in listen mode.
5617};
5618
5619
5620void DebuggerAgentProtocolServerThread::Run() {
5621 bool ok;
5622
5623 // Create the server socket and bind it to the requested port.
5624 server_ = i::OS::CreateSocket();
5625 CHECK(server_ != NULL);
5626 ok = server_->Bind(port_);
5627 CHECK(ok);
5628
5629 // Listen for new connections.
5630 ok = server_->Listen(1);
5631 CHECK(ok);
5632 listening_->Signal();
5633
5634 // Accept a connection.
5635 client_ = server_->Accept();
5636 CHECK(client_ != NULL);
5637
5638 // Receive a debugger agent protocol message.
5639 i::DebuggerAgentUtil::ReceiveMessage(client_);
5640}
5641
5642
5643TEST(DebuggerAgentProtocolOverflowHeader) {
5644 // Make sure this port is not used by other tests to allow tests to run in
5645 // parallel.
5646 const int kPort = 5860;
5647 static const char* kLocalhost = "localhost";
5648
5649 // Make a string with the port number.
5650 const int kPortBufferLen = 6;
5651 char port_str[kPortBufferLen];
5652 OS::SNPrintF(i::Vector<char>(port_str, kPortBufferLen), "%d", kPort);
5653
5654 // Initialize the socket library.
5655 i::Socket::Setup();
5656
5657 // Create a socket server to receive a debugger agent message.
5658 DebuggerAgentProtocolServerThread* server =
5659 new DebuggerAgentProtocolServerThread(kPort);
5660 server->Start();
5661 server->WaitForListening();
5662
5663 // Connect.
5664 i::Socket* client = i::OS::CreateSocket();
5665 CHECK(client != NULL);
5666 bool ok = client->Connect(kLocalhost, port_str);
5667 CHECK(ok);
5668
5669 // Send headers which overflow the receive buffer.
5670 static const int kBufferSize = 1000;
5671 char buffer[kBufferSize];
5672
5673 // Long key and short value: XXXX....XXXX:0\r\n.
5674 for (int i = 0; i < kBufferSize - 4; i++) {
5675 buffer[i] = 'X';
5676 }
5677 buffer[kBufferSize - 4] = ':';
5678 buffer[kBufferSize - 3] = '0';
5679 buffer[kBufferSize - 2] = '\r';
5680 buffer[kBufferSize - 1] = '\n';
5681 client->Send(buffer, kBufferSize);
5682
5683 // Short key and long value: X:XXXX....XXXX\r\n.
5684 buffer[0] = 'X';
5685 buffer[1] = ':';
5686 for (int i = 2; i < kBufferSize - 2; i++) {
5687 buffer[i] = 'X';
5688 }
5689 buffer[kBufferSize - 2] = '\r';
5690 buffer[kBufferSize - 1] = '\n';
5691 client->Send(buffer, kBufferSize);
5692
5693 // Add empty body to request.
5694 const char* content_length_zero_header = "Content-Length:0\r\n";
Steve Blockd0582a62009-12-15 09:54:21 +00005695 client->Send(content_length_zero_header,
5696 StrLength(content_length_zero_header));
Steve Blocka7e24c12009-10-30 11:49:00 +00005697 client->Send("\r\n", 2);
5698
5699 // Wait until data is received.
5700 server->Join();
5701
5702 // Check for empty body.
5703 CHECK(server->body() == NULL);
5704
5705 // Close the client before the server to avoid TIME_WAIT issues.
5706 client->Shutdown();
5707 delete client;
5708 delete server;
5709}
5710
5711
5712// Test for issue http://code.google.com/p/v8/issues/detail?id=289.
5713// Make sure that DebugGetLoadedScripts doesn't return scripts
5714// with disposed external source.
5715class EmptyExternalStringResource : public v8::String::ExternalStringResource {
5716 public:
5717 EmptyExternalStringResource() { empty_[0] = 0; }
5718 virtual ~EmptyExternalStringResource() {}
5719 virtual size_t length() const { return empty_.length(); }
5720 virtual const uint16_t* data() const { return empty_.start(); }
5721 private:
5722 ::v8::internal::EmbeddedVector<uint16_t, 1> empty_;
5723};
5724
5725
5726TEST(DebugGetLoadedScripts) {
5727 v8::HandleScope scope;
5728 DebugLocalContext env;
5729 env.ExposeDebug();
5730
5731 EmptyExternalStringResource source_ext_str;
5732 v8::Local<v8::String> source = v8::String::NewExternal(&source_ext_str);
5733 v8::Handle<v8::Script> evil_script = v8::Script::Compile(source);
5734 Handle<i::ExternalTwoByteString> i_source(
5735 i::ExternalTwoByteString::cast(*v8::Utils::OpenHandle(*source)));
5736 // This situation can happen if source was an external string disposed
5737 // by its owner.
5738 i_source->set_resource(0);
5739
5740 bool allow_natives_syntax = i::FLAG_allow_natives_syntax;
5741 i::FLAG_allow_natives_syntax = true;
5742 CompileRun(
5743 "var scripts = %DebugGetLoadedScripts();"
5744 "var count = scripts.length;"
5745 "for (var i = 0; i < count; ++i) {"
5746 " scripts[i].line_ends;"
5747 "}");
5748 // Must not crash while accessing line_ends.
5749 i::FLAG_allow_natives_syntax = allow_natives_syntax;
5750
5751 // Some scripts are retrieved - at least the number of native scripts.
5752 CHECK_GT((*env)->Global()->Get(v8::String::New("count"))->Int32Value(), 8);
5753}
5754
5755
5756// Test script break points set on lines.
5757TEST(ScriptNameAndData) {
5758 v8::HandleScope scope;
5759 DebugLocalContext env;
5760 env.ExposeDebug();
5761
5762 // Create functions for retrieving script name and data for the function on
5763 // the top frame when hitting a break point.
5764 frame_script_name = CompileFunction(&env,
5765 frame_script_name_source,
5766 "frame_script_name");
5767 frame_script_data = CompileFunction(&env,
5768 frame_script_data_source,
5769 "frame_script_data");
Andrei Popescu402d9372010-02-26 13:31:12 +00005770 compiled_script_data = CompileFunction(&env,
5771 compiled_script_data_source,
5772 "compiled_script_data");
Steve Blocka7e24c12009-10-30 11:49:00 +00005773
5774 v8::Debug::SetDebugEventListener(DebugEventBreakPointHitCount,
5775 v8::Undefined());
5776
5777 // Test function source.
5778 v8::Local<v8::String> script = v8::String::New(
5779 "function f() {\n"
5780 " debugger;\n"
5781 "}\n");
5782
5783 v8::ScriptOrigin origin1 = v8::ScriptOrigin(v8::String::New("name"));
5784 v8::Handle<v8::Script> script1 = v8::Script::Compile(script, &origin1);
5785 script1->SetData(v8::String::New("data"));
5786 script1->Run();
5787 v8::Local<v8::Function> f;
5788 f = v8::Local<v8::Function>::Cast(env->Global()->Get(v8::String::New("f")));
5789
5790 f->Call(env->Global(), 0, NULL);
5791 CHECK_EQ(1, break_point_hit_count);
5792 CHECK_EQ("name", last_script_name_hit);
5793 CHECK_EQ("data", last_script_data_hit);
5794
5795 // Compile the same script again without setting data. As the compilation
5796 // cache is disabled when debugging expect the data to be missing.
5797 v8::Script::Compile(script, &origin1)->Run();
5798 f = v8::Local<v8::Function>::Cast(env->Global()->Get(v8::String::New("f")));
5799 f->Call(env->Global(), 0, NULL);
5800 CHECK_EQ(2, break_point_hit_count);
5801 CHECK_EQ("name", last_script_name_hit);
5802 CHECK_EQ("", last_script_data_hit); // Undefined results in empty string.
5803
5804 v8::Local<v8::String> data_obj_source = v8::String::New(
5805 "({ a: 'abc',\n"
5806 " b: 123,\n"
5807 " toString: function() { return this.a + ' ' + this.b; }\n"
5808 "})\n");
5809 v8::Local<v8::Value> data_obj = v8::Script::Compile(data_obj_source)->Run();
5810 v8::ScriptOrigin origin2 = v8::ScriptOrigin(v8::String::New("new name"));
5811 v8::Handle<v8::Script> script2 = v8::Script::Compile(script, &origin2);
5812 script2->Run();
Steve Blockd0582a62009-12-15 09:54:21 +00005813 script2->SetData(data_obj->ToString());
Steve Blocka7e24c12009-10-30 11:49:00 +00005814 f = v8::Local<v8::Function>::Cast(env->Global()->Get(v8::String::New("f")));
5815 f->Call(env->Global(), 0, NULL);
5816 CHECK_EQ(3, break_point_hit_count);
5817 CHECK_EQ("new name", last_script_name_hit);
5818 CHECK_EQ("abc 123", last_script_data_hit);
Andrei Popescu402d9372010-02-26 13:31:12 +00005819
5820 v8::Handle<v8::Script> script3 =
5821 v8::Script::Compile(script, &origin2, NULL,
5822 v8::String::New("in compile"));
5823 CHECK_EQ("in compile", last_script_data_hit);
5824 script3->Run();
5825 f = v8::Local<v8::Function>::Cast(env->Global()->Get(v8::String::New("f")));
5826 f->Call(env->Global(), 0, NULL);
5827 CHECK_EQ(4, break_point_hit_count);
5828 CHECK_EQ("in compile", last_script_data_hit);
Steve Blocka7e24c12009-10-30 11:49:00 +00005829}
5830
5831
5832static v8::Persistent<v8::Context> expected_context;
5833static v8::Handle<v8::Value> expected_context_data;
5834
5835
5836// Check that the expected context is the one generating the debug event.
5837static void ContextCheckMessageHandler(const v8::Debug::Message& message) {
5838 CHECK(message.GetEventContext() == expected_context);
5839 CHECK(message.GetEventContext()->GetData()->StrictEquals(
5840 expected_context_data));
5841 message_handler_hit_count++;
5842
Steve Block3ce2e202009-11-05 08:53:23 +00005843 static char print_buffer[1000];
5844 v8::String::Value json(message.GetJSON());
5845 Utf16ToAscii(*json, json.length(), print_buffer);
5846
Steve Blocka7e24c12009-10-30 11:49:00 +00005847 // Send a continue command for break events.
Steve Block3ce2e202009-11-05 08:53:23 +00005848 if (IsBreakEventMessage(print_buffer)) {
Steve Blocka7e24c12009-10-30 11:49:00 +00005849 SendContinueCommand();
5850 }
5851}
5852
5853
5854// Test which creates two contexts and sets different embedder data on each.
5855// Checks that this data is set correctly and that when the debug message
5856// handler is called the expected context is the one active.
5857TEST(ContextData) {
5858 v8::HandleScope scope;
5859
5860 v8::Debug::SetMessageHandler2(ContextCheckMessageHandler);
5861
5862 // Create two contexts.
5863 v8::Persistent<v8::Context> context_1;
5864 v8::Persistent<v8::Context> context_2;
5865 v8::Handle<v8::ObjectTemplate> global_template =
5866 v8::Handle<v8::ObjectTemplate>();
5867 v8::Handle<v8::Value> global_object = v8::Handle<v8::Value>();
5868 context_1 = v8::Context::New(NULL, global_template, global_object);
5869 context_2 = v8::Context::New(NULL, global_template, global_object);
5870
5871 // Default data value is undefined.
5872 CHECK(context_1->GetData()->IsUndefined());
5873 CHECK(context_2->GetData()->IsUndefined());
5874
5875 // Set and check different data values.
Steve Blockd0582a62009-12-15 09:54:21 +00005876 v8::Handle<v8::String> data_1 = v8::String::New("1");
5877 v8::Handle<v8::String> data_2 = v8::String::New("2");
Steve Blocka7e24c12009-10-30 11:49:00 +00005878 context_1->SetData(data_1);
5879 context_2->SetData(data_2);
5880 CHECK(context_1->GetData()->StrictEquals(data_1));
5881 CHECK(context_2->GetData()->StrictEquals(data_2));
5882
5883 // Simple test function which causes a break.
5884 const char* source = "function f() { debugger; }";
5885
5886 // Enter and run function in the first context.
5887 {
5888 v8::Context::Scope context_scope(context_1);
5889 expected_context = context_1;
5890 expected_context_data = data_1;
5891 v8::Local<v8::Function> f = CompileFunction(source, "f");
5892 f->Call(context_1->Global(), 0, NULL);
5893 }
5894
5895
5896 // Enter and run function in the second context.
5897 {
5898 v8::Context::Scope context_scope(context_2);
5899 expected_context = context_2;
5900 expected_context_data = data_2;
5901 v8::Local<v8::Function> f = CompileFunction(source, "f");
5902 f->Call(context_2->Global(), 0, NULL);
5903 }
5904
5905 // Two times compile event and two times break event.
5906 CHECK_GT(message_handler_hit_count, 4);
5907
5908 v8::Debug::SetMessageHandler2(NULL);
5909 CheckDebuggerUnloaded();
5910}
5911
5912
5913// Debug message handler which issues a debug break when it hits a break event.
5914static int message_handler_break_hit_count = 0;
5915static void DebugBreakMessageHandler(const v8::Debug::Message& message) {
5916 // Schedule a debug break for break events.
5917 if (message.IsEvent() && message.GetEvent() == v8::Break) {
5918 message_handler_break_hit_count++;
5919 if (message_handler_break_hit_count == 1) {
5920 v8::Debug::DebugBreak();
5921 }
5922 }
5923
5924 // Issue a continue command if this event will not cause the VM to start
5925 // running.
5926 if (!message.WillStartRunning()) {
5927 SendContinueCommand();
5928 }
5929}
5930
5931
5932// Test that a debug break can be scheduled while in a message handler.
5933TEST(DebugBreakInMessageHandler) {
5934 v8::HandleScope scope;
5935 DebugLocalContext env;
5936
5937 v8::Debug::SetMessageHandler2(DebugBreakMessageHandler);
5938
5939 // Test functions.
5940 const char* script = "function f() { debugger; g(); } function g() { }";
5941 CompileRun(script);
5942 v8::Local<v8::Function> f =
5943 v8::Local<v8::Function>::Cast(env->Global()->Get(v8::String::New("f")));
5944 v8::Local<v8::Function> g =
5945 v8::Local<v8::Function>::Cast(env->Global()->Get(v8::String::New("g")));
5946
5947 // Call f then g. The debugger statement in f will casue a break which will
5948 // cause another break.
5949 f->Call(env->Global(), 0, NULL);
5950 CHECK_EQ(2, message_handler_break_hit_count);
5951 // Calling g will not cause any additional breaks.
5952 g->Call(env->Global(), 0, NULL);
5953 CHECK_EQ(2, message_handler_break_hit_count);
5954}
5955
5956
Steve Block6ded16b2010-05-10 14:33:55 +01005957#ifndef V8_INTERPRETED_REGEXP
Steve Blocka7e24c12009-10-30 11:49:00 +00005958// Debug event handler which gets the function on the top frame and schedules a
5959// break a number of times.
5960static void DebugEventDebugBreak(
5961 v8::DebugEvent event,
5962 v8::Handle<v8::Object> exec_state,
5963 v8::Handle<v8::Object> event_data,
5964 v8::Handle<v8::Value> data) {
5965
5966 if (event == v8::Break) {
5967 break_point_hit_count++;
5968
5969 // Get the name of the top frame function.
5970 if (!frame_function_name.IsEmpty()) {
5971 // Get the name of the function.
5972 const int argc = 1;
5973 v8::Handle<v8::Value> argv[argc] = { exec_state };
5974 v8::Handle<v8::Value> result = frame_function_name->Call(exec_state,
5975 argc, argv);
5976 if (result->IsUndefined()) {
5977 last_function_hit[0] = '\0';
5978 } else {
5979 CHECK(result->IsString());
5980 v8::Handle<v8::String> function_name(result->ToString());
5981 function_name->WriteAscii(last_function_hit);
5982 }
5983 }
5984
5985 // Keep forcing breaks.
5986 if (break_point_hit_count < 20) {
5987 v8::Debug::DebugBreak();
5988 }
5989 }
5990}
5991
5992
5993TEST(RegExpDebugBreak) {
5994 // This test only applies to native regexps.
5995 v8::HandleScope scope;
5996 DebugLocalContext env;
5997
5998 // Create a function for checking the function when hitting a break point.
5999 frame_function_name = CompileFunction(&env,
6000 frame_function_name_source,
6001 "frame_function_name");
6002
6003 // Test RegExp which matches white spaces and comments at the begining of a
6004 // source line.
6005 const char* script =
6006 "var sourceLineBeginningSkip = /^(?:[ \\v\\h]*(?:\\/\\*.*?\\*\\/)*)*/;\n"
6007 "function f(s) { return s.match(sourceLineBeginningSkip)[0].length; }";
6008
6009 v8::Local<v8::Function> f = CompileFunction(script, "f");
6010 const int argc = 1;
6011 v8::Handle<v8::Value> argv[argc] = { v8::String::New(" /* xxx */ a=0;") };
6012 v8::Local<v8::Value> result = f->Call(env->Global(), argc, argv);
6013 CHECK_EQ(12, result->Int32Value());
6014
6015 v8::Debug::SetDebugEventListener(DebugEventDebugBreak);
6016 v8::Debug::DebugBreak();
6017 result = f->Call(env->Global(), argc, argv);
6018
6019 // Check that there was only one break event. Matching RegExp should not
6020 // cause Break events.
6021 CHECK_EQ(1, break_point_hit_count);
6022 CHECK_EQ("f", last_function_hit);
6023}
Steve Block6ded16b2010-05-10 14:33:55 +01006024#endif // V8_INTERPRETED_REGEXP
Steve Blocka7e24c12009-10-30 11:49:00 +00006025
6026
6027// Common part of EvalContextData and NestedBreakEventContextData tests.
6028static void ExecuteScriptForContextCheck() {
6029 // Create a context.
6030 v8::Persistent<v8::Context> context_1;
6031 v8::Handle<v8::ObjectTemplate> global_template =
6032 v8::Handle<v8::ObjectTemplate>();
6033 v8::Handle<v8::Value> global_object = v8::Handle<v8::Value>();
6034 context_1 = v8::Context::New(NULL, global_template, global_object);
6035
6036 // Default data value is undefined.
6037 CHECK(context_1->GetData()->IsUndefined());
6038
6039 // Set and check a data value.
Steve Blockd0582a62009-12-15 09:54:21 +00006040 v8::Handle<v8::String> data_1 = v8::String::New("1");
Steve Blocka7e24c12009-10-30 11:49:00 +00006041 context_1->SetData(data_1);
6042 CHECK(context_1->GetData()->StrictEquals(data_1));
6043
6044 // Simple test function with eval that causes a break.
6045 const char* source = "function f() { eval('debugger;'); }";
6046
6047 // Enter and run function in the context.
6048 {
6049 v8::Context::Scope context_scope(context_1);
6050 expected_context = context_1;
6051 expected_context_data = data_1;
6052 v8::Local<v8::Function> f = CompileFunction(source, "f");
6053 f->Call(context_1->Global(), 0, NULL);
6054 }
6055}
6056
6057
6058// Test which creates a context and sets embedder data on it. Checks that this
6059// data is set correctly and that when the debug message handler is called for
6060// break event in an eval statement the expected context is the one returned by
6061// Message.GetEventContext.
6062TEST(EvalContextData) {
6063 v8::HandleScope scope;
6064 v8::Debug::SetMessageHandler2(ContextCheckMessageHandler);
6065
6066 ExecuteScriptForContextCheck();
6067
6068 // One time compile event and one time break event.
6069 CHECK_GT(message_handler_hit_count, 2);
6070 v8::Debug::SetMessageHandler2(NULL);
6071 CheckDebuggerUnloaded();
6072}
6073
6074
6075static bool sent_eval = false;
6076static int break_count = 0;
6077static int continue_command_send_count = 0;
6078// Check that the expected context is the one generating the debug event
6079// including the case of nested break event.
6080static void DebugEvalContextCheckMessageHandler(
6081 const v8::Debug::Message& message) {
6082 CHECK(message.GetEventContext() == expected_context);
6083 CHECK(message.GetEventContext()->GetData()->StrictEquals(
6084 expected_context_data));
6085 message_handler_hit_count++;
6086
Steve Block3ce2e202009-11-05 08:53:23 +00006087 static char print_buffer[1000];
6088 v8::String::Value json(message.GetJSON());
6089 Utf16ToAscii(*json, json.length(), print_buffer);
6090
6091 if (IsBreakEventMessage(print_buffer)) {
Steve Blocka7e24c12009-10-30 11:49:00 +00006092 break_count++;
6093 if (!sent_eval) {
6094 sent_eval = true;
6095
6096 const int kBufferSize = 1000;
6097 uint16_t buffer[kBufferSize];
6098 const char* eval_command =
6099 "{\"seq\":0,"
6100 "\"type\":\"request\","
6101 "\"command\":\"evaluate\","
6102 "arguments:{\"expression\":\"debugger;\","
6103 "\"global\":true,\"disable_break\":false}}";
6104
6105 // Send evaluate command.
6106 v8::Debug::SendCommand(buffer, AsciiToUtf16(eval_command, buffer));
6107 return;
6108 } else {
6109 // It's a break event caused by the evaluation request above.
6110 SendContinueCommand();
6111 continue_command_send_count++;
6112 }
Steve Block3ce2e202009-11-05 08:53:23 +00006113 } else if (IsEvaluateResponseMessage(print_buffer) &&
6114 continue_command_send_count < 2) {
Steve Blocka7e24c12009-10-30 11:49:00 +00006115 // Response to the evaluation request. We're still on the breakpoint so
6116 // send continue.
6117 SendContinueCommand();
6118 continue_command_send_count++;
6119 }
6120}
6121
6122
6123// Tests that context returned for break event is correct when the event occurs
6124// in 'evaluate' debugger request.
6125TEST(NestedBreakEventContextData) {
6126 v8::HandleScope scope;
6127 break_count = 0;
6128 message_handler_hit_count = 0;
6129 v8::Debug::SetMessageHandler2(DebugEvalContextCheckMessageHandler);
6130
6131 ExecuteScriptForContextCheck();
6132
6133 // One time compile event and two times break event.
6134 CHECK_GT(message_handler_hit_count, 3);
6135
6136 // One break from the source and another from the evaluate request.
6137 CHECK_EQ(break_count, 2);
6138 v8::Debug::SetMessageHandler2(NULL);
6139 CheckDebuggerUnloaded();
6140}
6141
6142
6143// Debug event listener which counts the script collected events.
6144int script_collected_count = 0;
6145static void DebugEventScriptCollectedEvent(v8::DebugEvent event,
6146 v8::Handle<v8::Object> exec_state,
6147 v8::Handle<v8::Object> event_data,
6148 v8::Handle<v8::Value> data) {
6149 // Count the number of breaks.
6150 if (event == v8::ScriptCollected) {
6151 script_collected_count++;
6152 }
6153}
6154
6155
6156// Test that scripts collected are reported through the debug event listener.
6157TEST(ScriptCollectedEvent) {
6158 break_point_hit_count = 0;
6159 script_collected_count = 0;
6160 v8::HandleScope scope;
6161 DebugLocalContext env;
6162
6163 // Request the loaded scripts to initialize the debugger script cache.
6164 Debug::GetLoadedScripts();
6165
6166 // Do garbage collection to ensure that only the script in this test will be
6167 // collected afterwards.
6168 Heap::CollectAllGarbage(false);
6169
6170 script_collected_count = 0;
6171 v8::Debug::SetDebugEventListener(DebugEventScriptCollectedEvent,
6172 v8::Undefined());
6173 {
6174 v8::Script::Compile(v8::String::New("eval('a=1')"))->Run();
6175 v8::Script::Compile(v8::String::New("eval('a=2')"))->Run();
6176 }
6177
6178 // Do garbage collection to collect the script above which is no longer
6179 // referenced.
6180 Heap::CollectAllGarbage(false);
6181
6182 CHECK_EQ(2, script_collected_count);
6183
6184 v8::Debug::SetDebugEventListener(NULL);
6185 CheckDebuggerUnloaded();
6186}
6187
6188
6189// Debug event listener which counts the script collected events.
6190int script_collected_message_count = 0;
6191static void ScriptCollectedMessageHandler(const v8::Debug::Message& message) {
6192 // Count the number of scripts collected.
6193 if (message.IsEvent() && message.GetEvent() == v8::ScriptCollected) {
6194 script_collected_message_count++;
6195 v8::Handle<v8::Context> context = message.GetEventContext();
6196 CHECK(context.IsEmpty());
6197 }
6198}
6199
6200
6201// Test that GetEventContext doesn't fail and return empty handle for
6202// ScriptCollected events.
6203TEST(ScriptCollectedEventContext) {
6204 script_collected_message_count = 0;
6205 v8::HandleScope scope;
6206
6207 { // Scope for the DebugLocalContext.
6208 DebugLocalContext env;
6209
6210 // Request the loaded scripts to initialize the debugger script cache.
6211 Debug::GetLoadedScripts();
6212
6213 // Do garbage collection to ensure that only the script in this test will be
6214 // collected afterwards.
6215 Heap::CollectAllGarbage(false);
6216
6217 v8::Debug::SetMessageHandler2(ScriptCollectedMessageHandler);
6218 {
6219 v8::Script::Compile(v8::String::New("eval('a=1')"))->Run();
6220 v8::Script::Compile(v8::String::New("eval('a=2')"))->Run();
6221 }
6222 }
6223
6224 // Do garbage collection to collect the script above which is no longer
6225 // referenced.
6226 Heap::CollectAllGarbage(false);
6227
6228 CHECK_EQ(2, script_collected_message_count);
6229
6230 v8::Debug::SetMessageHandler2(NULL);
6231}
6232
6233
6234// Debug event listener which counts the after compile events.
6235int after_compile_message_count = 0;
6236static void AfterCompileMessageHandler(const v8::Debug::Message& message) {
6237 // Count the number of scripts collected.
6238 if (message.IsEvent()) {
6239 if (message.GetEvent() == v8::AfterCompile) {
6240 after_compile_message_count++;
6241 } else if (message.GetEvent() == v8::Break) {
6242 SendContinueCommand();
6243 }
6244 }
6245}
6246
6247
6248// Tests that after compile event is sent as many times as there are scripts
6249// compiled.
6250TEST(AfterCompileMessageWhenMessageHandlerIsReset) {
6251 v8::HandleScope scope;
6252 DebugLocalContext env;
6253 after_compile_message_count = 0;
6254 const char* script = "var a=1";
6255
6256 v8::Debug::SetMessageHandler2(AfterCompileMessageHandler);
6257 v8::Script::Compile(v8::String::New(script))->Run();
6258 v8::Debug::SetMessageHandler2(NULL);
6259
6260 v8::Debug::SetMessageHandler2(AfterCompileMessageHandler);
6261 v8::Debug::DebugBreak();
6262 v8::Script::Compile(v8::String::New(script))->Run();
6263
6264 // Setting listener to NULL should cause debugger unload.
6265 v8::Debug::SetMessageHandler2(NULL);
6266 CheckDebuggerUnloaded();
6267
6268 // Compilation cache should be disabled when debugger is active.
6269 CHECK_EQ(2, after_compile_message_count);
6270}
6271
6272
6273// Tests that break event is sent when message handler is reset.
6274TEST(BreakMessageWhenMessageHandlerIsReset) {
6275 v8::HandleScope scope;
6276 DebugLocalContext env;
6277 after_compile_message_count = 0;
6278 const char* script = "function f() {};";
6279
6280 v8::Debug::SetMessageHandler2(AfterCompileMessageHandler);
6281 v8::Script::Compile(v8::String::New(script))->Run();
6282 v8::Debug::SetMessageHandler2(NULL);
6283
6284 v8::Debug::SetMessageHandler2(AfterCompileMessageHandler);
6285 v8::Debug::DebugBreak();
6286 v8::Local<v8::Function> f =
6287 v8::Local<v8::Function>::Cast(env->Global()->Get(v8::String::New("f")));
6288 f->Call(env->Global(), 0, NULL);
6289
6290 // Setting message handler to NULL should cause debugger unload.
6291 v8::Debug::SetMessageHandler2(NULL);
6292 CheckDebuggerUnloaded();
6293
6294 // Compilation cache should be disabled when debugger is active.
6295 CHECK_EQ(1, after_compile_message_count);
6296}
6297
6298
6299static int exception_event_count = 0;
6300static void ExceptionMessageHandler(const v8::Debug::Message& message) {
6301 if (message.IsEvent() && message.GetEvent() == v8::Exception) {
6302 exception_event_count++;
6303 SendContinueCommand();
6304 }
6305}
6306
6307
6308// Tests that exception event is sent when message handler is reset.
6309TEST(ExceptionMessageWhenMessageHandlerIsReset) {
6310 v8::HandleScope scope;
6311 DebugLocalContext env;
6312 exception_event_count = 0;
6313 const char* script = "function f() {throw new Error()};";
6314
6315 v8::Debug::SetMessageHandler2(AfterCompileMessageHandler);
6316 v8::Script::Compile(v8::String::New(script))->Run();
6317 v8::Debug::SetMessageHandler2(NULL);
6318
6319 v8::Debug::SetMessageHandler2(ExceptionMessageHandler);
6320 v8::Local<v8::Function> f =
6321 v8::Local<v8::Function>::Cast(env->Global()->Get(v8::String::New("f")));
6322 f->Call(env->Global(), 0, NULL);
6323
6324 // Setting message handler to NULL should cause debugger unload.
6325 v8::Debug::SetMessageHandler2(NULL);
6326 CheckDebuggerUnloaded();
6327
6328 CHECK_EQ(1, exception_event_count);
6329}
6330
6331
6332// Tests after compile event is sent when there are some provisional
6333// breakpoints out of the scripts lines range.
6334TEST(ProvisionalBreakpointOnLineOutOfRange) {
6335 v8::HandleScope scope;
6336 DebugLocalContext env;
6337 env.ExposeDebug();
6338 const char* script = "function f() {};";
6339 const char* resource_name = "test_resource";
6340
6341 // Set a couple of provisional breakpoint on lines out of the script lines
6342 // range.
6343 int sbp1 = SetScriptBreakPointByNameFromJS(resource_name, 3,
6344 -1 /* no column */);
6345 int sbp2 = SetScriptBreakPointByNameFromJS(resource_name, 5, 5);
6346
6347 after_compile_message_count = 0;
6348 v8::Debug::SetMessageHandler2(AfterCompileMessageHandler);
6349
6350 v8::ScriptOrigin origin(
6351 v8::String::New(resource_name),
6352 v8::Integer::New(10),
6353 v8::Integer::New(1));
6354 // Compile a script whose first line number is greater than the breakpoints'
6355 // lines.
6356 v8::Script::Compile(v8::String::New(script), &origin)->Run();
6357
6358 // If the script is compiled successfully there is exactly one after compile
6359 // event. In case of an exception in debugger code after compile event is not
6360 // sent.
6361 CHECK_EQ(1, after_compile_message_count);
6362
6363 ClearBreakPointFromJS(sbp1);
6364 ClearBreakPointFromJS(sbp2);
6365 v8::Debug::SetMessageHandler2(NULL);
6366}
6367
6368
6369static void BreakMessageHandler(const v8::Debug::Message& message) {
6370 if (message.IsEvent() && message.GetEvent() == v8::Break) {
6371 // Count the number of breaks.
6372 break_point_hit_count++;
6373
6374 v8::HandleScope scope;
6375 v8::Handle<v8::String> json = message.GetJSON();
6376
6377 SendContinueCommand();
6378 } else if (message.IsEvent() && message.GetEvent() == v8::AfterCompile) {
6379 v8::HandleScope scope;
6380
6381 bool is_debug_break = i::StackGuard::IsDebugBreak();
6382 // Force DebugBreak flag while serializer is working.
6383 i::StackGuard::DebugBreak();
6384
6385 // Force serialization to trigger some internal JS execution.
6386 v8::Handle<v8::String> json = message.GetJSON();
6387
6388 // Restore previous state.
6389 if (is_debug_break) {
6390 i::StackGuard::DebugBreak();
6391 } else {
6392 i::StackGuard::Continue(i::DEBUGBREAK);
6393 }
6394 }
6395}
6396
6397
6398// Test that if DebugBreak is forced it is ignored when code from
6399// debug-delay.js is executed.
6400TEST(NoDebugBreakInAfterCompileMessageHandler) {
6401 v8::HandleScope scope;
6402 DebugLocalContext env;
6403
6404 // Register a debug event listener which sets the break flag and counts.
6405 v8::Debug::SetMessageHandler2(BreakMessageHandler);
6406
6407 // Set the debug break flag.
6408 v8::Debug::DebugBreak();
6409
6410 // Create a function for testing stepping.
6411 const char* src = "function f() { eval('var x = 10;'); } ";
6412 v8::Local<v8::Function> f = CompileFunction(&env, src, "f");
6413
6414 // There should be only one break event.
6415 CHECK_EQ(1, break_point_hit_count);
6416
6417 // Set the debug break flag again.
6418 v8::Debug::DebugBreak();
6419 f->Call(env->Global(), 0, NULL);
6420 // There should be one more break event when the script is evaluated in 'f'.
6421 CHECK_EQ(2, break_point_hit_count);
6422
6423 // Get rid of the debug message handler.
6424 v8::Debug::SetMessageHandler2(NULL);
6425 CheckDebuggerUnloaded();
6426}
6427
6428
Leon Clarkee46be812010-01-19 14:06:41 +00006429static int counting_message_handler_counter;
6430
6431static void CountingMessageHandler(const v8::Debug::Message& message) {
6432 counting_message_handler_counter++;
6433}
6434
6435// Test that debug messages get processed when ProcessDebugMessages is called.
6436TEST(ProcessDebugMessages) {
6437 v8::HandleScope scope;
6438 DebugLocalContext env;
6439
6440 counting_message_handler_counter = 0;
6441
6442 v8::Debug::SetMessageHandler2(CountingMessageHandler);
6443
6444 const int kBufferSize = 1000;
6445 uint16_t buffer[kBufferSize];
6446 const char* scripts_command =
6447 "{\"seq\":0,"
6448 "\"type\":\"request\","
6449 "\"command\":\"scripts\"}";
6450
6451 // Send scripts command.
6452 v8::Debug::SendCommand(buffer, AsciiToUtf16(scripts_command, buffer));
6453
6454 CHECK_EQ(0, counting_message_handler_counter);
6455 v8::Debug::ProcessDebugMessages();
6456 // At least one message should come
6457 CHECK_GE(counting_message_handler_counter, 1);
6458
6459 counting_message_handler_counter = 0;
6460
6461 v8::Debug::SendCommand(buffer, AsciiToUtf16(scripts_command, buffer));
6462 v8::Debug::SendCommand(buffer, AsciiToUtf16(scripts_command, buffer));
6463 CHECK_EQ(0, counting_message_handler_counter);
6464 v8::Debug::ProcessDebugMessages();
6465 // At least two messages should come
6466 CHECK_GE(counting_message_handler_counter, 2);
6467
6468 // Get rid of the debug message handler.
6469 v8::Debug::SetMessageHandler2(NULL);
6470 CheckDebuggerUnloaded();
6471}
6472
6473
Steve Block6ded16b2010-05-10 14:33:55 +01006474struct BacktraceData {
Leon Clarked91b9f72010-01-27 17:25:45 +00006475 static int frame_counter;
6476 static void MessageHandler(const v8::Debug::Message& message) {
6477 char print_buffer[1000];
6478 v8::String::Value json(message.GetJSON());
6479 Utf16ToAscii(*json, json.length(), print_buffer, 1000);
6480
6481 if (strstr(print_buffer, "backtrace") == NULL) {
6482 return;
6483 }
6484 frame_counter = GetTotalFramesInt(print_buffer);
6485 }
6486};
6487
Steve Block6ded16b2010-05-10 14:33:55 +01006488int BacktraceData::frame_counter;
Leon Clarked91b9f72010-01-27 17:25:45 +00006489
6490
6491// Test that debug messages get processed when ProcessDebugMessages is called.
6492TEST(Backtrace) {
6493 v8::HandleScope scope;
6494 DebugLocalContext env;
6495
Steve Block6ded16b2010-05-10 14:33:55 +01006496 v8::Debug::SetMessageHandler2(BacktraceData::MessageHandler);
Leon Clarked91b9f72010-01-27 17:25:45 +00006497
6498 const int kBufferSize = 1000;
6499 uint16_t buffer[kBufferSize];
6500 const char* scripts_command =
6501 "{\"seq\":0,"
6502 "\"type\":\"request\","
6503 "\"command\":\"backtrace\"}";
6504
6505 // Check backtrace from ProcessDebugMessages.
Steve Block6ded16b2010-05-10 14:33:55 +01006506 BacktraceData::frame_counter = -10;
Leon Clarked91b9f72010-01-27 17:25:45 +00006507 v8::Debug::SendCommand(buffer, AsciiToUtf16(scripts_command, buffer));
6508 v8::Debug::ProcessDebugMessages();
Steve Block6ded16b2010-05-10 14:33:55 +01006509 CHECK_EQ(BacktraceData::frame_counter, 0);
Leon Clarked91b9f72010-01-27 17:25:45 +00006510
6511 v8::Handle<v8::String> void0 = v8::String::New("void(0)");
6512 v8::Handle<v8::Script> script = v8::Script::Compile(void0, void0);
6513
6514 // Check backtrace from "void(0)" script.
Steve Block6ded16b2010-05-10 14:33:55 +01006515 BacktraceData::frame_counter = -10;
Leon Clarked91b9f72010-01-27 17:25:45 +00006516 v8::Debug::SendCommand(buffer, AsciiToUtf16(scripts_command, buffer));
6517 script->Run();
Steve Block6ded16b2010-05-10 14:33:55 +01006518 CHECK_EQ(BacktraceData::frame_counter, 1);
Leon Clarked91b9f72010-01-27 17:25:45 +00006519
6520 // Get rid of the debug message handler.
6521 v8::Debug::SetMessageHandler2(NULL);
6522 CheckDebuggerUnloaded();
6523}
6524
6525
Steve Blocka7e24c12009-10-30 11:49:00 +00006526TEST(GetMirror) {
6527 v8::HandleScope scope;
6528 DebugLocalContext env;
6529 v8::Handle<v8::Value> obj = v8::Debug::GetMirror(v8::String::New("hodja"));
6530 v8::Handle<v8::Function> run_test = v8::Handle<v8::Function>::Cast(
6531 v8::Script::New(
6532 v8::String::New(
6533 "function runTest(mirror) {"
6534 " return mirror.isString() && (mirror.length() == 5);"
6535 "}"
6536 ""
6537 "runTest;"))->Run());
6538 v8::Handle<v8::Value> result = run_test->Call(env->Global(), 1, &obj);
6539 CHECK(result->IsTrue());
6540}
Steve Blockd0582a62009-12-15 09:54:21 +00006541
6542
6543// Test that the debug break flag works with function.apply.
6544TEST(DebugBreakFunctionApply) {
6545 v8::HandleScope scope;
6546 DebugLocalContext env;
6547
6548 // Create a function for testing breaking in apply.
6549 v8::Local<v8::Function> foo = CompileFunction(
6550 &env,
6551 "function baz(x) { }"
6552 "function bar(x) { baz(); }"
6553 "function foo(){ bar.apply(this, [1]); }",
6554 "foo");
6555
6556 // Register a debug event listener which steps and counts.
6557 v8::Debug::SetDebugEventListener(DebugEventBreakMax);
6558
6559 // Set the debug break flag before calling the code using function.apply.
6560 v8::Debug::DebugBreak();
6561
6562 // Limit the number of debug breaks. This is a regression test for issue 493
6563 // where this test would enter an infinite loop.
6564 break_point_hit_count = 0;
6565 max_break_point_hit_count = 10000; // 10000 => infinite loop.
6566 foo->Call(env->Global(), 0, NULL);
6567
6568 // When keeping the debug break several break will happen.
6569 CHECK_EQ(3, break_point_hit_count);
6570
6571 v8::Debug::SetDebugEventListener(NULL);
6572 CheckDebuggerUnloaded();
6573}
6574
6575
6576v8::Handle<v8::Context> debugee_context;
6577v8::Handle<v8::Context> debugger_context;
6578
6579
6580// Property getter that checks that current and calling contexts
6581// are both the debugee contexts.
6582static v8::Handle<v8::Value> NamedGetterWithCallingContextCheck(
6583 v8::Local<v8::String> name,
6584 const v8::AccessorInfo& info) {
6585 CHECK_EQ(0, strcmp(*v8::String::AsciiValue(name), "a"));
6586 v8::Handle<v8::Context> current = v8::Context::GetCurrent();
6587 CHECK(current == debugee_context);
6588 CHECK(current != debugger_context);
6589 v8::Handle<v8::Context> calling = v8::Context::GetCalling();
6590 CHECK(calling == debugee_context);
6591 CHECK(calling != debugger_context);
6592 return v8::Int32::New(1);
6593}
6594
6595
6596// Debug event listener that checks if the first argument of a function is
6597// an object with property 'a' == 1. If the property has custom accessor
6598// this handler will eventually invoke it.
6599static void DebugEventGetAtgumentPropertyValue(
6600 v8::DebugEvent event,
6601 v8::Handle<v8::Object> exec_state,
6602 v8::Handle<v8::Object> event_data,
6603 v8::Handle<v8::Value> data) {
6604 if (event == v8::Break) {
6605 break_point_hit_count++;
6606 CHECK(debugger_context == v8::Context::GetCurrent());
6607 v8::Handle<v8::Function> func(v8::Function::Cast(*CompileRun(
6608 "(function(exec_state) {\n"
6609 " return (exec_state.frame(0).argumentValue(0).property('a').\n"
6610 " value().value() == 1);\n"
6611 "})")));
6612 const int argc = 1;
6613 v8::Handle<v8::Value> argv[argc] = { exec_state };
6614 v8::Handle<v8::Value> result = func->Call(exec_state, argc, argv);
6615 CHECK(result->IsTrue());
6616 }
6617}
6618
6619
6620TEST(CallingContextIsNotDebugContext) {
6621 // Create and enter a debugee context.
6622 v8::HandleScope scope;
6623 DebugLocalContext env;
6624 env.ExposeDebug();
6625
6626 // Save handles to the debugger and debugee contexts to be used in
6627 // NamedGetterWithCallingContextCheck.
6628 debugee_context = v8::Local<v8::Context>(*env);
6629 debugger_context = v8::Utils::ToLocal(Debug::debug_context());
6630
6631 // Create object with 'a' property accessor.
6632 v8::Handle<v8::ObjectTemplate> named = v8::ObjectTemplate::New();
6633 named->SetAccessor(v8::String::New("a"),
6634 NamedGetterWithCallingContextCheck);
6635 env->Global()->Set(v8::String::New("obj"),
6636 named->NewInstance());
6637
6638 // Register the debug event listener
6639 v8::Debug::SetDebugEventListener(DebugEventGetAtgumentPropertyValue);
6640
6641 // Create a function that invokes debugger.
6642 v8::Local<v8::Function> foo = CompileFunction(
6643 &env,
6644 "function bar(x) { debugger; }"
6645 "function foo(){ bar(obj); }",
6646 "foo");
6647
6648 break_point_hit_count = 0;
6649 foo->Call(env->Global(), 0, NULL);
6650 CHECK_EQ(1, break_point_hit_count);
6651
6652 v8::Debug::SetDebugEventListener(NULL);
6653 debugee_context = v8::Handle<v8::Context>();
6654 debugger_context = v8::Handle<v8::Context>();
6655 CheckDebuggerUnloaded();
6656}
Steve Block6ded16b2010-05-10 14:33:55 +01006657
6658
6659TEST(DebugContextIsPreservedBetweenAccesses) {
6660 v8::HandleScope scope;
6661 v8::Local<v8::Context> context1 = v8::Debug::GetDebugContext();
6662 v8::Local<v8::Context> context2 = v8::Debug::GetDebugContext();
6663 CHECK_EQ(*context1, *context2);
Leon Clarkef7060e22010-06-03 12:02:55 +01006664}
6665
6666
6667static v8::Handle<v8::Value> expected_callback_data;
6668static void DebugEventContextChecker(const v8::Debug::EventDetails& details) {
6669 CHECK(details.GetEventContext() == expected_context);
6670 CHECK_EQ(expected_callback_data, details.GetCallbackData());
6671}
6672
6673// Check that event details contain context where debug event occured.
6674TEST(DebugEventContext) {
6675 v8::HandleScope scope;
6676 expected_callback_data = v8::Int32::New(2010);
6677 v8::Debug::SetDebugEventListener2(DebugEventContextChecker,
6678 expected_callback_data);
6679 expected_context = v8::Context::New();
6680 v8::Context::Scope context_scope(expected_context);
6681 v8::Script::Compile(v8::String::New("(function(){debugger;})();"))->Run();
6682 expected_context.Dispose();
6683 expected_context.Clear();
6684 v8::Debug::SetDebugEventListener(NULL);
6685 expected_context_data = v8::Handle<v8::Value>();
Steve Block6ded16b2010-05-10 14:33:55 +01006686 CheckDebuggerUnloaded();
6687}
Leon Clarkef7060e22010-06-03 12:02:55 +01006688
Ben Murdoch3bec4d22010-07-22 14:51:16 +01006689
6690static void* expected_break_data;
6691static bool was_debug_break_called;
6692static bool was_debug_event_called;
6693static void DebugEventBreakDataChecker(const v8::Debug::EventDetails& details) {
6694 if (details.GetEvent() == v8::BreakForCommand) {
6695 CHECK_EQ(expected_break_data, details.GetClientData());
6696 was_debug_event_called = true;
6697 } else if (details.GetEvent() == v8::Break) {
6698 was_debug_break_called = true;
6699 }
6700}
6701
6702// Check that event details contain context where debug event occured.
6703TEST(DebugEventBreakData) {
6704 v8::HandleScope scope;
6705 DebugLocalContext env;
6706 v8::Debug::SetDebugEventListener2(DebugEventBreakDataChecker);
6707
6708 TestClientData::constructor_call_counter = 0;
6709 TestClientData::destructor_call_counter = 0;
6710
6711 expected_break_data = NULL;
6712 was_debug_event_called = false;
6713 was_debug_break_called = false;
6714 v8::Debug::DebugBreakForCommand();
6715 v8::Script::Compile(v8::String::New("(function(x){return x;})(1);"))->Run();
6716 CHECK(was_debug_event_called);
6717 CHECK(!was_debug_break_called);
6718
6719 TestClientData* data1 = new TestClientData();
6720 expected_break_data = data1;
6721 was_debug_event_called = false;
6722 was_debug_break_called = false;
6723 v8::Debug::DebugBreakForCommand(data1);
6724 v8::Script::Compile(v8::String::New("(function(x){return x+1;})(1);"))->Run();
6725 CHECK(was_debug_event_called);
6726 CHECK(!was_debug_break_called);
6727
6728 expected_break_data = NULL;
6729 was_debug_event_called = false;
6730 was_debug_break_called = false;
6731 v8::Debug::DebugBreak();
6732 v8::Script::Compile(v8::String::New("(function(x){return x+2;})(1);"))->Run();
6733 CHECK(!was_debug_event_called);
6734 CHECK(was_debug_break_called);
6735
6736 TestClientData* data2 = new TestClientData();
6737 expected_break_data = data2;
6738 was_debug_event_called = false;
6739 was_debug_break_called = false;
6740 v8::Debug::DebugBreak();
6741 v8::Debug::DebugBreakForCommand(data2);
6742 v8::Script::Compile(v8::String::New("(function(x){return x+3;})(1);"))->Run();
6743 CHECK(was_debug_event_called);
6744 CHECK(was_debug_break_called);
6745
6746 CHECK_EQ(2, TestClientData::constructor_call_counter);
6747 CHECK_EQ(TestClientData::constructor_call_counter,
6748 TestClientData::destructor_call_counter);
6749
6750 v8::Debug::SetDebugEventListener(NULL);
6751 CheckDebuggerUnloaded();
6752}
6753
Kristian Monsen9dcf7e22010-06-28 14:14:28 +01006754#endif // ENABLE_DEBUGGER_SUPPORT