blob: b7962de2e9645f3d0d9319e92a37c2ee208997b4 [file] [log] [blame]
Ben Murdoch257744e2011-11-30 15:57:28 +00001// Copyright 2011 the V8 project authors. All rights reserved.
Steve Blocka7e24c12009-10-30 11:49:00 +00002// Redistribution and use in source and binary forms, with or without
3// modification, are permitted provided that the following conditions are
4// met:
5//
6// * Redistributions of source code must retain the above copyright
7// notice, this list of conditions and the following disclaimer.
8// * Redistributions in binary form must reproduce the above
9// copyright notice, this list of conditions and the following
10// disclaimer in the documentation and/or other materials provided
11// with the distribution.
12// * Neither the name of Google Inc. nor the names of its
13// contributors may be used to endorse or promote products derived
14// from this software without specific prior written permission.
15//
16// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27
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"
Ben Murdochb0fe1622011-05-05 13:52:32 +010035#include "cctest.h"
Steve Blocka7e24c12009-10-30 11:49:00 +000036#include "compilation-cache.h"
37#include "debug.h"
Ben Murdochb0fe1622011-05-05 13:52:32 +010038#include "deoptimizer.h"
Steve Blocka7e24c12009-10-30 11:49:00 +000039#include "platform.h"
40#include "stub-cache.h"
Ben Murdochb0fe1622011-05-05 13:52:32 +010041#include "utils.h"
Steve Blocka7e24c12009-10-30 11:49:00 +000042
43
44using ::v8::internal::EmbeddedVector;
45using ::v8::internal::Object;
46using ::v8::internal::OS;
47using ::v8::internal::Handle;
48using ::v8::internal::Heap;
49using ::v8::internal::JSGlobalProxy;
50using ::v8::internal::Code;
51using ::v8::internal::Debug;
52using ::v8::internal::Debugger;
53using ::v8::internal::CommandMessage;
54using ::v8::internal::CommandMessageQueue;
55using ::v8::internal::StepAction;
56using ::v8::internal::StepIn; // From StepAction enum
57using ::v8::internal::StepNext; // From StepAction enum
58using ::v8::internal::StepOut; // From StepAction enum
59using ::v8::internal::Vector;
Steve Blockd0582a62009-12-15 09:54:21 +000060using ::v8::internal::StrLength;
Steve Blocka7e24c12009-10-30 11:49:00 +000061
62// Size of temp buffer for formatting small strings.
63#define SMALL_STRING_BUFFER_SIZE 80
64
65// --- A d d i t i o n a l C h e c k H e l p e r s
66
67
68// Helper function used by the CHECK_EQ function when given Address
69// arguments. Should not be called directly.
70static inline void CheckEqualsHelper(const char* file, int line,
71 const char* expected_source,
72 ::v8::internal::Address expected,
73 const char* value_source,
74 ::v8::internal::Address value) {
75 if (expected != value) {
76 V8_Fatal(file, line, "CHECK_EQ(%s, %s) failed\n# "
77 "Expected: %i\n# Found: %i",
78 expected_source, value_source, expected, value);
79 }
80}
81
82
83// Helper function used by the CHECK_NE function when given Address
84// arguments. Should not be called directly.
85static inline void CheckNonEqualsHelper(const char* file, int line,
86 const char* unexpected_source,
87 ::v8::internal::Address unexpected,
88 const char* value_source,
89 ::v8::internal::Address value) {
90 if (unexpected == value) {
91 V8_Fatal(file, line, "CHECK_NE(%s, %s) failed\n# Value: %i",
92 unexpected_source, value_source, value);
93 }
94}
95
96
97// Helper function used by the CHECK function when given code
98// arguments. Should not be called directly.
99static inline void CheckEqualsHelper(const char* file, int line,
100 const char* expected_source,
101 const Code* expected,
102 const char* value_source,
103 const Code* value) {
104 if (expected != value) {
105 V8_Fatal(file, line, "CHECK_EQ(%s, %s) failed\n# "
106 "Expected: %p\n# Found: %p",
107 expected_source, value_source, expected, value);
108 }
109}
110
111
112static inline void CheckNonEqualsHelper(const char* file, int line,
113 const char* expected_source,
114 const Code* expected,
115 const char* value_source,
116 const Code* value) {
117 if (expected == value) {
118 V8_Fatal(file, line, "CHECK_NE(%s, %s) failed\n# Value: %p",
119 expected_source, value_source, value);
120 }
121}
122
123
124// --- H e l p e r C l a s s e s
125
126
127// Helper class for creating a V8 enviromnent for running tests
128class DebugLocalContext {
129 public:
130 inline DebugLocalContext(
131 v8::ExtensionConfiguration* extensions = 0,
132 v8::Handle<v8::ObjectTemplate> global_template =
133 v8::Handle<v8::ObjectTemplate>(),
134 v8::Handle<v8::Value> global_object = v8::Handle<v8::Value>())
135 : context_(v8::Context::New(extensions, global_template, global_object)) {
136 context_->Enter();
137 }
138 inline ~DebugLocalContext() {
139 context_->Exit();
140 context_.Dispose();
141 }
142 inline v8::Context* operator->() { return *context_; }
143 inline v8::Context* operator*() { return *context_; }
144 inline bool IsReady() { return !context_.IsEmpty(); }
145 void ExposeDebug() {
Steve Block44f0eee2011-05-26 01:26:41 +0100146 v8::internal::Debug* debug = v8::internal::Isolate::Current()->debug();
Steve Blocka7e24c12009-10-30 11:49:00 +0000147 // Expose the debug context global object in the global object for testing.
Steve Block44f0eee2011-05-26 01:26:41 +0100148 debug->Load();
149 debug->debug_context()->set_security_token(
Steve Blocka7e24c12009-10-30 11:49:00 +0000150 v8::Utils::OpenHandle(*context_)->security_token());
151
152 Handle<JSGlobalProxy> global(Handle<JSGlobalProxy>::cast(
153 v8::Utils::OpenHandle(*context_->Global())));
154 Handle<v8::internal::String> debug_string =
Steve Block44f0eee2011-05-26 01:26:41 +0100155 FACTORY->LookupAsciiSymbol("debug");
Steve Blocka7e24c12009-10-30 11:49:00 +0000156 SetProperty(global, debug_string,
Steve Block44f0eee2011-05-26 01:26:41 +0100157 Handle<Object>(debug->debug_context()->global_proxy()), DONT_ENUM,
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100158 ::v8::internal::kNonStrictMode);
Steve Blocka7e24c12009-10-30 11:49:00 +0000159 }
160 private:
161 v8::Persistent<v8::Context> context_;
162};
163
164
165// --- H e l p e r F u n c t i o n s
166
167
168// Compile and run the supplied source and return the fequested function.
169static v8::Local<v8::Function> CompileFunction(DebugLocalContext* env,
170 const char* source,
171 const char* function_name) {
172 v8::Script::Compile(v8::String::New(source))->Run();
173 return v8::Local<v8::Function>::Cast(
174 (*env)->Global()->Get(v8::String::New(function_name)));
175}
176
177
178// Compile and run the supplied source and return the requested function.
179static v8::Local<v8::Function> CompileFunction(const char* source,
180 const char* function_name) {
181 v8::Script::Compile(v8::String::New(source))->Run();
182 return v8::Local<v8::Function>::Cast(
183 v8::Context::GetCurrent()->Global()->Get(v8::String::New(function_name)));
184}
185
186
Steve Blocka7e24c12009-10-30 11:49:00 +0000187// Is there any debug info for the function?
188static bool HasDebugInfo(v8::Handle<v8::Function> fun) {
189 Handle<v8::internal::JSFunction> f = v8::Utils::OpenHandle(*fun);
190 Handle<v8::internal::SharedFunctionInfo> shared(f->shared());
191 return Debug::HasDebugInfo(shared);
192}
193
194
195// Set a break point in a function and return the associated break point
196// number.
197static int SetBreakPoint(Handle<v8::internal::JSFunction> fun, int position) {
198 static int break_point = 0;
199 Handle<v8::internal::SharedFunctionInfo> shared(fun->shared());
Steve Block44f0eee2011-05-26 01:26:41 +0100200 v8::internal::Debug* debug = v8::internal::Isolate::Current()->debug();
201 debug->SetBreakPoint(
Kristian Monsen9dcf7e22010-06-28 14:14:28 +0100202 shared,
203 Handle<Object>(v8::internal::Smi::FromInt(++break_point)),
204 &position);
Steve Blocka7e24c12009-10-30 11:49:00 +0000205 return break_point;
206}
207
208
209// Set a break point in a function and return the associated break point
210// number.
211static int SetBreakPoint(v8::Handle<v8::Function> fun, int position) {
212 return SetBreakPoint(v8::Utils::OpenHandle(*fun), position);
213}
214
215
216// Set a break point in a function using the Debug object and return the
217// associated break point number.
218static int SetBreakPointFromJS(const char* function_name,
219 int line, int position) {
220 EmbeddedVector<char, SMALL_STRING_BUFFER_SIZE> buffer;
221 OS::SNPrintF(buffer,
222 "debug.Debug.setBreakPoint(%s,%d,%d)",
223 function_name, line, position);
224 buffer[SMALL_STRING_BUFFER_SIZE - 1] = '\0';
225 v8::Handle<v8::String> str = v8::String::New(buffer.start());
226 return v8::Script::Compile(str)->Run()->Int32Value();
227}
228
229
230// Set a break point in a script identified by id using the global Debug object.
231static int SetScriptBreakPointByIdFromJS(int script_id, int line, int column) {
232 EmbeddedVector<char, SMALL_STRING_BUFFER_SIZE> buffer;
233 if (column >= 0) {
234 // Column specified set script break point on precise location.
235 OS::SNPrintF(buffer,
236 "debug.Debug.setScriptBreakPointById(%d,%d,%d)",
237 script_id, line, column);
238 } else {
239 // Column not specified set script break point on line.
240 OS::SNPrintF(buffer,
241 "debug.Debug.setScriptBreakPointById(%d,%d)",
242 script_id, line);
243 }
244 buffer[SMALL_STRING_BUFFER_SIZE - 1] = '\0';
245 {
246 v8::TryCatch try_catch;
247 v8::Handle<v8::String> str = v8::String::New(buffer.start());
248 v8::Handle<v8::Value> value = v8::Script::Compile(str)->Run();
249 CHECK(!try_catch.HasCaught());
250 return value->Int32Value();
251 }
252}
253
254
255// Set a break point in a script identified by name using the global Debug
256// object.
257static int SetScriptBreakPointByNameFromJS(const char* script_name,
258 int line, int column) {
259 EmbeddedVector<char, SMALL_STRING_BUFFER_SIZE> buffer;
260 if (column >= 0) {
261 // Column specified set script break point on precise location.
262 OS::SNPrintF(buffer,
263 "debug.Debug.setScriptBreakPointByName(\"%s\",%d,%d)",
264 script_name, line, column);
265 } else {
266 // Column not specified set script break point on line.
267 OS::SNPrintF(buffer,
268 "debug.Debug.setScriptBreakPointByName(\"%s\",%d)",
269 script_name, line);
270 }
271 buffer[SMALL_STRING_BUFFER_SIZE - 1] = '\0';
272 {
273 v8::TryCatch try_catch;
274 v8::Handle<v8::String> str = v8::String::New(buffer.start());
275 v8::Handle<v8::Value> value = v8::Script::Compile(str)->Run();
276 CHECK(!try_catch.HasCaught());
277 return value->Int32Value();
278 }
279}
280
281
282// Clear a break point.
283static void ClearBreakPoint(int break_point) {
Steve Block44f0eee2011-05-26 01:26:41 +0100284 v8::internal::Debug* debug = v8::internal::Isolate::Current()->debug();
285 debug->ClearBreakPoint(
Steve Blocka7e24c12009-10-30 11:49:00 +0000286 Handle<Object>(v8::internal::Smi::FromInt(break_point)));
287}
288
289
290// Clear a break point using the global Debug object.
291static void ClearBreakPointFromJS(int break_point_number) {
292 EmbeddedVector<char, SMALL_STRING_BUFFER_SIZE> buffer;
293 OS::SNPrintF(buffer,
294 "debug.Debug.clearBreakPoint(%d)",
295 break_point_number);
296 buffer[SMALL_STRING_BUFFER_SIZE - 1] = '\0';
297 v8::Script::Compile(v8::String::New(buffer.start()))->Run();
298}
299
300
301static void EnableScriptBreakPointFromJS(int break_point_number) {
302 EmbeddedVector<char, SMALL_STRING_BUFFER_SIZE> buffer;
303 OS::SNPrintF(buffer,
304 "debug.Debug.enableScriptBreakPoint(%d)",
305 break_point_number);
306 buffer[SMALL_STRING_BUFFER_SIZE - 1] = '\0';
307 v8::Script::Compile(v8::String::New(buffer.start()))->Run();
308}
309
310
311static void DisableScriptBreakPointFromJS(int break_point_number) {
312 EmbeddedVector<char, SMALL_STRING_BUFFER_SIZE> buffer;
313 OS::SNPrintF(buffer,
314 "debug.Debug.disableScriptBreakPoint(%d)",
315 break_point_number);
316 buffer[SMALL_STRING_BUFFER_SIZE - 1] = '\0';
317 v8::Script::Compile(v8::String::New(buffer.start()))->Run();
318}
319
320
321static void ChangeScriptBreakPointConditionFromJS(int break_point_number,
322 const char* condition) {
323 EmbeddedVector<char, SMALL_STRING_BUFFER_SIZE> buffer;
324 OS::SNPrintF(buffer,
325 "debug.Debug.changeScriptBreakPointCondition(%d, \"%s\")",
326 break_point_number, condition);
327 buffer[SMALL_STRING_BUFFER_SIZE - 1] = '\0';
328 v8::Script::Compile(v8::String::New(buffer.start()))->Run();
329}
330
331
332static void ChangeScriptBreakPointIgnoreCountFromJS(int break_point_number,
333 int ignoreCount) {
334 EmbeddedVector<char, SMALL_STRING_BUFFER_SIZE> buffer;
335 OS::SNPrintF(buffer,
336 "debug.Debug.changeScriptBreakPointIgnoreCount(%d, %d)",
337 break_point_number, ignoreCount);
338 buffer[SMALL_STRING_BUFFER_SIZE - 1] = '\0';
339 v8::Script::Compile(v8::String::New(buffer.start()))->Run();
340}
341
342
343// Change break on exception.
344static void ChangeBreakOnException(bool caught, bool uncaught) {
Steve Block44f0eee2011-05-26 01:26:41 +0100345 v8::internal::Debug* debug = v8::internal::Isolate::Current()->debug();
346 debug->ChangeBreakOnException(v8::internal::BreakException, caught);
347 debug->ChangeBreakOnException(v8::internal::BreakUncaughtException, uncaught);
Steve Blocka7e24c12009-10-30 11:49:00 +0000348}
349
350
351// Change break on exception using the global Debug object.
352static void ChangeBreakOnExceptionFromJS(bool caught, bool uncaught) {
353 if (caught) {
354 v8::Script::Compile(
355 v8::String::New("debug.Debug.setBreakOnException()"))->Run();
356 } else {
357 v8::Script::Compile(
358 v8::String::New("debug.Debug.clearBreakOnException()"))->Run();
359 }
360 if (uncaught) {
361 v8::Script::Compile(
362 v8::String::New("debug.Debug.setBreakOnUncaughtException()"))->Run();
363 } else {
364 v8::Script::Compile(
365 v8::String::New("debug.Debug.clearBreakOnUncaughtException()"))->Run();
366 }
367}
368
369
370// Prepare to step to next break location.
371static void PrepareStep(StepAction step_action) {
Steve Block44f0eee2011-05-26 01:26:41 +0100372 v8::internal::Debug* debug = v8::internal::Isolate::Current()->debug();
373 debug->PrepareStep(step_action, 1);
Steve Blocka7e24c12009-10-30 11:49:00 +0000374}
375
376
377// This function is in namespace v8::internal to be friend with class
378// v8::internal::Debug.
379namespace v8 {
380namespace internal {
381
382// Collect the currently debugged functions.
383Handle<FixedArray> GetDebuggedFunctions() {
Steve Block44f0eee2011-05-26 01:26:41 +0100384 Debug* debug = Isolate::Current()->debug();
385
386 v8::internal::DebugInfoListNode* node = debug->debug_info_list_;
Steve Blocka7e24c12009-10-30 11:49:00 +0000387
388 // Find the number of debugged functions.
389 int count = 0;
390 while (node) {
391 count++;
392 node = node->next();
393 }
394
395 // Allocate array for the debugged functions
396 Handle<FixedArray> debugged_functions =
Steve Block44f0eee2011-05-26 01:26:41 +0100397 FACTORY->NewFixedArray(count);
Steve Blocka7e24c12009-10-30 11:49:00 +0000398
399 // Run through the debug info objects and collect all functions.
400 count = 0;
401 while (node) {
402 debugged_functions->set(count++, *node->debug_info());
403 node = node->next();
404 }
405
406 return debugged_functions;
407}
408
409
410static Handle<Code> ComputeCallDebugBreak(int argc) {
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100411 CALL_HEAP_FUNCTION(
Steve Block44f0eee2011-05-26 01:26:41 +0100412 v8::internal::Isolate::Current(),
413 v8::internal::Isolate::Current()->stub_cache()->ComputeCallDebugBreak(
414 argc, Code::CALL_IC),
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100415 Code);
Steve Blocka7e24c12009-10-30 11:49:00 +0000416}
417
418
419// Check that the debugger has been fully unloaded.
420void CheckDebuggerUnloaded(bool check_functions) {
421 // Check that the debugger context is cleared and that there is no debug
422 // information stored for the debugger.
Steve Block44f0eee2011-05-26 01:26:41 +0100423 CHECK(Isolate::Current()->debug()->debug_context().is_null());
424 CHECK_EQ(NULL, Isolate::Current()->debug()->debug_info_list_);
Steve Blocka7e24c12009-10-30 11:49:00 +0000425
426 // Collect garbage to ensure weak handles are cleared.
Steve Block44f0eee2011-05-26 01:26:41 +0100427 HEAP->CollectAllGarbage(false);
428 HEAP->CollectAllGarbage(false);
Steve Blocka7e24c12009-10-30 11:49:00 +0000429
430 // Iterate the head and check that there are no debugger related objects left.
431 HeapIterator iterator;
Leon Clarked91b9f72010-01-27 17:25:45 +0000432 for (HeapObject* obj = iterator.next(); obj != NULL; obj = iterator.next()) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000433 CHECK(!obj->IsDebugInfo());
434 CHECK(!obj->IsBreakPointInfo());
435
436 // If deep check of functions is requested check that no debug break code
437 // is left in all functions.
438 if (check_functions) {
439 if (obj->IsJSFunction()) {
440 JSFunction* fun = JSFunction::cast(obj);
441 for (RelocIterator it(fun->shared()->code()); !it.done(); it.next()) {
442 RelocInfo::Mode rmode = it.rinfo()->rmode();
443 if (RelocInfo::IsCodeTarget(rmode)) {
444 CHECK(!Debug::IsDebugBreak(it.rinfo()->target_address()));
445 } else if (RelocInfo::IsJSReturn(rmode)) {
446 CHECK(!Debug::IsDebugBreakAtReturn(it.rinfo()));
447 }
448 }
449 }
450 }
451 }
452}
453
454
Steve Block6ded16b2010-05-10 14:33:55 +0100455void ForceUnloadDebugger() {
Steve Block44f0eee2011-05-26 01:26:41 +0100456 Isolate::Current()->debugger()->never_unload_debugger_ = false;
457 Isolate::Current()->debugger()->UnloadDebugger();
Steve Block6ded16b2010-05-10 14:33:55 +0100458}
459
460
Steve Blocka7e24c12009-10-30 11:49:00 +0000461} } // namespace v8::internal
462
463
464// Check that the debugger has been fully unloaded.
465static void CheckDebuggerUnloaded(bool check_functions = false) {
Leon Clarkee46be812010-01-19 14:06:41 +0000466 // Let debugger to unload itself synchronously
467 v8::Debug::ProcessDebugMessages();
468
Steve Blocka7e24c12009-10-30 11:49:00 +0000469 v8::internal::CheckDebuggerUnloaded(check_functions);
470}
471
472
473// Inherit from BreakLocationIterator to get access to protected parts for
474// testing.
475class TestBreakLocationIterator: public v8::internal::BreakLocationIterator {
476 public:
477 explicit TestBreakLocationIterator(Handle<v8::internal::DebugInfo> debug_info)
478 : BreakLocationIterator(debug_info, v8::internal::SOURCE_BREAK_LOCATIONS) {}
479 v8::internal::RelocIterator* it() { return reloc_iterator_; }
480 v8::internal::RelocIterator* it_original() {
481 return reloc_iterator_original_;
482 }
483};
484
485
486// Compile a function, set a break point and check that the call at the break
487// location in the code is the expected debug_break function.
488void CheckDebugBreakFunction(DebugLocalContext* env,
489 const char* source, const char* name,
490 int position, v8::internal::RelocInfo::Mode mode,
491 Code* debug_break) {
Steve Block44f0eee2011-05-26 01:26:41 +0100492 v8::internal::Debug* debug = v8::internal::Isolate::Current()->debug();
493
Steve Blocka7e24c12009-10-30 11:49:00 +0000494 // Create function and set the break point.
495 Handle<v8::internal::JSFunction> fun = v8::Utils::OpenHandle(
496 *CompileFunction(env, source, name));
497 int bp = SetBreakPoint(fun, position);
498
499 // Check that the debug break function is as expected.
500 Handle<v8::internal::SharedFunctionInfo> shared(fun->shared());
501 CHECK(Debug::HasDebugInfo(shared));
502 TestBreakLocationIterator it1(Debug::GetDebugInfo(shared));
503 it1.FindBreakLocationFromPosition(position);
Ben Murdoch257744e2011-11-30 15:57:28 +0000504 v8::internal::RelocInfo::Mode actual_mode = it1.it()->rinfo()->rmode();
505 if (actual_mode == v8::internal::RelocInfo::CODE_TARGET_WITH_ID) {
506 actual_mode = v8::internal::RelocInfo::CODE_TARGET;
507 }
508 CHECK_EQ(mode, actual_mode);
Steve Blocka7e24c12009-10-30 11:49:00 +0000509 if (mode != v8::internal::RelocInfo::JS_RETURN) {
510 CHECK_EQ(debug_break,
511 Code::GetCodeFromTargetAddress(it1.it()->rinfo()->target_address()));
512 } else {
513 CHECK(Debug::IsDebugBreakAtReturn(it1.it()->rinfo()));
514 }
515
516 // Clear the break point and check that the debug break function is no longer
517 // there
518 ClearBreakPoint(bp);
Steve Block44f0eee2011-05-26 01:26:41 +0100519 CHECK(!debug->HasDebugInfo(shared));
520 CHECK(debug->EnsureDebugInfo(shared));
Steve Blocka7e24c12009-10-30 11:49:00 +0000521 TestBreakLocationIterator it2(Debug::GetDebugInfo(shared));
522 it2.FindBreakLocationFromPosition(position);
Ben Murdoch257744e2011-11-30 15:57:28 +0000523 actual_mode = it2.it()->rinfo()->rmode();
524 if (actual_mode == v8::internal::RelocInfo::CODE_TARGET_WITH_ID) {
525 actual_mode = v8::internal::RelocInfo::CODE_TARGET;
526 }
527 CHECK_EQ(mode, actual_mode);
Steve Blocka7e24c12009-10-30 11:49:00 +0000528 if (mode == v8::internal::RelocInfo::JS_RETURN) {
529 CHECK(!Debug::IsDebugBreakAtReturn(it2.it()->rinfo()));
530 }
531}
532
533
534// --- D e b u g E v e n t H a n d l e r s
535// ---
536// --- The different tests uses a number of debug event handlers.
537// ---
538
539
Ben Murdochb0fe1622011-05-05 13:52:32 +0100540// Source for the JavaScript function which picks out the function
541// name of a frame.
Steve Blocka7e24c12009-10-30 11:49:00 +0000542const char* frame_function_name_source =
Ben Murdochb0fe1622011-05-05 13:52:32 +0100543 "function frame_function_name(exec_state, frame_number) {"
544 " return exec_state.frame(frame_number).func().name();"
Steve Blocka7e24c12009-10-30 11:49:00 +0000545 "}";
546v8::Local<v8::Function> frame_function_name;
547
548
Ben Murdochb0fe1622011-05-05 13:52:32 +0100549// Source for the JavaScript function which pick out the name of the
550// first argument of a frame.
551const char* frame_argument_name_source =
552 "function frame_argument_name(exec_state, frame_number) {"
553 " return exec_state.frame(frame_number).argumentName(0);"
554 "}";
555v8::Local<v8::Function> frame_argument_name;
556
557
558// Source for the JavaScript function which pick out the value of the
559// first argument of a frame.
560const char* frame_argument_value_source =
561 "function frame_argument_value(exec_state, frame_number) {"
562 " return exec_state.frame(frame_number).argumentValue(0).value_;"
563 "}";
564v8::Local<v8::Function> frame_argument_value;
565
566
567// Source for the JavaScript function which pick out the name of the
568// first argument of a frame.
569const char* frame_local_name_source =
570 "function frame_local_name(exec_state, frame_number) {"
571 " return exec_state.frame(frame_number).localName(0);"
572 "}";
573v8::Local<v8::Function> frame_local_name;
574
575
576// Source for the JavaScript function which pick out the value of the
577// first argument of a frame.
578const char* frame_local_value_source =
579 "function frame_local_value(exec_state, frame_number) {"
580 " return exec_state.frame(frame_number).localValue(0).value_;"
581 "}";
582v8::Local<v8::Function> frame_local_value;
583
584
585// Source for the JavaScript function which picks out the source line for the
Steve Blocka7e24c12009-10-30 11:49:00 +0000586// top frame.
587const char* frame_source_line_source =
588 "function frame_source_line(exec_state) {"
589 " return exec_state.frame(0).sourceLine();"
590 "}";
591v8::Local<v8::Function> frame_source_line;
592
593
Ben Murdochb0fe1622011-05-05 13:52:32 +0100594// Source for the JavaScript function which picks out the source column for the
Steve Blocka7e24c12009-10-30 11:49:00 +0000595// top frame.
596const char* frame_source_column_source =
597 "function frame_source_column(exec_state) {"
598 " return exec_state.frame(0).sourceColumn();"
599 "}";
600v8::Local<v8::Function> frame_source_column;
601
602
Ben Murdochb0fe1622011-05-05 13:52:32 +0100603// Source for the JavaScript function which picks out the script name for the
Steve Blocka7e24c12009-10-30 11:49:00 +0000604// top frame.
605const char* frame_script_name_source =
606 "function frame_script_name(exec_state) {"
607 " return exec_state.frame(0).func().script().name();"
608 "}";
609v8::Local<v8::Function> frame_script_name;
610
611
Ben Murdochb0fe1622011-05-05 13:52:32 +0100612// Source for the JavaScript function which picks out the script data for the
Steve Blocka7e24c12009-10-30 11:49:00 +0000613// top frame.
614const char* frame_script_data_source =
615 "function frame_script_data(exec_state) {"
616 " return exec_state.frame(0).func().script().data();"
617 "}";
618v8::Local<v8::Function> frame_script_data;
619
620
Ben Murdochb0fe1622011-05-05 13:52:32 +0100621// Source for the JavaScript function which picks out the script data from
Andrei Popescu402d9372010-02-26 13:31:12 +0000622// AfterCompile event
623const char* compiled_script_data_source =
624 "function compiled_script_data(event_data) {"
625 " return event_data.script().data();"
626 "}";
627v8::Local<v8::Function> compiled_script_data;
628
629
Ben Murdochb0fe1622011-05-05 13:52:32 +0100630// Source for the JavaScript function which returns the number of frames.
Steve Blocka7e24c12009-10-30 11:49:00 +0000631static const char* frame_count_source =
632 "function frame_count(exec_state) {"
633 " return exec_state.frameCount();"
634 "}";
635v8::Handle<v8::Function> frame_count;
636
637
638// Global variable to store the last function hit - used by some tests.
639char last_function_hit[80];
640
641// Global variable to store the name and data for last script hit - used by some
642// tests.
643char last_script_name_hit[80];
644char last_script_data_hit[80];
645
646// Global variables to store the last source position - used by some tests.
647int last_source_line = -1;
648int last_source_column = -1;
649
650// Debug event handler which counts the break points which have been hit.
651int break_point_hit_count = 0;
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000652int break_point_hit_count_deoptimize = 0;
Steve Blocka7e24c12009-10-30 11:49:00 +0000653static void DebugEventBreakPointHitCount(v8::DebugEvent event,
654 v8::Handle<v8::Object> exec_state,
655 v8::Handle<v8::Object> event_data,
656 v8::Handle<v8::Value> data) {
Steve Block44f0eee2011-05-26 01:26:41 +0100657 Debug* debug = v8::internal::Isolate::Current()->debug();
Steve Blocka7e24c12009-10-30 11:49:00 +0000658 // When hitting a debug event listener there must be a break set.
Steve Block44f0eee2011-05-26 01:26:41 +0100659 CHECK_NE(debug->break_id(), 0);
Steve Blocka7e24c12009-10-30 11:49:00 +0000660
661 // Count the number of breaks.
662 if (event == v8::Break) {
663 break_point_hit_count++;
664 if (!frame_function_name.IsEmpty()) {
665 // Get the name of the function.
Ben Murdochb0fe1622011-05-05 13:52:32 +0100666 const int argc = 2;
667 v8::Handle<v8::Value> argv[argc] = { exec_state, v8::Integer::New(0) };
Steve Blocka7e24c12009-10-30 11:49:00 +0000668 v8::Handle<v8::Value> result = frame_function_name->Call(exec_state,
669 argc, argv);
670 if (result->IsUndefined()) {
671 last_function_hit[0] = '\0';
672 } else {
673 CHECK(result->IsString());
674 v8::Handle<v8::String> function_name(result->ToString());
675 function_name->WriteAscii(last_function_hit);
676 }
677 }
678
679 if (!frame_source_line.IsEmpty()) {
680 // Get the source line.
681 const int argc = 1;
682 v8::Handle<v8::Value> argv[argc] = { exec_state };
683 v8::Handle<v8::Value> result = frame_source_line->Call(exec_state,
684 argc, argv);
685 CHECK(result->IsNumber());
686 last_source_line = result->Int32Value();
687 }
688
689 if (!frame_source_column.IsEmpty()) {
690 // Get the source column.
691 const int argc = 1;
692 v8::Handle<v8::Value> argv[argc] = { exec_state };
693 v8::Handle<v8::Value> result = frame_source_column->Call(exec_state,
694 argc, argv);
695 CHECK(result->IsNumber());
696 last_source_column = result->Int32Value();
697 }
698
699 if (!frame_script_name.IsEmpty()) {
700 // Get the script name of the function script.
701 const int argc = 1;
702 v8::Handle<v8::Value> argv[argc] = { exec_state };
703 v8::Handle<v8::Value> result = frame_script_name->Call(exec_state,
704 argc, argv);
705 if (result->IsUndefined()) {
706 last_script_name_hit[0] = '\0';
707 } else {
708 CHECK(result->IsString());
709 v8::Handle<v8::String> script_name(result->ToString());
710 script_name->WriteAscii(last_script_name_hit);
711 }
712 }
713
714 if (!frame_script_data.IsEmpty()) {
715 // Get the script data of the function script.
716 const int argc = 1;
717 v8::Handle<v8::Value> argv[argc] = { exec_state };
718 v8::Handle<v8::Value> result = frame_script_data->Call(exec_state,
719 argc, argv);
720 if (result->IsUndefined()) {
721 last_script_data_hit[0] = '\0';
722 } else {
723 result = result->ToString();
724 CHECK(result->IsString());
725 v8::Handle<v8::String> script_data(result->ToString());
726 script_data->WriteAscii(last_script_data_hit);
727 }
728 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000729
730 // Perform a full deoptimization when the specified number of
731 // breaks have been hit.
732 if (break_point_hit_count == break_point_hit_count_deoptimize) {
733 i::Deoptimizer::DeoptimizeAll();
734 }
Andrei Popescu402d9372010-02-26 13:31:12 +0000735 } else if (event == v8::AfterCompile && !compiled_script_data.IsEmpty()) {
736 const int argc = 1;
737 v8::Handle<v8::Value> argv[argc] = { event_data };
738 v8::Handle<v8::Value> result = compiled_script_data->Call(exec_state,
739 argc, argv);
740 if (result->IsUndefined()) {
741 last_script_data_hit[0] = '\0';
742 } else {
743 result = result->ToString();
744 CHECK(result->IsString());
745 v8::Handle<v8::String> script_data(result->ToString());
746 script_data->WriteAscii(last_script_data_hit);
747 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000748 }
749}
750
751
752// Debug event handler which counts a number of events and collects the stack
753// height if there is a function compiled for that.
754int exception_hit_count = 0;
755int uncaught_exception_hit_count = 0;
756int last_js_stack_height = -1;
757
758static void DebugEventCounterClear() {
759 break_point_hit_count = 0;
760 exception_hit_count = 0;
761 uncaught_exception_hit_count = 0;
762}
763
764static void DebugEventCounter(v8::DebugEvent event,
765 v8::Handle<v8::Object> exec_state,
766 v8::Handle<v8::Object> event_data,
767 v8::Handle<v8::Value> data) {
Steve Block44f0eee2011-05-26 01:26:41 +0100768 v8::internal::Debug* debug = v8::internal::Isolate::Current()->debug();
769
Steve Blocka7e24c12009-10-30 11:49:00 +0000770 // When hitting a debug event listener there must be a break set.
Steve Block44f0eee2011-05-26 01:26:41 +0100771 CHECK_NE(debug->break_id(), 0);
Steve Blocka7e24c12009-10-30 11:49:00 +0000772
773 // Count the number of breaks.
774 if (event == v8::Break) {
775 break_point_hit_count++;
776 } else if (event == v8::Exception) {
777 exception_hit_count++;
778
779 // Check whether the exception was uncaught.
780 v8::Local<v8::String> fun_name = v8::String::New("uncaught");
781 v8::Local<v8::Function> fun =
782 v8::Function::Cast(*event_data->Get(fun_name));
783 v8::Local<v8::Value> result = *fun->Call(event_data, 0, NULL);
784 if (result->IsTrue()) {
785 uncaught_exception_hit_count++;
786 }
787 }
788
789 // Collect the JavsScript stack height if the function frame_count is
790 // compiled.
791 if (!frame_count.IsEmpty()) {
792 static const int kArgc = 1;
793 v8::Handle<v8::Value> argv[kArgc] = { exec_state };
794 // Using exec_state as receiver is just to have a receiver.
795 v8::Handle<v8::Value> result = frame_count->Call(exec_state, kArgc, argv);
796 last_js_stack_height = result->Int32Value();
797 }
798}
799
800
801// Debug event handler which evaluates a number of expressions when a break
802// point is hit. Each evaluated expression is compared with an expected value.
803// For this debug event handler to work the following two global varaibles
804// must be initialized.
805// checks: An array of expressions and expected results
806// evaluate_check_function: A JavaScript function (see below)
807
808// Structure for holding checks to do.
809struct EvaluateCheck {
810 const char* expr; // An expression to evaluate when a break point is hit.
811 v8::Handle<v8::Value> expected; // The expected result.
812};
813// Array of checks to do.
814struct EvaluateCheck* checks = NULL;
815// Source for The JavaScript function which can do the evaluation when a break
816// point is hit.
817const char* evaluate_check_source =
818 "function evaluate_check(exec_state, expr, expected) {"
819 " return exec_state.frame(0).evaluate(expr).value() === expected;"
820 "}";
821v8::Local<v8::Function> evaluate_check_function;
822
823// The actual debug event described by the longer comment above.
824static void DebugEventEvaluate(v8::DebugEvent event,
825 v8::Handle<v8::Object> exec_state,
826 v8::Handle<v8::Object> event_data,
827 v8::Handle<v8::Value> data) {
Steve Block44f0eee2011-05-26 01:26:41 +0100828 v8::internal::Debug* debug = v8::internal::Isolate::Current()->debug();
Steve Blocka7e24c12009-10-30 11:49:00 +0000829 // When hitting a debug event listener there must be a break set.
Steve Block44f0eee2011-05-26 01:26:41 +0100830 CHECK_NE(debug->break_id(), 0);
Steve Blocka7e24c12009-10-30 11:49:00 +0000831
832 if (event == v8::Break) {
833 for (int i = 0; checks[i].expr != NULL; i++) {
834 const int argc = 3;
835 v8::Handle<v8::Value> argv[argc] = { exec_state,
836 v8::String::New(checks[i].expr),
837 checks[i].expected };
838 v8::Handle<v8::Value> result =
839 evaluate_check_function->Call(exec_state, argc, argv);
840 if (!result->IsTrue()) {
841 v8::String::AsciiValue ascii(checks[i].expected->ToString());
842 V8_Fatal(__FILE__, __LINE__, "%s != %s", checks[i].expr, *ascii);
843 }
844 }
845 }
846}
847
848
849// This debug event listener removes a breakpoint in a function
850int debug_event_remove_break_point = 0;
851static void DebugEventRemoveBreakPoint(v8::DebugEvent event,
852 v8::Handle<v8::Object> exec_state,
853 v8::Handle<v8::Object> event_data,
854 v8::Handle<v8::Value> data) {
Steve Block44f0eee2011-05-26 01:26:41 +0100855 v8::internal::Debug* debug = v8::internal::Isolate::Current()->debug();
Steve Blocka7e24c12009-10-30 11:49:00 +0000856 // When hitting a debug event listener there must be a break set.
Steve Block44f0eee2011-05-26 01:26:41 +0100857 CHECK_NE(debug->break_id(), 0);
Steve Blocka7e24c12009-10-30 11:49:00 +0000858
859 if (event == v8::Break) {
860 break_point_hit_count++;
861 v8::Handle<v8::Function> fun = v8::Handle<v8::Function>::Cast(data);
862 ClearBreakPoint(debug_event_remove_break_point);
863 }
864}
865
866
867// Debug event handler which counts break points hit and performs a step
868// afterwards.
869StepAction step_action = StepIn; // Step action to perform when stepping.
870static void DebugEventStep(v8::DebugEvent event,
871 v8::Handle<v8::Object> exec_state,
872 v8::Handle<v8::Object> event_data,
873 v8::Handle<v8::Value> data) {
Steve Block44f0eee2011-05-26 01:26:41 +0100874 v8::internal::Debug* debug = v8::internal::Isolate::Current()->debug();
Steve Blocka7e24c12009-10-30 11:49:00 +0000875 // When hitting a debug event listener there must be a break set.
Steve Block44f0eee2011-05-26 01:26:41 +0100876 CHECK_NE(debug->break_id(), 0);
Steve Blocka7e24c12009-10-30 11:49:00 +0000877
878 if (event == v8::Break) {
879 break_point_hit_count++;
880 PrepareStep(step_action);
881 }
882}
883
884
885// Debug event handler which counts break points hit and performs a step
886// afterwards. For each call the expected function is checked.
887// For this debug event handler to work the following two global varaibles
888// must be initialized.
889// expected_step_sequence: An array of the expected function call sequence.
890// frame_function_name: A JavaScript function (see below).
891
892// String containing the expected function call sequence. Note: this only works
893// if functions have name length of one.
894const char* expected_step_sequence = NULL;
895
896// The actual debug event described by the longer comment above.
897static void DebugEventStepSequence(v8::DebugEvent event,
898 v8::Handle<v8::Object> exec_state,
899 v8::Handle<v8::Object> event_data,
900 v8::Handle<v8::Value> data) {
Steve Block44f0eee2011-05-26 01:26:41 +0100901 v8::internal::Debug* debug = v8::internal::Isolate::Current()->debug();
Steve Blocka7e24c12009-10-30 11:49:00 +0000902 // When hitting a debug event listener there must be a break set.
Steve Block44f0eee2011-05-26 01:26:41 +0100903 CHECK_NE(debug->break_id(), 0);
Steve Blocka7e24c12009-10-30 11:49:00 +0000904
905 if (event == v8::Break || event == v8::Exception) {
906 // Check that the current function is the expected.
907 CHECK(break_point_hit_count <
Steve Blockd0582a62009-12-15 09:54:21 +0000908 StrLength(expected_step_sequence));
Ben Murdochb0fe1622011-05-05 13:52:32 +0100909 const int argc = 2;
910 v8::Handle<v8::Value> argv[argc] = { exec_state, v8::Integer::New(0) };
Steve Blocka7e24c12009-10-30 11:49:00 +0000911 v8::Handle<v8::Value> result = frame_function_name->Call(exec_state,
912 argc, argv);
913 CHECK(result->IsString());
914 v8::String::AsciiValue function_name(result->ToString());
Steve Blockd0582a62009-12-15 09:54:21 +0000915 CHECK_EQ(1, StrLength(*function_name));
Steve Blocka7e24c12009-10-30 11:49:00 +0000916 CHECK_EQ((*function_name)[0],
917 expected_step_sequence[break_point_hit_count]);
918
919 // Perform step.
920 break_point_hit_count++;
921 PrepareStep(step_action);
922 }
923}
924
925
926// Debug event handler which performs a garbage collection.
927static void DebugEventBreakPointCollectGarbage(
928 v8::DebugEvent event,
929 v8::Handle<v8::Object> exec_state,
930 v8::Handle<v8::Object> event_data,
931 v8::Handle<v8::Value> data) {
Steve Block44f0eee2011-05-26 01:26:41 +0100932 v8::internal::Debug* debug = v8::internal::Isolate::Current()->debug();
Steve Blocka7e24c12009-10-30 11:49:00 +0000933 // When hitting a debug event listener there must be a break set.
Steve Block44f0eee2011-05-26 01:26:41 +0100934 CHECK_NE(debug->break_id(), 0);
Steve Blocka7e24c12009-10-30 11:49:00 +0000935
936 // Perform a garbage collection when break point is hit and continue. Based
937 // on the number of break points hit either scavenge or mark compact
938 // collector is used.
939 if (event == v8::Break) {
940 break_point_hit_count++;
941 if (break_point_hit_count % 2 == 0) {
942 // Scavenge.
Steve Block44f0eee2011-05-26 01:26:41 +0100943 HEAP->CollectGarbage(v8::internal::NEW_SPACE);
Steve Blocka7e24c12009-10-30 11:49:00 +0000944 } else {
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100945 // Mark sweep compact.
Steve Block44f0eee2011-05-26 01:26:41 +0100946 HEAP->CollectAllGarbage(true);
Steve Blocka7e24c12009-10-30 11:49:00 +0000947 }
948 }
949}
950
951
952// Debug event handler which re-issues a debug break and calls the garbage
953// collector to have the heap verified.
954static void DebugEventBreak(v8::DebugEvent event,
955 v8::Handle<v8::Object> exec_state,
956 v8::Handle<v8::Object> event_data,
957 v8::Handle<v8::Value> data) {
Steve Block44f0eee2011-05-26 01:26:41 +0100958 v8::internal::Debug* debug = v8::internal::Isolate::Current()->debug();
Steve Blocka7e24c12009-10-30 11:49:00 +0000959 // When hitting a debug event listener there must be a break set.
Steve Block44f0eee2011-05-26 01:26:41 +0100960 CHECK_NE(debug->break_id(), 0);
Steve Blocka7e24c12009-10-30 11:49:00 +0000961
962 if (event == v8::Break) {
963 // Count the number of breaks.
964 break_point_hit_count++;
965
966 // Run the garbage collector to enforce heap verification if option
967 // --verify-heap is set.
Steve Block44f0eee2011-05-26 01:26:41 +0100968 HEAP->CollectGarbage(v8::internal::NEW_SPACE);
Steve Blocka7e24c12009-10-30 11:49:00 +0000969
970 // Set the break flag again to come back here as soon as possible.
971 v8::Debug::DebugBreak();
972 }
973}
974
975
Steve Blockd0582a62009-12-15 09:54:21 +0000976// Debug event handler which re-issues a debug break until a limit has been
977// reached.
978int max_break_point_hit_count = 0;
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -0800979bool terminate_after_max_break_point_hit = false;
Steve Blockd0582a62009-12-15 09:54:21 +0000980static void DebugEventBreakMax(v8::DebugEvent event,
981 v8::Handle<v8::Object> exec_state,
982 v8::Handle<v8::Object> event_data,
983 v8::Handle<v8::Value> data) {
Steve Block44f0eee2011-05-26 01:26:41 +0100984 v8::internal::Debug* debug = v8::internal::Isolate::Current()->debug();
Steve Blockd0582a62009-12-15 09:54:21 +0000985 // When hitting a debug event listener there must be a break set.
Steve Block44f0eee2011-05-26 01:26:41 +0100986 CHECK_NE(debug->break_id(), 0);
Steve Blockd0582a62009-12-15 09:54:21 +0000987
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -0800988 if (event == v8::Break) {
989 if (break_point_hit_count < max_break_point_hit_count) {
990 // Count the number of breaks.
991 break_point_hit_count++;
Steve Blockd0582a62009-12-15 09:54:21 +0000992
Ben Murdoch3fb3ca82011-12-02 17:19:32 +0000993 // Collect the JavsScript stack height if the function frame_count is
994 // compiled.
995 if (!frame_count.IsEmpty()) {
996 static const int kArgc = 1;
997 v8::Handle<v8::Value> argv[kArgc] = { exec_state };
998 // Using exec_state as receiver is just to have a receiver.
999 v8::Handle<v8::Value> result =
1000 frame_count->Call(exec_state, kArgc, argv);
1001 last_js_stack_height = result->Int32Value();
1002 }
1003
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -08001004 // Set the break flag again to come back here as soon as possible.
1005 v8::Debug::DebugBreak();
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001006
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -08001007 } else if (terminate_after_max_break_point_hit) {
1008 // Terminate execution after the last break if requested.
1009 v8::V8::TerminateExecution();
1010 }
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00001011
1012 // Perform a full deoptimization when the specified number of
1013 // breaks have been hit.
1014 if (break_point_hit_count == break_point_hit_count_deoptimize) {
1015 i::Deoptimizer::DeoptimizeAll();
1016 }
Steve Blockd0582a62009-12-15 09:54:21 +00001017 }
1018}
1019
1020
Steve Blocka7e24c12009-10-30 11:49:00 +00001021// --- M e s s a g e C a l l b a c k
1022
1023
1024// Message callback which counts the number of messages.
1025int message_callback_count = 0;
1026
1027static void MessageCallbackCountClear() {
1028 message_callback_count = 0;
1029}
1030
1031static void MessageCallbackCount(v8::Handle<v8::Message> message,
1032 v8::Handle<v8::Value> data) {
1033 message_callback_count++;
1034}
1035
1036
1037// --- T h e A c t u a l T e s t s
1038
1039
1040// Test that the debug break function is the expected one for different kinds
1041// of break locations.
1042TEST(DebugStub) {
1043 using ::v8::internal::Builtins;
Steve Block44f0eee2011-05-26 01:26:41 +01001044 using ::v8::internal::Isolate;
Steve Blocka7e24c12009-10-30 11:49:00 +00001045 v8::HandleScope scope;
1046 DebugLocalContext env;
1047
1048 CheckDebugBreakFunction(&env,
1049 "function f1(){}", "f1",
1050 0,
1051 v8::internal::RelocInfo::JS_RETURN,
1052 NULL);
1053 CheckDebugBreakFunction(&env,
1054 "function f2(){x=1;}", "f2",
1055 0,
Steve Block1e0659c2011-05-24 12:43:12 +01001056 v8::internal::RelocInfo::CODE_TARGET_CONTEXT,
Steve Block44f0eee2011-05-26 01:26:41 +01001057 Isolate::Current()->builtins()->builtin(
1058 Builtins::kStoreIC_DebugBreak));
Steve Blocka7e24c12009-10-30 11:49:00 +00001059 CheckDebugBreakFunction(&env,
1060 "function f3(){var a=x;}", "f3",
1061 0,
1062 v8::internal::RelocInfo::CODE_TARGET_CONTEXT,
Steve Block44f0eee2011-05-26 01:26:41 +01001063 Isolate::Current()->builtins()->builtin(
1064 Builtins::kLoadIC_DebugBreak));
Steve Blocka7e24c12009-10-30 11:49:00 +00001065
1066// TODO(1240753): Make the test architecture independent or split
1067// parts of the debugger into architecture dependent files. This
1068// part currently disabled as it is not portable between IA32/ARM.
1069// Currently on ICs for keyed store/load on ARM.
1070#if !defined (__arm__) && !defined(__thumb__)
1071 CheckDebugBreakFunction(
1072 &env,
1073 "function f4(){var index='propertyName'; var a={}; a[index] = 'x';}",
1074 "f4",
1075 0,
1076 v8::internal::RelocInfo::CODE_TARGET,
Steve Block44f0eee2011-05-26 01:26:41 +01001077 Isolate::Current()->builtins()->builtin(
1078 Builtins::kKeyedStoreIC_DebugBreak));
Steve Blocka7e24c12009-10-30 11:49:00 +00001079 CheckDebugBreakFunction(
1080 &env,
1081 "function f5(){var index='propertyName'; var a={}; return a[index];}",
1082 "f5",
1083 0,
1084 v8::internal::RelocInfo::CODE_TARGET,
Steve Block44f0eee2011-05-26 01:26:41 +01001085 Isolate::Current()->builtins()->builtin(
1086 Builtins::kKeyedLoadIC_DebugBreak));
Steve Blocka7e24c12009-10-30 11:49:00 +00001087#endif
1088
1089 // Check the debug break code stubs for call ICs with different number of
1090 // parameters.
1091 Handle<Code> debug_break_0 = v8::internal::ComputeCallDebugBreak(0);
1092 Handle<Code> debug_break_1 = v8::internal::ComputeCallDebugBreak(1);
1093 Handle<Code> debug_break_4 = v8::internal::ComputeCallDebugBreak(4);
1094
1095 CheckDebugBreakFunction(&env,
1096 "function f4_0(){x();}", "f4_0",
1097 0,
1098 v8::internal::RelocInfo::CODE_TARGET_CONTEXT,
1099 *debug_break_0);
1100
1101 CheckDebugBreakFunction(&env,
1102 "function f4_1(){x(1);}", "f4_1",
1103 0,
1104 v8::internal::RelocInfo::CODE_TARGET_CONTEXT,
1105 *debug_break_1);
1106
1107 CheckDebugBreakFunction(&env,
1108 "function f4_4(){x(1,2,3,4);}", "f4_4",
1109 0,
1110 v8::internal::RelocInfo::CODE_TARGET_CONTEXT,
1111 *debug_break_4);
1112}
1113
1114
1115// Test that the debug info in the VM is in sync with the functions being
1116// debugged.
1117TEST(DebugInfo) {
1118 v8::HandleScope scope;
1119 DebugLocalContext env;
1120 // Create a couple of functions for the test.
1121 v8::Local<v8::Function> foo =
1122 CompileFunction(&env, "function foo(){}", "foo");
1123 v8::Local<v8::Function> bar =
1124 CompileFunction(&env, "function bar(){}", "bar");
1125 // Initially no functions are debugged.
1126 CHECK_EQ(0, v8::internal::GetDebuggedFunctions()->length());
1127 CHECK(!HasDebugInfo(foo));
1128 CHECK(!HasDebugInfo(bar));
1129 // One function (foo) is debugged.
1130 int bp1 = SetBreakPoint(foo, 0);
1131 CHECK_EQ(1, v8::internal::GetDebuggedFunctions()->length());
1132 CHECK(HasDebugInfo(foo));
1133 CHECK(!HasDebugInfo(bar));
1134 // Two functions are debugged.
1135 int bp2 = SetBreakPoint(bar, 0);
1136 CHECK_EQ(2, v8::internal::GetDebuggedFunctions()->length());
1137 CHECK(HasDebugInfo(foo));
1138 CHECK(HasDebugInfo(bar));
1139 // One function (bar) is debugged.
1140 ClearBreakPoint(bp1);
1141 CHECK_EQ(1, v8::internal::GetDebuggedFunctions()->length());
1142 CHECK(!HasDebugInfo(foo));
1143 CHECK(HasDebugInfo(bar));
1144 // No functions are debugged.
1145 ClearBreakPoint(bp2);
1146 CHECK_EQ(0, v8::internal::GetDebuggedFunctions()->length());
1147 CHECK(!HasDebugInfo(foo));
1148 CHECK(!HasDebugInfo(bar));
1149}
1150
1151
1152// Test that a break point can be set at an IC store location.
1153TEST(BreakPointICStore) {
1154 break_point_hit_count = 0;
1155 v8::HandleScope scope;
1156 DebugLocalContext env;
1157
1158 v8::Debug::SetDebugEventListener(DebugEventBreakPointHitCount,
1159 v8::Undefined());
1160 v8::Script::Compile(v8::String::New("function foo(){bar=0;}"))->Run();
1161 v8::Local<v8::Function> foo =
1162 v8::Local<v8::Function>::Cast(env->Global()->Get(v8::String::New("foo")));
1163
1164 // Run without breakpoints.
1165 foo->Call(env->Global(), 0, NULL);
1166 CHECK_EQ(0, break_point_hit_count);
1167
1168 // Run with breakpoint
1169 int bp = SetBreakPoint(foo, 0);
1170 foo->Call(env->Global(), 0, NULL);
1171 CHECK_EQ(1, break_point_hit_count);
1172 foo->Call(env->Global(), 0, NULL);
1173 CHECK_EQ(2, break_point_hit_count);
1174
1175 // Run without breakpoints.
1176 ClearBreakPoint(bp);
1177 foo->Call(env->Global(), 0, NULL);
1178 CHECK_EQ(2, break_point_hit_count);
1179
1180 v8::Debug::SetDebugEventListener(NULL);
1181 CheckDebuggerUnloaded();
1182}
1183
1184
1185// Test that a break point can be set at an IC load location.
1186TEST(BreakPointICLoad) {
1187 break_point_hit_count = 0;
1188 v8::HandleScope scope;
1189 DebugLocalContext env;
1190 v8::Debug::SetDebugEventListener(DebugEventBreakPointHitCount,
1191 v8::Undefined());
1192 v8::Script::Compile(v8::String::New("bar=1"))->Run();
1193 v8::Script::Compile(v8::String::New("function foo(){var x=bar;}"))->Run();
1194 v8::Local<v8::Function> foo =
1195 v8::Local<v8::Function>::Cast(env->Global()->Get(v8::String::New("foo")));
1196
1197 // Run without breakpoints.
1198 foo->Call(env->Global(), 0, NULL);
1199 CHECK_EQ(0, break_point_hit_count);
1200
Steve Block44f0eee2011-05-26 01:26:41 +01001201 // Run with breakpoint.
Steve Blocka7e24c12009-10-30 11:49:00 +00001202 int bp = SetBreakPoint(foo, 0);
1203 foo->Call(env->Global(), 0, NULL);
1204 CHECK_EQ(1, break_point_hit_count);
1205 foo->Call(env->Global(), 0, NULL);
1206 CHECK_EQ(2, break_point_hit_count);
1207
1208 // Run without breakpoints.
1209 ClearBreakPoint(bp);
1210 foo->Call(env->Global(), 0, NULL);
1211 CHECK_EQ(2, break_point_hit_count);
1212
1213 v8::Debug::SetDebugEventListener(NULL);
1214 CheckDebuggerUnloaded();
1215}
1216
1217
1218// Test that a break point can be set at an IC call location.
1219TEST(BreakPointICCall) {
1220 break_point_hit_count = 0;
1221 v8::HandleScope scope;
1222 DebugLocalContext env;
1223 v8::Debug::SetDebugEventListener(DebugEventBreakPointHitCount,
1224 v8::Undefined());
1225 v8::Script::Compile(v8::String::New("function bar(){}"))->Run();
1226 v8::Script::Compile(v8::String::New("function foo(){bar();}"))->Run();
1227 v8::Local<v8::Function> foo =
1228 v8::Local<v8::Function>::Cast(env->Global()->Get(v8::String::New("foo")));
1229
1230 // Run without breakpoints.
1231 foo->Call(env->Global(), 0, NULL);
1232 CHECK_EQ(0, break_point_hit_count);
1233
Steve Block44f0eee2011-05-26 01:26:41 +01001234 // Run with breakpoint
Steve Blocka7e24c12009-10-30 11:49:00 +00001235 int bp = SetBreakPoint(foo, 0);
1236 foo->Call(env->Global(), 0, NULL);
1237 CHECK_EQ(1, break_point_hit_count);
1238 foo->Call(env->Global(), 0, NULL);
1239 CHECK_EQ(2, break_point_hit_count);
1240
1241 // Run without breakpoints.
1242 ClearBreakPoint(bp);
1243 foo->Call(env->Global(), 0, NULL);
1244 CHECK_EQ(2, break_point_hit_count);
1245
1246 v8::Debug::SetDebugEventListener(NULL);
1247 CheckDebuggerUnloaded();
1248}
1249
1250
Kristian Monsen80d68ea2010-09-08 11:05:35 +01001251// Test that a break point can be set at an IC call location and survive a GC.
1252TEST(BreakPointICCallWithGC) {
1253 break_point_hit_count = 0;
1254 v8::HandleScope scope;
1255 DebugLocalContext env;
1256 v8::Debug::SetDebugEventListener(DebugEventBreakPointCollectGarbage,
1257 v8::Undefined());
1258 v8::Script::Compile(v8::String::New("function bar(){return 1;}"))->Run();
1259 v8::Script::Compile(v8::String::New("function foo(){return bar();}"))->Run();
1260 v8::Local<v8::Function> foo =
1261 v8::Local<v8::Function>::Cast(env->Global()->Get(v8::String::New("foo")));
1262
1263 // Run without breakpoints.
1264 CHECK_EQ(1, foo->Call(env->Global(), 0, NULL)->Int32Value());
1265 CHECK_EQ(0, break_point_hit_count);
1266
1267 // Run with breakpoint.
1268 int bp = SetBreakPoint(foo, 0);
1269 CHECK_EQ(1, foo->Call(env->Global(), 0, NULL)->Int32Value());
1270 CHECK_EQ(1, break_point_hit_count);
1271 CHECK_EQ(1, foo->Call(env->Global(), 0, NULL)->Int32Value());
1272 CHECK_EQ(2, break_point_hit_count);
1273
1274 // Run without breakpoints.
1275 ClearBreakPoint(bp);
1276 foo->Call(env->Global(), 0, NULL);
1277 CHECK_EQ(2, break_point_hit_count);
1278
1279 v8::Debug::SetDebugEventListener(NULL);
1280 CheckDebuggerUnloaded();
1281}
1282
1283
1284// Test that a break point can be set at an IC call location and survive a GC.
1285TEST(BreakPointConstructCallWithGC) {
1286 break_point_hit_count = 0;
1287 v8::HandleScope scope;
1288 DebugLocalContext env;
1289 v8::Debug::SetDebugEventListener(DebugEventBreakPointCollectGarbage,
1290 v8::Undefined());
1291 v8::Script::Compile(v8::String::New("function bar(){ this.x = 1;}"))->Run();
1292 v8::Script::Compile(v8::String::New(
1293 "function foo(){return new bar(1).x;}"))->Run();
1294 v8::Local<v8::Function> foo =
1295 v8::Local<v8::Function>::Cast(env->Global()->Get(v8::String::New("foo")));
1296
1297 // Run without breakpoints.
1298 CHECK_EQ(1, foo->Call(env->Global(), 0, NULL)->Int32Value());
1299 CHECK_EQ(0, break_point_hit_count);
1300
1301 // Run with breakpoint.
1302 int bp = SetBreakPoint(foo, 0);
1303 CHECK_EQ(1, foo->Call(env->Global(), 0, NULL)->Int32Value());
1304 CHECK_EQ(1, break_point_hit_count);
1305 CHECK_EQ(1, foo->Call(env->Global(), 0, NULL)->Int32Value());
1306 CHECK_EQ(2, break_point_hit_count);
1307
1308 // Run without breakpoints.
1309 ClearBreakPoint(bp);
1310 foo->Call(env->Global(), 0, NULL);
1311 CHECK_EQ(2, break_point_hit_count);
1312
1313 v8::Debug::SetDebugEventListener(NULL);
1314 CheckDebuggerUnloaded();
1315}
1316
1317
Steve Blocka7e24c12009-10-30 11:49:00 +00001318// Test that a break point can be set at a return store location.
1319TEST(BreakPointReturn) {
1320 break_point_hit_count = 0;
1321 v8::HandleScope scope;
1322 DebugLocalContext env;
1323
1324 // Create a functions for checking the source line and column when hitting
1325 // a break point.
1326 frame_source_line = CompileFunction(&env,
1327 frame_source_line_source,
1328 "frame_source_line");
1329 frame_source_column = CompileFunction(&env,
1330 frame_source_column_source,
1331 "frame_source_column");
1332
1333
1334 v8::Debug::SetDebugEventListener(DebugEventBreakPointHitCount,
1335 v8::Undefined());
1336 v8::Script::Compile(v8::String::New("function foo(){}"))->Run();
1337 v8::Local<v8::Function> foo =
1338 v8::Local<v8::Function>::Cast(env->Global()->Get(v8::String::New("foo")));
1339
1340 // Run without breakpoints.
1341 foo->Call(env->Global(), 0, NULL);
1342 CHECK_EQ(0, break_point_hit_count);
1343
1344 // Run with breakpoint
1345 int bp = SetBreakPoint(foo, 0);
1346 foo->Call(env->Global(), 0, NULL);
1347 CHECK_EQ(1, break_point_hit_count);
1348 CHECK_EQ(0, last_source_line);
Ben Murdochbb769b22010-08-11 14:56:33 +01001349 CHECK_EQ(15, last_source_column);
Steve Blocka7e24c12009-10-30 11:49:00 +00001350 foo->Call(env->Global(), 0, NULL);
1351 CHECK_EQ(2, break_point_hit_count);
1352 CHECK_EQ(0, last_source_line);
Ben Murdochbb769b22010-08-11 14:56:33 +01001353 CHECK_EQ(15, last_source_column);
Steve Blocka7e24c12009-10-30 11:49:00 +00001354
1355 // Run without breakpoints.
1356 ClearBreakPoint(bp);
1357 foo->Call(env->Global(), 0, NULL);
1358 CHECK_EQ(2, break_point_hit_count);
1359
1360 v8::Debug::SetDebugEventListener(NULL);
1361 CheckDebuggerUnloaded();
1362}
1363
1364
1365static void CallWithBreakPoints(v8::Local<v8::Object> recv,
1366 v8::Local<v8::Function> f,
1367 int break_point_count,
1368 int call_count) {
1369 break_point_hit_count = 0;
1370 for (int i = 0; i < call_count; i++) {
1371 f->Call(recv, 0, NULL);
1372 CHECK_EQ((i + 1) * break_point_count, break_point_hit_count);
1373 }
1374}
1375
1376// Test GC during break point processing.
1377TEST(GCDuringBreakPointProcessing) {
1378 break_point_hit_count = 0;
1379 v8::HandleScope scope;
1380 DebugLocalContext env;
1381
1382 v8::Debug::SetDebugEventListener(DebugEventBreakPointCollectGarbage,
1383 v8::Undefined());
1384 v8::Local<v8::Function> foo;
1385
1386 // Test IC store break point with garbage collection.
1387 foo = CompileFunction(&env, "function foo(){bar=0;}", "foo");
1388 SetBreakPoint(foo, 0);
1389 CallWithBreakPoints(env->Global(), foo, 1, 10);
1390
1391 // Test IC load break point with garbage collection.
1392 foo = CompileFunction(&env, "bar=1;function foo(){var x=bar;}", "foo");
1393 SetBreakPoint(foo, 0);
1394 CallWithBreakPoints(env->Global(), foo, 1, 10);
1395
1396 // Test IC call break point with garbage collection.
1397 foo = CompileFunction(&env, "function bar(){};function foo(){bar();}", "foo");
1398 SetBreakPoint(foo, 0);
1399 CallWithBreakPoints(env->Global(), foo, 1, 10);
1400
1401 // Test return break point with garbage collection.
1402 foo = CompileFunction(&env, "function foo(){}", "foo");
1403 SetBreakPoint(foo, 0);
1404 CallWithBreakPoints(env->Global(), foo, 1, 25);
1405
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001406 // Test debug break slot break point with garbage collection.
1407 foo = CompileFunction(&env, "function foo(){var a;}", "foo");
1408 SetBreakPoint(foo, 0);
1409 CallWithBreakPoints(env->Global(), foo, 1, 25);
1410
Steve Blocka7e24c12009-10-30 11:49:00 +00001411 v8::Debug::SetDebugEventListener(NULL);
1412 CheckDebuggerUnloaded();
1413}
1414
1415
1416// Call the function three times with different garbage collections in between
1417// and make sure that the break point survives.
Ben Murdochbb769b22010-08-11 14:56:33 +01001418static void CallAndGC(v8::Local<v8::Object> recv,
1419 v8::Local<v8::Function> f,
1420 bool force_compaction) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001421 break_point_hit_count = 0;
1422
1423 for (int i = 0; i < 3; i++) {
1424 // Call function.
1425 f->Call(recv, 0, NULL);
1426 CHECK_EQ(1 + i * 3, break_point_hit_count);
1427
1428 // Scavenge and call function.
Steve Block44f0eee2011-05-26 01:26:41 +01001429 HEAP->CollectGarbage(v8::internal::NEW_SPACE);
Steve Blocka7e24c12009-10-30 11:49:00 +00001430 f->Call(recv, 0, NULL);
1431 CHECK_EQ(2 + i * 3, break_point_hit_count);
1432
1433 // Mark sweep (and perhaps compact) and call function.
Steve Block44f0eee2011-05-26 01:26:41 +01001434 HEAP->CollectAllGarbage(force_compaction);
Steve Blocka7e24c12009-10-30 11:49:00 +00001435 f->Call(recv, 0, NULL);
1436 CHECK_EQ(3 + i * 3, break_point_hit_count);
1437 }
1438}
1439
1440
Ben Murdochbb769b22010-08-11 14:56:33 +01001441static void TestBreakPointSurviveGC(bool force_compaction) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001442 break_point_hit_count = 0;
1443 v8::HandleScope scope;
1444 DebugLocalContext env;
1445
1446 v8::Debug::SetDebugEventListener(DebugEventBreakPointHitCount,
1447 v8::Undefined());
1448 v8::Local<v8::Function> foo;
1449
1450 // Test IC store break point with garbage collection.
Ben Murdochbb769b22010-08-11 14:56:33 +01001451 {
1452 v8::Local<v8::Function> bar =
1453 CompileFunction(&env, "function foo(){}", "foo");
1454 foo = CompileFunction(&env, "function foo(){bar=0;}", "foo");
1455 SetBreakPoint(foo, 0);
1456 }
1457 CallAndGC(env->Global(), foo, force_compaction);
Steve Blocka7e24c12009-10-30 11:49:00 +00001458
1459 // Test IC load break point with garbage collection.
Ben Murdochbb769b22010-08-11 14:56:33 +01001460 {
1461 v8::Local<v8::Function> bar =
1462 CompileFunction(&env, "function foo(){}", "foo");
1463 foo = CompileFunction(&env, "bar=1;function foo(){var x=bar;}", "foo");
1464 SetBreakPoint(foo, 0);
1465 }
1466 CallAndGC(env->Global(), foo, force_compaction);
Steve Blocka7e24c12009-10-30 11:49:00 +00001467
1468 // Test IC call break point with garbage collection.
Ben Murdochbb769b22010-08-11 14:56:33 +01001469 {
1470 v8::Local<v8::Function> bar =
1471 CompileFunction(&env, "function foo(){}", "foo");
1472 foo = CompileFunction(&env,
1473 "function bar(){};function foo(){bar();}",
1474 "foo");
1475 SetBreakPoint(foo, 0);
1476 }
1477 CallAndGC(env->Global(), foo, force_compaction);
Steve Blocka7e24c12009-10-30 11:49:00 +00001478
1479 // Test return break point with garbage collection.
Ben Murdochbb769b22010-08-11 14:56:33 +01001480 {
1481 v8::Local<v8::Function> bar =
1482 CompileFunction(&env, "function foo(){}", "foo");
1483 foo = CompileFunction(&env, "function foo(){}", "foo");
1484 SetBreakPoint(foo, 0);
1485 }
1486 CallAndGC(env->Global(), foo, force_compaction);
1487
1488 // Test non IC break point with garbage collection.
1489 {
1490 v8::Local<v8::Function> bar =
1491 CompileFunction(&env, "function foo(){}", "foo");
1492 foo = CompileFunction(&env, "function foo(){var bar=0;}", "foo");
1493 SetBreakPoint(foo, 0);
1494 }
1495 CallAndGC(env->Global(), foo, force_compaction);
1496
Steve Blocka7e24c12009-10-30 11:49:00 +00001497
1498 v8::Debug::SetDebugEventListener(NULL);
1499 CheckDebuggerUnloaded();
1500}
1501
1502
Ben Murdochbb769b22010-08-11 14:56:33 +01001503// Test that a break point can be set at a return store location.
1504TEST(BreakPointSurviveGC) {
1505 TestBreakPointSurviveGC(false);
1506 TestBreakPointSurviveGC(true);
1507}
1508
1509
Steve Blocka7e24c12009-10-30 11:49:00 +00001510// Test that break points can be set using the global Debug object.
1511TEST(BreakPointThroughJavaScript) {
1512 break_point_hit_count = 0;
1513 v8::HandleScope scope;
1514 DebugLocalContext env;
1515 env.ExposeDebug();
1516
1517 v8::Debug::SetDebugEventListener(DebugEventBreakPointHitCount,
1518 v8::Undefined());
1519 v8::Script::Compile(v8::String::New("function bar(){}"))->Run();
1520 v8::Script::Compile(v8::String::New("function foo(){bar();bar();}"))->Run();
1521 // 012345678901234567890
1522 // 1 2
1523 // Break points are set at position 3 and 9
1524 v8::Local<v8::Script> foo = v8::Script::Compile(v8::String::New("foo()"));
1525
1526 // Run without breakpoints.
1527 foo->Run();
1528 CHECK_EQ(0, break_point_hit_count);
1529
1530 // Run with one breakpoint
1531 int bp1 = SetBreakPointFromJS("foo", 0, 3);
1532 foo->Run();
1533 CHECK_EQ(1, break_point_hit_count);
1534 foo->Run();
1535 CHECK_EQ(2, break_point_hit_count);
1536
1537 // Run with two breakpoints
1538 int bp2 = SetBreakPointFromJS("foo", 0, 9);
1539 foo->Run();
1540 CHECK_EQ(4, break_point_hit_count);
1541 foo->Run();
1542 CHECK_EQ(6, break_point_hit_count);
1543
1544 // Run with one breakpoint
1545 ClearBreakPointFromJS(bp2);
1546 foo->Run();
1547 CHECK_EQ(7, break_point_hit_count);
1548 foo->Run();
1549 CHECK_EQ(8, break_point_hit_count);
1550
1551 // Run without breakpoints.
1552 ClearBreakPointFromJS(bp1);
1553 foo->Run();
1554 CHECK_EQ(8, break_point_hit_count);
1555
1556 v8::Debug::SetDebugEventListener(NULL);
1557 CheckDebuggerUnloaded();
1558
1559 // Make sure that the break point numbers are consecutive.
1560 CHECK_EQ(1, bp1);
1561 CHECK_EQ(2, bp2);
1562}
1563
1564
1565// Test that break points on scripts identified by name can be set using the
1566// global Debug object.
1567TEST(ScriptBreakPointByNameThroughJavaScript) {
1568 break_point_hit_count = 0;
1569 v8::HandleScope scope;
1570 DebugLocalContext env;
1571 env.ExposeDebug();
1572
1573 v8::Debug::SetDebugEventListener(DebugEventBreakPointHitCount,
1574 v8::Undefined());
1575
1576 v8::Local<v8::String> script = v8::String::New(
1577 "function f() {\n"
1578 " function h() {\n"
1579 " a = 0; // line 2\n"
1580 " }\n"
1581 " b = 1; // line 4\n"
1582 " return h();\n"
1583 "}\n"
1584 "\n"
1585 "function g() {\n"
1586 " function h() {\n"
1587 " a = 0;\n"
1588 " }\n"
1589 " b = 2; // line 12\n"
1590 " h();\n"
1591 " b = 3; // line 14\n"
1592 " f(); // line 15\n"
1593 "}");
1594
1595 // Compile the script and get the two functions.
1596 v8::ScriptOrigin origin =
1597 v8::ScriptOrigin(v8::String::New("test"));
1598 v8::Script::Compile(script, &origin)->Run();
1599 v8::Local<v8::Function> f =
1600 v8::Local<v8::Function>::Cast(env->Global()->Get(v8::String::New("f")));
1601 v8::Local<v8::Function> g =
1602 v8::Local<v8::Function>::Cast(env->Global()->Get(v8::String::New("g")));
1603
1604 // Call f and g without break points.
1605 break_point_hit_count = 0;
1606 f->Call(env->Global(), 0, NULL);
1607 CHECK_EQ(0, break_point_hit_count);
1608 g->Call(env->Global(), 0, NULL);
1609 CHECK_EQ(0, break_point_hit_count);
1610
1611 // Call f and g with break point on line 12.
1612 int sbp1 = SetScriptBreakPointByNameFromJS("test", 12, 0);
1613 break_point_hit_count = 0;
1614 f->Call(env->Global(), 0, NULL);
1615 CHECK_EQ(0, break_point_hit_count);
1616 g->Call(env->Global(), 0, NULL);
1617 CHECK_EQ(1, break_point_hit_count);
1618
1619 // Remove the break point again.
1620 break_point_hit_count = 0;
1621 ClearBreakPointFromJS(sbp1);
1622 f->Call(env->Global(), 0, NULL);
1623 CHECK_EQ(0, break_point_hit_count);
1624 g->Call(env->Global(), 0, NULL);
1625 CHECK_EQ(0, break_point_hit_count);
1626
1627 // Call f and g with break point on line 2.
1628 int sbp2 = SetScriptBreakPointByNameFromJS("test", 2, 0);
1629 break_point_hit_count = 0;
1630 f->Call(env->Global(), 0, NULL);
1631 CHECK_EQ(1, break_point_hit_count);
1632 g->Call(env->Global(), 0, NULL);
1633 CHECK_EQ(2, break_point_hit_count);
1634
1635 // Call f and g with break point on line 2, 4, 12, 14 and 15.
1636 int sbp3 = SetScriptBreakPointByNameFromJS("test", 4, 0);
1637 int sbp4 = SetScriptBreakPointByNameFromJS("test", 12, 0);
1638 int sbp5 = SetScriptBreakPointByNameFromJS("test", 14, 0);
1639 int sbp6 = SetScriptBreakPointByNameFromJS("test", 15, 0);
1640 break_point_hit_count = 0;
1641 f->Call(env->Global(), 0, NULL);
1642 CHECK_EQ(2, break_point_hit_count);
1643 g->Call(env->Global(), 0, NULL);
1644 CHECK_EQ(7, break_point_hit_count);
1645
1646 // Remove all the break points again.
1647 break_point_hit_count = 0;
1648 ClearBreakPointFromJS(sbp2);
1649 ClearBreakPointFromJS(sbp3);
1650 ClearBreakPointFromJS(sbp4);
1651 ClearBreakPointFromJS(sbp5);
1652 ClearBreakPointFromJS(sbp6);
1653 f->Call(env->Global(), 0, NULL);
1654 CHECK_EQ(0, break_point_hit_count);
1655 g->Call(env->Global(), 0, NULL);
1656 CHECK_EQ(0, break_point_hit_count);
1657
1658 v8::Debug::SetDebugEventListener(NULL);
1659 CheckDebuggerUnloaded();
1660
1661 // Make sure that the break point numbers are consecutive.
1662 CHECK_EQ(1, sbp1);
1663 CHECK_EQ(2, sbp2);
1664 CHECK_EQ(3, sbp3);
1665 CHECK_EQ(4, sbp4);
1666 CHECK_EQ(5, sbp5);
1667 CHECK_EQ(6, sbp6);
1668}
1669
1670
1671TEST(ScriptBreakPointByIdThroughJavaScript) {
1672 break_point_hit_count = 0;
1673 v8::HandleScope scope;
1674 DebugLocalContext env;
1675 env.ExposeDebug();
1676
1677 v8::Debug::SetDebugEventListener(DebugEventBreakPointHitCount,
1678 v8::Undefined());
1679
1680 v8::Local<v8::String> source = v8::String::New(
1681 "function f() {\n"
1682 " function h() {\n"
1683 " a = 0; // line 2\n"
1684 " }\n"
1685 " b = 1; // line 4\n"
1686 " return h();\n"
1687 "}\n"
1688 "\n"
1689 "function g() {\n"
1690 " function h() {\n"
1691 " a = 0;\n"
1692 " }\n"
1693 " b = 2; // line 12\n"
1694 " h();\n"
1695 " b = 3; // line 14\n"
1696 " f(); // line 15\n"
1697 "}");
1698
1699 // Compile the script and get the two functions.
1700 v8::ScriptOrigin origin =
1701 v8::ScriptOrigin(v8::String::New("test"));
1702 v8::Local<v8::Script> script = v8::Script::Compile(source, &origin);
1703 script->Run();
1704 v8::Local<v8::Function> f =
1705 v8::Local<v8::Function>::Cast(env->Global()->Get(v8::String::New("f")));
1706 v8::Local<v8::Function> g =
1707 v8::Local<v8::Function>::Cast(env->Global()->Get(v8::String::New("g")));
1708
1709 // Get the script id knowing that internally it is a 32 integer.
1710 uint32_t script_id = script->Id()->Uint32Value();
1711
1712 // Call f and g without break points.
1713 break_point_hit_count = 0;
1714 f->Call(env->Global(), 0, NULL);
1715 CHECK_EQ(0, break_point_hit_count);
1716 g->Call(env->Global(), 0, NULL);
1717 CHECK_EQ(0, break_point_hit_count);
1718
1719 // Call f and g with break point on line 12.
1720 int sbp1 = SetScriptBreakPointByIdFromJS(script_id, 12, 0);
1721 break_point_hit_count = 0;
1722 f->Call(env->Global(), 0, NULL);
1723 CHECK_EQ(0, break_point_hit_count);
1724 g->Call(env->Global(), 0, NULL);
1725 CHECK_EQ(1, break_point_hit_count);
1726
1727 // Remove the break point again.
1728 break_point_hit_count = 0;
1729 ClearBreakPointFromJS(sbp1);
1730 f->Call(env->Global(), 0, NULL);
1731 CHECK_EQ(0, break_point_hit_count);
1732 g->Call(env->Global(), 0, NULL);
1733 CHECK_EQ(0, break_point_hit_count);
1734
1735 // Call f and g with break point on line 2.
1736 int sbp2 = SetScriptBreakPointByIdFromJS(script_id, 2, 0);
1737 break_point_hit_count = 0;
1738 f->Call(env->Global(), 0, NULL);
1739 CHECK_EQ(1, break_point_hit_count);
1740 g->Call(env->Global(), 0, NULL);
1741 CHECK_EQ(2, break_point_hit_count);
1742
1743 // Call f and g with break point on line 2, 4, 12, 14 and 15.
1744 int sbp3 = SetScriptBreakPointByIdFromJS(script_id, 4, 0);
1745 int sbp4 = SetScriptBreakPointByIdFromJS(script_id, 12, 0);
1746 int sbp5 = SetScriptBreakPointByIdFromJS(script_id, 14, 0);
1747 int sbp6 = SetScriptBreakPointByIdFromJS(script_id, 15, 0);
1748 break_point_hit_count = 0;
1749 f->Call(env->Global(), 0, NULL);
1750 CHECK_EQ(2, break_point_hit_count);
1751 g->Call(env->Global(), 0, NULL);
1752 CHECK_EQ(7, break_point_hit_count);
1753
1754 // Remove all the break points again.
1755 break_point_hit_count = 0;
1756 ClearBreakPointFromJS(sbp2);
1757 ClearBreakPointFromJS(sbp3);
1758 ClearBreakPointFromJS(sbp4);
1759 ClearBreakPointFromJS(sbp5);
1760 ClearBreakPointFromJS(sbp6);
1761 f->Call(env->Global(), 0, NULL);
1762 CHECK_EQ(0, break_point_hit_count);
1763 g->Call(env->Global(), 0, NULL);
1764 CHECK_EQ(0, break_point_hit_count);
1765
1766 v8::Debug::SetDebugEventListener(NULL);
1767 CheckDebuggerUnloaded();
1768
1769 // Make sure that the break point numbers are consecutive.
1770 CHECK_EQ(1, sbp1);
1771 CHECK_EQ(2, sbp2);
1772 CHECK_EQ(3, sbp3);
1773 CHECK_EQ(4, sbp4);
1774 CHECK_EQ(5, sbp5);
1775 CHECK_EQ(6, sbp6);
1776}
1777
1778
1779// Test conditional script break points.
1780TEST(EnableDisableScriptBreakPoint) {
1781 break_point_hit_count = 0;
1782 v8::HandleScope scope;
1783 DebugLocalContext env;
1784 env.ExposeDebug();
1785
1786 v8::Debug::SetDebugEventListener(DebugEventBreakPointHitCount,
1787 v8::Undefined());
1788
1789 v8::Local<v8::String> script = v8::String::New(
1790 "function f() {\n"
1791 " a = 0; // line 1\n"
1792 "};");
1793
1794 // Compile the script and get function f.
1795 v8::ScriptOrigin origin =
1796 v8::ScriptOrigin(v8::String::New("test"));
1797 v8::Script::Compile(script, &origin)->Run();
1798 v8::Local<v8::Function> f =
1799 v8::Local<v8::Function>::Cast(env->Global()->Get(v8::String::New("f")));
1800
1801 // Set script break point on line 1 (in function f).
1802 int sbp = SetScriptBreakPointByNameFromJS("test", 1, 0);
1803
1804 // Call f while enabeling and disabling the script break point.
1805 break_point_hit_count = 0;
1806 f->Call(env->Global(), 0, NULL);
1807 CHECK_EQ(1, break_point_hit_count);
1808
1809 DisableScriptBreakPointFromJS(sbp);
1810 f->Call(env->Global(), 0, NULL);
1811 CHECK_EQ(1, break_point_hit_count);
1812
1813 EnableScriptBreakPointFromJS(sbp);
1814 f->Call(env->Global(), 0, NULL);
1815 CHECK_EQ(2, break_point_hit_count);
1816
1817 DisableScriptBreakPointFromJS(sbp);
1818 f->Call(env->Global(), 0, NULL);
1819 CHECK_EQ(2, break_point_hit_count);
1820
1821 // Reload the script and get f again checking that the disabeling survives.
1822 v8::Script::Compile(script, &origin)->Run();
1823 f = v8::Local<v8::Function>::Cast(env->Global()->Get(v8::String::New("f")));
1824 f->Call(env->Global(), 0, NULL);
1825 CHECK_EQ(2, break_point_hit_count);
1826
1827 EnableScriptBreakPointFromJS(sbp);
1828 f->Call(env->Global(), 0, NULL);
1829 CHECK_EQ(3, break_point_hit_count);
1830
1831 v8::Debug::SetDebugEventListener(NULL);
1832 CheckDebuggerUnloaded();
1833}
1834
1835
1836// Test conditional script break points.
1837TEST(ConditionalScriptBreakPoint) {
1838 break_point_hit_count = 0;
1839 v8::HandleScope scope;
1840 DebugLocalContext env;
1841 env.ExposeDebug();
1842
1843 v8::Debug::SetDebugEventListener(DebugEventBreakPointHitCount,
1844 v8::Undefined());
1845
1846 v8::Local<v8::String> script = v8::String::New(
1847 "count = 0;\n"
1848 "function f() {\n"
1849 " g(count++); // line 2\n"
1850 "};\n"
1851 "function g(x) {\n"
1852 " var a=x; // line 5\n"
1853 "};");
1854
1855 // Compile the script and get function f.
1856 v8::ScriptOrigin origin =
1857 v8::ScriptOrigin(v8::String::New("test"));
1858 v8::Script::Compile(script, &origin)->Run();
1859 v8::Local<v8::Function> f =
1860 v8::Local<v8::Function>::Cast(env->Global()->Get(v8::String::New("f")));
1861
1862 // Set script break point on line 5 (in function g).
1863 int sbp1 = SetScriptBreakPointByNameFromJS("test", 5, 0);
1864
1865 // Call f with different conditions on the script break point.
1866 break_point_hit_count = 0;
1867 ChangeScriptBreakPointConditionFromJS(sbp1, "false");
1868 f->Call(env->Global(), 0, NULL);
1869 CHECK_EQ(0, break_point_hit_count);
1870
1871 ChangeScriptBreakPointConditionFromJS(sbp1, "true");
1872 break_point_hit_count = 0;
1873 f->Call(env->Global(), 0, NULL);
1874 CHECK_EQ(1, break_point_hit_count);
1875
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001876 ChangeScriptBreakPointConditionFromJS(sbp1, "x % 2 == 0");
Steve Blocka7e24c12009-10-30 11:49:00 +00001877 break_point_hit_count = 0;
1878 for (int i = 0; i < 10; i++) {
1879 f->Call(env->Global(), 0, NULL);
1880 }
1881 CHECK_EQ(5, break_point_hit_count);
1882
1883 // Reload the script and get f again checking that the condition survives.
1884 v8::Script::Compile(script, &origin)->Run();
1885 f = v8::Local<v8::Function>::Cast(env->Global()->Get(v8::String::New("f")));
1886
1887 break_point_hit_count = 0;
1888 for (int i = 0; i < 10; i++) {
1889 f->Call(env->Global(), 0, NULL);
1890 }
1891 CHECK_EQ(5, break_point_hit_count);
1892
1893 v8::Debug::SetDebugEventListener(NULL);
1894 CheckDebuggerUnloaded();
1895}
1896
1897
1898// Test ignore count on script break points.
1899TEST(ScriptBreakPointIgnoreCount) {
1900 break_point_hit_count = 0;
1901 v8::HandleScope scope;
1902 DebugLocalContext env;
1903 env.ExposeDebug();
1904
1905 v8::Debug::SetDebugEventListener(DebugEventBreakPointHitCount,
1906 v8::Undefined());
1907
1908 v8::Local<v8::String> script = v8::String::New(
1909 "function f() {\n"
1910 " a = 0; // line 1\n"
1911 "};");
1912
1913 // Compile the script and get function f.
1914 v8::ScriptOrigin origin =
1915 v8::ScriptOrigin(v8::String::New("test"));
1916 v8::Script::Compile(script, &origin)->Run();
1917 v8::Local<v8::Function> f =
1918 v8::Local<v8::Function>::Cast(env->Global()->Get(v8::String::New("f")));
1919
1920 // Set script break point on line 1 (in function f).
1921 int sbp = SetScriptBreakPointByNameFromJS("test", 1, 0);
1922
1923 // Call f with different ignores on the script break point.
1924 break_point_hit_count = 0;
1925 ChangeScriptBreakPointIgnoreCountFromJS(sbp, 1);
1926 f->Call(env->Global(), 0, NULL);
1927 CHECK_EQ(0, break_point_hit_count);
1928 f->Call(env->Global(), 0, NULL);
1929 CHECK_EQ(1, break_point_hit_count);
1930
1931 ChangeScriptBreakPointIgnoreCountFromJS(sbp, 5);
1932 break_point_hit_count = 0;
1933 for (int i = 0; i < 10; i++) {
1934 f->Call(env->Global(), 0, NULL);
1935 }
1936 CHECK_EQ(5, break_point_hit_count);
1937
1938 // Reload the script and get f again checking that the ignore survives.
1939 v8::Script::Compile(script, &origin)->Run();
1940 f = v8::Local<v8::Function>::Cast(env->Global()->Get(v8::String::New("f")));
1941
1942 break_point_hit_count = 0;
1943 for (int i = 0; i < 10; i++) {
1944 f->Call(env->Global(), 0, NULL);
1945 }
1946 CHECK_EQ(5, break_point_hit_count);
1947
1948 v8::Debug::SetDebugEventListener(NULL);
1949 CheckDebuggerUnloaded();
1950}
1951
1952
1953// Test that script break points survive when a script is reloaded.
1954TEST(ScriptBreakPointReload) {
1955 break_point_hit_count = 0;
1956 v8::HandleScope scope;
1957 DebugLocalContext env;
1958 env.ExposeDebug();
1959
1960 v8::Debug::SetDebugEventListener(DebugEventBreakPointHitCount,
1961 v8::Undefined());
1962
1963 v8::Local<v8::Function> f;
1964 v8::Local<v8::String> script = v8::String::New(
1965 "function f() {\n"
1966 " function h() {\n"
1967 " a = 0; // line 2\n"
1968 " }\n"
1969 " b = 1; // line 4\n"
1970 " return h();\n"
1971 "}");
1972
1973 v8::ScriptOrigin origin_1 = v8::ScriptOrigin(v8::String::New("1"));
1974 v8::ScriptOrigin origin_2 = v8::ScriptOrigin(v8::String::New("2"));
1975
1976 // Set a script break point before the script is loaded.
1977 SetScriptBreakPointByNameFromJS("1", 2, 0);
1978
1979 // Compile the script and get the function.
1980 v8::Script::Compile(script, &origin_1)->Run();
1981 f = v8::Local<v8::Function>::Cast(env->Global()->Get(v8::String::New("f")));
1982
1983 // Call f and check that the script break point is active.
1984 break_point_hit_count = 0;
1985 f->Call(env->Global(), 0, NULL);
1986 CHECK_EQ(1, break_point_hit_count);
1987
1988 // Compile the script again with a different script data and get the
1989 // function.
1990 v8::Script::Compile(script, &origin_2)->Run();
1991 f = v8::Local<v8::Function>::Cast(env->Global()->Get(v8::String::New("f")));
1992
1993 // Call f and check that no break points are set.
1994 break_point_hit_count = 0;
1995 f->Call(env->Global(), 0, NULL);
1996 CHECK_EQ(0, break_point_hit_count);
1997
1998 // Compile the script again and get the function.
1999 v8::Script::Compile(script, &origin_1)->Run();
2000 f = v8::Local<v8::Function>::Cast(env->Global()->Get(v8::String::New("f")));
2001
2002 // Call f and check that the script break point is active.
2003 break_point_hit_count = 0;
2004 f->Call(env->Global(), 0, NULL);
2005 CHECK_EQ(1, break_point_hit_count);
2006
2007 v8::Debug::SetDebugEventListener(NULL);
2008 CheckDebuggerUnloaded();
2009}
2010
2011
2012// Test when several scripts has the same script data
2013TEST(ScriptBreakPointMultiple) {
2014 break_point_hit_count = 0;
2015 v8::HandleScope scope;
2016 DebugLocalContext env;
2017 env.ExposeDebug();
2018
2019 v8::Debug::SetDebugEventListener(DebugEventBreakPointHitCount,
2020 v8::Undefined());
2021
2022 v8::Local<v8::Function> f;
2023 v8::Local<v8::String> script_f = v8::String::New(
2024 "function f() {\n"
2025 " a = 0; // line 1\n"
2026 "}");
2027
2028 v8::Local<v8::Function> g;
2029 v8::Local<v8::String> script_g = v8::String::New(
2030 "function g() {\n"
2031 " b = 0; // line 1\n"
2032 "}");
2033
2034 v8::ScriptOrigin origin =
2035 v8::ScriptOrigin(v8::String::New("test"));
2036
2037 // Set a script break point before the scripts are loaded.
2038 int sbp = SetScriptBreakPointByNameFromJS("test", 1, 0);
2039
2040 // Compile the scripts with same script data and get the functions.
2041 v8::Script::Compile(script_f, &origin)->Run();
2042 f = v8::Local<v8::Function>::Cast(env->Global()->Get(v8::String::New("f")));
2043 v8::Script::Compile(script_g, &origin)->Run();
2044 g = v8::Local<v8::Function>::Cast(env->Global()->Get(v8::String::New("g")));
2045
2046 // Call f and g and check that the script break point is active.
2047 break_point_hit_count = 0;
2048 f->Call(env->Global(), 0, NULL);
2049 CHECK_EQ(1, break_point_hit_count);
2050 g->Call(env->Global(), 0, NULL);
2051 CHECK_EQ(2, break_point_hit_count);
2052
2053 // Clear the script break point.
2054 ClearBreakPointFromJS(sbp);
2055
2056 // Call f and g and check that the script break point is no longer active.
2057 break_point_hit_count = 0;
2058 f->Call(env->Global(), 0, NULL);
2059 CHECK_EQ(0, break_point_hit_count);
2060 g->Call(env->Global(), 0, NULL);
2061 CHECK_EQ(0, break_point_hit_count);
2062
2063 // Set script break point with the scripts loaded.
2064 sbp = SetScriptBreakPointByNameFromJS("test", 1, 0);
2065
2066 // Call f and g and check that the script break point is active.
2067 break_point_hit_count = 0;
2068 f->Call(env->Global(), 0, NULL);
2069 CHECK_EQ(1, break_point_hit_count);
2070 g->Call(env->Global(), 0, NULL);
2071 CHECK_EQ(2, break_point_hit_count);
2072
2073 v8::Debug::SetDebugEventListener(NULL);
2074 CheckDebuggerUnloaded();
2075}
2076
2077
2078// Test the script origin which has both name and line offset.
2079TEST(ScriptBreakPointLineOffset) {
2080 break_point_hit_count = 0;
2081 v8::HandleScope scope;
2082 DebugLocalContext env;
2083 env.ExposeDebug();
2084
2085 v8::Debug::SetDebugEventListener(DebugEventBreakPointHitCount,
2086 v8::Undefined());
2087
2088 v8::Local<v8::Function> f;
2089 v8::Local<v8::String> script = v8::String::New(
2090 "function f() {\n"
2091 " a = 0; // line 8 as this script has line offset 7\n"
2092 " b = 0; // line 9 as this script has line offset 7\n"
2093 "}");
2094
2095 // Create script origin both name and line offset.
2096 v8::ScriptOrigin origin(v8::String::New("test.html"),
2097 v8::Integer::New(7));
2098
2099 // Set two script break points before the script is loaded.
2100 int sbp1 = SetScriptBreakPointByNameFromJS("test.html", 8, 0);
2101 int sbp2 = SetScriptBreakPointByNameFromJS("test.html", 9, 0);
2102
2103 // Compile the script and get the function.
2104 v8::Script::Compile(script, &origin)->Run();
2105 f = v8::Local<v8::Function>::Cast(env->Global()->Get(v8::String::New("f")));
2106
2107 // Call f and check that the script break point is active.
2108 break_point_hit_count = 0;
2109 f->Call(env->Global(), 0, NULL);
2110 CHECK_EQ(2, break_point_hit_count);
2111
2112 // Clear the script break points.
2113 ClearBreakPointFromJS(sbp1);
2114 ClearBreakPointFromJS(sbp2);
2115
2116 // Call f and check that no script break points are active.
2117 break_point_hit_count = 0;
2118 f->Call(env->Global(), 0, NULL);
2119 CHECK_EQ(0, break_point_hit_count);
2120
2121 // Set a script break point with the script loaded.
2122 sbp1 = SetScriptBreakPointByNameFromJS("test.html", 9, 0);
2123
2124 // Call f and check that the script break point is active.
2125 break_point_hit_count = 0;
2126 f->Call(env->Global(), 0, NULL);
2127 CHECK_EQ(1, break_point_hit_count);
2128
2129 v8::Debug::SetDebugEventListener(NULL);
2130 CheckDebuggerUnloaded();
2131}
2132
2133
2134// Test script break points set on lines.
2135TEST(ScriptBreakPointLine) {
2136 v8::HandleScope scope;
2137 DebugLocalContext env;
2138 env.ExposeDebug();
2139
2140 // Create a function for checking the function when hitting a break point.
2141 frame_function_name = CompileFunction(&env,
2142 frame_function_name_source,
2143 "frame_function_name");
2144
2145 v8::Debug::SetDebugEventListener(DebugEventBreakPointHitCount,
2146 v8::Undefined());
2147
2148 v8::Local<v8::Function> f;
2149 v8::Local<v8::Function> g;
2150 v8::Local<v8::String> script = v8::String::New(
2151 "a = 0 // line 0\n"
2152 "function f() {\n"
2153 " a = 1; // line 2\n"
2154 "}\n"
2155 " a = 2; // line 4\n"
2156 " /* xx */ function g() { // line 5\n"
2157 " function h() { // line 6\n"
2158 " a = 3; // line 7\n"
2159 " }\n"
2160 " h(); // line 9\n"
2161 " a = 4; // line 10\n"
2162 " }\n"
2163 " a=5; // line 12");
2164
2165 // Set a couple script break point before the script is loaded.
2166 int sbp1 = SetScriptBreakPointByNameFromJS("test.html", 0, -1);
2167 int sbp2 = SetScriptBreakPointByNameFromJS("test.html", 1, -1);
2168 int sbp3 = SetScriptBreakPointByNameFromJS("test.html", 5, -1);
2169
2170 // Compile the script and get the function.
2171 break_point_hit_count = 0;
2172 v8::ScriptOrigin origin(v8::String::New("test.html"), v8::Integer::New(0));
2173 v8::Script::Compile(script, &origin)->Run();
2174 f = v8::Local<v8::Function>::Cast(env->Global()->Get(v8::String::New("f")));
2175 g = v8::Local<v8::Function>::Cast(env->Global()->Get(v8::String::New("g")));
2176
Ben Murdoch69a99ed2011-11-30 16:03:39 +00002177 // Check that a break point was hit when the script was run.
Steve Blocka7e24c12009-10-30 11:49:00 +00002178 CHECK_EQ(1, break_point_hit_count);
Steve Blockd0582a62009-12-15 09:54:21 +00002179 CHECK_EQ(0, StrLength(last_function_hit));
Steve Blocka7e24c12009-10-30 11:49:00 +00002180
2181 // Call f and check that the script break point.
2182 f->Call(env->Global(), 0, NULL);
2183 CHECK_EQ(2, break_point_hit_count);
2184 CHECK_EQ("f", last_function_hit);
2185
2186 // Call g and check that the script break point.
2187 g->Call(env->Global(), 0, NULL);
2188 CHECK_EQ(3, break_point_hit_count);
2189 CHECK_EQ("g", last_function_hit);
2190
2191 // Clear the script break point on g and set one on h.
2192 ClearBreakPointFromJS(sbp3);
2193 int sbp4 = SetScriptBreakPointByNameFromJS("test.html", 6, -1);
2194
2195 // Call g and check that the script break point in h is hit.
2196 g->Call(env->Global(), 0, NULL);
2197 CHECK_EQ(4, break_point_hit_count);
2198 CHECK_EQ("h", last_function_hit);
2199
2200 // Clear break points in f and h. Set a new one in the script between
2201 // functions f and g and test that there is no break points in f and g any
2202 // more.
2203 ClearBreakPointFromJS(sbp2);
2204 ClearBreakPointFromJS(sbp4);
2205 int sbp5 = SetScriptBreakPointByNameFromJS("test.html", 4, -1);
2206 break_point_hit_count = 0;
2207 f->Call(env->Global(), 0, NULL);
2208 g->Call(env->Global(), 0, NULL);
2209 CHECK_EQ(0, break_point_hit_count);
2210
2211 // Reload the script which should hit two break points.
2212 break_point_hit_count = 0;
2213 v8::Script::Compile(script, &origin)->Run();
2214 CHECK_EQ(2, break_point_hit_count);
Steve Blockd0582a62009-12-15 09:54:21 +00002215 CHECK_EQ(0, StrLength(last_function_hit));
Steve Blocka7e24c12009-10-30 11:49:00 +00002216
2217 // Set a break point in the code after the last function decleration.
2218 int sbp6 = SetScriptBreakPointByNameFromJS("test.html", 12, -1);
2219
2220 // Reload the script which should hit three break points.
2221 break_point_hit_count = 0;
2222 v8::Script::Compile(script, &origin)->Run();
2223 CHECK_EQ(3, break_point_hit_count);
Steve Blockd0582a62009-12-15 09:54:21 +00002224 CHECK_EQ(0, StrLength(last_function_hit));
Steve Blocka7e24c12009-10-30 11:49:00 +00002225
2226 // Clear the last break points, and reload the script which should not hit any
2227 // break points.
2228 ClearBreakPointFromJS(sbp1);
2229 ClearBreakPointFromJS(sbp5);
2230 ClearBreakPointFromJS(sbp6);
2231 break_point_hit_count = 0;
2232 v8::Script::Compile(script, &origin)->Run();
2233 CHECK_EQ(0, break_point_hit_count);
2234
2235 v8::Debug::SetDebugEventListener(NULL);
2236 CheckDebuggerUnloaded();
2237}
2238
2239
Kristian Monsen9dcf7e22010-06-28 14:14:28 +01002240// Test top level script break points set on lines.
2241TEST(ScriptBreakPointLineTopLevel) {
2242 v8::HandleScope scope;
2243 DebugLocalContext env;
2244 env.ExposeDebug();
2245
2246 v8::Debug::SetDebugEventListener(DebugEventBreakPointHitCount,
2247 v8::Undefined());
2248
2249 v8::Local<v8::String> script = v8::String::New(
2250 "function f() {\n"
2251 " a = 1; // line 1\n"
2252 "}\n"
2253 "a = 2; // line 3\n");
2254 v8::Local<v8::Function> f;
2255 {
2256 v8::HandleScope scope;
2257 v8::Script::Compile(script, v8::String::New("test.html"))->Run();
2258 }
2259 f = v8::Local<v8::Function>::Cast(env->Global()->Get(v8::String::New("f")));
2260
Steve Block44f0eee2011-05-26 01:26:41 +01002261 HEAP->CollectAllGarbage(false);
Kristian Monsen9dcf7e22010-06-28 14:14:28 +01002262
2263 SetScriptBreakPointByNameFromJS("test.html", 3, -1);
2264
2265 // Call f and check that there was no break points.
2266 break_point_hit_count = 0;
2267 f->Call(env->Global(), 0, NULL);
2268 CHECK_EQ(0, break_point_hit_count);
2269
2270 // Recompile and run script and check that break point was hit.
2271 break_point_hit_count = 0;
2272 v8::Script::Compile(script, v8::String::New("test.html"))->Run();
2273 CHECK_EQ(1, break_point_hit_count);
2274
2275 // Call f and check that there are still no break points.
2276 break_point_hit_count = 0;
2277 f = v8::Local<v8::Function>::Cast(env->Global()->Get(v8::String::New("f")));
2278 CHECK_EQ(0, break_point_hit_count);
2279
2280 v8::Debug::SetDebugEventListener(NULL);
2281 CheckDebuggerUnloaded();
2282}
2283
2284
Steve Block8defd9f2010-07-08 12:39:36 +01002285// Test that it is possible to add and remove break points in a top level
2286// function which has no references but has not been collected yet.
2287TEST(ScriptBreakPointTopLevelCrash) {
2288 v8::HandleScope scope;
2289 DebugLocalContext env;
2290 env.ExposeDebug();
2291
2292 v8::Debug::SetDebugEventListener(DebugEventBreakPointHitCount,
2293 v8::Undefined());
2294
2295 v8::Local<v8::String> script_source = v8::String::New(
2296 "function f() {\n"
2297 " return 0;\n"
2298 "}\n"
2299 "f()");
2300
2301 int sbp1 = SetScriptBreakPointByNameFromJS("test.html", 3, -1);
2302 {
2303 v8::HandleScope scope;
2304 break_point_hit_count = 0;
2305 v8::Script::Compile(script_source, v8::String::New("test.html"))->Run();
2306 CHECK_EQ(1, break_point_hit_count);
2307 }
2308
2309 int sbp2 = SetScriptBreakPointByNameFromJS("test.html", 3, -1);
2310 ClearBreakPointFromJS(sbp1);
2311 ClearBreakPointFromJS(sbp2);
2312
2313 v8::Debug::SetDebugEventListener(NULL);
2314 CheckDebuggerUnloaded();
2315}
2316
2317
Steve Blocka7e24c12009-10-30 11:49:00 +00002318// Test that it is possible to remove the last break point for a function
2319// inside the break handling of that break point.
2320TEST(RemoveBreakPointInBreak) {
2321 v8::HandleScope scope;
2322 DebugLocalContext env;
2323
2324 v8::Local<v8::Function> foo =
2325 CompileFunction(&env, "function foo(){a=1;}", "foo");
2326 debug_event_remove_break_point = SetBreakPoint(foo, 0);
2327
2328 // Register the debug event listener pasing the function
2329 v8::Debug::SetDebugEventListener(DebugEventRemoveBreakPoint, foo);
2330
2331 break_point_hit_count = 0;
2332 foo->Call(env->Global(), 0, NULL);
2333 CHECK_EQ(1, break_point_hit_count);
2334
2335 break_point_hit_count = 0;
2336 foo->Call(env->Global(), 0, NULL);
2337 CHECK_EQ(0, break_point_hit_count);
2338
2339 v8::Debug::SetDebugEventListener(NULL);
2340 CheckDebuggerUnloaded();
2341}
2342
2343
2344// Test that the debugger statement causes a break.
2345TEST(DebuggerStatement) {
2346 break_point_hit_count = 0;
2347 v8::HandleScope scope;
2348 DebugLocalContext env;
2349 v8::Debug::SetDebugEventListener(DebugEventBreakPointHitCount,
2350 v8::Undefined());
2351 v8::Script::Compile(v8::String::New("function bar(){debugger}"))->Run();
2352 v8::Script::Compile(v8::String::New(
2353 "function foo(){debugger;debugger;}"))->Run();
2354 v8::Local<v8::Function> foo =
2355 v8::Local<v8::Function>::Cast(env->Global()->Get(v8::String::New("foo")));
2356 v8::Local<v8::Function> bar =
2357 v8::Local<v8::Function>::Cast(env->Global()->Get(v8::String::New("bar")));
2358
2359 // Run function with debugger statement
2360 bar->Call(env->Global(), 0, NULL);
2361 CHECK_EQ(1, break_point_hit_count);
2362
2363 // Run function with two debugger statement
2364 foo->Call(env->Global(), 0, NULL);
2365 CHECK_EQ(3, break_point_hit_count);
2366
2367 v8::Debug::SetDebugEventListener(NULL);
2368 CheckDebuggerUnloaded();
2369}
2370
2371
Steve Block8defd9f2010-07-08 12:39:36 +01002372// Test setting a breakpoint on the debugger statement.
Leon Clarke4515c472010-02-03 11:58:03 +00002373TEST(DebuggerStatementBreakpoint) {
2374 break_point_hit_count = 0;
2375 v8::HandleScope scope;
2376 DebugLocalContext env;
2377 v8::Debug::SetDebugEventListener(DebugEventBreakPointHitCount,
2378 v8::Undefined());
2379 v8::Script::Compile(v8::String::New("function foo(){debugger;}"))->Run();
2380 v8::Local<v8::Function> foo =
2381 v8::Local<v8::Function>::Cast(env->Global()->Get(v8::String::New("foo")));
2382
2383 // The debugger statement triggers breakpint hit
2384 foo->Call(env->Global(), 0, NULL);
2385 CHECK_EQ(1, break_point_hit_count);
2386
2387 int bp = SetBreakPoint(foo, 0);
2388
2389 // Set breakpoint does not duplicate hits
2390 foo->Call(env->Global(), 0, NULL);
2391 CHECK_EQ(2, break_point_hit_count);
2392
2393 ClearBreakPoint(bp);
2394 v8::Debug::SetDebugEventListener(NULL);
2395 CheckDebuggerUnloaded();
2396}
2397
2398
Steve Blocka7e24c12009-10-30 11:49:00 +00002399// Thest that the evaluation of expressions when a break point is hit generates
2400// the correct results.
2401TEST(DebugEvaluate) {
2402 v8::HandleScope scope;
2403 DebugLocalContext env;
2404 env.ExposeDebug();
2405
2406 // Create a function for checking the evaluation when hitting a break point.
2407 evaluate_check_function = CompileFunction(&env,
2408 evaluate_check_source,
2409 "evaluate_check");
2410 // Register the debug event listener
2411 v8::Debug::SetDebugEventListener(DebugEventEvaluate);
2412
2413 // Different expected vaules of x and a when in a break point (u = undefined,
2414 // d = Hello, world!).
2415 struct EvaluateCheck checks_uu[] = {
2416 {"x", v8::Undefined()},
2417 {"a", v8::Undefined()},
2418 {NULL, v8::Handle<v8::Value>()}
2419 };
2420 struct EvaluateCheck checks_hu[] = {
2421 {"x", v8::String::New("Hello, world!")},
2422 {"a", v8::Undefined()},
2423 {NULL, v8::Handle<v8::Value>()}
2424 };
2425 struct EvaluateCheck checks_hh[] = {
2426 {"x", v8::String::New("Hello, world!")},
2427 {"a", v8::String::New("Hello, world!")},
2428 {NULL, v8::Handle<v8::Value>()}
2429 };
2430
2431 // Simple test function. The "y=0" is in the function foo to provide a break
2432 // location. For "y=0" the "y" is at position 15 in the barbar function
2433 // therefore setting breakpoint at position 15 will break at "y=0" and
2434 // setting it higher will break after.
2435 v8::Local<v8::Function> foo = CompileFunction(&env,
2436 "function foo(x) {"
2437 " var a;"
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01002438 " y=0;" // To ensure break location 1.
Steve Blocka7e24c12009-10-30 11:49:00 +00002439 " a=x;"
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01002440 " y=0;" // To ensure break location 2.
Steve Blocka7e24c12009-10-30 11:49:00 +00002441 "}",
2442 "foo");
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01002443 const int foo_break_position_1 = 15;
2444 const int foo_break_position_2 = 29;
Steve Blocka7e24c12009-10-30 11:49:00 +00002445
2446 // Arguments with one parameter "Hello, world!"
2447 v8::Handle<v8::Value> argv_foo[1] = { v8::String::New("Hello, world!") };
2448
2449 // Call foo with breakpoint set before a=x and undefined as parameter.
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01002450 int bp = SetBreakPoint(foo, foo_break_position_1);
Steve Blocka7e24c12009-10-30 11:49:00 +00002451 checks = checks_uu;
2452 foo->Call(env->Global(), 0, NULL);
2453
2454 // Call foo with breakpoint set before a=x and parameter "Hello, world!".
2455 checks = checks_hu;
2456 foo->Call(env->Global(), 1, argv_foo);
2457
2458 // Call foo with breakpoint set after a=x and parameter "Hello, world!".
2459 ClearBreakPoint(bp);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01002460 SetBreakPoint(foo, foo_break_position_2);
Steve Blocka7e24c12009-10-30 11:49:00 +00002461 checks = checks_hh;
2462 foo->Call(env->Global(), 1, argv_foo);
2463
2464 // Test function with an inner function. The "y=0" is in function barbar
2465 // to provide a break location. For "y=0" the "y" is at position 8 in the
2466 // barbar function therefore setting breakpoint at position 8 will break at
2467 // "y=0" and setting it higher will break after.
2468 v8::Local<v8::Function> bar = CompileFunction(&env,
2469 "y = 0;"
2470 "x = 'Goodbye, world!';"
2471 "function bar(x, b) {"
2472 " var a;"
2473 " function barbar() {"
2474 " y=0; /* To ensure break location.*/"
2475 " a=x;"
2476 " };"
2477 " debug.Debug.clearAllBreakPoints();"
2478 " barbar();"
2479 " y=0;a=x;"
2480 "}",
2481 "bar");
2482 const int barbar_break_position = 8;
2483
2484 // Call bar setting breakpoint before a=x in barbar and undefined as
2485 // parameter.
2486 checks = checks_uu;
2487 v8::Handle<v8::Value> argv_bar_1[2] = {
2488 v8::Undefined(),
2489 v8::Number::New(barbar_break_position)
2490 };
2491 bar->Call(env->Global(), 2, argv_bar_1);
2492
2493 // Call bar setting breakpoint before a=x in barbar and parameter
2494 // "Hello, world!".
2495 checks = checks_hu;
2496 v8::Handle<v8::Value> argv_bar_2[2] = {
2497 v8::String::New("Hello, world!"),
2498 v8::Number::New(barbar_break_position)
2499 };
2500 bar->Call(env->Global(), 2, argv_bar_2);
2501
2502 // Call bar setting breakpoint after a=x in barbar and parameter
2503 // "Hello, world!".
2504 checks = checks_hh;
2505 v8::Handle<v8::Value> argv_bar_3[2] = {
2506 v8::String::New("Hello, world!"),
2507 v8::Number::New(barbar_break_position + 1)
2508 };
2509 bar->Call(env->Global(), 2, argv_bar_3);
2510
2511 v8::Debug::SetDebugEventListener(NULL);
2512 CheckDebuggerUnloaded();
2513}
2514
Leon Clarkee46be812010-01-19 14:06:41 +00002515// Copies a C string to a 16-bit string. Does not check for buffer overflow.
2516// Does not use the V8 engine to convert strings, so it can be used
2517// in any thread. Returns the length of the string.
2518int AsciiToUtf16(const char* input_buffer, uint16_t* output_buffer) {
2519 int i;
2520 for (i = 0; input_buffer[i] != '\0'; ++i) {
2521 // ASCII does not use chars > 127, but be careful anyway.
2522 output_buffer[i] = static_cast<unsigned char>(input_buffer[i]);
2523 }
2524 output_buffer[i] = 0;
2525 return i;
2526}
2527
2528// Copies a 16-bit string to a C string by dropping the high byte of
2529// each character. Does not check for buffer overflow.
2530// Can be used in any thread. Requires string length as an input.
2531int Utf16ToAscii(const uint16_t* input_buffer, int length,
2532 char* output_buffer, int output_len = -1) {
2533 if (output_len >= 0) {
2534 if (length > output_len - 1) {
2535 length = output_len - 1;
2536 }
2537 }
2538
2539 for (int i = 0; i < length; ++i) {
2540 output_buffer[i] = static_cast<char>(input_buffer[i]);
2541 }
2542 output_buffer[length] = '\0';
2543 return length;
2544}
2545
2546
2547// We match parts of the message to get evaluate result int value.
2548bool GetEvaluateStringResult(char *message, char* buffer, int buffer_size) {
Leon Clarked91b9f72010-01-27 17:25:45 +00002549 if (strstr(message, "\"command\":\"evaluate\"") == NULL) {
2550 return false;
2551 }
2552 const char* prefix = "\"text\":\"";
2553 char* pos1 = strstr(message, prefix);
2554 if (pos1 == NULL) {
2555 return false;
2556 }
2557 pos1 += strlen(prefix);
2558 char* pos2 = strchr(pos1, '"');
2559 if (pos2 == NULL) {
Leon Clarkee46be812010-01-19 14:06:41 +00002560 return false;
2561 }
2562 Vector<char> buf(buffer, buffer_size);
Leon Clarked91b9f72010-01-27 17:25:45 +00002563 int len = static_cast<int>(pos2 - pos1);
2564 if (len > buffer_size - 1) {
2565 len = buffer_size - 1;
2566 }
2567 OS::StrNCpy(buf, pos1, len);
Leon Clarkee46be812010-01-19 14:06:41 +00002568 buffer[buffer_size - 1] = '\0';
2569 return true;
2570}
2571
2572
2573struct EvaluateResult {
2574 static const int kBufferSize = 20;
2575 char buffer[kBufferSize];
2576};
2577
2578struct DebugProcessDebugMessagesData {
2579 static const int kArraySize = 5;
2580 int counter;
2581 EvaluateResult results[kArraySize];
2582
2583 void reset() {
2584 counter = 0;
2585 }
2586 EvaluateResult* current() {
2587 return &results[counter % kArraySize];
2588 }
2589 void next() {
2590 counter++;
2591 }
2592};
2593
2594DebugProcessDebugMessagesData process_debug_messages_data;
2595
2596static void DebugProcessDebugMessagesHandler(
2597 const uint16_t* message,
2598 int length,
2599 v8::Debug::ClientData* client_data) {
2600
2601 const int kBufferSize = 100000;
2602 char print_buffer[kBufferSize];
2603 Utf16ToAscii(message, length, print_buffer, kBufferSize);
2604
2605 EvaluateResult* array_item = process_debug_messages_data.current();
2606
2607 bool res = GetEvaluateStringResult(print_buffer,
2608 array_item->buffer,
2609 EvaluateResult::kBufferSize);
2610 if (res) {
2611 process_debug_messages_data.next();
2612 }
2613}
2614
2615// Test that the evaluation of expressions works even from ProcessDebugMessages
2616// i.e. with empty stack.
2617TEST(DebugEvaluateWithoutStack) {
2618 v8::Debug::SetMessageHandler(DebugProcessDebugMessagesHandler);
2619
2620 v8::HandleScope scope;
2621 DebugLocalContext env;
2622
2623 const char* source =
2624 "var v1 = 'Pinguin';\n function getAnimal() { return 'Capy' + 'bara'; }";
2625
2626 v8::Script::Compile(v8::String::New(source))->Run();
2627
2628 v8::Debug::ProcessDebugMessages();
2629
2630 const int kBufferSize = 1000;
2631 uint16_t buffer[kBufferSize];
2632
2633 const char* command_111 = "{\"seq\":111,"
2634 "\"type\":\"request\","
2635 "\"command\":\"evaluate\","
2636 "\"arguments\":{"
2637 " \"global\":true,"
2638 " \"expression\":\"v1\",\"disable_break\":true"
2639 "}}";
2640
2641 v8::Debug::SendCommand(buffer, AsciiToUtf16(command_111, buffer));
2642
2643 const char* command_112 = "{\"seq\":112,"
2644 "\"type\":\"request\","
2645 "\"command\":\"evaluate\","
2646 "\"arguments\":{"
2647 " \"global\":true,"
2648 " \"expression\":\"getAnimal()\",\"disable_break\":true"
2649 "}}";
2650
2651 v8::Debug::SendCommand(buffer, AsciiToUtf16(command_112, buffer));
2652
2653 const char* command_113 = "{\"seq\":113,"
2654 "\"type\":\"request\","
2655 "\"command\":\"evaluate\","
2656 "\"arguments\":{"
2657 " \"global\":true,"
2658 " \"expression\":\"239 + 566\",\"disable_break\":true"
2659 "}}";
2660
2661 v8::Debug::SendCommand(buffer, AsciiToUtf16(command_113, buffer));
2662
2663 v8::Debug::ProcessDebugMessages();
2664
2665 CHECK_EQ(3, process_debug_messages_data.counter);
2666
Leon Clarked91b9f72010-01-27 17:25:45 +00002667 CHECK_EQ(strcmp("Pinguin", process_debug_messages_data.results[0].buffer), 0);
2668 CHECK_EQ(strcmp("Capybara", process_debug_messages_data.results[1].buffer),
2669 0);
2670 CHECK_EQ(strcmp("805", process_debug_messages_data.results[2].buffer), 0);
Leon Clarkee46be812010-01-19 14:06:41 +00002671
2672 v8::Debug::SetMessageHandler(NULL);
2673 v8::Debug::SetDebugEventListener(NULL);
2674 CheckDebuggerUnloaded();
2675}
2676
Steve Blocka7e24c12009-10-30 11:49:00 +00002677
2678// Simple test of the stepping mechanism using only store ICs.
2679TEST(DebugStepLinear) {
2680 v8::HandleScope scope;
2681 DebugLocalContext env;
2682
2683 // Create a function for testing stepping.
2684 v8::Local<v8::Function> foo = CompileFunction(&env,
2685 "function foo(){a=1;b=1;c=1;}",
2686 "foo");
Ben Murdochb0fe1622011-05-05 13:52:32 +01002687
2688 // Run foo to allow it to get optimized.
2689 CompileRun("a=0; b=0; c=0; foo();");
2690
Steve Blocka7e24c12009-10-30 11:49:00 +00002691 SetBreakPoint(foo, 3);
2692
2693 // Register a debug event listener which steps and counts.
2694 v8::Debug::SetDebugEventListener(DebugEventStep);
2695
2696 step_action = StepIn;
2697 break_point_hit_count = 0;
2698 foo->Call(env->Global(), 0, NULL);
2699
2700 // With stepping all break locations are hit.
2701 CHECK_EQ(4, break_point_hit_count);
2702
2703 v8::Debug::SetDebugEventListener(NULL);
2704 CheckDebuggerUnloaded();
2705
2706 // Register a debug event listener which just counts.
2707 v8::Debug::SetDebugEventListener(DebugEventBreakPointHitCount);
2708
2709 SetBreakPoint(foo, 3);
2710 break_point_hit_count = 0;
2711 foo->Call(env->Global(), 0, NULL);
2712
2713 // Without stepping only active break points are hit.
2714 CHECK_EQ(1, break_point_hit_count);
2715
2716 v8::Debug::SetDebugEventListener(NULL);
2717 CheckDebuggerUnloaded();
2718}
2719
2720
2721// Test of the stepping mechanism for keyed load in a loop.
2722TEST(DebugStepKeyedLoadLoop) {
2723 v8::HandleScope scope;
2724 DebugLocalContext env;
2725
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01002726 // Register a debug event listener which steps and counts.
2727 v8::Debug::SetDebugEventListener(DebugEventStep);
2728
Steve Blocka7e24c12009-10-30 11:49:00 +00002729 // Create a function for testing stepping of keyed load. The statement 'y=1'
2730 // is there to have more than one breakable statement in the loop, TODO(315).
2731 v8::Local<v8::Function> foo = CompileFunction(
2732 &env,
2733 "function foo(a) {\n"
2734 " var x;\n"
2735 " var len = a.length;\n"
2736 " for (var i = 0; i < len; i++) {\n"
2737 " y = 1;\n"
2738 " x = a[i];\n"
2739 " }\n"
Ben Murdochb0fe1622011-05-05 13:52:32 +01002740 "}\n"
2741 "y=0\n",
Steve Blocka7e24c12009-10-30 11:49:00 +00002742 "foo");
2743
2744 // Create array [0,1,2,3,4,5,6,7,8,9]
2745 v8::Local<v8::Array> a = v8::Array::New(10);
2746 for (int i = 0; i < 10; i++) {
2747 a->Set(v8::Number::New(i), v8::Number::New(i));
2748 }
2749
2750 // Call function without any break points to ensure inlining is in place.
2751 const int kArgc = 1;
2752 v8::Handle<v8::Value> args[kArgc] = { a };
2753 foo->Call(env->Global(), kArgc, args);
2754
Steve Blocka7e24c12009-10-30 11:49:00 +00002755 // Setup break point and step through the function.
2756 SetBreakPoint(foo, 3);
2757 step_action = StepNext;
2758 break_point_hit_count = 0;
2759 foo->Call(env->Global(), kArgc, args);
2760
2761 // With stepping all break locations are hit.
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01002762 CHECK_EQ(33, break_point_hit_count);
Steve Blocka7e24c12009-10-30 11:49:00 +00002763
2764 v8::Debug::SetDebugEventListener(NULL);
2765 CheckDebuggerUnloaded();
2766}
2767
2768
2769// Test of the stepping mechanism for keyed store in a loop.
2770TEST(DebugStepKeyedStoreLoop) {
2771 v8::HandleScope scope;
2772 DebugLocalContext env;
2773
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01002774 // Register a debug event listener which steps and counts.
2775 v8::Debug::SetDebugEventListener(DebugEventStep);
2776
Steve Blocka7e24c12009-10-30 11:49:00 +00002777 // Create a function for testing stepping of keyed store. The statement 'y=1'
2778 // is there to have more than one breakable statement in the loop, TODO(315).
2779 v8::Local<v8::Function> foo = CompileFunction(
2780 &env,
2781 "function foo(a) {\n"
2782 " var len = a.length;\n"
2783 " for (var i = 0; i < len; i++) {\n"
2784 " y = 1;\n"
2785 " a[i] = 42;\n"
2786 " }\n"
Ben Murdochb0fe1622011-05-05 13:52:32 +01002787 "}\n"
2788 "y=0\n",
Steve Blocka7e24c12009-10-30 11:49:00 +00002789 "foo");
2790
2791 // Create array [0,1,2,3,4,5,6,7,8,9]
2792 v8::Local<v8::Array> a = v8::Array::New(10);
2793 for (int i = 0; i < 10; i++) {
2794 a->Set(v8::Number::New(i), v8::Number::New(i));
2795 }
2796
2797 // Call function without any break points to ensure inlining is in place.
2798 const int kArgc = 1;
2799 v8::Handle<v8::Value> args[kArgc] = { a };
2800 foo->Call(env->Global(), kArgc, args);
2801
Steve Blocka7e24c12009-10-30 11:49:00 +00002802 // Setup break point and step through the function.
2803 SetBreakPoint(foo, 3);
2804 step_action = StepNext;
2805 break_point_hit_count = 0;
2806 foo->Call(env->Global(), kArgc, args);
2807
2808 // With stepping all break locations are hit.
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01002809 CHECK_EQ(32, break_point_hit_count);
Steve Blocka7e24c12009-10-30 11:49:00 +00002810
2811 v8::Debug::SetDebugEventListener(NULL);
2812 CheckDebuggerUnloaded();
2813}
2814
2815
Kristian Monsen25f61362010-05-21 11:50:48 +01002816// Test of the stepping mechanism for named load in a loop.
2817TEST(DebugStepNamedLoadLoop) {
2818 v8::HandleScope scope;
2819 DebugLocalContext env;
2820
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01002821 // Register a debug event listener which steps and counts.
2822 v8::Debug::SetDebugEventListener(DebugEventStep);
2823
Kristian Monsen25f61362010-05-21 11:50:48 +01002824 // Create a function for testing stepping of named load.
2825 v8::Local<v8::Function> foo = CompileFunction(
2826 &env,
2827 "function foo() {\n"
2828 " var a = [];\n"
2829 " var s = \"\";\n"
2830 " for (var i = 0; i < 10; i++) {\n"
2831 " var v = new V(i, i + 1);\n"
2832 " v.y;\n"
2833 " a.length;\n" // Special case: array length.
2834 " s.length;\n" // Special case: string length.
2835 " }\n"
2836 "}\n"
2837 "function V(x, y) {\n"
2838 " this.x = x;\n"
2839 " this.y = y;\n"
2840 "}\n",
2841 "foo");
2842
2843 // Call function without any break points to ensure inlining is in place.
2844 foo->Call(env->Global(), 0, NULL);
2845
Kristian Monsen25f61362010-05-21 11:50:48 +01002846 // Setup break point and step through the function.
2847 SetBreakPoint(foo, 4);
2848 step_action = StepNext;
2849 break_point_hit_count = 0;
2850 foo->Call(env->Global(), 0, NULL);
2851
2852 // With stepping all break locations are hit.
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01002853 CHECK_EQ(53, break_point_hit_count);
Kristian Monsen25f61362010-05-21 11:50:48 +01002854
2855 v8::Debug::SetDebugEventListener(NULL);
2856 CheckDebuggerUnloaded();
2857}
2858
2859
Ben Murdochb0fe1622011-05-05 13:52:32 +01002860static void DoDebugStepNamedStoreLoop(int expected) {
Iain Merrick75681382010-08-19 15:07:18 +01002861 v8::HandleScope scope;
2862 DebugLocalContext env;
2863
Ben Murdochb0fe1622011-05-05 13:52:32 +01002864 // Register a debug event listener which steps and counts.
2865 v8::Debug::SetDebugEventListener(DebugEventStep);
Iain Merrick75681382010-08-19 15:07:18 +01002866
2867 // Create a function for testing stepping of named store.
2868 v8::Local<v8::Function> foo = CompileFunction(
2869 &env,
2870 "function foo() {\n"
2871 " var a = {a:1};\n"
2872 " for (var i = 0; i < 10; i++) {\n"
2873 " a.a = 2\n"
2874 " }\n"
2875 "}\n",
2876 "foo");
2877
2878 // Call function without any break points to ensure inlining is in place.
2879 foo->Call(env->Global(), 0, NULL);
2880
Iain Merrick75681382010-08-19 15:07:18 +01002881 // Setup break point and step through the function.
2882 SetBreakPoint(foo, 3);
2883 step_action = StepNext;
2884 break_point_hit_count = 0;
2885 foo->Call(env->Global(), 0, NULL);
2886
2887 // With stepping all expected break locations are hit.
2888 CHECK_EQ(expected, break_point_hit_count);
2889
2890 v8::Debug::SetDebugEventListener(NULL);
2891 CheckDebuggerUnloaded();
2892}
2893
2894
2895// Test of the stepping mechanism for named load in a loop.
Ben Murdochb0fe1622011-05-05 13:52:32 +01002896TEST(DebugStepNamedStoreLoop) {
Iain Merrick75681382010-08-19 15:07:18 +01002897 DoDebugStepNamedStoreLoop(22);
2898}
2899
2900
Steve Blocka7e24c12009-10-30 11:49:00 +00002901// Test the stepping mechanism with different ICs.
2902TEST(DebugStepLinearMixedICs) {
2903 v8::HandleScope scope;
2904 DebugLocalContext env;
2905
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01002906 // Register a debug event listener which steps and counts.
2907 v8::Debug::SetDebugEventListener(DebugEventStep);
2908
Steve Blocka7e24c12009-10-30 11:49:00 +00002909 // Create a function for testing stepping.
2910 v8::Local<v8::Function> foo = CompileFunction(&env,
2911 "function bar() {};"
2912 "function foo() {"
2913 " var x;"
2914 " var index='name';"
2915 " var y = {};"
2916 " a=1;b=2;x=a;y[index]=3;x=y[index];bar();}", "foo");
Ben Murdochb0fe1622011-05-05 13:52:32 +01002917
2918 // Run functions to allow them to get optimized.
2919 CompileRun("a=0; b=0; bar(); foo();");
2920
Steve Blocka7e24c12009-10-30 11:49:00 +00002921 SetBreakPoint(foo, 0);
2922
Steve Blocka7e24c12009-10-30 11:49:00 +00002923 step_action = StepIn;
2924 break_point_hit_count = 0;
2925 foo->Call(env->Global(), 0, NULL);
2926
2927 // With stepping all break locations are hit.
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01002928 CHECK_EQ(11, break_point_hit_count);
Steve Blocka7e24c12009-10-30 11:49:00 +00002929
2930 v8::Debug::SetDebugEventListener(NULL);
2931 CheckDebuggerUnloaded();
2932
2933 // Register a debug event listener which just counts.
2934 v8::Debug::SetDebugEventListener(DebugEventBreakPointHitCount);
2935
2936 SetBreakPoint(foo, 0);
2937 break_point_hit_count = 0;
2938 foo->Call(env->Global(), 0, NULL);
2939
2940 // Without stepping only active break points are hit.
2941 CHECK_EQ(1, break_point_hit_count);
2942
2943 v8::Debug::SetDebugEventListener(NULL);
2944 CheckDebuggerUnloaded();
2945}
2946
2947
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01002948TEST(DebugStepDeclarations) {
2949 v8::HandleScope scope;
2950 DebugLocalContext env;
2951
2952 // Register a debug event listener which steps and counts.
2953 v8::Debug::SetDebugEventListener(DebugEventStep);
2954
Ben Murdochb0fe1622011-05-05 13:52:32 +01002955 // Create a function for testing stepping. Run it to allow it to get
2956 // optimized.
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01002957 const char* src = "function foo() { "
2958 " var a;"
2959 " var b = 1;"
2960 " var c = foo;"
2961 " var d = Math.floor;"
2962 " var e = b + d(1.2);"
Ben Murdochb0fe1622011-05-05 13:52:32 +01002963 "}"
2964 "foo()";
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01002965 v8::Local<v8::Function> foo = CompileFunction(&env, src, "foo");
Ben Murdochb0fe1622011-05-05 13:52:32 +01002966
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01002967 SetBreakPoint(foo, 0);
2968
2969 // Stepping through the declarations.
2970 step_action = StepIn;
2971 break_point_hit_count = 0;
2972 foo->Call(env->Global(), 0, NULL);
2973 CHECK_EQ(6, break_point_hit_count);
2974
2975 // Get rid of the debug event listener.
2976 v8::Debug::SetDebugEventListener(NULL);
2977 CheckDebuggerUnloaded();
2978}
2979
2980
2981TEST(DebugStepLocals) {
2982 v8::HandleScope scope;
2983 DebugLocalContext env;
2984
2985 // Register a debug event listener which steps and counts.
2986 v8::Debug::SetDebugEventListener(DebugEventStep);
2987
Ben Murdochb0fe1622011-05-05 13:52:32 +01002988 // Create a function for testing stepping. Run it to allow it to get
2989 // optimized.
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01002990 const char* src = "function foo() { "
2991 " var a,b;"
2992 " a = 1;"
2993 " b = a + 2;"
2994 " b = 1 + 2 + 3;"
2995 " a = Math.floor(b);"
Ben Murdochb0fe1622011-05-05 13:52:32 +01002996 "}"
2997 "foo()";
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01002998 v8::Local<v8::Function> foo = CompileFunction(&env, src, "foo");
Ben Murdochb0fe1622011-05-05 13:52:32 +01002999
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01003000 SetBreakPoint(foo, 0);
3001
3002 // Stepping through the declarations.
3003 step_action = StepIn;
3004 break_point_hit_count = 0;
3005 foo->Call(env->Global(), 0, NULL);
3006 CHECK_EQ(6, break_point_hit_count);
3007
3008 // Get rid of the debug event listener.
3009 v8::Debug::SetDebugEventListener(NULL);
3010 CheckDebuggerUnloaded();
3011}
3012
3013
Steve Blocka7e24c12009-10-30 11:49:00 +00003014TEST(DebugStepIf) {
3015 v8::HandleScope scope;
3016 DebugLocalContext env;
3017
3018 // Register a debug event listener which steps and counts.
3019 v8::Debug::SetDebugEventListener(DebugEventStep);
3020
Ben Murdochb0fe1622011-05-05 13:52:32 +01003021 // Create a function for testing stepping. Run it to allow it to get
3022 // optimized.
Steve Blocka7e24c12009-10-30 11:49:00 +00003023 const int argc = 1;
3024 const char* src = "function foo(x) { "
3025 " a = 1;"
3026 " if (x) {"
3027 " b = 1;"
3028 " } else {"
3029 " c = 1;"
3030 " d = 1;"
3031 " }"
Ben Murdochb0fe1622011-05-05 13:52:32 +01003032 "}"
3033 "a=0; b=0; c=0; d=0; foo()";
Steve Blocka7e24c12009-10-30 11:49:00 +00003034 v8::Local<v8::Function> foo = CompileFunction(&env, src, "foo");
3035 SetBreakPoint(foo, 0);
3036
3037 // Stepping through the true part.
3038 step_action = StepIn;
3039 break_point_hit_count = 0;
3040 v8::Handle<v8::Value> argv_true[argc] = { v8::True() };
3041 foo->Call(env->Global(), argc, argv_true);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01003042 CHECK_EQ(4, break_point_hit_count);
Steve Blocka7e24c12009-10-30 11:49:00 +00003043
3044 // Stepping through the false part.
3045 step_action = StepIn;
3046 break_point_hit_count = 0;
3047 v8::Handle<v8::Value> argv_false[argc] = { v8::False() };
3048 foo->Call(env->Global(), argc, argv_false);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01003049 CHECK_EQ(5, break_point_hit_count);
Steve Blocka7e24c12009-10-30 11:49:00 +00003050
3051 // Get rid of the debug event listener.
3052 v8::Debug::SetDebugEventListener(NULL);
3053 CheckDebuggerUnloaded();
3054}
3055
3056
3057TEST(DebugStepSwitch) {
3058 v8::HandleScope scope;
3059 DebugLocalContext env;
3060
3061 // Register a debug event listener which steps and counts.
3062 v8::Debug::SetDebugEventListener(DebugEventStep);
3063
Ben Murdochb0fe1622011-05-05 13:52:32 +01003064 // Create a function for testing stepping. Run it to allow it to get
3065 // optimized.
Steve Blocka7e24c12009-10-30 11:49:00 +00003066 const int argc = 1;
3067 const char* src = "function foo(x) { "
3068 " a = 1;"
3069 " switch (x) {"
3070 " case 1:"
3071 " b = 1;"
3072 " case 2:"
3073 " c = 1;"
3074 " break;"
3075 " case 3:"
3076 " d = 1;"
3077 " e = 1;"
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01003078 " f = 1;"
Steve Blocka7e24c12009-10-30 11:49:00 +00003079 " break;"
3080 " }"
Ben Murdochb0fe1622011-05-05 13:52:32 +01003081 "}"
3082 "a=0; b=0; c=0; d=0; e=0; f=0; foo()";
Steve Blocka7e24c12009-10-30 11:49:00 +00003083 v8::Local<v8::Function> foo = CompileFunction(&env, src, "foo");
3084 SetBreakPoint(foo, 0);
3085
3086 // One case with fall-through.
3087 step_action = StepIn;
3088 break_point_hit_count = 0;
3089 v8::Handle<v8::Value> argv_1[argc] = { v8::Number::New(1) };
3090 foo->Call(env->Global(), argc, argv_1);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01003091 CHECK_EQ(6, break_point_hit_count);
Steve Blocka7e24c12009-10-30 11:49:00 +00003092
3093 // Another case.
3094 step_action = StepIn;
3095 break_point_hit_count = 0;
3096 v8::Handle<v8::Value> argv_2[argc] = { v8::Number::New(2) };
3097 foo->Call(env->Global(), argc, argv_2);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01003098 CHECK_EQ(5, break_point_hit_count);
Steve Blocka7e24c12009-10-30 11:49:00 +00003099
3100 // Last case.
3101 step_action = StepIn;
3102 break_point_hit_count = 0;
3103 v8::Handle<v8::Value> argv_3[argc] = { v8::Number::New(3) };
3104 foo->Call(env->Global(), argc, argv_3);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01003105 CHECK_EQ(7, break_point_hit_count);
3106
3107 // Get rid of the debug event listener.
3108 v8::Debug::SetDebugEventListener(NULL);
3109 CheckDebuggerUnloaded();
3110}
3111
3112
3113TEST(DebugStepWhile) {
3114 v8::HandleScope scope;
3115 DebugLocalContext env;
3116
3117 // Register a debug event listener which steps and counts.
3118 v8::Debug::SetDebugEventListener(DebugEventStep);
3119
Ben Murdochb0fe1622011-05-05 13:52:32 +01003120 // Create a function for testing stepping. Run it to allow it to get
3121 // optimized.
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01003122 const int argc = 1;
3123 const char* src = "function foo(x) { "
3124 " var a = 0;"
3125 " while (a < x) {"
3126 " a++;"
3127 " }"
Ben Murdochb0fe1622011-05-05 13:52:32 +01003128 "}"
3129 "foo()";
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01003130 v8::Local<v8::Function> foo = CompileFunction(&env, src, "foo");
3131 SetBreakPoint(foo, 8); // "var a = 0;"
3132
3133 // Looping 10 times.
3134 step_action = StepIn;
3135 break_point_hit_count = 0;
3136 v8::Handle<v8::Value> argv_10[argc] = { v8::Number::New(10) };
3137 foo->Call(env->Global(), argc, argv_10);
Ben Murdochb0fe1622011-05-05 13:52:32 +01003138 CHECK_EQ(22, break_point_hit_count);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01003139
3140 // Looping 100 times.
3141 step_action = StepIn;
3142 break_point_hit_count = 0;
3143 v8::Handle<v8::Value> argv_100[argc] = { v8::Number::New(100) };
3144 foo->Call(env->Global(), argc, argv_100);
Ben Murdochb0fe1622011-05-05 13:52:32 +01003145 CHECK_EQ(202, break_point_hit_count);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01003146
3147 // Get rid of the debug event listener.
3148 v8::Debug::SetDebugEventListener(NULL);
3149 CheckDebuggerUnloaded();
3150}
3151
3152
3153TEST(DebugStepDoWhile) {
3154 v8::HandleScope scope;
3155 DebugLocalContext env;
3156
3157 // Register a debug event listener which steps and counts.
3158 v8::Debug::SetDebugEventListener(DebugEventStep);
3159
Ben Murdochb0fe1622011-05-05 13:52:32 +01003160 // Create a function for testing stepping. Run it to allow it to get
3161 // optimized.
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01003162 const int argc = 1;
3163 const char* src = "function foo(x) { "
3164 " var a = 0;"
3165 " do {"
3166 " a++;"
3167 " } while (a < x)"
Ben Murdochb0fe1622011-05-05 13:52:32 +01003168 "}"
3169 "foo()";
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01003170 v8::Local<v8::Function> foo = CompileFunction(&env, src, "foo");
3171 SetBreakPoint(foo, 8); // "var a = 0;"
3172
3173 // Looping 10 times.
3174 step_action = StepIn;
3175 break_point_hit_count = 0;
3176 v8::Handle<v8::Value> argv_10[argc] = { v8::Number::New(10) };
3177 foo->Call(env->Global(), argc, argv_10);
3178 CHECK_EQ(22, break_point_hit_count);
3179
3180 // Looping 100 times.
3181 step_action = StepIn;
3182 break_point_hit_count = 0;
3183 v8::Handle<v8::Value> argv_100[argc] = { v8::Number::New(100) };
3184 foo->Call(env->Global(), argc, argv_100);
3185 CHECK_EQ(202, break_point_hit_count);
Steve Blocka7e24c12009-10-30 11:49:00 +00003186
3187 // Get rid of the debug event listener.
3188 v8::Debug::SetDebugEventListener(NULL);
3189 CheckDebuggerUnloaded();
3190}
3191
3192
3193TEST(DebugStepFor) {
3194 v8::HandleScope scope;
3195 DebugLocalContext env;
3196
3197 // Register a debug event listener which steps and counts.
3198 v8::Debug::SetDebugEventListener(DebugEventStep);
3199
Ben Murdochb0fe1622011-05-05 13:52:32 +01003200 // Create a function for testing stepping. Run it to allow it to get
3201 // optimized.
Steve Blocka7e24c12009-10-30 11:49:00 +00003202 const int argc = 1;
3203 const char* src = "function foo(x) { "
3204 " a = 1;"
3205 " for (i = 0; i < x; i++) {"
3206 " b = 1;"
3207 " }"
Ben Murdochb0fe1622011-05-05 13:52:32 +01003208 "}"
3209 "a=0; b=0; i=0; foo()";
Steve Blocka7e24c12009-10-30 11:49:00 +00003210 v8::Local<v8::Function> foo = CompileFunction(&env, src, "foo");
Ben Murdochb0fe1622011-05-05 13:52:32 +01003211
Steve Blocka7e24c12009-10-30 11:49:00 +00003212 SetBreakPoint(foo, 8); // "a = 1;"
3213
3214 // Looping 10 times.
3215 step_action = StepIn;
3216 break_point_hit_count = 0;
3217 v8::Handle<v8::Value> argv_10[argc] = { v8::Number::New(10) };
3218 foo->Call(env->Global(), argc, argv_10);
3219 CHECK_EQ(23, break_point_hit_count);
3220
3221 // Looping 100 times.
3222 step_action = StepIn;
3223 break_point_hit_count = 0;
3224 v8::Handle<v8::Value> argv_100[argc] = { v8::Number::New(100) };
3225 foo->Call(env->Global(), argc, argv_100);
3226 CHECK_EQ(203, break_point_hit_count);
3227
3228 // Get rid of the debug event listener.
3229 v8::Debug::SetDebugEventListener(NULL);
3230 CheckDebuggerUnloaded();
3231}
3232
3233
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01003234TEST(DebugStepForContinue) {
3235 v8::HandleScope scope;
3236 DebugLocalContext env;
3237
3238 // Register a debug event listener which steps and counts.
3239 v8::Debug::SetDebugEventListener(DebugEventStep);
3240
Ben Murdochb0fe1622011-05-05 13:52:32 +01003241 // Create a function for testing stepping. Run it to allow it to get
3242 // optimized.
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01003243 const int argc = 1;
3244 const char* src = "function foo(x) { "
3245 " var a = 0;"
3246 " var b = 0;"
3247 " var c = 0;"
3248 " for (var i = 0; i < x; i++) {"
3249 " a++;"
3250 " if (a % 2 == 0) continue;"
3251 " b++;"
3252 " c++;"
3253 " }"
3254 " return b;"
Ben Murdochb0fe1622011-05-05 13:52:32 +01003255 "}"
3256 "foo()";
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01003257 v8::Local<v8::Function> foo = CompileFunction(&env, src, "foo");
3258 v8::Handle<v8::Value> result;
3259 SetBreakPoint(foo, 8); // "var a = 0;"
3260
3261 // Each loop generates 4 or 5 steps depending on whether a is equal.
3262
3263 // Looping 10 times.
3264 step_action = StepIn;
3265 break_point_hit_count = 0;
3266 v8::Handle<v8::Value> argv_10[argc] = { v8::Number::New(10) };
3267 result = foo->Call(env->Global(), argc, argv_10);
3268 CHECK_EQ(5, result->Int32Value());
3269 CHECK_EQ(50, break_point_hit_count);
3270
3271 // Looping 100 times.
3272 step_action = StepIn;
3273 break_point_hit_count = 0;
3274 v8::Handle<v8::Value> argv_100[argc] = { v8::Number::New(100) };
3275 result = foo->Call(env->Global(), argc, argv_100);
3276 CHECK_EQ(50, result->Int32Value());
3277 CHECK_EQ(455, break_point_hit_count);
3278
3279 // Get rid of the debug event listener.
3280 v8::Debug::SetDebugEventListener(NULL);
3281 CheckDebuggerUnloaded();
3282}
3283
3284
3285TEST(DebugStepForBreak) {
3286 v8::HandleScope scope;
3287 DebugLocalContext env;
3288
3289 // Register a debug event listener which steps and counts.
3290 v8::Debug::SetDebugEventListener(DebugEventStep);
3291
Ben Murdochb0fe1622011-05-05 13:52:32 +01003292 // Create a function for testing stepping. Run it to allow it to get
3293 // optimized.
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01003294 const int argc = 1;
3295 const char* src = "function foo(x) { "
3296 " var a = 0;"
3297 " var b = 0;"
3298 " var c = 0;"
3299 " for (var i = 0; i < 1000; i++) {"
3300 " a++;"
3301 " if (a == x) break;"
3302 " b++;"
3303 " c++;"
3304 " }"
3305 " return b;"
Ben Murdochb0fe1622011-05-05 13:52:32 +01003306 "}"
3307 "foo()";
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01003308 v8::Local<v8::Function> foo = CompileFunction(&env, src, "foo");
3309 v8::Handle<v8::Value> result;
3310 SetBreakPoint(foo, 8); // "var a = 0;"
3311
3312 // Each loop generates 5 steps except for the last (when break is executed)
3313 // which only generates 4.
3314
3315 // Looping 10 times.
3316 step_action = StepIn;
3317 break_point_hit_count = 0;
3318 v8::Handle<v8::Value> argv_10[argc] = { v8::Number::New(10) };
3319 result = foo->Call(env->Global(), argc, argv_10);
3320 CHECK_EQ(9, result->Int32Value());
3321 CHECK_EQ(53, break_point_hit_count);
3322
3323 // Looping 100 times.
3324 step_action = StepIn;
3325 break_point_hit_count = 0;
3326 v8::Handle<v8::Value> argv_100[argc] = { v8::Number::New(100) };
3327 result = foo->Call(env->Global(), argc, argv_100);
3328 CHECK_EQ(99, result->Int32Value());
3329 CHECK_EQ(503, break_point_hit_count);
3330
3331 // Get rid of the debug event listener.
3332 v8::Debug::SetDebugEventListener(NULL);
3333 CheckDebuggerUnloaded();
3334}
3335
3336
3337TEST(DebugStepForIn) {
3338 v8::HandleScope scope;
3339 DebugLocalContext env;
3340
3341 // Register a debug event listener which steps and counts.
3342 v8::Debug::SetDebugEventListener(DebugEventStep);
3343
Ben Murdochb0fe1622011-05-05 13:52:32 +01003344 // Create a function for testing stepping. Run it to allow it to get
3345 // optimized.
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01003346 v8::Local<v8::Function> foo;
3347 const char* src_1 = "function foo() { "
3348 " var a = [1, 2];"
3349 " for (x in a) {"
3350 " b = 0;"
3351 " }"
Ben Murdochb0fe1622011-05-05 13:52:32 +01003352 "}"
3353 "foo()";
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01003354 foo = CompileFunction(&env, src_1, "foo");
3355 SetBreakPoint(foo, 0); // "var a = ..."
3356
3357 step_action = StepIn;
3358 break_point_hit_count = 0;
3359 foo->Call(env->Global(), 0, NULL);
3360 CHECK_EQ(6, break_point_hit_count);
3361
Ben Murdochb0fe1622011-05-05 13:52:32 +01003362 // Create a function for testing stepping. Run it to allow it to get
3363 // optimized.
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01003364 const char* src_2 = "function foo() { "
3365 " var a = {a:[1, 2, 3]};"
3366 " for (x in a.a) {"
3367 " b = 0;"
3368 " }"
Ben Murdochb0fe1622011-05-05 13:52:32 +01003369 "}"
3370 "foo()";
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01003371 foo = CompileFunction(&env, src_2, "foo");
3372 SetBreakPoint(foo, 0); // "var a = ..."
3373
3374 step_action = StepIn;
3375 break_point_hit_count = 0;
3376 foo->Call(env->Global(), 0, NULL);
3377 CHECK_EQ(8, break_point_hit_count);
3378
3379 // Get rid of the debug event listener.
3380 v8::Debug::SetDebugEventListener(NULL);
3381 CheckDebuggerUnloaded();
3382}
3383
3384
3385TEST(DebugStepWith) {
3386 v8::HandleScope scope;
3387 DebugLocalContext env;
3388
3389 // Register a debug event listener which steps and counts.
3390 v8::Debug::SetDebugEventListener(DebugEventStep);
3391
Ben Murdochb0fe1622011-05-05 13:52:32 +01003392 // Create a function for testing stepping. Run it to allow it to get
3393 // optimized.
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01003394 const char* src = "function foo(x) { "
3395 " var a = {};"
3396 " with (a) {}"
3397 " with (b) {}"
Ben Murdochb0fe1622011-05-05 13:52:32 +01003398 "}"
3399 "foo()";
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01003400 env->Global()->Set(v8::String::New("b"), v8::Object::New());
3401 v8::Local<v8::Function> foo = CompileFunction(&env, src, "foo");
3402 v8::Handle<v8::Value> result;
3403 SetBreakPoint(foo, 8); // "var a = {};"
3404
3405 step_action = StepIn;
3406 break_point_hit_count = 0;
3407 foo->Call(env->Global(), 0, NULL);
3408 CHECK_EQ(4, break_point_hit_count);
3409
3410 // Get rid of the debug event listener.
3411 v8::Debug::SetDebugEventListener(NULL);
3412 CheckDebuggerUnloaded();
3413}
3414
3415
3416TEST(DebugConditional) {
3417 v8::HandleScope scope;
3418 DebugLocalContext env;
3419
3420 // Register a debug event listener which steps and counts.
3421 v8::Debug::SetDebugEventListener(DebugEventStep);
3422
Ben Murdochb0fe1622011-05-05 13:52:32 +01003423 // Create a function for testing stepping. Run it to allow it to get
3424 // optimized.
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01003425 const char* src = "function foo(x) { "
3426 " var a;"
3427 " a = x ? 1 : 2;"
3428 " return a;"
Ben Murdochb0fe1622011-05-05 13:52:32 +01003429 "}"
3430 "foo()";
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01003431 v8::Local<v8::Function> foo = CompileFunction(&env, src, "foo");
3432 SetBreakPoint(foo, 0); // "var a;"
3433
3434 step_action = StepIn;
3435 break_point_hit_count = 0;
3436 foo->Call(env->Global(), 0, NULL);
3437 CHECK_EQ(5, break_point_hit_count);
3438
3439 step_action = StepIn;
3440 break_point_hit_count = 0;
3441 const int argc = 1;
3442 v8::Handle<v8::Value> argv_true[argc] = { v8::True() };
3443 foo->Call(env->Global(), argc, argv_true);
3444 CHECK_EQ(5, break_point_hit_count);
3445
3446 // Get rid of the debug event listener.
3447 v8::Debug::SetDebugEventListener(NULL);
3448 CheckDebuggerUnloaded();
3449}
3450
3451
Steve Blocka7e24c12009-10-30 11:49:00 +00003452TEST(StepInOutSimple) {
3453 v8::HandleScope scope;
3454 DebugLocalContext env;
3455
3456 // Create a function for checking the function when hitting a break point.
3457 frame_function_name = CompileFunction(&env,
3458 frame_function_name_source,
3459 "frame_function_name");
3460
3461 // Register a debug event listener which steps and counts.
3462 v8::Debug::SetDebugEventListener(DebugEventStepSequence);
3463
Ben Murdochb0fe1622011-05-05 13:52:32 +01003464 // Create a function for testing stepping. Run it to allow it to get
3465 // optimized.
Steve Blocka7e24c12009-10-30 11:49:00 +00003466 const char* src = "function a() {b();c();}; "
3467 "function b() {c();}; "
Ben Murdochb0fe1622011-05-05 13:52:32 +01003468 "function c() {}; "
3469 "a(); b(); c()";
Steve Blocka7e24c12009-10-30 11:49:00 +00003470 v8::Local<v8::Function> a = CompileFunction(&env, src, "a");
3471 SetBreakPoint(a, 0);
3472
3473 // Step through invocation of a with step in.
3474 step_action = StepIn;
3475 break_point_hit_count = 0;
3476 expected_step_sequence = "abcbaca";
3477 a->Call(env->Global(), 0, NULL);
Steve Blockd0582a62009-12-15 09:54:21 +00003478 CHECK_EQ(StrLength(expected_step_sequence),
3479 break_point_hit_count);
Steve Blocka7e24c12009-10-30 11:49:00 +00003480
3481 // Step through invocation of a with step next.
3482 step_action = StepNext;
3483 break_point_hit_count = 0;
3484 expected_step_sequence = "aaa";
3485 a->Call(env->Global(), 0, NULL);
Steve Blockd0582a62009-12-15 09:54:21 +00003486 CHECK_EQ(StrLength(expected_step_sequence),
3487 break_point_hit_count);
Steve Blocka7e24c12009-10-30 11:49:00 +00003488
3489 // Step through invocation of a with step out.
3490 step_action = StepOut;
3491 break_point_hit_count = 0;
3492 expected_step_sequence = "a";
3493 a->Call(env->Global(), 0, NULL);
Steve Blockd0582a62009-12-15 09:54:21 +00003494 CHECK_EQ(StrLength(expected_step_sequence),
3495 break_point_hit_count);
Steve Blocka7e24c12009-10-30 11:49:00 +00003496
3497 // Get rid of the debug event listener.
3498 v8::Debug::SetDebugEventListener(NULL);
3499 CheckDebuggerUnloaded();
3500}
3501
3502
3503TEST(StepInOutTree) {
3504 v8::HandleScope scope;
3505 DebugLocalContext env;
3506
3507 // Create a function for checking the function when hitting a break point.
3508 frame_function_name = CompileFunction(&env,
3509 frame_function_name_source,
3510 "frame_function_name");
3511
3512 // Register a debug event listener which steps and counts.
3513 v8::Debug::SetDebugEventListener(DebugEventStepSequence);
3514
Ben Murdochb0fe1622011-05-05 13:52:32 +01003515 // Create a function for testing stepping. Run it to allow it to get
3516 // optimized.
Steve Blocka7e24c12009-10-30 11:49:00 +00003517 const char* src = "function a() {b(c(d()),d());c(d());d()}; "
3518 "function b(x,y) {c();}; "
3519 "function c(x) {}; "
Ben Murdochb0fe1622011-05-05 13:52:32 +01003520 "function d() {}; "
3521 "a(); b(); c(); d()";
Steve Blocka7e24c12009-10-30 11:49:00 +00003522 v8::Local<v8::Function> a = CompileFunction(&env, src, "a");
3523 SetBreakPoint(a, 0);
3524
3525 // Step through invocation of a with step in.
3526 step_action = StepIn;
3527 break_point_hit_count = 0;
3528 expected_step_sequence = "adacadabcbadacada";
3529 a->Call(env->Global(), 0, NULL);
Steve Blockd0582a62009-12-15 09:54:21 +00003530 CHECK_EQ(StrLength(expected_step_sequence),
3531 break_point_hit_count);
Steve Blocka7e24c12009-10-30 11:49:00 +00003532
3533 // Step through invocation of a with step next.
3534 step_action = StepNext;
3535 break_point_hit_count = 0;
3536 expected_step_sequence = "aaaa";
3537 a->Call(env->Global(), 0, NULL);
Steve Blockd0582a62009-12-15 09:54:21 +00003538 CHECK_EQ(StrLength(expected_step_sequence),
3539 break_point_hit_count);
Steve Blocka7e24c12009-10-30 11:49:00 +00003540
3541 // Step through invocation of a with step out.
3542 step_action = StepOut;
3543 break_point_hit_count = 0;
3544 expected_step_sequence = "a";
3545 a->Call(env->Global(), 0, NULL);
Steve Blockd0582a62009-12-15 09:54:21 +00003546 CHECK_EQ(StrLength(expected_step_sequence),
3547 break_point_hit_count);
Steve Blocka7e24c12009-10-30 11:49:00 +00003548
3549 // Get rid of the debug event listener.
3550 v8::Debug::SetDebugEventListener(NULL);
3551 CheckDebuggerUnloaded(true);
3552}
3553
3554
3555TEST(StepInOutBranch) {
3556 v8::HandleScope scope;
3557 DebugLocalContext env;
3558
3559 // Create a function for checking the function when hitting a break point.
3560 frame_function_name = CompileFunction(&env,
3561 frame_function_name_source,
3562 "frame_function_name");
3563
3564 // Register a debug event listener which steps and counts.
3565 v8::Debug::SetDebugEventListener(DebugEventStepSequence);
3566
Ben Murdochb0fe1622011-05-05 13:52:32 +01003567 // Create a function for testing stepping. Run it to allow it to get
3568 // optimized.
Steve Blocka7e24c12009-10-30 11:49:00 +00003569 const char* src = "function a() {b(false);c();}; "
3570 "function b(x) {if(x){c();};}; "
Ben Murdochb0fe1622011-05-05 13:52:32 +01003571 "function c() {}; "
3572 "a(); b(); c()";
Steve Blocka7e24c12009-10-30 11:49:00 +00003573 v8::Local<v8::Function> a = CompileFunction(&env, src, "a");
3574 SetBreakPoint(a, 0);
3575
3576 // Step through invocation of a.
3577 step_action = StepIn;
3578 break_point_hit_count = 0;
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01003579 expected_step_sequence = "abbaca";
Steve Blocka7e24c12009-10-30 11:49:00 +00003580 a->Call(env->Global(), 0, NULL);
Steve Blockd0582a62009-12-15 09:54:21 +00003581 CHECK_EQ(StrLength(expected_step_sequence),
3582 break_point_hit_count);
Steve Blocka7e24c12009-10-30 11:49:00 +00003583
3584 // Get rid of the debug event listener.
3585 v8::Debug::SetDebugEventListener(NULL);
3586 CheckDebuggerUnloaded();
3587}
3588
3589
3590// Test that step in does not step into native functions.
3591TEST(DebugStepNatives) {
3592 v8::HandleScope scope;
3593 DebugLocalContext env;
3594
3595 // Create a function for testing stepping.
3596 v8::Local<v8::Function> foo = CompileFunction(
3597 &env,
3598 "function foo(){debugger;Math.sin(1);}",
3599 "foo");
3600
3601 // Register a debug event listener which steps and counts.
3602 v8::Debug::SetDebugEventListener(DebugEventStep);
3603
3604 step_action = StepIn;
3605 break_point_hit_count = 0;
3606 foo->Call(env->Global(), 0, NULL);
3607
3608 // With stepping all break locations are hit.
3609 CHECK_EQ(3, break_point_hit_count);
3610
3611 v8::Debug::SetDebugEventListener(NULL);
3612 CheckDebuggerUnloaded();
3613
3614 // Register a debug event listener which just counts.
3615 v8::Debug::SetDebugEventListener(DebugEventBreakPointHitCount);
3616
3617 break_point_hit_count = 0;
3618 foo->Call(env->Global(), 0, NULL);
3619
3620 // Without stepping only active break points are hit.
3621 CHECK_EQ(1, break_point_hit_count);
3622
3623 v8::Debug::SetDebugEventListener(NULL);
3624 CheckDebuggerUnloaded();
3625}
3626
3627
3628// Test that step in works with function.apply.
3629TEST(DebugStepFunctionApply) {
3630 v8::HandleScope scope;
3631 DebugLocalContext env;
3632
3633 // Create a function for testing stepping.
3634 v8::Local<v8::Function> foo = CompileFunction(
3635 &env,
3636 "function bar(x, y, z) { if (x == 1) { a = y; b = z; } }"
3637 "function foo(){ debugger; bar.apply(this, [1,2,3]); }",
3638 "foo");
3639
3640 // Register a debug event listener which steps and counts.
3641 v8::Debug::SetDebugEventListener(DebugEventStep);
3642
3643 step_action = StepIn;
3644 break_point_hit_count = 0;
3645 foo->Call(env->Global(), 0, NULL);
3646
3647 // With stepping all break locations are hit.
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01003648 CHECK_EQ(7, break_point_hit_count);
Steve Blocka7e24c12009-10-30 11:49:00 +00003649
3650 v8::Debug::SetDebugEventListener(NULL);
3651 CheckDebuggerUnloaded();
3652
3653 // Register a debug event listener which just counts.
3654 v8::Debug::SetDebugEventListener(DebugEventBreakPointHitCount);
3655
3656 break_point_hit_count = 0;
3657 foo->Call(env->Global(), 0, NULL);
3658
3659 // Without stepping only the debugger statement is hit.
3660 CHECK_EQ(1, break_point_hit_count);
3661
3662 v8::Debug::SetDebugEventListener(NULL);
3663 CheckDebuggerUnloaded();
3664}
3665
3666
3667// Test that step in works with function.call.
3668TEST(DebugStepFunctionCall) {
3669 v8::HandleScope scope;
3670 DebugLocalContext env;
3671
3672 // Create a function for testing stepping.
3673 v8::Local<v8::Function> foo = CompileFunction(
3674 &env,
3675 "function bar(x, y, z) { if (x == 1) { a = y; b = z; } }"
3676 "function foo(a){ debugger;"
3677 " if (a) {"
3678 " bar.call(this, 1, 2, 3);"
3679 " } else {"
3680 " bar.call(this, 0);"
3681 " }"
3682 "}",
3683 "foo");
3684
3685 // Register a debug event listener which steps and counts.
3686 v8::Debug::SetDebugEventListener(DebugEventStep);
3687 step_action = StepIn;
3688
3689 // Check stepping where the if condition in bar is false.
3690 break_point_hit_count = 0;
3691 foo->Call(env->Global(), 0, NULL);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01003692 CHECK_EQ(6, break_point_hit_count);
Steve Blocka7e24c12009-10-30 11:49:00 +00003693
3694 // Check stepping where the if condition in bar is true.
3695 break_point_hit_count = 0;
3696 const int argc = 1;
3697 v8::Handle<v8::Value> argv[argc] = { v8::True() };
3698 foo->Call(env->Global(), argc, argv);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01003699 CHECK_EQ(8, break_point_hit_count);
Steve Blocka7e24c12009-10-30 11:49:00 +00003700
3701 v8::Debug::SetDebugEventListener(NULL);
3702 CheckDebuggerUnloaded();
3703
3704 // Register a debug event listener which just counts.
3705 v8::Debug::SetDebugEventListener(DebugEventBreakPointHitCount);
3706
3707 break_point_hit_count = 0;
3708 foo->Call(env->Global(), 0, NULL);
3709
3710 // Without stepping only the debugger statement is hit.
3711 CHECK_EQ(1, break_point_hit_count);
3712
3713 v8::Debug::SetDebugEventListener(NULL);
3714 CheckDebuggerUnloaded();
3715}
3716
3717
Steve Blockd0582a62009-12-15 09:54:21 +00003718// Tests that breakpoint will be hit if it's set in script.
3719TEST(PauseInScript) {
3720 v8::HandleScope scope;
3721 DebugLocalContext env;
3722 env.ExposeDebug();
3723
3724 // Register a debug event listener which counts.
3725 v8::Debug::SetDebugEventListener(DebugEventCounter);
3726
3727 // Create a script that returns a function.
3728 const char* src = "(function (evt) {})";
3729 const char* script_name = "StepInHandlerTest";
3730
3731 // Set breakpoint in the script.
3732 SetScriptBreakPointByNameFromJS(script_name, 0, -1);
3733 break_point_hit_count = 0;
3734
3735 v8::ScriptOrigin origin(v8::String::New(script_name), v8::Integer::New(0));
3736 v8::Handle<v8::Script> script = v8::Script::Compile(v8::String::New(src),
3737 &origin);
3738 v8::Local<v8::Value> r = script->Run();
3739
3740 CHECK(r->IsFunction());
3741 CHECK_EQ(1, break_point_hit_count);
3742
3743 // Get rid of the debug event listener.
3744 v8::Debug::SetDebugEventListener(NULL);
3745 CheckDebuggerUnloaded();
3746}
3747
3748
Steve Blocka7e24c12009-10-30 11:49:00 +00003749// Test break on exceptions. For each exception break combination the number
3750// of debug event exception callbacks and message callbacks are collected. The
3751// number of debug event exception callbacks are used to check that the
3752// debugger is called correctly and the number of message callbacks is used to
3753// check that uncaught exceptions are still returned even if there is a break
3754// for them.
3755TEST(BreakOnException) {
3756 v8::HandleScope scope;
3757 DebugLocalContext env;
3758 env.ExposeDebug();
3759
Steve Block44f0eee2011-05-26 01:26:41 +01003760 v8::internal::Isolate::Current()->TraceException(false);
Steve Blocka7e24c12009-10-30 11:49:00 +00003761
3762 // Create functions for testing break on exception.
3763 v8::Local<v8::Function> throws =
3764 CompileFunction(&env, "function throws(){throw 1;}", "throws");
3765 v8::Local<v8::Function> caught =
3766 CompileFunction(&env,
3767 "function caught(){try {throws();} catch(e) {};}",
3768 "caught");
3769 v8::Local<v8::Function> notCaught =
3770 CompileFunction(&env, "function notCaught(){throws();}", "notCaught");
3771
3772 v8::V8::AddMessageListener(MessageCallbackCount);
3773 v8::Debug::SetDebugEventListener(DebugEventCounter);
3774
Ben Murdoch086aeea2011-05-13 15:57:08 +01003775 // Initial state should be no break on exceptions.
Steve Blocka7e24c12009-10-30 11:49:00 +00003776 DebugEventCounterClear();
3777 MessageCallbackCountClear();
3778 caught->Call(env->Global(), 0, NULL);
3779 CHECK_EQ(0, exception_hit_count);
3780 CHECK_EQ(0, uncaught_exception_hit_count);
3781 CHECK_EQ(0, message_callback_count);
3782 notCaught->Call(env->Global(), 0, NULL);
Ben Murdoch086aeea2011-05-13 15:57:08 +01003783 CHECK_EQ(0, exception_hit_count);
3784 CHECK_EQ(0, uncaught_exception_hit_count);
Steve Blocka7e24c12009-10-30 11:49:00 +00003785 CHECK_EQ(1, message_callback_count);
3786
3787 // No break on exception
3788 DebugEventCounterClear();
3789 MessageCallbackCountClear();
3790 ChangeBreakOnException(false, false);
3791 caught->Call(env->Global(), 0, NULL);
3792 CHECK_EQ(0, exception_hit_count);
3793 CHECK_EQ(0, uncaught_exception_hit_count);
3794 CHECK_EQ(0, message_callback_count);
3795 notCaught->Call(env->Global(), 0, NULL);
3796 CHECK_EQ(0, exception_hit_count);
3797 CHECK_EQ(0, uncaught_exception_hit_count);
3798 CHECK_EQ(1, message_callback_count);
3799
3800 // Break on uncaught exception
3801 DebugEventCounterClear();
3802 MessageCallbackCountClear();
3803 ChangeBreakOnException(false, true);
3804 caught->Call(env->Global(), 0, NULL);
3805 CHECK_EQ(0, exception_hit_count);
3806 CHECK_EQ(0, uncaught_exception_hit_count);
3807 CHECK_EQ(0, message_callback_count);
3808 notCaught->Call(env->Global(), 0, NULL);
3809 CHECK_EQ(1, exception_hit_count);
3810 CHECK_EQ(1, uncaught_exception_hit_count);
3811 CHECK_EQ(1, message_callback_count);
3812
3813 // Break on exception and uncaught exception
3814 DebugEventCounterClear();
3815 MessageCallbackCountClear();
3816 ChangeBreakOnException(true, true);
3817 caught->Call(env->Global(), 0, NULL);
3818 CHECK_EQ(1, exception_hit_count);
3819 CHECK_EQ(0, uncaught_exception_hit_count);
3820 CHECK_EQ(0, message_callback_count);
3821 notCaught->Call(env->Global(), 0, NULL);
3822 CHECK_EQ(2, exception_hit_count);
3823 CHECK_EQ(1, uncaught_exception_hit_count);
3824 CHECK_EQ(1, message_callback_count);
3825
3826 // Break on exception
3827 DebugEventCounterClear();
3828 MessageCallbackCountClear();
3829 ChangeBreakOnException(true, false);
3830 caught->Call(env->Global(), 0, NULL);
3831 CHECK_EQ(1, exception_hit_count);
3832 CHECK_EQ(0, uncaught_exception_hit_count);
3833 CHECK_EQ(0, message_callback_count);
3834 notCaught->Call(env->Global(), 0, NULL);
3835 CHECK_EQ(2, exception_hit_count);
3836 CHECK_EQ(1, uncaught_exception_hit_count);
3837 CHECK_EQ(1, message_callback_count);
3838
3839 // No break on exception using JavaScript
3840 DebugEventCounterClear();
3841 MessageCallbackCountClear();
3842 ChangeBreakOnExceptionFromJS(false, false);
3843 caught->Call(env->Global(), 0, NULL);
3844 CHECK_EQ(0, exception_hit_count);
3845 CHECK_EQ(0, uncaught_exception_hit_count);
3846 CHECK_EQ(0, message_callback_count);
3847 notCaught->Call(env->Global(), 0, NULL);
3848 CHECK_EQ(0, exception_hit_count);
3849 CHECK_EQ(0, uncaught_exception_hit_count);
3850 CHECK_EQ(1, message_callback_count);
3851
3852 // Break on uncaught exception using JavaScript
3853 DebugEventCounterClear();
3854 MessageCallbackCountClear();
3855 ChangeBreakOnExceptionFromJS(false, true);
3856 caught->Call(env->Global(), 0, NULL);
3857 CHECK_EQ(0, exception_hit_count);
3858 CHECK_EQ(0, uncaught_exception_hit_count);
3859 CHECK_EQ(0, message_callback_count);
3860 notCaught->Call(env->Global(), 0, NULL);
3861 CHECK_EQ(1, exception_hit_count);
3862 CHECK_EQ(1, uncaught_exception_hit_count);
3863 CHECK_EQ(1, message_callback_count);
3864
3865 // Break on exception and uncaught exception using JavaScript
3866 DebugEventCounterClear();
3867 MessageCallbackCountClear();
3868 ChangeBreakOnExceptionFromJS(true, true);
3869 caught->Call(env->Global(), 0, NULL);
3870 CHECK_EQ(1, exception_hit_count);
3871 CHECK_EQ(0, message_callback_count);
3872 CHECK_EQ(0, uncaught_exception_hit_count);
3873 notCaught->Call(env->Global(), 0, NULL);
3874 CHECK_EQ(2, exception_hit_count);
3875 CHECK_EQ(1, uncaught_exception_hit_count);
3876 CHECK_EQ(1, message_callback_count);
3877
3878 // Break on exception using JavaScript
3879 DebugEventCounterClear();
3880 MessageCallbackCountClear();
3881 ChangeBreakOnExceptionFromJS(true, false);
3882 caught->Call(env->Global(), 0, NULL);
3883 CHECK_EQ(1, exception_hit_count);
3884 CHECK_EQ(0, uncaught_exception_hit_count);
3885 CHECK_EQ(0, message_callback_count);
3886 notCaught->Call(env->Global(), 0, NULL);
3887 CHECK_EQ(2, exception_hit_count);
3888 CHECK_EQ(1, uncaught_exception_hit_count);
3889 CHECK_EQ(1, message_callback_count);
3890
3891 v8::Debug::SetDebugEventListener(NULL);
3892 CheckDebuggerUnloaded();
3893 v8::V8::RemoveMessageListeners(MessageCallbackCount);
3894}
3895
3896
3897// Test break on exception from compiler errors. When compiling using
3898// v8::Script::Compile there is no JavaScript stack whereas when compiling using
3899// eval there are JavaScript frames.
3900TEST(BreakOnCompileException) {
3901 v8::HandleScope scope;
3902 DebugLocalContext env;
3903
Ben Murdoch086aeea2011-05-13 15:57:08 +01003904 // For this test, we want to break on uncaught exceptions:
3905 ChangeBreakOnException(false, true);
3906
Steve Block44f0eee2011-05-26 01:26:41 +01003907 v8::internal::Isolate::Current()->TraceException(false);
Steve Blocka7e24c12009-10-30 11:49:00 +00003908
3909 // Create a function for checking the function when hitting a break point.
3910 frame_count = CompileFunction(&env, frame_count_source, "frame_count");
3911
3912 v8::V8::AddMessageListener(MessageCallbackCount);
3913 v8::Debug::SetDebugEventListener(DebugEventCounter);
3914
3915 DebugEventCounterClear();
3916 MessageCallbackCountClear();
3917
3918 // Check initial state.
3919 CHECK_EQ(0, exception_hit_count);
3920 CHECK_EQ(0, uncaught_exception_hit_count);
3921 CHECK_EQ(0, message_callback_count);
3922 CHECK_EQ(-1, last_js_stack_height);
3923
3924 // Throws SyntaxError: Unexpected end of input
3925 v8::Script::Compile(v8::String::New("+++"));
3926 CHECK_EQ(1, exception_hit_count);
3927 CHECK_EQ(1, uncaught_exception_hit_count);
3928 CHECK_EQ(1, message_callback_count);
3929 CHECK_EQ(0, last_js_stack_height); // No JavaScript stack.
3930
3931 // Throws SyntaxError: Unexpected identifier
3932 v8::Script::Compile(v8::String::New("x x"));
3933 CHECK_EQ(2, exception_hit_count);
3934 CHECK_EQ(2, uncaught_exception_hit_count);
3935 CHECK_EQ(2, message_callback_count);
3936 CHECK_EQ(0, last_js_stack_height); // No JavaScript stack.
3937
3938 // Throws SyntaxError: Unexpected end of input
3939 v8::Script::Compile(v8::String::New("eval('+++')"))->Run();
3940 CHECK_EQ(3, exception_hit_count);
3941 CHECK_EQ(3, uncaught_exception_hit_count);
3942 CHECK_EQ(3, message_callback_count);
3943 CHECK_EQ(1, last_js_stack_height);
3944
3945 // Throws SyntaxError: Unexpected identifier
3946 v8::Script::Compile(v8::String::New("eval('x x')"))->Run();
3947 CHECK_EQ(4, exception_hit_count);
3948 CHECK_EQ(4, uncaught_exception_hit_count);
3949 CHECK_EQ(4, message_callback_count);
3950 CHECK_EQ(1, last_js_stack_height);
3951}
3952
3953
3954TEST(StepWithException) {
3955 v8::HandleScope scope;
3956 DebugLocalContext env;
3957
Ben Murdoch086aeea2011-05-13 15:57:08 +01003958 // For this test, we want to break on uncaught exceptions:
3959 ChangeBreakOnException(false, true);
3960
Steve Blocka7e24c12009-10-30 11:49:00 +00003961 // Create a function for checking the function when hitting a break point.
3962 frame_function_name = CompileFunction(&env,
3963 frame_function_name_source,
3964 "frame_function_name");
3965
3966 // Register a debug event listener which steps and counts.
3967 v8::Debug::SetDebugEventListener(DebugEventStepSequence);
3968
3969 // Create functions for testing stepping.
3970 const char* src = "function a() { n(); }; "
3971 "function b() { c(); }; "
3972 "function c() { n(); }; "
3973 "function d() { x = 1; try { e(); } catch(x) { x = 2; } }; "
3974 "function e() { n(); }; "
3975 "function f() { x = 1; try { g(); } catch(x) { x = 2; } }; "
3976 "function g() { h(); }; "
3977 "function h() { x = 1; throw 1; }; ";
3978
3979 // Step through invocation of a.
3980 v8::Local<v8::Function> a = CompileFunction(&env, src, "a");
3981 SetBreakPoint(a, 0);
3982 step_action = StepIn;
3983 break_point_hit_count = 0;
3984 expected_step_sequence = "aa";
3985 a->Call(env->Global(), 0, NULL);
Steve Blockd0582a62009-12-15 09:54:21 +00003986 CHECK_EQ(StrLength(expected_step_sequence),
3987 break_point_hit_count);
Steve Blocka7e24c12009-10-30 11:49:00 +00003988
3989 // Step through invocation of b + c.
3990 v8::Local<v8::Function> b = CompileFunction(&env, src, "b");
3991 SetBreakPoint(b, 0);
3992 step_action = StepIn;
3993 break_point_hit_count = 0;
3994 expected_step_sequence = "bcc";
3995 b->Call(env->Global(), 0, NULL);
Steve Blockd0582a62009-12-15 09:54:21 +00003996 CHECK_EQ(StrLength(expected_step_sequence),
3997 break_point_hit_count);
Steve Blocka7e24c12009-10-30 11:49:00 +00003998 // Step through invocation of d + e.
3999 v8::Local<v8::Function> d = CompileFunction(&env, src, "d");
4000 SetBreakPoint(d, 0);
4001 ChangeBreakOnException(false, true);
4002 step_action = StepIn;
4003 break_point_hit_count = 0;
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01004004 expected_step_sequence = "ddedd";
Steve Blocka7e24c12009-10-30 11:49:00 +00004005 d->Call(env->Global(), 0, NULL);
Steve Blockd0582a62009-12-15 09:54:21 +00004006 CHECK_EQ(StrLength(expected_step_sequence),
4007 break_point_hit_count);
Steve Blocka7e24c12009-10-30 11:49:00 +00004008
4009 // Step through invocation of d + e now with break on caught exceptions.
4010 ChangeBreakOnException(true, true);
4011 step_action = StepIn;
4012 break_point_hit_count = 0;
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01004013 expected_step_sequence = "ddeedd";
Steve Blocka7e24c12009-10-30 11:49:00 +00004014 d->Call(env->Global(), 0, NULL);
Steve Blockd0582a62009-12-15 09:54:21 +00004015 CHECK_EQ(StrLength(expected_step_sequence),
4016 break_point_hit_count);
Steve Blocka7e24c12009-10-30 11:49:00 +00004017
4018 // Step through invocation of f + g + h.
4019 v8::Local<v8::Function> f = CompileFunction(&env, src, "f");
4020 SetBreakPoint(f, 0);
4021 ChangeBreakOnException(false, true);
4022 step_action = StepIn;
4023 break_point_hit_count = 0;
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01004024 expected_step_sequence = "ffghhff";
Steve Blocka7e24c12009-10-30 11:49:00 +00004025 f->Call(env->Global(), 0, NULL);
Steve Blockd0582a62009-12-15 09:54:21 +00004026 CHECK_EQ(StrLength(expected_step_sequence),
4027 break_point_hit_count);
Steve Blocka7e24c12009-10-30 11:49:00 +00004028
4029 // Step through invocation of f + g + h now with break on caught exceptions.
4030 ChangeBreakOnException(true, true);
4031 step_action = StepIn;
4032 break_point_hit_count = 0;
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01004033 expected_step_sequence = "ffghhhff";
Steve Blocka7e24c12009-10-30 11:49:00 +00004034 f->Call(env->Global(), 0, NULL);
Steve Blockd0582a62009-12-15 09:54:21 +00004035 CHECK_EQ(StrLength(expected_step_sequence),
4036 break_point_hit_count);
Steve Blocka7e24c12009-10-30 11:49:00 +00004037
4038 // Get rid of the debug event listener.
4039 v8::Debug::SetDebugEventListener(NULL);
4040 CheckDebuggerUnloaded();
4041}
4042
4043
4044TEST(DebugBreak) {
4045 v8::HandleScope scope;
4046 DebugLocalContext env;
4047
4048 // This test should be run with option --verify-heap. As --verify-heap is
4049 // only available in debug mode only check for it in that case.
4050#ifdef DEBUG
4051 CHECK(v8::internal::FLAG_verify_heap);
4052#endif
4053
4054 // Register a debug event listener which sets the break flag and counts.
4055 v8::Debug::SetDebugEventListener(DebugEventBreak);
4056
4057 // Create a function for testing stepping.
4058 const char* src = "function f0() {}"
4059 "function f1(x1) {}"
4060 "function f2(x1,x2) {}"
4061 "function f3(x1,x2,x3) {}";
4062 v8::Local<v8::Function> f0 = CompileFunction(&env, src, "f0");
4063 v8::Local<v8::Function> f1 = CompileFunction(&env, src, "f1");
4064 v8::Local<v8::Function> f2 = CompileFunction(&env, src, "f2");
4065 v8::Local<v8::Function> f3 = CompileFunction(&env, src, "f3");
4066
4067 // Call the function to make sure it is compiled.
4068 v8::Handle<v8::Value> argv[] = { v8::Number::New(1),
4069 v8::Number::New(1),
4070 v8::Number::New(1),
4071 v8::Number::New(1) };
4072
4073 // Call all functions to make sure that they are compiled.
4074 f0->Call(env->Global(), 0, NULL);
4075 f1->Call(env->Global(), 0, NULL);
4076 f2->Call(env->Global(), 0, NULL);
4077 f3->Call(env->Global(), 0, NULL);
4078
4079 // Set the debug break flag.
4080 v8::Debug::DebugBreak();
4081
4082 // Call all functions with different argument count.
4083 break_point_hit_count = 0;
4084 for (unsigned int i = 0; i < ARRAY_SIZE(argv); i++) {
4085 f0->Call(env->Global(), i, argv);
4086 f1->Call(env->Global(), i, argv);
4087 f2->Call(env->Global(), i, argv);
4088 f3->Call(env->Global(), i, argv);
4089 }
4090
4091 // One break for each function called.
4092 CHECK_EQ(4 * ARRAY_SIZE(argv), break_point_hit_count);
4093
4094 // Get rid of the debug event listener.
4095 v8::Debug::SetDebugEventListener(NULL);
4096 CheckDebuggerUnloaded();
4097}
4098
4099
4100// Test to ensure that JavaScript code keeps running while the debug break
4101// through the stack limit flag is set but breaks are disabled.
4102TEST(DisableBreak) {
4103 v8::HandleScope scope;
4104 DebugLocalContext env;
4105
4106 // Register a debug event listener which sets the break flag and counts.
4107 v8::Debug::SetDebugEventListener(DebugEventCounter);
4108
4109 // Create a function for testing stepping.
4110 const char* src = "function f() {g()};function g(){i=0; while(i<10){i++}}";
4111 v8::Local<v8::Function> f = CompileFunction(&env, src, "f");
4112
4113 // Set the debug break flag.
4114 v8::Debug::DebugBreak();
4115
4116 // Call all functions with different argument count.
4117 break_point_hit_count = 0;
4118 f->Call(env->Global(), 0, NULL);
4119 CHECK_EQ(1, break_point_hit_count);
4120
4121 {
4122 v8::Debug::DebugBreak();
4123 v8::internal::DisableBreak disable_break(true);
4124 f->Call(env->Global(), 0, NULL);
4125 CHECK_EQ(1, break_point_hit_count);
4126 }
4127
4128 f->Call(env->Global(), 0, NULL);
4129 CHECK_EQ(2, break_point_hit_count);
4130
4131 // Get rid of the debug event listener.
4132 v8::Debug::SetDebugEventListener(NULL);
4133 CheckDebuggerUnloaded();
4134}
4135
Leon Clarkee46be812010-01-19 14:06:41 +00004136static const char* kSimpleExtensionSource =
4137 "(function Foo() {"
4138 " return 4;"
4139 "})() ";
4140
4141// http://crbug.com/28933
4142// Test that debug break is disabled when bootstrapper is active.
4143TEST(NoBreakWhenBootstrapping) {
4144 v8::HandleScope scope;
4145
4146 // Register a debug event listener which sets the break flag and counts.
4147 v8::Debug::SetDebugEventListener(DebugEventCounter);
4148
4149 // Set the debug break flag.
4150 v8::Debug::DebugBreak();
4151 break_point_hit_count = 0;
4152 {
4153 // Create a context with an extension to make sure that some JavaScript
4154 // code is executed during bootstrapping.
4155 v8::RegisterExtension(new v8::Extension("simpletest",
4156 kSimpleExtensionSource));
4157 const char* extension_names[] = { "simpletest" };
4158 v8::ExtensionConfiguration extensions(1, extension_names);
4159 v8::Persistent<v8::Context> context = v8::Context::New(&extensions);
4160 context.Dispose();
4161 }
4162 // Check that no DebugBreak events occured during the context creation.
4163 CHECK_EQ(0, break_point_hit_count);
4164
4165 // Get rid of the debug event listener.
4166 v8::Debug::SetDebugEventListener(NULL);
4167 CheckDebuggerUnloaded();
4168}
Steve Blocka7e24c12009-10-30 11:49:00 +00004169
4170static v8::Handle<v8::Array> NamedEnum(const v8::AccessorInfo&) {
4171 v8::Handle<v8::Array> result = v8::Array::New(3);
4172 result->Set(v8::Integer::New(0), v8::String::New("a"));
4173 result->Set(v8::Integer::New(1), v8::String::New("b"));
4174 result->Set(v8::Integer::New(2), v8::String::New("c"));
4175 return result;
4176}
4177
4178
4179static v8::Handle<v8::Array> IndexedEnum(const v8::AccessorInfo&) {
4180 v8::Handle<v8::Array> result = v8::Array::New(2);
4181 result->Set(v8::Integer::New(0), v8::Number::New(1));
4182 result->Set(v8::Integer::New(1), v8::Number::New(10));
4183 return result;
4184}
4185
4186
4187static v8::Handle<v8::Value> NamedGetter(v8::Local<v8::String> name,
4188 const v8::AccessorInfo& info) {
4189 v8::String::AsciiValue n(name);
4190 if (strcmp(*n, "a") == 0) {
4191 return v8::String::New("AA");
4192 } else if (strcmp(*n, "b") == 0) {
4193 return v8::String::New("BB");
4194 } else if (strcmp(*n, "c") == 0) {
4195 return v8::String::New("CC");
4196 } else {
4197 return v8::Undefined();
4198 }
4199
4200 return name;
4201}
4202
4203
4204static v8::Handle<v8::Value> IndexedGetter(uint32_t index,
4205 const v8::AccessorInfo& info) {
4206 return v8::Number::New(index + 1);
4207}
4208
4209
4210TEST(InterceptorPropertyMirror) {
4211 // Create a V8 environment with debug access.
4212 v8::HandleScope scope;
4213 DebugLocalContext env;
4214 env.ExposeDebug();
4215
4216 // Create object with named interceptor.
4217 v8::Handle<v8::ObjectTemplate> named = v8::ObjectTemplate::New();
4218 named->SetNamedPropertyHandler(NamedGetter, NULL, NULL, NULL, NamedEnum);
4219 env->Global()->Set(v8::String::New("intercepted_named"),
4220 named->NewInstance());
4221
4222 // Create object with indexed interceptor.
4223 v8::Handle<v8::ObjectTemplate> indexed = v8::ObjectTemplate::New();
4224 indexed->SetIndexedPropertyHandler(IndexedGetter,
4225 NULL,
4226 NULL,
4227 NULL,
4228 IndexedEnum);
4229 env->Global()->Set(v8::String::New("intercepted_indexed"),
4230 indexed->NewInstance());
4231
4232 // Create object with both named and indexed interceptor.
4233 v8::Handle<v8::ObjectTemplate> both = v8::ObjectTemplate::New();
4234 both->SetNamedPropertyHandler(NamedGetter, NULL, NULL, NULL, NamedEnum);
4235 both->SetIndexedPropertyHandler(IndexedGetter, NULL, NULL, NULL, IndexedEnum);
4236 env->Global()->Set(v8::String::New("intercepted_both"), both->NewInstance());
4237
4238 // Get mirrors for the three objects with interceptor.
4239 CompileRun(
4240 "named_mirror = debug.MakeMirror(intercepted_named);"
4241 "indexed_mirror = debug.MakeMirror(intercepted_indexed);"
4242 "both_mirror = debug.MakeMirror(intercepted_both)");
4243 CHECK(CompileRun(
4244 "named_mirror instanceof debug.ObjectMirror")->BooleanValue());
4245 CHECK(CompileRun(
4246 "indexed_mirror instanceof debug.ObjectMirror")->BooleanValue());
4247 CHECK(CompileRun(
4248 "both_mirror instanceof debug.ObjectMirror")->BooleanValue());
4249
4250 // Get the property names from the interceptors
4251 CompileRun(
4252 "named_names = named_mirror.propertyNames();"
4253 "indexed_names = indexed_mirror.propertyNames();"
4254 "both_names = both_mirror.propertyNames()");
4255 CHECK_EQ(3, CompileRun("named_names.length")->Int32Value());
4256 CHECK_EQ(2, CompileRun("indexed_names.length")->Int32Value());
4257 CHECK_EQ(5, CompileRun("both_names.length")->Int32Value());
4258
4259 // Check the expected number of properties.
4260 const char* source;
4261 source = "named_mirror.properties().length";
4262 CHECK_EQ(3, CompileRun(source)->Int32Value());
4263
4264 source = "indexed_mirror.properties().length";
4265 CHECK_EQ(2, CompileRun(source)->Int32Value());
4266
4267 source = "both_mirror.properties().length";
4268 CHECK_EQ(5, CompileRun(source)->Int32Value());
4269
4270 // 1 is PropertyKind.Named;
4271 source = "both_mirror.properties(1).length";
4272 CHECK_EQ(3, CompileRun(source)->Int32Value());
4273
4274 // 2 is PropertyKind.Indexed;
4275 source = "both_mirror.properties(2).length";
4276 CHECK_EQ(2, CompileRun(source)->Int32Value());
4277
4278 // 3 is PropertyKind.Named | PropertyKind.Indexed;
4279 source = "both_mirror.properties(3).length";
4280 CHECK_EQ(5, CompileRun(source)->Int32Value());
4281
4282 // Get the interceptor properties for the object with only named interceptor.
4283 CompileRun("named_values = named_mirror.properties()");
4284
4285 // Check that the properties are interceptor properties.
4286 for (int i = 0; i < 3; i++) {
4287 EmbeddedVector<char, SMALL_STRING_BUFFER_SIZE> buffer;
4288 OS::SNPrintF(buffer,
4289 "named_values[%d] instanceof debug.PropertyMirror", i);
4290 CHECK(CompileRun(buffer.start())->BooleanValue());
4291
Ben Murdoch257744e2011-11-30 15:57:28 +00004292 // 5 is PropertyType.Interceptor
Steve Blocka7e24c12009-10-30 11:49:00 +00004293 OS::SNPrintF(buffer, "named_values[%d].propertyType()", i);
Ben Murdoch257744e2011-11-30 15:57:28 +00004294 CHECK_EQ(5, CompileRun(buffer.start())->Int32Value());
Steve Blocka7e24c12009-10-30 11:49:00 +00004295
4296 OS::SNPrintF(buffer, "named_values[%d].isNative()", i);
4297 CHECK(CompileRun(buffer.start())->BooleanValue());
4298 }
4299
4300 // Get the interceptor properties for the object with only indexed
4301 // interceptor.
4302 CompileRun("indexed_values = indexed_mirror.properties()");
4303
4304 // Check that the properties are interceptor properties.
4305 for (int i = 0; i < 2; i++) {
4306 EmbeddedVector<char, SMALL_STRING_BUFFER_SIZE> buffer;
4307 OS::SNPrintF(buffer,
4308 "indexed_values[%d] instanceof debug.PropertyMirror", i);
4309 CHECK(CompileRun(buffer.start())->BooleanValue());
4310 }
4311
4312 // Get the interceptor properties for the object with both types of
4313 // interceptors.
4314 CompileRun("both_values = both_mirror.properties()");
4315
4316 // Check that the properties are interceptor properties.
4317 for (int i = 0; i < 5; i++) {
4318 EmbeddedVector<char, SMALL_STRING_BUFFER_SIZE> buffer;
4319 OS::SNPrintF(buffer, "both_values[%d] instanceof debug.PropertyMirror", i);
4320 CHECK(CompileRun(buffer.start())->BooleanValue());
4321 }
4322
4323 // Check the property names.
4324 source = "both_values[0].name() == 'a'";
4325 CHECK(CompileRun(source)->BooleanValue());
4326
4327 source = "both_values[1].name() == 'b'";
4328 CHECK(CompileRun(source)->BooleanValue());
4329
4330 source = "both_values[2].name() == 'c'";
4331 CHECK(CompileRun(source)->BooleanValue());
4332
4333 source = "both_values[3].name() == 1";
4334 CHECK(CompileRun(source)->BooleanValue());
4335
4336 source = "both_values[4].name() == 10";
4337 CHECK(CompileRun(source)->BooleanValue());
4338}
4339
4340
4341TEST(HiddenPrototypePropertyMirror) {
4342 // Create a V8 environment with debug access.
4343 v8::HandleScope scope;
4344 DebugLocalContext env;
4345 env.ExposeDebug();
4346
4347 v8::Handle<v8::FunctionTemplate> t0 = v8::FunctionTemplate::New();
4348 t0->InstanceTemplate()->Set(v8::String::New("x"), v8::Number::New(0));
4349 v8::Handle<v8::FunctionTemplate> t1 = v8::FunctionTemplate::New();
4350 t1->SetHiddenPrototype(true);
4351 t1->InstanceTemplate()->Set(v8::String::New("y"), v8::Number::New(1));
4352 v8::Handle<v8::FunctionTemplate> t2 = v8::FunctionTemplate::New();
4353 t2->SetHiddenPrototype(true);
4354 t2->InstanceTemplate()->Set(v8::String::New("z"), v8::Number::New(2));
4355 v8::Handle<v8::FunctionTemplate> t3 = v8::FunctionTemplate::New();
4356 t3->InstanceTemplate()->Set(v8::String::New("u"), v8::Number::New(3));
4357
4358 // Create object and set them on the global object.
4359 v8::Handle<v8::Object> o0 = t0->GetFunction()->NewInstance();
4360 env->Global()->Set(v8::String::New("o0"), o0);
4361 v8::Handle<v8::Object> o1 = t1->GetFunction()->NewInstance();
4362 env->Global()->Set(v8::String::New("o1"), o1);
4363 v8::Handle<v8::Object> o2 = t2->GetFunction()->NewInstance();
4364 env->Global()->Set(v8::String::New("o2"), o2);
4365 v8::Handle<v8::Object> o3 = t3->GetFunction()->NewInstance();
4366 env->Global()->Set(v8::String::New("o3"), o3);
4367
4368 // Get mirrors for the four objects.
4369 CompileRun(
4370 "o0_mirror = debug.MakeMirror(o0);"
4371 "o1_mirror = debug.MakeMirror(o1);"
4372 "o2_mirror = debug.MakeMirror(o2);"
4373 "o3_mirror = debug.MakeMirror(o3)");
4374 CHECK(CompileRun("o0_mirror instanceof debug.ObjectMirror")->BooleanValue());
4375 CHECK(CompileRun("o1_mirror instanceof debug.ObjectMirror")->BooleanValue());
4376 CHECK(CompileRun("o2_mirror instanceof debug.ObjectMirror")->BooleanValue());
4377 CHECK(CompileRun("o3_mirror instanceof debug.ObjectMirror")->BooleanValue());
4378
4379 // Check that each object has one property.
4380 CHECK_EQ(1, CompileRun(
4381 "o0_mirror.propertyNames().length")->Int32Value());
4382 CHECK_EQ(1, CompileRun(
4383 "o1_mirror.propertyNames().length")->Int32Value());
4384 CHECK_EQ(1, CompileRun(
4385 "o2_mirror.propertyNames().length")->Int32Value());
4386 CHECK_EQ(1, CompileRun(
4387 "o3_mirror.propertyNames().length")->Int32Value());
4388
4389 // Set o1 as prototype for o0. o1 has the hidden prototype flag so all
4390 // properties on o1 should be seen on o0.
4391 o0->Set(v8::String::New("__proto__"), o1);
4392 CHECK_EQ(2, CompileRun(
4393 "o0_mirror.propertyNames().length")->Int32Value());
4394 CHECK_EQ(0, CompileRun(
4395 "o0_mirror.property('x').value().value()")->Int32Value());
4396 CHECK_EQ(1, CompileRun(
4397 "o0_mirror.property('y').value().value()")->Int32Value());
4398
4399 // Set o2 as prototype for o0 (it will end up after o1 as o1 has the hidden
4400 // prototype flag. o2 also has the hidden prototype flag so all properties
4401 // on o2 should be seen on o0 as well as properties on o1.
4402 o0->Set(v8::String::New("__proto__"), o2);
4403 CHECK_EQ(3, CompileRun(
4404 "o0_mirror.propertyNames().length")->Int32Value());
4405 CHECK_EQ(0, CompileRun(
4406 "o0_mirror.property('x').value().value()")->Int32Value());
4407 CHECK_EQ(1, CompileRun(
4408 "o0_mirror.property('y').value().value()")->Int32Value());
4409 CHECK_EQ(2, CompileRun(
4410 "o0_mirror.property('z').value().value()")->Int32Value());
4411
4412 // Set o3 as prototype for o0 (it will end up after o1 and o2 as both o1 and
4413 // o2 has the hidden prototype flag. o3 does not have the hidden prototype
4414 // flag so properties on o3 should not be seen on o0 whereas the properties
4415 // from o1 and o2 should still be seen on o0.
4416 // Final prototype chain: o0 -> o1 -> o2 -> o3
4417 // Hidden prototypes: ^^ ^^
4418 o0->Set(v8::String::New("__proto__"), o3);
4419 CHECK_EQ(3, CompileRun(
4420 "o0_mirror.propertyNames().length")->Int32Value());
4421 CHECK_EQ(1, CompileRun(
4422 "o3_mirror.propertyNames().length")->Int32Value());
4423 CHECK_EQ(0, CompileRun(
4424 "o0_mirror.property('x').value().value()")->Int32Value());
4425 CHECK_EQ(1, CompileRun(
4426 "o0_mirror.property('y').value().value()")->Int32Value());
4427 CHECK_EQ(2, CompileRun(
4428 "o0_mirror.property('z').value().value()")->Int32Value());
4429 CHECK(CompileRun("o0_mirror.property('u').isUndefined()")->BooleanValue());
4430
4431 // The prototype (__proto__) for o0 should be o3 as o1 and o2 are hidden.
4432 CHECK(CompileRun("o0_mirror.protoObject() == o3_mirror")->BooleanValue());
4433}
4434
4435
4436static v8::Handle<v8::Value> ProtperyXNativeGetter(
4437 v8::Local<v8::String> property, const v8::AccessorInfo& info) {
4438 return v8::Integer::New(10);
4439}
4440
4441
4442TEST(NativeGetterPropertyMirror) {
4443 // Create a V8 environment with debug access.
4444 v8::HandleScope scope;
4445 DebugLocalContext env;
4446 env.ExposeDebug();
4447
4448 v8::Handle<v8::String> name = v8::String::New("x");
4449 // Create object with named accessor.
4450 v8::Handle<v8::ObjectTemplate> named = v8::ObjectTemplate::New();
4451 named->SetAccessor(name, &ProtperyXNativeGetter, NULL,
4452 v8::Handle<v8::Value>(), v8::DEFAULT, v8::None);
4453
4454 // Create object with named property getter.
4455 env->Global()->Set(v8::String::New("instance"), named->NewInstance());
4456 CHECK_EQ(10, CompileRun("instance.x")->Int32Value());
4457
4458 // Get mirror for the object with property getter.
4459 CompileRun("instance_mirror = debug.MakeMirror(instance);");
4460 CHECK(CompileRun(
4461 "instance_mirror instanceof debug.ObjectMirror")->BooleanValue());
4462
4463 CompileRun("named_names = instance_mirror.propertyNames();");
4464 CHECK_EQ(1, CompileRun("named_names.length")->Int32Value());
4465 CHECK(CompileRun("named_names[0] == 'x'")->BooleanValue());
4466 CHECK(CompileRun(
4467 "instance_mirror.property('x').value().isNumber()")->BooleanValue());
4468 CHECK(CompileRun(
4469 "instance_mirror.property('x').value().value() == 10")->BooleanValue());
4470}
4471
4472
4473static v8::Handle<v8::Value> ProtperyXNativeGetterThrowingError(
4474 v8::Local<v8::String> property, const v8::AccessorInfo& info) {
4475 return CompileRun("throw new Error('Error message');");
4476}
4477
4478
4479TEST(NativeGetterThrowingErrorPropertyMirror) {
4480 // Create a V8 environment with debug access.
4481 v8::HandleScope scope;
4482 DebugLocalContext env;
4483 env.ExposeDebug();
4484
4485 v8::Handle<v8::String> name = v8::String::New("x");
4486 // Create object with named accessor.
4487 v8::Handle<v8::ObjectTemplate> named = v8::ObjectTemplate::New();
4488 named->SetAccessor(name, &ProtperyXNativeGetterThrowingError, NULL,
4489 v8::Handle<v8::Value>(), v8::DEFAULT, v8::None);
4490
4491 // Create object with named property getter.
4492 env->Global()->Set(v8::String::New("instance"), named->NewInstance());
4493
4494 // Get mirror for the object with property getter.
4495 CompileRun("instance_mirror = debug.MakeMirror(instance);");
4496 CHECK(CompileRun(
4497 "instance_mirror instanceof debug.ObjectMirror")->BooleanValue());
4498 CompileRun("named_names = instance_mirror.propertyNames();");
4499 CHECK_EQ(1, CompileRun("named_names.length")->Int32Value());
4500 CHECK(CompileRun("named_names[0] == 'x'")->BooleanValue());
4501 CHECK(CompileRun(
4502 "instance_mirror.property('x').value().isError()")->BooleanValue());
4503
4504 // Check that the message is that passed to the Error constructor.
4505 CHECK(CompileRun(
4506 "instance_mirror.property('x').value().message() == 'Error message'")->
4507 BooleanValue());
4508}
4509
4510
Steve Blockd0582a62009-12-15 09:54:21 +00004511// Test that hidden properties object is not returned as an unnamed property
4512// among regular properties.
4513// See http://crbug.com/26491
4514TEST(NoHiddenProperties) {
4515 // Create a V8 environment with debug access.
4516 v8::HandleScope scope;
4517 DebugLocalContext env;
4518 env.ExposeDebug();
4519
4520 // Create an object in the global scope.
4521 const char* source = "var obj = {a: 1};";
4522 v8::Script::Compile(v8::String::New(source))->Run();
4523 v8::Local<v8::Object> obj = v8::Local<v8::Object>::Cast(
4524 env->Global()->Get(v8::String::New("obj")));
4525 // Set a hidden property on the object.
4526 obj->SetHiddenValue(v8::String::New("v8::test-debug::a"),
4527 v8::Int32::New(11));
4528
4529 // Get mirror for the object with property getter.
4530 CompileRun("var obj_mirror = debug.MakeMirror(obj);");
4531 CHECK(CompileRun(
4532 "obj_mirror instanceof debug.ObjectMirror")->BooleanValue());
4533 CompileRun("var named_names = obj_mirror.propertyNames();");
4534 // There should be exactly one property. But there is also an unnamed
4535 // property whose value is hidden properties dictionary. The latter
4536 // property should not be in the list of reguar properties.
4537 CHECK_EQ(1, CompileRun("named_names.length")->Int32Value());
4538 CHECK(CompileRun("named_names[0] == 'a'")->BooleanValue());
4539 CHECK(CompileRun(
4540 "obj_mirror.property('a').value().value() == 1")->BooleanValue());
4541
4542 // Object created by t0 will become hidden prototype of object 'obj'.
4543 v8::Handle<v8::FunctionTemplate> t0 = v8::FunctionTemplate::New();
4544 t0->InstanceTemplate()->Set(v8::String::New("b"), v8::Number::New(2));
4545 t0->SetHiddenPrototype(true);
4546 v8::Handle<v8::FunctionTemplate> t1 = v8::FunctionTemplate::New();
4547 t1->InstanceTemplate()->Set(v8::String::New("c"), v8::Number::New(3));
4548
4549 // Create proto objects, add hidden properties to them and set them on
4550 // the global object.
4551 v8::Handle<v8::Object> protoObj = t0->GetFunction()->NewInstance();
4552 protoObj->SetHiddenValue(v8::String::New("v8::test-debug::b"),
4553 v8::Int32::New(12));
4554 env->Global()->Set(v8::String::New("protoObj"), protoObj);
4555 v8::Handle<v8::Object> grandProtoObj = t1->GetFunction()->NewInstance();
4556 grandProtoObj->SetHiddenValue(v8::String::New("v8::test-debug::c"),
4557 v8::Int32::New(13));
4558 env->Global()->Set(v8::String::New("grandProtoObj"), grandProtoObj);
4559
4560 // Setting prototypes: obj->protoObj->grandProtoObj
4561 protoObj->Set(v8::String::New("__proto__"), grandProtoObj);
4562 obj->Set(v8::String::New("__proto__"), protoObj);
4563
4564 // Get mirror for the object with property getter.
4565 CompileRun("var obj_mirror = debug.MakeMirror(obj);");
4566 CHECK(CompileRun(
4567 "obj_mirror instanceof debug.ObjectMirror")->BooleanValue());
4568 CompileRun("var named_names = obj_mirror.propertyNames();");
4569 // There should be exactly two properties - one from the object itself and
4570 // another from its hidden prototype.
4571 CHECK_EQ(2, CompileRun("named_names.length")->Int32Value());
4572 CHECK(CompileRun("named_names.sort(); named_names[0] == 'a' &&"
4573 "named_names[1] == 'b'")->BooleanValue());
4574 CHECK(CompileRun(
4575 "obj_mirror.property('a').value().value() == 1")->BooleanValue());
4576 CHECK(CompileRun(
4577 "obj_mirror.property('b').value().value() == 2")->BooleanValue());
4578}
4579
Steve Blocka7e24c12009-10-30 11:49:00 +00004580
4581// Multithreaded tests of JSON debugger protocol
4582
4583// Support classes
4584
Steve Blocka7e24c12009-10-30 11:49:00 +00004585// Provides synchronization between k threads, where k is an input to the
4586// constructor. The Wait() call blocks a thread until it is called for the
4587// k'th time, then all calls return. Each ThreadBarrier object can only
4588// be used once.
4589class ThreadBarrier {
4590 public:
4591 explicit ThreadBarrier(int num_threads);
4592 ~ThreadBarrier();
4593 void Wait();
4594 private:
4595 int num_threads_;
4596 int num_blocked_;
4597 v8::internal::Mutex* lock_;
4598 v8::internal::Semaphore* sem_;
4599 bool invalid_;
4600};
4601
4602ThreadBarrier::ThreadBarrier(int num_threads)
4603 : num_threads_(num_threads), num_blocked_(0) {
4604 lock_ = OS::CreateMutex();
4605 sem_ = OS::CreateSemaphore(0);
4606 invalid_ = false; // A barrier may only be used once. Then it is invalid.
4607}
4608
4609// Do not call, due to race condition with Wait().
4610// Could be resolved with Pthread condition variables.
4611ThreadBarrier::~ThreadBarrier() {
4612 lock_->Lock();
4613 delete lock_;
4614 delete sem_;
4615}
4616
4617void ThreadBarrier::Wait() {
4618 lock_->Lock();
4619 CHECK(!invalid_);
4620 if (num_blocked_ == num_threads_ - 1) {
4621 // Signal and unblock all waiting threads.
4622 for (int i = 0; i < num_threads_ - 1; ++i) {
4623 sem_->Signal();
4624 }
4625 invalid_ = true;
4626 printf("BARRIER\n\n");
4627 fflush(stdout);
4628 lock_->Unlock();
4629 } else { // Wait for the semaphore.
4630 ++num_blocked_;
4631 lock_->Unlock(); // Potential race condition with destructor because
4632 sem_->Wait(); // these two lines are not atomic.
4633 }
4634}
4635
4636// A set containing enough barriers and semaphores for any of the tests.
4637class Barriers {
4638 public:
4639 Barriers();
4640 void Initialize();
4641 ThreadBarrier barrier_1;
4642 ThreadBarrier barrier_2;
4643 ThreadBarrier barrier_3;
4644 ThreadBarrier barrier_4;
4645 ThreadBarrier barrier_5;
4646 v8::internal::Semaphore* semaphore_1;
4647 v8::internal::Semaphore* semaphore_2;
4648};
4649
4650Barriers::Barriers() : barrier_1(2), barrier_2(2),
4651 barrier_3(2), barrier_4(2), barrier_5(2) {}
4652
4653void Barriers::Initialize() {
4654 semaphore_1 = OS::CreateSemaphore(0);
4655 semaphore_2 = OS::CreateSemaphore(0);
4656}
4657
4658
4659// We match parts of the message to decide if it is a break message.
4660bool IsBreakEventMessage(char *message) {
4661 const char* type_event = "\"type\":\"event\"";
4662 const char* event_break = "\"event\":\"break\"";
4663 // Does the message contain both type:event and event:break?
4664 return strstr(message, type_event) != NULL &&
4665 strstr(message, event_break) != NULL;
4666}
4667
4668
Steve Block3ce2e202009-11-05 08:53:23 +00004669// We match parts of the message to decide if it is a exception message.
4670bool IsExceptionEventMessage(char *message) {
4671 const char* type_event = "\"type\":\"event\"";
4672 const char* event_exception = "\"event\":\"exception\"";
4673 // Does the message contain both type:event and event:exception?
4674 return strstr(message, type_event) != NULL &&
4675 strstr(message, event_exception) != NULL;
4676}
4677
4678
4679// We match the message wether it is an evaluate response message.
4680bool IsEvaluateResponseMessage(char* message) {
4681 const char* type_response = "\"type\":\"response\"";
4682 const char* command_evaluate = "\"command\":\"evaluate\"";
4683 // Does the message contain both type:response and command:evaluate?
4684 return strstr(message, type_response) != NULL &&
4685 strstr(message, command_evaluate) != NULL;
4686}
4687
4688
Andrei Popescu402d9372010-02-26 13:31:12 +00004689static int StringToInt(const char* s) {
4690 return atoi(s); // NOLINT
4691}
4692
4693
Steve Block3ce2e202009-11-05 08:53:23 +00004694// We match parts of the message to get evaluate result int value.
4695int GetEvaluateIntResult(char *message) {
4696 const char* value = "\"value\":";
4697 char* pos = strstr(message, value);
4698 if (pos == NULL) {
4699 return -1;
4700 }
4701 int res = -1;
Andrei Popescu402d9372010-02-26 13:31:12 +00004702 res = StringToInt(pos + strlen(value));
Steve Block3ce2e202009-11-05 08:53:23 +00004703 return res;
4704}
4705
4706
4707// We match parts of the message to get hit breakpoint id.
4708int GetBreakpointIdFromBreakEventMessage(char *message) {
4709 const char* breakpoints = "\"breakpoints\":[";
4710 char* pos = strstr(message, breakpoints);
4711 if (pos == NULL) {
4712 return -1;
4713 }
4714 int res = -1;
Andrei Popescu402d9372010-02-26 13:31:12 +00004715 res = StringToInt(pos + strlen(breakpoints));
Steve Block3ce2e202009-11-05 08:53:23 +00004716 return res;
4717}
4718
4719
Leon Clarked91b9f72010-01-27 17:25:45 +00004720// We match parts of the message to get total frames number.
4721int GetTotalFramesInt(char *message) {
4722 const char* prefix = "\"totalFrames\":";
4723 char* pos = strstr(message, prefix);
4724 if (pos == NULL) {
4725 return -1;
4726 }
4727 pos += strlen(prefix);
Andrei Popescu402d9372010-02-26 13:31:12 +00004728 int res = StringToInt(pos);
Leon Clarked91b9f72010-01-27 17:25:45 +00004729 return res;
4730}
4731
4732
Iain Merrick9ac36c92010-09-13 15:29:50 +01004733// We match parts of the message to get source line.
4734int GetSourceLineFromBreakEventMessage(char *message) {
4735 const char* source_line = "\"sourceLine\":";
4736 char* pos = strstr(message, source_line);
4737 if (pos == NULL) {
4738 return -1;
4739 }
4740 int res = -1;
4741 res = StringToInt(pos + strlen(source_line));
4742 return res;
4743}
4744
Steve Blocka7e24c12009-10-30 11:49:00 +00004745/* Test MessageQueues */
4746/* Tests the message queues that hold debugger commands and
4747 * response messages to the debugger. Fills queues and makes
4748 * them grow.
4749 */
4750Barriers message_queue_barriers;
4751
4752// This is the debugger thread, that executes no v8 calls except
4753// placing JSON debugger commands in the queue.
4754class MessageQueueDebuggerThread : public v8::internal::Thread {
4755 public:
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00004756 MessageQueueDebuggerThread()
4757 : Thread("MessageQueueDebuggerThread") { }
Steve Blocka7e24c12009-10-30 11:49:00 +00004758 void Run();
4759};
4760
4761static void MessageHandler(const uint16_t* message, int length,
4762 v8::Debug::ClientData* client_data) {
4763 static char print_buffer[1000];
4764 Utf16ToAscii(message, length, print_buffer);
4765 if (IsBreakEventMessage(print_buffer)) {
4766 // Lets test script wait until break occurs to send commands.
4767 // Signals when a break is reported.
4768 message_queue_barriers.semaphore_2->Signal();
4769 }
4770
4771 // Allow message handler to block on a semaphore, to test queueing of
4772 // messages while blocked.
4773 message_queue_barriers.semaphore_1->Wait();
Steve Blocka7e24c12009-10-30 11:49:00 +00004774}
4775
4776void MessageQueueDebuggerThread::Run() {
4777 const int kBufferSize = 1000;
4778 uint16_t buffer_1[kBufferSize];
4779 uint16_t buffer_2[kBufferSize];
4780 const char* command_1 =
4781 "{\"seq\":117,"
4782 "\"type\":\"request\","
4783 "\"command\":\"evaluate\","
4784 "\"arguments\":{\"expression\":\"1+2\"}}";
4785 const char* command_2 =
4786 "{\"seq\":118,"
4787 "\"type\":\"request\","
4788 "\"command\":\"evaluate\","
4789 "\"arguments\":{\"expression\":\"1+a\"}}";
4790 const char* command_3 =
4791 "{\"seq\":119,"
4792 "\"type\":\"request\","
4793 "\"command\":\"evaluate\","
4794 "\"arguments\":{\"expression\":\"c.d * b\"}}";
4795 const char* command_continue =
4796 "{\"seq\":106,"
4797 "\"type\":\"request\","
4798 "\"command\":\"continue\"}";
4799 const char* command_single_step =
4800 "{\"seq\":107,"
4801 "\"type\":\"request\","
4802 "\"command\":\"continue\","
4803 "\"arguments\":{\"stepaction\":\"next\"}}";
4804
4805 /* Interleaved sequence of actions by the two threads:*/
4806 // Main thread compiles and runs source_1
4807 message_queue_barriers.semaphore_1->Signal();
4808 message_queue_barriers.barrier_1.Wait();
4809 // Post 6 commands, filling the command queue and making it expand.
4810 // These calls return immediately, but the commands stay on the queue
4811 // until the execution of source_2.
4812 // Note: AsciiToUtf16 executes before SendCommand, so command is copied
4813 // to buffer before buffer is sent to SendCommand.
4814 v8::Debug::SendCommand(buffer_1, AsciiToUtf16(command_1, buffer_1));
4815 v8::Debug::SendCommand(buffer_2, AsciiToUtf16(command_2, buffer_2));
4816 v8::Debug::SendCommand(buffer_2, AsciiToUtf16(command_3, buffer_2));
4817 v8::Debug::SendCommand(buffer_2, AsciiToUtf16(command_3, buffer_2));
4818 v8::Debug::SendCommand(buffer_2, AsciiToUtf16(command_3, buffer_2));
4819 message_queue_barriers.barrier_2.Wait();
4820 // Main thread compiles and runs source_2.
4821 // Queued commands are executed at the start of compilation of source_2(
4822 // beforeCompile event).
4823 // Free the message handler to process all the messages from the queue. 7
4824 // messages are expected: 2 afterCompile events and 5 responses.
4825 // All the commands added so far will fail to execute as long as call stack
4826 // is empty on beforeCompile event.
4827 for (int i = 0; i < 6 ; ++i) {
4828 message_queue_barriers.semaphore_1->Signal();
4829 }
4830 message_queue_barriers.barrier_3.Wait();
4831 // Main thread compiles and runs source_3.
4832 // Don't stop in the afterCompile handler.
4833 message_queue_barriers.semaphore_1->Signal();
4834 // source_3 includes a debugger statement, which causes a break event.
4835 // Wait on break event from hitting "debugger" statement
4836 message_queue_barriers.semaphore_2->Wait();
4837 // These should execute after the "debugger" statement in source_2
4838 v8::Debug::SendCommand(buffer_1, AsciiToUtf16(command_1, buffer_1));
4839 v8::Debug::SendCommand(buffer_2, AsciiToUtf16(command_2, buffer_2));
4840 v8::Debug::SendCommand(buffer_2, AsciiToUtf16(command_3, buffer_2));
4841 v8::Debug::SendCommand(buffer_2, AsciiToUtf16(command_single_step, buffer_2));
4842 // Run after 2 break events, 4 responses.
4843 for (int i = 0; i < 6 ; ++i) {
4844 message_queue_barriers.semaphore_1->Signal();
4845 }
4846 // Wait on break event after a single step executes.
4847 message_queue_barriers.semaphore_2->Wait();
4848 v8::Debug::SendCommand(buffer_1, AsciiToUtf16(command_2, buffer_1));
4849 v8::Debug::SendCommand(buffer_2, AsciiToUtf16(command_continue, buffer_2));
4850 // Run after 2 responses.
4851 for (int i = 0; i < 2 ; ++i) {
4852 message_queue_barriers.semaphore_1->Signal();
4853 }
4854 // Main thread continues running source_3 to end, waits for this thread.
4855}
4856
Steve Blocka7e24c12009-10-30 11:49:00 +00004857
4858// This thread runs the v8 engine.
4859TEST(MessageQueues) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00004860 MessageQueueDebuggerThread message_queue_debugger_thread;
Steve Block44f0eee2011-05-26 01:26:41 +01004861
Steve Blocka7e24c12009-10-30 11:49:00 +00004862 // Create a V8 environment
4863 v8::HandleScope scope;
4864 DebugLocalContext env;
4865 message_queue_barriers.Initialize();
4866 v8::Debug::SetMessageHandler(MessageHandler);
4867 message_queue_debugger_thread.Start();
4868
4869 const char* source_1 = "a = 3; b = 4; c = new Object(); c.d = 5;";
4870 const char* source_2 = "e = 17;";
4871 const char* source_3 = "a = 4; debugger; a = 5; a = 6; a = 7;";
4872
4873 // See MessageQueueDebuggerThread::Run for interleaved sequence of
4874 // API calls and events in the two threads.
4875 CompileRun(source_1);
4876 message_queue_barriers.barrier_1.Wait();
4877 message_queue_barriers.barrier_2.Wait();
4878 CompileRun(source_2);
4879 message_queue_barriers.barrier_3.Wait();
4880 CompileRun(source_3);
4881 message_queue_debugger_thread.Join();
4882 fflush(stdout);
4883}
4884
4885
4886class TestClientData : public v8::Debug::ClientData {
4887 public:
4888 TestClientData() {
4889 constructor_call_counter++;
4890 }
4891 virtual ~TestClientData() {
4892 destructor_call_counter++;
4893 }
4894
4895 static void ResetCounters() {
4896 constructor_call_counter = 0;
4897 destructor_call_counter = 0;
4898 }
4899
4900 static int constructor_call_counter;
4901 static int destructor_call_counter;
4902};
4903
4904int TestClientData::constructor_call_counter = 0;
4905int TestClientData::destructor_call_counter = 0;
4906
4907
4908// Tests that MessageQueue doesn't destroy client data when expands and
4909// does destroy when it dies.
4910TEST(MessageQueueExpandAndDestroy) {
4911 TestClientData::ResetCounters();
4912 { // Create a scope for the queue.
4913 CommandMessageQueue queue(1);
4914 queue.Put(CommandMessage::New(Vector<uint16_t>::empty(),
4915 new TestClientData()));
4916 queue.Put(CommandMessage::New(Vector<uint16_t>::empty(),
4917 new TestClientData()));
4918 queue.Put(CommandMessage::New(Vector<uint16_t>::empty(),
4919 new TestClientData()));
4920 CHECK_EQ(0, TestClientData::destructor_call_counter);
4921 queue.Get().Dispose();
4922 CHECK_EQ(1, TestClientData::destructor_call_counter);
4923 queue.Put(CommandMessage::New(Vector<uint16_t>::empty(),
4924 new TestClientData()));
4925 queue.Put(CommandMessage::New(Vector<uint16_t>::empty(),
4926 new TestClientData()));
4927 queue.Put(CommandMessage::New(Vector<uint16_t>::empty(),
4928 new TestClientData()));
4929 queue.Put(CommandMessage::New(Vector<uint16_t>::empty(),
4930 new TestClientData()));
4931 queue.Put(CommandMessage::New(Vector<uint16_t>::empty(),
4932 new TestClientData()));
4933 CHECK_EQ(1, TestClientData::destructor_call_counter);
4934 queue.Get().Dispose();
4935 CHECK_EQ(2, TestClientData::destructor_call_counter);
4936 }
4937 // All the client data should be destroyed when the queue is destroyed.
4938 CHECK_EQ(TestClientData::destructor_call_counter,
4939 TestClientData::destructor_call_counter);
4940}
4941
4942
4943static int handled_client_data_instances_count = 0;
4944static void MessageHandlerCountingClientData(
4945 const v8::Debug::Message& message) {
4946 if (message.GetClientData() != NULL) {
4947 handled_client_data_instances_count++;
4948 }
4949}
4950
4951
4952// Tests that all client data passed to the debugger are sent to the handler.
4953TEST(SendClientDataToHandler) {
4954 // Create a V8 environment
4955 v8::HandleScope scope;
4956 DebugLocalContext env;
4957 TestClientData::ResetCounters();
4958 handled_client_data_instances_count = 0;
4959 v8::Debug::SetMessageHandler2(MessageHandlerCountingClientData);
4960 const char* source_1 = "a = 3; b = 4; c = new Object(); c.d = 5;";
4961 const int kBufferSize = 1000;
4962 uint16_t buffer[kBufferSize];
4963 const char* command_1 =
4964 "{\"seq\":117,"
4965 "\"type\":\"request\","
4966 "\"command\":\"evaluate\","
4967 "\"arguments\":{\"expression\":\"1+2\"}}";
4968 const char* command_2 =
4969 "{\"seq\":118,"
4970 "\"type\":\"request\","
4971 "\"command\":\"evaluate\","
4972 "\"arguments\":{\"expression\":\"1+a\"}}";
4973 const char* command_continue =
4974 "{\"seq\":106,"
4975 "\"type\":\"request\","
4976 "\"command\":\"continue\"}";
4977
4978 v8::Debug::SendCommand(buffer, AsciiToUtf16(command_1, buffer),
4979 new TestClientData());
4980 v8::Debug::SendCommand(buffer, AsciiToUtf16(command_2, buffer), NULL);
4981 v8::Debug::SendCommand(buffer, AsciiToUtf16(command_2, buffer),
4982 new TestClientData());
4983 v8::Debug::SendCommand(buffer, AsciiToUtf16(command_2, buffer),
4984 new TestClientData());
4985 // All the messages will be processed on beforeCompile event.
4986 CompileRun(source_1);
4987 v8::Debug::SendCommand(buffer, AsciiToUtf16(command_continue, buffer));
4988 CHECK_EQ(3, TestClientData::constructor_call_counter);
4989 CHECK_EQ(TestClientData::constructor_call_counter,
4990 handled_client_data_instances_count);
4991 CHECK_EQ(TestClientData::constructor_call_counter,
4992 TestClientData::destructor_call_counter);
4993}
4994
4995
4996/* Test ThreadedDebugging */
4997/* This test interrupts a running infinite loop that is
4998 * occupying the v8 thread by a break command from the
4999 * debugger thread. It then changes the value of a
5000 * global object, to make the loop terminate.
5001 */
5002
5003Barriers threaded_debugging_barriers;
5004
5005class V8Thread : public v8::internal::Thread {
5006 public:
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00005007 V8Thread() : Thread("V8Thread") { }
Steve Blocka7e24c12009-10-30 11:49:00 +00005008 void Run();
5009};
5010
5011class DebuggerThread : public v8::internal::Thread {
5012 public:
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00005013 DebuggerThread() : Thread("DebuggerThread") { }
Steve Blocka7e24c12009-10-30 11:49:00 +00005014 void Run();
5015};
5016
5017
5018static v8::Handle<v8::Value> ThreadedAtBarrier1(const v8::Arguments& args) {
5019 threaded_debugging_barriers.barrier_1.Wait();
5020 return v8::Undefined();
5021}
5022
5023
5024static void ThreadedMessageHandler(const v8::Debug::Message& message) {
5025 static char print_buffer[1000];
5026 v8::String::Value json(message.GetJSON());
5027 Utf16ToAscii(*json, json.length(), print_buffer);
5028 if (IsBreakEventMessage(print_buffer)) {
Iain Merrick9ac36c92010-09-13 15:29:50 +01005029 // Check that we are inside the while loop.
5030 int source_line = GetSourceLineFromBreakEventMessage(print_buffer);
5031 CHECK(8 <= source_line && source_line <= 13);
Steve Blocka7e24c12009-10-30 11:49:00 +00005032 threaded_debugging_barriers.barrier_2.Wait();
5033 }
Steve Blocka7e24c12009-10-30 11:49:00 +00005034}
5035
5036
5037void V8Thread::Run() {
5038 const char* source =
5039 "flag = true;\n"
5040 "function bar( new_value ) {\n"
5041 " flag = new_value;\n"
5042 " return \"Return from bar(\" + new_value + \")\";\n"
5043 "}\n"
5044 "\n"
5045 "function foo() {\n"
5046 " var x = 1;\n"
5047 " while ( flag == true ) {\n"
5048 " if ( x == 1 ) {\n"
5049 " ThreadedAtBarrier1();\n"
5050 " }\n"
5051 " x = x + 1;\n"
5052 " }\n"
5053 "}\n"
5054 "\n"
5055 "foo();\n";
5056
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00005057 v8::V8::Initialize();
Steve Blocka7e24c12009-10-30 11:49:00 +00005058 v8::HandleScope scope;
5059 DebugLocalContext env;
5060 v8::Debug::SetMessageHandler2(&ThreadedMessageHandler);
5061 v8::Handle<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New();
5062 global_template->Set(v8::String::New("ThreadedAtBarrier1"),
5063 v8::FunctionTemplate::New(ThreadedAtBarrier1));
5064 v8::Handle<v8::Context> context = v8::Context::New(NULL, global_template);
5065 v8::Context::Scope context_scope(context);
5066
5067 CompileRun(source);
5068}
5069
5070void DebuggerThread::Run() {
5071 const int kBufSize = 1000;
5072 uint16_t buffer[kBufSize];
5073
5074 const char* command_1 = "{\"seq\":102,"
5075 "\"type\":\"request\","
5076 "\"command\":\"evaluate\","
5077 "\"arguments\":{\"expression\":\"bar(false)\"}}";
5078 const char* command_2 = "{\"seq\":103,"
5079 "\"type\":\"request\","
5080 "\"command\":\"continue\"}";
5081
5082 threaded_debugging_barriers.barrier_1.Wait();
5083 v8::Debug::DebugBreak();
5084 threaded_debugging_barriers.barrier_2.Wait();
5085 v8::Debug::SendCommand(buffer, AsciiToUtf16(command_1, buffer));
5086 v8::Debug::SendCommand(buffer, AsciiToUtf16(command_2, buffer));
5087}
5088
Steve Blocka7e24c12009-10-30 11:49:00 +00005089
5090TEST(ThreadedDebugging) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00005091 DebuggerThread debugger_thread;
5092 V8Thread v8_thread;
Steve Block44f0eee2011-05-26 01:26:41 +01005093
Steve Blocka7e24c12009-10-30 11:49:00 +00005094 // Create a V8 environment
5095 threaded_debugging_barriers.Initialize();
5096
5097 v8_thread.Start();
5098 debugger_thread.Start();
5099
5100 v8_thread.Join();
5101 debugger_thread.Join();
5102}
5103
5104/* Test RecursiveBreakpoints */
5105/* In this test, the debugger evaluates a function with a breakpoint, after
5106 * hitting a breakpoint in another function. We do this with both values
5107 * of the flag enabling recursive breakpoints, and verify that the second
5108 * breakpoint is hit when enabled, and missed when disabled.
5109 */
5110
5111class BreakpointsV8Thread : public v8::internal::Thread {
5112 public:
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00005113 BreakpointsV8Thread() : Thread("BreakpointsV8Thread") { }
Steve Blocka7e24c12009-10-30 11:49:00 +00005114 void Run();
5115};
5116
5117class BreakpointsDebuggerThread : public v8::internal::Thread {
5118 public:
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00005119 explicit BreakpointsDebuggerThread(bool global_evaluate)
5120 : Thread("BreakpointsDebuggerThread"),
Steve Block44f0eee2011-05-26 01:26:41 +01005121 global_evaluate_(global_evaluate) {}
Steve Blocka7e24c12009-10-30 11:49:00 +00005122 void Run();
Leon Clarked91b9f72010-01-27 17:25:45 +00005123
5124 private:
5125 bool global_evaluate_;
Steve Blocka7e24c12009-10-30 11:49:00 +00005126};
5127
5128
5129Barriers* breakpoints_barriers;
Steve Block3ce2e202009-11-05 08:53:23 +00005130int break_event_breakpoint_id;
5131int evaluate_int_result;
Steve Blocka7e24c12009-10-30 11:49:00 +00005132
5133static void BreakpointsMessageHandler(const v8::Debug::Message& message) {
5134 static char print_buffer[1000];
5135 v8::String::Value json(message.GetJSON());
5136 Utf16ToAscii(*json, json.length(), print_buffer);
Steve Blocka7e24c12009-10-30 11:49:00 +00005137
Steve Blocka7e24c12009-10-30 11:49:00 +00005138 if (IsBreakEventMessage(print_buffer)) {
Steve Block3ce2e202009-11-05 08:53:23 +00005139 break_event_breakpoint_id =
5140 GetBreakpointIdFromBreakEventMessage(print_buffer);
5141 breakpoints_barriers->semaphore_1->Signal();
5142 } else if (IsEvaluateResponseMessage(print_buffer)) {
5143 evaluate_int_result = GetEvaluateIntResult(print_buffer);
Steve Blocka7e24c12009-10-30 11:49:00 +00005144 breakpoints_barriers->semaphore_1->Signal();
5145 }
5146}
5147
5148
5149void BreakpointsV8Thread::Run() {
5150 const char* source_1 = "var y_global = 3;\n"
5151 "function cat( new_value ) {\n"
5152 " var x = new_value;\n"
Steve Block3ce2e202009-11-05 08:53:23 +00005153 " y_global = y_global + 4;\n"
Steve Blocka7e24c12009-10-30 11:49:00 +00005154 " x = 3 * x + 1;\n"
Steve Block3ce2e202009-11-05 08:53:23 +00005155 " y_global = y_global + 5;\n"
Steve Blocka7e24c12009-10-30 11:49:00 +00005156 " return x;\n"
5157 "}\n"
5158 "\n"
5159 "function dog() {\n"
5160 " var x = 1;\n"
5161 " x = y_global;"
5162 " var z = 3;"
5163 " x += 100;\n"
5164 " return x;\n"
5165 "}\n"
5166 "\n";
5167 const char* source_2 = "cat(17);\n"
5168 "cat(19);\n";
5169
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00005170 v8::V8::Initialize();
Steve Blocka7e24c12009-10-30 11:49:00 +00005171 v8::HandleScope scope;
5172 DebugLocalContext env;
5173 v8::Debug::SetMessageHandler2(&BreakpointsMessageHandler);
5174
5175 CompileRun(source_1);
5176 breakpoints_barriers->barrier_1.Wait();
5177 breakpoints_barriers->barrier_2.Wait();
5178 CompileRun(source_2);
5179}
5180
5181
5182void BreakpointsDebuggerThread::Run() {
5183 const int kBufSize = 1000;
5184 uint16_t buffer[kBufSize];
5185
5186 const char* command_1 = "{\"seq\":101,"
5187 "\"type\":\"request\","
5188 "\"command\":\"setbreakpoint\","
5189 "\"arguments\":{\"type\":\"function\",\"target\":\"cat\",\"line\":3}}";
5190 const char* command_2 = "{\"seq\":102,"
5191 "\"type\":\"request\","
5192 "\"command\":\"setbreakpoint\","
5193 "\"arguments\":{\"type\":\"function\",\"target\":\"dog\",\"line\":3}}";
Leon Clarked91b9f72010-01-27 17:25:45 +00005194 const char* command_3;
5195 if (this->global_evaluate_) {
5196 command_3 = "{\"seq\":103,"
5197 "\"type\":\"request\","
5198 "\"command\":\"evaluate\","
5199 "\"arguments\":{\"expression\":\"dog()\",\"disable_break\":false,"
5200 "\"global\":true}}";
5201 } else {
5202 command_3 = "{\"seq\":103,"
5203 "\"type\":\"request\","
5204 "\"command\":\"evaluate\","
5205 "\"arguments\":{\"expression\":\"dog()\",\"disable_break\":false}}";
5206 }
5207 const char* command_4;
5208 if (this->global_evaluate_) {
5209 command_4 = "{\"seq\":104,"
5210 "\"type\":\"request\","
5211 "\"command\":\"evaluate\","
5212 "\"arguments\":{\"expression\":\"100 + 8\",\"disable_break\":true,"
5213 "\"global\":true}}";
5214 } else {
5215 command_4 = "{\"seq\":104,"
5216 "\"type\":\"request\","
5217 "\"command\":\"evaluate\","
5218 "\"arguments\":{\"expression\":\"x + 1\",\"disable_break\":true}}";
5219 }
Steve Block3ce2e202009-11-05 08:53:23 +00005220 const char* command_5 = "{\"seq\":105,"
Steve Blocka7e24c12009-10-30 11:49:00 +00005221 "\"type\":\"request\","
5222 "\"command\":\"continue\"}";
Steve Block3ce2e202009-11-05 08:53:23 +00005223 const char* command_6 = "{\"seq\":106,"
Steve Blocka7e24c12009-10-30 11:49:00 +00005224 "\"type\":\"request\","
5225 "\"command\":\"continue\"}";
Leon Clarked91b9f72010-01-27 17:25:45 +00005226 const char* command_7;
5227 if (this->global_evaluate_) {
5228 command_7 = "{\"seq\":107,"
5229 "\"type\":\"request\","
5230 "\"command\":\"evaluate\","
5231 "\"arguments\":{\"expression\":\"dog()\",\"disable_break\":true,"
5232 "\"global\":true}}";
5233 } else {
5234 command_7 = "{\"seq\":107,"
5235 "\"type\":\"request\","
5236 "\"command\":\"evaluate\","
5237 "\"arguments\":{\"expression\":\"dog()\",\"disable_break\":true}}";
5238 }
Steve Block3ce2e202009-11-05 08:53:23 +00005239 const char* command_8 = "{\"seq\":108,"
Steve Blocka7e24c12009-10-30 11:49:00 +00005240 "\"type\":\"request\","
5241 "\"command\":\"continue\"}";
5242
5243
5244 // v8 thread initializes, runs source_1
5245 breakpoints_barriers->barrier_1.Wait();
Steve Block3ce2e202009-11-05 08:53:23 +00005246 // 1:Set breakpoint in cat() (will get id 1).
Steve Blocka7e24c12009-10-30 11:49:00 +00005247 v8::Debug::SendCommand(buffer, AsciiToUtf16(command_1, buffer));
Steve Block3ce2e202009-11-05 08:53:23 +00005248 // 2:Set breakpoint in dog() (will get id 2).
Steve Blocka7e24c12009-10-30 11:49:00 +00005249 v8::Debug::SendCommand(buffer, AsciiToUtf16(command_2, buffer));
5250 breakpoints_barriers->barrier_2.Wait();
Steve Block3ce2e202009-11-05 08:53:23 +00005251 // V8 thread starts compiling source_2.
Steve Blocka7e24c12009-10-30 11:49:00 +00005252 // Automatic break happens, to run queued commands
5253 // breakpoints_barriers->semaphore_1->Wait();
5254 // Commands 1 through 3 run, thread continues.
5255 // v8 thread runs source_2 to breakpoint in cat().
5256 // message callback receives break event.
5257 breakpoints_barriers->semaphore_1->Wait();
Steve Block3ce2e202009-11-05 08:53:23 +00005258 // Must have hit breakpoint #1.
5259 CHECK_EQ(1, break_event_breakpoint_id);
Steve Blocka7e24c12009-10-30 11:49:00 +00005260 // 4:Evaluate dog() (which has a breakpoint).
5261 v8::Debug::SendCommand(buffer, AsciiToUtf16(command_3, buffer));
Steve Block3ce2e202009-11-05 08:53:23 +00005262 // V8 thread hits breakpoint in dog().
Steve Blocka7e24c12009-10-30 11:49:00 +00005263 breakpoints_barriers->semaphore_1->Wait(); // wait for break event
Steve Block3ce2e202009-11-05 08:53:23 +00005264 // Must have hit breakpoint #2.
5265 CHECK_EQ(2, break_event_breakpoint_id);
5266 // 5:Evaluate (x + 1).
Steve Blocka7e24c12009-10-30 11:49:00 +00005267 v8::Debug::SendCommand(buffer, AsciiToUtf16(command_4, buffer));
Steve Block3ce2e202009-11-05 08:53:23 +00005268 // Evaluate (x + 1) finishes.
5269 breakpoints_barriers->semaphore_1->Wait();
5270 // Must have result 108.
5271 CHECK_EQ(108, evaluate_int_result);
5272 // 6:Continue evaluation of dog().
Steve Blocka7e24c12009-10-30 11:49:00 +00005273 v8::Debug::SendCommand(buffer, AsciiToUtf16(command_5, buffer));
Steve Block3ce2e202009-11-05 08:53:23 +00005274 // Evaluate dog() finishes.
5275 breakpoints_barriers->semaphore_1->Wait();
5276 // Must have result 107.
5277 CHECK_EQ(107, evaluate_int_result);
Steve Blocka7e24c12009-10-30 11:49:00 +00005278 // 7:Continue evaluation of source_2, finish cat(17), hit breakpoint
5279 // in cat(19).
5280 v8::Debug::SendCommand(buffer, AsciiToUtf16(command_6, buffer));
Steve Block3ce2e202009-11-05 08:53:23 +00005281 // Message callback gets break event.
Steve Blocka7e24c12009-10-30 11:49:00 +00005282 breakpoints_barriers->semaphore_1->Wait(); // wait for break event
Steve Block3ce2e202009-11-05 08:53:23 +00005283 // Must have hit breakpoint #1.
5284 CHECK_EQ(1, break_event_breakpoint_id);
5285 // 8: Evaluate dog() with breaks disabled.
Steve Blocka7e24c12009-10-30 11:49:00 +00005286 v8::Debug::SendCommand(buffer, AsciiToUtf16(command_7, buffer));
Steve Block3ce2e202009-11-05 08:53:23 +00005287 // Evaluate dog() finishes.
5288 breakpoints_barriers->semaphore_1->Wait();
5289 // Must have result 116.
5290 CHECK_EQ(116, evaluate_int_result);
Steve Blocka7e24c12009-10-30 11:49:00 +00005291 // 9: Continue evaluation of source2, reach end.
5292 v8::Debug::SendCommand(buffer, AsciiToUtf16(command_8, buffer));
5293}
5294
Leon Clarked91b9f72010-01-27 17:25:45 +00005295void TestRecursiveBreakpointsGeneric(bool global_evaluate) {
Leon Clarkeeab96aa2010-01-27 16:31:12 +00005296 i::FLAG_debugger_auto_break = true;
Leon Clarke888f6722010-01-27 15:57:47 +00005297
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00005298 BreakpointsDebuggerThread breakpoints_debugger_thread(global_evaluate);
5299 BreakpointsV8Thread breakpoints_v8_thread;
Leon Clarked91b9f72010-01-27 17:25:45 +00005300
Steve Blocka7e24c12009-10-30 11:49:00 +00005301 // Create a V8 environment
5302 Barriers stack_allocated_breakpoints_barriers;
5303 stack_allocated_breakpoints_barriers.Initialize();
5304 breakpoints_barriers = &stack_allocated_breakpoints_barriers;
5305
5306 breakpoints_v8_thread.Start();
5307 breakpoints_debugger_thread.Start();
5308
5309 breakpoints_v8_thread.Join();
5310 breakpoints_debugger_thread.Join();
5311}
5312
Leon Clarked91b9f72010-01-27 17:25:45 +00005313TEST(RecursiveBreakpoints) {
5314 TestRecursiveBreakpointsGeneric(false);
5315}
5316
5317TEST(RecursiveBreakpointsGlobal) {
5318 TestRecursiveBreakpointsGeneric(true);
5319}
5320
Steve Blocka7e24c12009-10-30 11:49:00 +00005321
5322static void DummyDebugEventListener(v8::DebugEvent event,
5323 v8::Handle<v8::Object> exec_state,
5324 v8::Handle<v8::Object> event_data,
5325 v8::Handle<v8::Value> data) {
5326}
5327
5328
5329TEST(SetDebugEventListenerOnUninitializedVM) {
5330 v8::Debug::SetDebugEventListener(DummyDebugEventListener);
5331}
5332
5333
5334static void DummyMessageHandler(const v8::Debug::Message& message) {
5335}
5336
5337
5338TEST(SetMessageHandlerOnUninitializedVM) {
5339 v8::Debug::SetMessageHandler2(DummyMessageHandler);
5340}
5341
5342
5343TEST(DebugBreakOnUninitializedVM) {
5344 v8::Debug::DebugBreak();
5345}
5346
5347
5348TEST(SendCommandToUninitializedVM) {
5349 const char* dummy_command = "{}";
5350 uint16_t dummy_buffer[80];
5351 int dummy_length = AsciiToUtf16(dummy_command, dummy_buffer);
5352 v8::Debug::SendCommand(dummy_buffer, dummy_length);
5353}
5354
5355
5356// Source for a JavaScript function which returns the data parameter of a
5357// function called in the context of the debugger. If no data parameter is
5358// passed it throws an exception.
5359static const char* debugger_call_with_data_source =
5360 "function debugger_call_with_data(exec_state, data) {"
5361 " if (data) return data;"
5362 " throw 'No data!'"
5363 "}";
5364v8::Handle<v8::Function> debugger_call_with_data;
5365
5366
5367// Source for a JavaScript function which returns the data parameter of a
5368// function called in the context of the debugger. If no data parameter is
5369// passed it throws an exception.
5370static const char* debugger_call_with_closure_source =
5371 "var x = 3;"
5372 "(function (exec_state) {"
5373 " if (exec_state.y) return x - 1;"
5374 " exec_state.y = x;"
5375 " return exec_state.y"
5376 "})";
5377v8::Handle<v8::Function> debugger_call_with_closure;
5378
5379// Function to retrieve the number of JavaScript frames by calling a JavaScript
5380// in the debugger.
5381static v8::Handle<v8::Value> CheckFrameCount(const v8::Arguments& args) {
5382 CHECK(v8::Debug::Call(frame_count)->IsNumber());
5383 CHECK_EQ(args[0]->Int32Value(),
5384 v8::Debug::Call(frame_count)->Int32Value());
5385 return v8::Undefined();
5386}
5387
5388
5389// Function to retrieve the source line of the top JavaScript frame by calling a
5390// JavaScript function in the debugger.
5391static v8::Handle<v8::Value> CheckSourceLine(const v8::Arguments& args) {
5392 CHECK(v8::Debug::Call(frame_source_line)->IsNumber());
5393 CHECK_EQ(args[0]->Int32Value(),
5394 v8::Debug::Call(frame_source_line)->Int32Value());
5395 return v8::Undefined();
5396}
5397
5398
5399// Function to test passing an additional parameter to a JavaScript function
5400// called in the debugger. It also tests that functions called in the debugger
5401// can throw exceptions.
5402static v8::Handle<v8::Value> CheckDataParameter(const v8::Arguments& args) {
5403 v8::Handle<v8::String> data = v8::String::New("Test");
5404 CHECK(v8::Debug::Call(debugger_call_with_data, data)->IsString());
5405
5406 CHECK(v8::Debug::Call(debugger_call_with_data).IsEmpty());
5407 CHECK(v8::Debug::Call(debugger_call_with_data).IsEmpty());
5408
5409 v8::TryCatch catcher;
5410 v8::Debug::Call(debugger_call_with_data);
5411 CHECK(catcher.HasCaught());
5412 CHECK(catcher.Exception()->IsString());
5413
5414 return v8::Undefined();
5415}
5416
5417
5418// Function to test using a JavaScript with closure in the debugger.
5419static v8::Handle<v8::Value> CheckClosure(const v8::Arguments& args) {
5420 CHECK(v8::Debug::Call(debugger_call_with_closure)->IsNumber());
5421 CHECK_EQ(3, v8::Debug::Call(debugger_call_with_closure)->Int32Value());
5422 return v8::Undefined();
5423}
5424
5425
5426// Test functions called through the debugger.
5427TEST(CallFunctionInDebugger) {
5428 // Create and enter a context with the functions CheckFrameCount,
5429 // CheckSourceLine and CheckDataParameter installed.
5430 v8::HandleScope scope;
5431 v8::Handle<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New();
5432 global_template->Set(v8::String::New("CheckFrameCount"),
5433 v8::FunctionTemplate::New(CheckFrameCount));
5434 global_template->Set(v8::String::New("CheckSourceLine"),
5435 v8::FunctionTemplate::New(CheckSourceLine));
5436 global_template->Set(v8::String::New("CheckDataParameter"),
5437 v8::FunctionTemplate::New(CheckDataParameter));
5438 global_template->Set(v8::String::New("CheckClosure"),
5439 v8::FunctionTemplate::New(CheckClosure));
5440 v8::Handle<v8::Context> context = v8::Context::New(NULL, global_template);
5441 v8::Context::Scope context_scope(context);
5442
5443 // Compile a function for checking the number of JavaScript frames.
5444 v8::Script::Compile(v8::String::New(frame_count_source))->Run();
5445 frame_count = v8::Local<v8::Function>::Cast(
5446 context->Global()->Get(v8::String::New("frame_count")));
5447
5448 // Compile a function for returning the source line for the top frame.
5449 v8::Script::Compile(v8::String::New(frame_source_line_source))->Run();
5450 frame_source_line = v8::Local<v8::Function>::Cast(
5451 context->Global()->Get(v8::String::New("frame_source_line")));
5452
5453 // Compile a function returning the data parameter.
5454 v8::Script::Compile(v8::String::New(debugger_call_with_data_source))->Run();
5455 debugger_call_with_data = v8::Local<v8::Function>::Cast(
5456 context->Global()->Get(v8::String::New("debugger_call_with_data")));
5457
5458 // Compile a function capturing closure.
5459 debugger_call_with_closure = v8::Local<v8::Function>::Cast(
5460 v8::Script::Compile(
5461 v8::String::New(debugger_call_with_closure_source))->Run());
5462
Steve Block6ded16b2010-05-10 14:33:55 +01005463 // Calling a function through the debugger returns 0 frames if there are
5464 // no JavaScript frames.
5465 CHECK_EQ(v8::Integer::New(0), v8::Debug::Call(frame_count));
Steve Blocka7e24c12009-10-30 11:49:00 +00005466
5467 // Test that the number of frames can be retrieved.
5468 v8::Script::Compile(v8::String::New("CheckFrameCount(1)"))->Run();
5469 v8::Script::Compile(v8::String::New("function f() {"
5470 " CheckFrameCount(2);"
5471 "}; f()"))->Run();
5472
5473 // Test that the source line can be retrieved.
5474 v8::Script::Compile(v8::String::New("CheckSourceLine(0)"))->Run();
5475 v8::Script::Compile(v8::String::New("function f() {\n"
5476 " CheckSourceLine(1)\n"
5477 " CheckSourceLine(2)\n"
5478 " CheckSourceLine(3)\n"
5479 "}; f()"))->Run();
5480
5481 // Test that a parameter can be passed to a function called in the debugger.
5482 v8::Script::Compile(v8::String::New("CheckDataParameter()"))->Run();
5483
5484 // Test that a function with closure can be run in the debugger.
5485 v8::Script::Compile(v8::String::New("CheckClosure()"))->Run();
5486
5487
5488 // Test that the source line is correct when there is a line offset.
5489 v8::ScriptOrigin origin(v8::String::New("test"),
5490 v8::Integer::New(7));
5491 v8::Script::Compile(v8::String::New("CheckSourceLine(7)"), &origin)->Run();
5492 v8::Script::Compile(v8::String::New("function f() {\n"
5493 " CheckSourceLine(8)\n"
5494 " CheckSourceLine(9)\n"
5495 " CheckSourceLine(10)\n"
5496 "}; f()"), &origin)->Run();
5497}
5498
5499
5500// Debugger message handler which counts the number of breaks.
5501static void SendContinueCommand();
5502static void MessageHandlerBreakPointHitCount(
5503 const v8::Debug::Message& message) {
5504 if (message.IsEvent() && message.GetEvent() == v8::Break) {
5505 // Count the number of breaks.
5506 break_point_hit_count++;
5507
5508 SendContinueCommand();
5509 }
5510}
5511
5512
5513// Test that clearing the debug event listener actually clears all break points
5514// and related information.
5515TEST(DebuggerUnload) {
5516 DebugLocalContext env;
5517
5518 // Check debugger is unloaded before it is used.
5519 CheckDebuggerUnloaded();
5520
5521 // Set a debug event listener.
5522 break_point_hit_count = 0;
5523 v8::Debug::SetDebugEventListener(DebugEventBreakPointHitCount,
5524 v8::Undefined());
5525 {
5526 v8::HandleScope scope;
5527 // Create a couple of functions for the test.
5528 v8::Local<v8::Function> foo =
5529 CompileFunction(&env, "function foo(){x=1}", "foo");
5530 v8::Local<v8::Function> bar =
5531 CompileFunction(&env, "function bar(){y=2}", "bar");
5532
5533 // Set some break points.
5534 SetBreakPoint(foo, 0);
5535 SetBreakPoint(foo, 4);
5536 SetBreakPoint(bar, 0);
5537 SetBreakPoint(bar, 4);
5538
5539 // Make sure that the break points are there.
5540 break_point_hit_count = 0;
5541 foo->Call(env->Global(), 0, NULL);
5542 CHECK_EQ(2, break_point_hit_count);
5543 bar->Call(env->Global(), 0, NULL);
5544 CHECK_EQ(4, break_point_hit_count);
5545 }
5546
5547 // Remove the debug event listener without clearing breakpoints. Do this
5548 // outside a handle scope.
5549 v8::Debug::SetDebugEventListener(NULL);
5550 CheckDebuggerUnloaded(true);
5551
5552 // Now set a debug message handler.
5553 break_point_hit_count = 0;
5554 v8::Debug::SetMessageHandler2(MessageHandlerBreakPointHitCount);
5555 {
5556 v8::HandleScope scope;
5557
5558 // Get the test functions again.
5559 v8::Local<v8::Function> foo =
5560 v8::Local<v8::Function>::Cast(env->Global()->Get(v8::String::New("foo")));
5561 v8::Local<v8::Function> bar =
5562 v8::Local<v8::Function>::Cast(env->Global()->Get(v8::String::New("foo")));
5563
5564 foo->Call(env->Global(), 0, NULL);
5565 CHECK_EQ(0, break_point_hit_count);
5566
5567 // Set break points and run again.
5568 SetBreakPoint(foo, 0);
5569 SetBreakPoint(foo, 4);
5570 foo->Call(env->Global(), 0, NULL);
5571 CHECK_EQ(2, break_point_hit_count);
5572 }
5573
5574 // Remove the debug message handler without clearing breakpoints. Do this
5575 // outside a handle scope.
5576 v8::Debug::SetMessageHandler2(NULL);
5577 CheckDebuggerUnloaded(true);
5578}
5579
5580
5581// Sends continue command to the debugger.
5582static void SendContinueCommand() {
5583 const int kBufferSize = 1000;
5584 uint16_t buffer[kBufferSize];
5585 const char* command_continue =
5586 "{\"seq\":0,"
5587 "\"type\":\"request\","
5588 "\"command\":\"continue\"}";
5589
5590 v8::Debug::SendCommand(buffer, AsciiToUtf16(command_continue, buffer));
5591}
5592
5593
5594// Debugger message handler which counts the number of times it is called.
5595static int message_handler_hit_count = 0;
5596static void MessageHandlerHitCount(const v8::Debug::Message& message) {
5597 message_handler_hit_count++;
5598
Steve Block3ce2e202009-11-05 08:53:23 +00005599 static char print_buffer[1000];
5600 v8::String::Value json(message.GetJSON());
5601 Utf16ToAscii(*json, json.length(), print_buffer);
5602 if (IsExceptionEventMessage(print_buffer)) {
5603 // Send a continue command for exception events.
5604 SendContinueCommand();
5605 }
Steve Blocka7e24c12009-10-30 11:49:00 +00005606}
5607
5608
5609// Test clearing the debug message handler.
5610TEST(DebuggerClearMessageHandler) {
5611 v8::HandleScope scope;
5612 DebugLocalContext env;
5613
5614 // Check debugger is unloaded before it is used.
5615 CheckDebuggerUnloaded();
5616
5617 // Set a debug message handler.
5618 v8::Debug::SetMessageHandler2(MessageHandlerHitCount);
5619
5620 // Run code to throw a unhandled exception. This should end up in the message
5621 // handler.
5622 CompileRun("throw 1");
5623
5624 // The message handler should be called.
5625 CHECK_GT(message_handler_hit_count, 0);
5626
5627 // Clear debug message handler.
5628 message_handler_hit_count = 0;
5629 v8::Debug::SetMessageHandler(NULL);
5630
5631 // Run code to throw a unhandled exception. This should end up in the message
5632 // handler.
5633 CompileRun("throw 1");
5634
5635 // The message handler should not be called more.
5636 CHECK_EQ(0, message_handler_hit_count);
5637
5638 CheckDebuggerUnloaded(true);
5639}
5640
5641
5642// Debugger message handler which clears the message handler while active.
5643static void MessageHandlerClearingMessageHandler(
5644 const v8::Debug::Message& message) {
5645 message_handler_hit_count++;
5646
5647 // Clear debug message handler.
5648 v8::Debug::SetMessageHandler(NULL);
5649}
5650
5651
5652// Test clearing the debug message handler while processing a debug event.
5653TEST(DebuggerClearMessageHandlerWhileActive) {
5654 v8::HandleScope scope;
5655 DebugLocalContext env;
5656
5657 // Check debugger is unloaded before it is used.
5658 CheckDebuggerUnloaded();
5659
5660 // Set a debug message handler.
5661 v8::Debug::SetMessageHandler2(MessageHandlerClearingMessageHandler);
5662
5663 // Run code to throw a unhandled exception. This should end up in the message
5664 // handler.
5665 CompileRun("throw 1");
5666
5667 // The message handler should be called.
5668 CHECK_EQ(1, message_handler_hit_count);
5669
5670 CheckDebuggerUnloaded(true);
5671}
5672
5673
5674/* Test DebuggerHostDispatch */
5675/* In this test, the debugger waits for a command on a breakpoint
5676 * and is dispatching host commands while in the infinite loop.
5677 */
5678
5679class HostDispatchV8Thread : public v8::internal::Thread {
5680 public:
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00005681 HostDispatchV8Thread() : Thread("HostDispatchV8Thread") { }
Steve Blocka7e24c12009-10-30 11:49:00 +00005682 void Run();
5683};
5684
5685class HostDispatchDebuggerThread : public v8::internal::Thread {
5686 public:
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00005687 HostDispatchDebuggerThread() : Thread("HostDispatchDebuggerThread") { }
Steve Blocka7e24c12009-10-30 11:49:00 +00005688 void Run();
5689};
5690
5691Barriers* host_dispatch_barriers;
5692
5693static void HostDispatchMessageHandler(const v8::Debug::Message& message) {
5694 static char print_buffer[1000];
5695 v8::String::Value json(message.GetJSON());
5696 Utf16ToAscii(*json, json.length(), print_buffer);
Steve Blocka7e24c12009-10-30 11:49:00 +00005697}
5698
5699
5700static void HostDispatchDispatchHandler() {
5701 host_dispatch_barriers->semaphore_1->Signal();
5702}
5703
5704
5705void HostDispatchV8Thread::Run() {
5706 const char* source_1 = "var y_global = 3;\n"
5707 "function cat( new_value ) {\n"
5708 " var x = new_value;\n"
5709 " y_global = 4;\n"
5710 " x = 3 * x + 1;\n"
5711 " y_global = 5;\n"
5712 " return x;\n"
5713 "}\n"
5714 "\n";
5715 const char* source_2 = "cat(17);\n";
5716
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00005717 v8::V8::Initialize();
Steve Blocka7e24c12009-10-30 11:49:00 +00005718 v8::HandleScope scope;
5719 DebugLocalContext env;
5720
5721 // Setup message and host dispatch handlers.
5722 v8::Debug::SetMessageHandler2(HostDispatchMessageHandler);
5723 v8::Debug::SetHostDispatchHandler(HostDispatchDispatchHandler, 10 /* ms */);
5724
5725 CompileRun(source_1);
5726 host_dispatch_barriers->barrier_1.Wait();
5727 host_dispatch_barriers->barrier_2.Wait();
5728 CompileRun(source_2);
5729}
5730
5731
5732void HostDispatchDebuggerThread::Run() {
5733 const int kBufSize = 1000;
5734 uint16_t buffer[kBufSize];
5735
5736 const char* command_1 = "{\"seq\":101,"
5737 "\"type\":\"request\","
5738 "\"command\":\"setbreakpoint\","
5739 "\"arguments\":{\"type\":\"function\",\"target\":\"cat\",\"line\":3}}";
5740 const char* command_2 = "{\"seq\":102,"
5741 "\"type\":\"request\","
5742 "\"command\":\"continue\"}";
5743
5744 // v8 thread initializes, runs source_1
5745 host_dispatch_barriers->barrier_1.Wait();
5746 // 1: Set breakpoint in cat().
5747 v8::Debug::SendCommand(buffer, AsciiToUtf16(command_1, buffer));
5748
5749 host_dispatch_barriers->barrier_2.Wait();
5750 // v8 thread starts compiling source_2.
5751 // Break happens, to run queued commands and host dispatches.
5752 // Wait for host dispatch to be processed.
5753 host_dispatch_barriers->semaphore_1->Wait();
5754 // 2: Continue evaluation
5755 v8::Debug::SendCommand(buffer, AsciiToUtf16(command_2, buffer));
5756}
5757
Steve Blocka7e24c12009-10-30 11:49:00 +00005758
5759TEST(DebuggerHostDispatch) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00005760 HostDispatchDebuggerThread host_dispatch_debugger_thread;
5761 HostDispatchV8Thread host_dispatch_v8_thread;
Steve Blocka7e24c12009-10-30 11:49:00 +00005762 i::FLAG_debugger_auto_break = true;
5763
5764 // Create a V8 environment
5765 Barriers stack_allocated_host_dispatch_barriers;
5766 stack_allocated_host_dispatch_barriers.Initialize();
5767 host_dispatch_barriers = &stack_allocated_host_dispatch_barriers;
5768
5769 host_dispatch_v8_thread.Start();
5770 host_dispatch_debugger_thread.Start();
5771
5772 host_dispatch_v8_thread.Join();
5773 host_dispatch_debugger_thread.Join();
5774}
5775
5776
Steve Blockd0582a62009-12-15 09:54:21 +00005777/* Test DebugMessageDispatch */
5778/* In this test, the V8 thread waits for a message from the debug thread.
5779 * The DebugMessageDispatchHandler is executed from the debugger thread
5780 * which signals the V8 thread to wake up.
5781 */
5782
5783class DebugMessageDispatchV8Thread : public v8::internal::Thread {
5784 public:
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00005785 DebugMessageDispatchV8Thread() : Thread("DebugMessageDispatchV8Thread") { }
Steve Blockd0582a62009-12-15 09:54:21 +00005786 void Run();
5787};
5788
5789class DebugMessageDispatchDebuggerThread : public v8::internal::Thread {
5790 public:
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00005791 DebugMessageDispatchDebuggerThread()
5792 : Thread("DebugMessageDispatchDebuggerThread") { }
Steve Blockd0582a62009-12-15 09:54:21 +00005793 void Run();
5794};
5795
5796Barriers* debug_message_dispatch_barriers;
5797
5798
5799static void DebugMessageHandler() {
5800 debug_message_dispatch_barriers->semaphore_1->Signal();
5801}
5802
5803
5804void DebugMessageDispatchV8Thread::Run() {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00005805 v8::V8::Initialize();
Steve Blockd0582a62009-12-15 09:54:21 +00005806 v8::HandleScope scope;
5807 DebugLocalContext env;
5808
5809 // Setup debug message dispatch handler.
5810 v8::Debug::SetDebugMessageDispatchHandler(DebugMessageHandler);
5811
5812 CompileRun("var y = 1 + 2;\n");
5813 debug_message_dispatch_barriers->barrier_1.Wait();
5814 debug_message_dispatch_barriers->semaphore_1->Wait();
5815 debug_message_dispatch_barriers->barrier_2.Wait();
5816}
5817
5818
5819void DebugMessageDispatchDebuggerThread::Run() {
5820 debug_message_dispatch_barriers->barrier_1.Wait();
5821 SendContinueCommand();
5822 debug_message_dispatch_barriers->barrier_2.Wait();
5823}
5824
Steve Blockd0582a62009-12-15 09:54:21 +00005825
5826TEST(DebuggerDebugMessageDispatch) {
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00005827 DebugMessageDispatchDebuggerThread debug_message_dispatch_debugger_thread;
5828 DebugMessageDispatchV8Thread debug_message_dispatch_v8_thread;
Steve Block44f0eee2011-05-26 01:26:41 +01005829
Steve Blockd0582a62009-12-15 09:54:21 +00005830 i::FLAG_debugger_auto_break = true;
5831
5832 // Create a V8 environment
5833 Barriers stack_allocated_debug_message_dispatch_barriers;
5834 stack_allocated_debug_message_dispatch_barriers.Initialize();
5835 debug_message_dispatch_barriers =
5836 &stack_allocated_debug_message_dispatch_barriers;
5837
5838 debug_message_dispatch_v8_thread.Start();
5839 debug_message_dispatch_debugger_thread.Start();
5840
5841 debug_message_dispatch_v8_thread.Join();
5842 debug_message_dispatch_debugger_thread.Join();
5843}
5844
5845
Steve Blocka7e24c12009-10-30 11:49:00 +00005846TEST(DebuggerAgent) {
Ben Murdoch69a99ed2011-11-30 16:03:39 +00005847 v8::V8::Initialize();
Steve Block44f0eee2011-05-26 01:26:41 +01005848 i::Debugger* debugger = i::Isolate::Current()->debugger();
Steve Blocka7e24c12009-10-30 11:49:00 +00005849 // Make sure these ports is not used by other tests to allow tests to run in
5850 // parallel.
5851 const int kPort1 = 5858;
5852 const int kPort2 = 5857;
5853 const int kPort3 = 5856;
5854
5855 // Make a string with the port2 number.
5856 const int kPortBufferLen = 6;
5857 char port2_str[kPortBufferLen];
5858 OS::SNPrintF(i::Vector<char>(port2_str, kPortBufferLen), "%d", kPort2);
5859
5860 bool ok;
5861
5862 // Initialize the socket library.
5863 i::Socket::Setup();
5864
5865 // Test starting and stopping the agent without any client connection.
Steve Block44f0eee2011-05-26 01:26:41 +01005866 debugger->StartAgent("test", kPort1);
5867 debugger->StopAgent();
Steve Blocka7e24c12009-10-30 11:49:00 +00005868 // Test starting the agent, connecting a client and shutting down the agent
5869 // with the client connected.
Steve Block44f0eee2011-05-26 01:26:41 +01005870 ok = debugger->StartAgent("test", kPort2);
Steve Blocka7e24c12009-10-30 11:49:00 +00005871 CHECK(ok);
Steve Block44f0eee2011-05-26 01:26:41 +01005872 debugger->WaitForAgent();
Steve Blocka7e24c12009-10-30 11:49:00 +00005873 i::Socket* client = i::OS::CreateSocket();
5874 ok = client->Connect("localhost", port2_str);
5875 CHECK(ok);
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00005876 // It is important to wait for a message from the agent. Otherwise,
5877 // we can close the server socket during "accept" syscall, making it failing
5878 // (at least on Linux), and the test will work incorrectly.
5879 char buf;
5880 ok = client->Receive(&buf, 1) == 1;
5881 CHECK(ok);
Steve Block44f0eee2011-05-26 01:26:41 +01005882 debugger->StopAgent();
Steve Blocka7e24c12009-10-30 11:49:00 +00005883 delete client;
5884
5885 // Test starting and stopping the agent with the required port already
5886 // occoupied.
5887 i::Socket* server = i::OS::CreateSocket();
5888 server->Bind(kPort3);
5889
Steve Block44f0eee2011-05-26 01:26:41 +01005890 debugger->StartAgent("test", kPort3);
5891 debugger->StopAgent();
Steve Blocka7e24c12009-10-30 11:49:00 +00005892
5893 delete server;
5894}
5895
5896
5897class DebuggerAgentProtocolServerThread : public i::Thread {
5898 public:
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00005899 explicit DebuggerAgentProtocolServerThread(int port)
5900 : Thread("DebuggerAgentProtocolServerThread"),
Steve Block44f0eee2011-05-26 01:26:41 +01005901 port_(port),
5902 server_(NULL),
5903 client_(NULL),
Steve Blocka7e24c12009-10-30 11:49:00 +00005904 listening_(OS::CreateSemaphore(0)) {
5905 }
5906 ~DebuggerAgentProtocolServerThread() {
5907 // Close both sockets.
5908 delete client_;
5909 delete server_;
5910 delete listening_;
5911 }
5912
5913 void Run();
5914 void WaitForListening() { listening_->Wait(); }
5915 char* body() { return *body_; }
5916
5917 private:
5918 int port_;
5919 i::SmartPointer<char> body_;
5920 i::Socket* server_; // Server socket used for bind/accept.
5921 i::Socket* client_; // Single client connection used by the test.
5922 i::Semaphore* listening_; // Signalled when the server is in listen mode.
5923};
5924
5925
5926void DebuggerAgentProtocolServerThread::Run() {
5927 bool ok;
5928
5929 // Create the server socket and bind it to the requested port.
5930 server_ = i::OS::CreateSocket();
5931 CHECK(server_ != NULL);
5932 ok = server_->Bind(port_);
5933 CHECK(ok);
5934
5935 // Listen for new connections.
5936 ok = server_->Listen(1);
5937 CHECK(ok);
5938 listening_->Signal();
5939
5940 // Accept a connection.
5941 client_ = server_->Accept();
5942 CHECK(client_ != NULL);
5943
5944 // Receive a debugger agent protocol message.
5945 i::DebuggerAgentUtil::ReceiveMessage(client_);
5946}
5947
5948
5949TEST(DebuggerAgentProtocolOverflowHeader) {
5950 // Make sure this port is not used by other tests to allow tests to run in
5951 // parallel.
5952 const int kPort = 5860;
5953 static const char* kLocalhost = "localhost";
5954
5955 // Make a string with the port number.
5956 const int kPortBufferLen = 6;
5957 char port_str[kPortBufferLen];
5958 OS::SNPrintF(i::Vector<char>(port_str, kPortBufferLen), "%d", kPort);
5959
5960 // Initialize the socket library.
5961 i::Socket::Setup();
5962
5963 // Create a socket server to receive a debugger agent message.
5964 DebuggerAgentProtocolServerThread* server =
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00005965 new DebuggerAgentProtocolServerThread(kPort);
Steve Blocka7e24c12009-10-30 11:49:00 +00005966 server->Start();
5967 server->WaitForListening();
5968
5969 // Connect.
5970 i::Socket* client = i::OS::CreateSocket();
5971 CHECK(client != NULL);
5972 bool ok = client->Connect(kLocalhost, port_str);
5973 CHECK(ok);
5974
5975 // Send headers which overflow the receive buffer.
5976 static const int kBufferSize = 1000;
5977 char buffer[kBufferSize];
5978
5979 // Long key and short value: XXXX....XXXX:0\r\n.
5980 for (int i = 0; i < kBufferSize - 4; i++) {
5981 buffer[i] = 'X';
5982 }
5983 buffer[kBufferSize - 4] = ':';
5984 buffer[kBufferSize - 3] = '0';
5985 buffer[kBufferSize - 2] = '\r';
5986 buffer[kBufferSize - 1] = '\n';
5987 client->Send(buffer, kBufferSize);
5988
5989 // Short key and long value: X:XXXX....XXXX\r\n.
5990 buffer[0] = 'X';
5991 buffer[1] = ':';
5992 for (int i = 2; i < kBufferSize - 2; i++) {
5993 buffer[i] = 'X';
5994 }
5995 buffer[kBufferSize - 2] = '\r';
5996 buffer[kBufferSize - 1] = '\n';
5997 client->Send(buffer, kBufferSize);
5998
5999 // Add empty body to request.
6000 const char* content_length_zero_header = "Content-Length:0\r\n";
Steve Blockd0582a62009-12-15 09:54:21 +00006001 client->Send(content_length_zero_header,
6002 StrLength(content_length_zero_header));
Steve Blocka7e24c12009-10-30 11:49:00 +00006003 client->Send("\r\n", 2);
6004
6005 // Wait until data is received.
6006 server->Join();
6007
6008 // Check for empty body.
6009 CHECK(server->body() == NULL);
6010
6011 // Close the client before the server to avoid TIME_WAIT issues.
6012 client->Shutdown();
6013 delete client;
6014 delete server;
6015}
6016
6017
6018// Test for issue http://code.google.com/p/v8/issues/detail?id=289.
6019// Make sure that DebugGetLoadedScripts doesn't return scripts
6020// with disposed external source.
6021class EmptyExternalStringResource : public v8::String::ExternalStringResource {
6022 public:
6023 EmptyExternalStringResource() { empty_[0] = 0; }
6024 virtual ~EmptyExternalStringResource() {}
6025 virtual size_t length() const { return empty_.length(); }
6026 virtual const uint16_t* data() const { return empty_.start(); }
6027 private:
6028 ::v8::internal::EmbeddedVector<uint16_t, 1> empty_;
6029};
6030
6031
6032TEST(DebugGetLoadedScripts) {
6033 v8::HandleScope scope;
6034 DebugLocalContext env;
6035 env.ExposeDebug();
6036
6037 EmptyExternalStringResource source_ext_str;
6038 v8::Local<v8::String> source = v8::String::NewExternal(&source_ext_str);
6039 v8::Handle<v8::Script> evil_script = v8::Script::Compile(source);
6040 Handle<i::ExternalTwoByteString> i_source(
6041 i::ExternalTwoByteString::cast(*v8::Utils::OpenHandle(*source)));
6042 // This situation can happen if source was an external string disposed
6043 // by its owner.
6044 i_source->set_resource(0);
6045
6046 bool allow_natives_syntax = i::FLAG_allow_natives_syntax;
6047 i::FLAG_allow_natives_syntax = true;
6048 CompileRun(
6049 "var scripts = %DebugGetLoadedScripts();"
6050 "var count = scripts.length;"
6051 "for (var i = 0; i < count; ++i) {"
6052 " scripts[i].line_ends;"
6053 "}");
6054 // Must not crash while accessing line_ends.
6055 i::FLAG_allow_natives_syntax = allow_natives_syntax;
6056
6057 // Some scripts are retrieved - at least the number of native scripts.
6058 CHECK_GT((*env)->Global()->Get(v8::String::New("count"))->Int32Value(), 8);
6059}
6060
6061
6062// Test script break points set on lines.
6063TEST(ScriptNameAndData) {
6064 v8::HandleScope scope;
6065 DebugLocalContext env;
6066 env.ExposeDebug();
6067
6068 // Create functions for retrieving script name and data for the function on
6069 // the top frame when hitting a break point.
6070 frame_script_name = CompileFunction(&env,
6071 frame_script_name_source,
6072 "frame_script_name");
6073 frame_script_data = CompileFunction(&env,
6074 frame_script_data_source,
6075 "frame_script_data");
Andrei Popescu402d9372010-02-26 13:31:12 +00006076 compiled_script_data = CompileFunction(&env,
6077 compiled_script_data_source,
6078 "compiled_script_data");
Steve Blocka7e24c12009-10-30 11:49:00 +00006079
6080 v8::Debug::SetDebugEventListener(DebugEventBreakPointHitCount,
6081 v8::Undefined());
6082
6083 // Test function source.
6084 v8::Local<v8::String> script = v8::String::New(
6085 "function f() {\n"
6086 " debugger;\n"
6087 "}\n");
6088
6089 v8::ScriptOrigin origin1 = v8::ScriptOrigin(v8::String::New("name"));
6090 v8::Handle<v8::Script> script1 = v8::Script::Compile(script, &origin1);
6091 script1->SetData(v8::String::New("data"));
6092 script1->Run();
6093 v8::Local<v8::Function> f;
6094 f = v8::Local<v8::Function>::Cast(env->Global()->Get(v8::String::New("f")));
6095
6096 f->Call(env->Global(), 0, NULL);
6097 CHECK_EQ(1, break_point_hit_count);
6098 CHECK_EQ("name", last_script_name_hit);
6099 CHECK_EQ("data", last_script_data_hit);
6100
6101 // Compile the same script again without setting data. As the compilation
6102 // cache is disabled when debugging expect the data to be missing.
6103 v8::Script::Compile(script, &origin1)->Run();
6104 f = v8::Local<v8::Function>::Cast(env->Global()->Get(v8::String::New("f")));
6105 f->Call(env->Global(), 0, NULL);
6106 CHECK_EQ(2, break_point_hit_count);
6107 CHECK_EQ("name", last_script_name_hit);
6108 CHECK_EQ("", last_script_data_hit); // Undefined results in empty string.
6109
6110 v8::Local<v8::String> data_obj_source = v8::String::New(
6111 "({ a: 'abc',\n"
6112 " b: 123,\n"
6113 " toString: function() { return this.a + ' ' + this.b; }\n"
6114 "})\n");
6115 v8::Local<v8::Value> data_obj = v8::Script::Compile(data_obj_source)->Run();
6116 v8::ScriptOrigin origin2 = v8::ScriptOrigin(v8::String::New("new name"));
6117 v8::Handle<v8::Script> script2 = v8::Script::Compile(script, &origin2);
6118 script2->Run();
Steve Blockd0582a62009-12-15 09:54:21 +00006119 script2->SetData(data_obj->ToString());
Steve Blocka7e24c12009-10-30 11:49:00 +00006120 f = v8::Local<v8::Function>::Cast(env->Global()->Get(v8::String::New("f")));
6121 f->Call(env->Global(), 0, NULL);
6122 CHECK_EQ(3, break_point_hit_count);
6123 CHECK_EQ("new name", last_script_name_hit);
6124 CHECK_EQ("abc 123", last_script_data_hit);
Andrei Popescu402d9372010-02-26 13:31:12 +00006125
6126 v8::Handle<v8::Script> script3 =
6127 v8::Script::Compile(script, &origin2, NULL,
6128 v8::String::New("in compile"));
6129 CHECK_EQ("in compile", last_script_data_hit);
6130 script3->Run();
6131 f = v8::Local<v8::Function>::Cast(env->Global()->Get(v8::String::New("f")));
6132 f->Call(env->Global(), 0, NULL);
6133 CHECK_EQ(4, break_point_hit_count);
6134 CHECK_EQ("in compile", last_script_data_hit);
Steve Blocka7e24c12009-10-30 11:49:00 +00006135}
6136
6137
6138static v8::Persistent<v8::Context> expected_context;
6139static v8::Handle<v8::Value> expected_context_data;
6140
6141
6142// Check that the expected context is the one generating the debug event.
6143static void ContextCheckMessageHandler(const v8::Debug::Message& message) {
6144 CHECK(message.GetEventContext() == expected_context);
6145 CHECK(message.GetEventContext()->GetData()->StrictEquals(
6146 expected_context_data));
6147 message_handler_hit_count++;
6148
Steve Block3ce2e202009-11-05 08:53:23 +00006149 static char print_buffer[1000];
6150 v8::String::Value json(message.GetJSON());
6151 Utf16ToAscii(*json, json.length(), print_buffer);
6152
Steve Blocka7e24c12009-10-30 11:49:00 +00006153 // Send a continue command for break events.
Steve Block3ce2e202009-11-05 08:53:23 +00006154 if (IsBreakEventMessage(print_buffer)) {
Steve Blocka7e24c12009-10-30 11:49:00 +00006155 SendContinueCommand();
6156 }
6157}
6158
6159
6160// Test which creates two contexts and sets different embedder data on each.
6161// Checks that this data is set correctly and that when the debug message
6162// handler is called the expected context is the one active.
6163TEST(ContextData) {
6164 v8::HandleScope scope;
6165
6166 v8::Debug::SetMessageHandler2(ContextCheckMessageHandler);
6167
6168 // Create two contexts.
6169 v8::Persistent<v8::Context> context_1;
6170 v8::Persistent<v8::Context> context_2;
6171 v8::Handle<v8::ObjectTemplate> global_template =
6172 v8::Handle<v8::ObjectTemplate>();
6173 v8::Handle<v8::Value> global_object = v8::Handle<v8::Value>();
6174 context_1 = v8::Context::New(NULL, global_template, global_object);
6175 context_2 = v8::Context::New(NULL, global_template, global_object);
6176
6177 // Default data value is undefined.
6178 CHECK(context_1->GetData()->IsUndefined());
6179 CHECK(context_2->GetData()->IsUndefined());
6180
6181 // Set and check different data values.
Steve Blockd0582a62009-12-15 09:54:21 +00006182 v8::Handle<v8::String> data_1 = v8::String::New("1");
6183 v8::Handle<v8::String> data_2 = v8::String::New("2");
Steve Blocka7e24c12009-10-30 11:49:00 +00006184 context_1->SetData(data_1);
6185 context_2->SetData(data_2);
6186 CHECK(context_1->GetData()->StrictEquals(data_1));
6187 CHECK(context_2->GetData()->StrictEquals(data_2));
6188
6189 // Simple test function which causes a break.
6190 const char* source = "function f() { debugger; }";
6191
6192 // Enter and run function in the first context.
6193 {
6194 v8::Context::Scope context_scope(context_1);
6195 expected_context = context_1;
6196 expected_context_data = data_1;
6197 v8::Local<v8::Function> f = CompileFunction(source, "f");
6198 f->Call(context_1->Global(), 0, NULL);
6199 }
6200
6201
6202 // Enter and run function in the second context.
6203 {
6204 v8::Context::Scope context_scope(context_2);
6205 expected_context = context_2;
6206 expected_context_data = data_2;
6207 v8::Local<v8::Function> f = CompileFunction(source, "f");
6208 f->Call(context_2->Global(), 0, NULL);
6209 }
6210
6211 // Two times compile event and two times break event.
6212 CHECK_GT(message_handler_hit_count, 4);
6213
6214 v8::Debug::SetMessageHandler2(NULL);
6215 CheckDebuggerUnloaded();
6216}
6217
6218
6219// Debug message handler which issues a debug break when it hits a break event.
6220static int message_handler_break_hit_count = 0;
6221static void DebugBreakMessageHandler(const v8::Debug::Message& message) {
6222 // Schedule a debug break for break events.
6223 if (message.IsEvent() && message.GetEvent() == v8::Break) {
6224 message_handler_break_hit_count++;
6225 if (message_handler_break_hit_count == 1) {
6226 v8::Debug::DebugBreak();
6227 }
6228 }
6229
6230 // Issue a continue command if this event will not cause the VM to start
6231 // running.
6232 if (!message.WillStartRunning()) {
6233 SendContinueCommand();
6234 }
6235}
6236
6237
6238// Test that a debug break can be scheduled while in a message handler.
6239TEST(DebugBreakInMessageHandler) {
6240 v8::HandleScope scope;
6241 DebugLocalContext env;
6242
6243 v8::Debug::SetMessageHandler2(DebugBreakMessageHandler);
6244
6245 // Test functions.
6246 const char* script = "function f() { debugger; g(); } function g() { }";
6247 CompileRun(script);
6248 v8::Local<v8::Function> f =
6249 v8::Local<v8::Function>::Cast(env->Global()->Get(v8::String::New("f")));
6250 v8::Local<v8::Function> g =
6251 v8::Local<v8::Function>::Cast(env->Global()->Get(v8::String::New("g")));
6252
6253 // Call f then g. The debugger statement in f will casue a break which will
6254 // cause another break.
6255 f->Call(env->Global(), 0, NULL);
6256 CHECK_EQ(2, message_handler_break_hit_count);
6257 // Calling g will not cause any additional breaks.
6258 g->Call(env->Global(), 0, NULL);
6259 CHECK_EQ(2, message_handler_break_hit_count);
6260}
6261
6262
Steve Block6ded16b2010-05-10 14:33:55 +01006263#ifndef V8_INTERPRETED_REGEXP
Steve Blocka7e24c12009-10-30 11:49:00 +00006264// Debug event handler which gets the function on the top frame and schedules a
6265// break a number of times.
6266static void DebugEventDebugBreak(
6267 v8::DebugEvent event,
6268 v8::Handle<v8::Object> exec_state,
6269 v8::Handle<v8::Object> event_data,
6270 v8::Handle<v8::Value> data) {
6271
6272 if (event == v8::Break) {
6273 break_point_hit_count++;
6274
6275 // Get the name of the top frame function.
6276 if (!frame_function_name.IsEmpty()) {
6277 // Get the name of the function.
Ben Murdochb0fe1622011-05-05 13:52:32 +01006278 const int argc = 2;
6279 v8::Handle<v8::Value> argv[argc] = { exec_state, v8::Integer::New(0) };
Steve Blocka7e24c12009-10-30 11:49:00 +00006280 v8::Handle<v8::Value> result = frame_function_name->Call(exec_state,
6281 argc, argv);
6282 if (result->IsUndefined()) {
6283 last_function_hit[0] = '\0';
6284 } else {
6285 CHECK(result->IsString());
6286 v8::Handle<v8::String> function_name(result->ToString());
6287 function_name->WriteAscii(last_function_hit);
6288 }
6289 }
6290
6291 // Keep forcing breaks.
6292 if (break_point_hit_count < 20) {
6293 v8::Debug::DebugBreak();
6294 }
6295 }
6296}
6297
6298
6299TEST(RegExpDebugBreak) {
6300 // This test only applies to native regexps.
6301 v8::HandleScope scope;
6302 DebugLocalContext env;
6303
6304 // Create a function for checking the function when hitting a break point.
6305 frame_function_name = CompileFunction(&env,
6306 frame_function_name_source,
6307 "frame_function_name");
6308
6309 // Test RegExp which matches white spaces and comments at the begining of a
6310 // source line.
6311 const char* script =
6312 "var sourceLineBeginningSkip = /^(?:[ \\v\\h]*(?:\\/\\*.*?\\*\\/)*)*/;\n"
6313 "function f(s) { return s.match(sourceLineBeginningSkip)[0].length; }";
6314
6315 v8::Local<v8::Function> f = CompileFunction(script, "f");
6316 const int argc = 1;
6317 v8::Handle<v8::Value> argv[argc] = { v8::String::New(" /* xxx */ a=0;") };
6318 v8::Local<v8::Value> result = f->Call(env->Global(), argc, argv);
6319 CHECK_EQ(12, result->Int32Value());
6320
6321 v8::Debug::SetDebugEventListener(DebugEventDebugBreak);
6322 v8::Debug::DebugBreak();
6323 result = f->Call(env->Global(), argc, argv);
6324
6325 // Check that there was only one break event. Matching RegExp should not
6326 // cause Break events.
6327 CHECK_EQ(1, break_point_hit_count);
6328 CHECK_EQ("f", last_function_hit);
6329}
Steve Block6ded16b2010-05-10 14:33:55 +01006330#endif // V8_INTERPRETED_REGEXP
Steve Blocka7e24c12009-10-30 11:49:00 +00006331
6332
6333// Common part of EvalContextData and NestedBreakEventContextData tests.
6334static void ExecuteScriptForContextCheck() {
6335 // Create a context.
6336 v8::Persistent<v8::Context> context_1;
6337 v8::Handle<v8::ObjectTemplate> global_template =
6338 v8::Handle<v8::ObjectTemplate>();
Ben Murdoch257744e2011-11-30 15:57:28 +00006339 context_1 = v8::Context::New(NULL, global_template);
Steve Blocka7e24c12009-10-30 11:49:00 +00006340
6341 // Default data value is undefined.
6342 CHECK(context_1->GetData()->IsUndefined());
6343
6344 // Set and check a data value.
Steve Blockd0582a62009-12-15 09:54:21 +00006345 v8::Handle<v8::String> data_1 = v8::String::New("1");
Steve Blocka7e24c12009-10-30 11:49:00 +00006346 context_1->SetData(data_1);
6347 CHECK(context_1->GetData()->StrictEquals(data_1));
6348
6349 // Simple test function with eval that causes a break.
6350 const char* source = "function f() { eval('debugger;'); }";
6351
6352 // Enter and run function in the context.
6353 {
6354 v8::Context::Scope context_scope(context_1);
6355 expected_context = context_1;
6356 expected_context_data = data_1;
6357 v8::Local<v8::Function> f = CompileFunction(source, "f");
6358 f->Call(context_1->Global(), 0, NULL);
6359 }
6360}
6361
6362
6363// Test which creates a context and sets embedder data on it. Checks that this
6364// data is set correctly and that when the debug message handler is called for
6365// break event in an eval statement the expected context is the one returned by
6366// Message.GetEventContext.
6367TEST(EvalContextData) {
6368 v8::HandleScope scope;
6369 v8::Debug::SetMessageHandler2(ContextCheckMessageHandler);
6370
6371 ExecuteScriptForContextCheck();
6372
6373 // One time compile event and one time break event.
6374 CHECK_GT(message_handler_hit_count, 2);
6375 v8::Debug::SetMessageHandler2(NULL);
6376 CheckDebuggerUnloaded();
6377}
6378
6379
6380static bool sent_eval = false;
6381static int break_count = 0;
6382static int continue_command_send_count = 0;
6383// Check that the expected context is the one generating the debug event
6384// including the case of nested break event.
6385static void DebugEvalContextCheckMessageHandler(
6386 const v8::Debug::Message& message) {
6387 CHECK(message.GetEventContext() == expected_context);
6388 CHECK(message.GetEventContext()->GetData()->StrictEquals(
6389 expected_context_data));
6390 message_handler_hit_count++;
6391
Steve Block3ce2e202009-11-05 08:53:23 +00006392 static char print_buffer[1000];
6393 v8::String::Value json(message.GetJSON());
6394 Utf16ToAscii(*json, json.length(), print_buffer);
6395
6396 if (IsBreakEventMessage(print_buffer)) {
Steve Blocka7e24c12009-10-30 11:49:00 +00006397 break_count++;
6398 if (!sent_eval) {
6399 sent_eval = true;
6400
6401 const int kBufferSize = 1000;
6402 uint16_t buffer[kBufferSize];
6403 const char* eval_command =
Ben Murdoch257744e2011-11-30 15:57:28 +00006404 "{\"seq\":0,"
6405 "\"type\":\"request\","
6406 "\"command\":\"evaluate\","
6407 "\"arguments\":{\"expression\":\"debugger;\","
6408 "\"global\":true,\"disable_break\":false}}";
Steve Blocka7e24c12009-10-30 11:49:00 +00006409
6410 // Send evaluate command.
6411 v8::Debug::SendCommand(buffer, AsciiToUtf16(eval_command, buffer));
6412 return;
6413 } else {
6414 // It's a break event caused by the evaluation request above.
6415 SendContinueCommand();
6416 continue_command_send_count++;
6417 }
Steve Block3ce2e202009-11-05 08:53:23 +00006418 } else if (IsEvaluateResponseMessage(print_buffer) &&
6419 continue_command_send_count < 2) {
Steve Blocka7e24c12009-10-30 11:49:00 +00006420 // Response to the evaluation request. We're still on the breakpoint so
6421 // send continue.
6422 SendContinueCommand();
6423 continue_command_send_count++;
6424 }
6425}
6426
6427
6428// Tests that context returned for break event is correct when the event occurs
6429// in 'evaluate' debugger request.
6430TEST(NestedBreakEventContextData) {
6431 v8::HandleScope scope;
6432 break_count = 0;
6433 message_handler_hit_count = 0;
6434 v8::Debug::SetMessageHandler2(DebugEvalContextCheckMessageHandler);
6435
6436 ExecuteScriptForContextCheck();
6437
6438 // One time compile event and two times break event.
6439 CHECK_GT(message_handler_hit_count, 3);
6440
6441 // One break from the source and another from the evaluate request.
6442 CHECK_EQ(break_count, 2);
6443 v8::Debug::SetMessageHandler2(NULL);
6444 CheckDebuggerUnloaded();
6445}
6446
6447
6448// Debug event listener which counts the script collected events.
6449int script_collected_count = 0;
6450static void DebugEventScriptCollectedEvent(v8::DebugEvent event,
6451 v8::Handle<v8::Object> exec_state,
6452 v8::Handle<v8::Object> event_data,
6453 v8::Handle<v8::Value> data) {
6454 // Count the number of breaks.
6455 if (event == v8::ScriptCollected) {
6456 script_collected_count++;
6457 }
6458}
6459
6460
6461// Test that scripts collected are reported through the debug event listener.
6462TEST(ScriptCollectedEvent) {
Steve Block44f0eee2011-05-26 01:26:41 +01006463 v8::internal::Debug* debug = v8::internal::Isolate::Current()->debug();
Steve Blocka7e24c12009-10-30 11:49:00 +00006464 break_point_hit_count = 0;
6465 script_collected_count = 0;
6466 v8::HandleScope scope;
6467 DebugLocalContext env;
6468
6469 // Request the loaded scripts to initialize the debugger script cache.
Steve Block44f0eee2011-05-26 01:26:41 +01006470 debug->GetLoadedScripts();
Steve Blocka7e24c12009-10-30 11:49:00 +00006471
6472 // Do garbage collection to ensure that only the script in this test will be
6473 // collected afterwards.
Steve Block44f0eee2011-05-26 01:26:41 +01006474 HEAP->CollectAllGarbage(false);
Steve Blocka7e24c12009-10-30 11:49:00 +00006475
6476 script_collected_count = 0;
6477 v8::Debug::SetDebugEventListener(DebugEventScriptCollectedEvent,
6478 v8::Undefined());
6479 {
6480 v8::Script::Compile(v8::String::New("eval('a=1')"))->Run();
6481 v8::Script::Compile(v8::String::New("eval('a=2')"))->Run();
6482 }
6483
6484 // Do garbage collection to collect the script above which is no longer
6485 // referenced.
Steve Block44f0eee2011-05-26 01:26:41 +01006486 HEAP->CollectAllGarbage(false);
Steve Blocka7e24c12009-10-30 11:49:00 +00006487
6488 CHECK_EQ(2, script_collected_count);
6489
6490 v8::Debug::SetDebugEventListener(NULL);
6491 CheckDebuggerUnloaded();
6492}
6493
6494
6495// Debug event listener which counts the script collected events.
6496int script_collected_message_count = 0;
6497static void ScriptCollectedMessageHandler(const v8::Debug::Message& message) {
6498 // Count the number of scripts collected.
6499 if (message.IsEvent() && message.GetEvent() == v8::ScriptCollected) {
6500 script_collected_message_count++;
6501 v8::Handle<v8::Context> context = message.GetEventContext();
6502 CHECK(context.IsEmpty());
6503 }
6504}
6505
6506
6507// Test that GetEventContext doesn't fail and return empty handle for
6508// ScriptCollected events.
6509TEST(ScriptCollectedEventContext) {
Steve Block44f0eee2011-05-26 01:26:41 +01006510 v8::internal::Debug* debug = v8::internal::Isolate::Current()->debug();
Steve Blocka7e24c12009-10-30 11:49:00 +00006511 script_collected_message_count = 0;
6512 v8::HandleScope scope;
6513
6514 { // Scope for the DebugLocalContext.
6515 DebugLocalContext env;
6516
6517 // Request the loaded scripts to initialize the debugger script cache.
Steve Block44f0eee2011-05-26 01:26:41 +01006518 debug->GetLoadedScripts();
Steve Blocka7e24c12009-10-30 11:49:00 +00006519
6520 // Do garbage collection to ensure that only the script in this test will be
6521 // collected afterwards.
Steve Block44f0eee2011-05-26 01:26:41 +01006522 HEAP->CollectAllGarbage(false);
Steve Blocka7e24c12009-10-30 11:49:00 +00006523
6524 v8::Debug::SetMessageHandler2(ScriptCollectedMessageHandler);
6525 {
6526 v8::Script::Compile(v8::String::New("eval('a=1')"))->Run();
6527 v8::Script::Compile(v8::String::New("eval('a=2')"))->Run();
6528 }
6529 }
6530
6531 // Do garbage collection to collect the script above which is no longer
6532 // referenced.
Steve Block44f0eee2011-05-26 01:26:41 +01006533 HEAP->CollectAllGarbage(false);
Steve Blocka7e24c12009-10-30 11:49:00 +00006534
6535 CHECK_EQ(2, script_collected_message_count);
6536
6537 v8::Debug::SetMessageHandler2(NULL);
6538}
6539
6540
6541// Debug event listener which counts the after compile events.
6542int after_compile_message_count = 0;
6543static void AfterCompileMessageHandler(const v8::Debug::Message& message) {
6544 // Count the number of scripts collected.
6545 if (message.IsEvent()) {
6546 if (message.GetEvent() == v8::AfterCompile) {
6547 after_compile_message_count++;
6548 } else if (message.GetEvent() == v8::Break) {
6549 SendContinueCommand();
6550 }
6551 }
6552}
6553
6554
6555// Tests that after compile event is sent as many times as there are scripts
6556// compiled.
6557TEST(AfterCompileMessageWhenMessageHandlerIsReset) {
6558 v8::HandleScope scope;
6559 DebugLocalContext env;
6560 after_compile_message_count = 0;
6561 const char* script = "var a=1";
6562
6563 v8::Debug::SetMessageHandler2(AfterCompileMessageHandler);
6564 v8::Script::Compile(v8::String::New(script))->Run();
6565 v8::Debug::SetMessageHandler2(NULL);
6566
6567 v8::Debug::SetMessageHandler2(AfterCompileMessageHandler);
6568 v8::Debug::DebugBreak();
6569 v8::Script::Compile(v8::String::New(script))->Run();
6570
6571 // Setting listener to NULL should cause debugger unload.
6572 v8::Debug::SetMessageHandler2(NULL);
6573 CheckDebuggerUnloaded();
6574
6575 // Compilation cache should be disabled when debugger is active.
6576 CHECK_EQ(2, after_compile_message_count);
6577}
6578
6579
6580// Tests that break event is sent when message handler is reset.
6581TEST(BreakMessageWhenMessageHandlerIsReset) {
6582 v8::HandleScope scope;
6583 DebugLocalContext env;
6584 after_compile_message_count = 0;
6585 const char* script = "function f() {};";
6586
6587 v8::Debug::SetMessageHandler2(AfterCompileMessageHandler);
6588 v8::Script::Compile(v8::String::New(script))->Run();
6589 v8::Debug::SetMessageHandler2(NULL);
6590
6591 v8::Debug::SetMessageHandler2(AfterCompileMessageHandler);
6592 v8::Debug::DebugBreak();
6593 v8::Local<v8::Function> f =
6594 v8::Local<v8::Function>::Cast(env->Global()->Get(v8::String::New("f")));
6595 f->Call(env->Global(), 0, NULL);
6596
6597 // Setting message handler to NULL should cause debugger unload.
6598 v8::Debug::SetMessageHandler2(NULL);
6599 CheckDebuggerUnloaded();
6600
6601 // Compilation cache should be disabled when debugger is active.
6602 CHECK_EQ(1, after_compile_message_count);
6603}
6604
6605
6606static int exception_event_count = 0;
6607static void ExceptionMessageHandler(const v8::Debug::Message& message) {
6608 if (message.IsEvent() && message.GetEvent() == v8::Exception) {
6609 exception_event_count++;
6610 SendContinueCommand();
6611 }
6612}
6613
6614
6615// Tests that exception event is sent when message handler is reset.
6616TEST(ExceptionMessageWhenMessageHandlerIsReset) {
6617 v8::HandleScope scope;
6618 DebugLocalContext env;
Ben Murdoch086aeea2011-05-13 15:57:08 +01006619
6620 // For this test, we want to break on uncaught exceptions:
6621 ChangeBreakOnException(false, true);
6622
Steve Blocka7e24c12009-10-30 11:49:00 +00006623 exception_event_count = 0;
6624 const char* script = "function f() {throw new Error()};";
6625
6626 v8::Debug::SetMessageHandler2(AfterCompileMessageHandler);
6627 v8::Script::Compile(v8::String::New(script))->Run();
6628 v8::Debug::SetMessageHandler2(NULL);
6629
6630 v8::Debug::SetMessageHandler2(ExceptionMessageHandler);
6631 v8::Local<v8::Function> f =
6632 v8::Local<v8::Function>::Cast(env->Global()->Get(v8::String::New("f")));
6633 f->Call(env->Global(), 0, NULL);
6634
6635 // Setting message handler to NULL should cause debugger unload.
6636 v8::Debug::SetMessageHandler2(NULL);
6637 CheckDebuggerUnloaded();
6638
6639 CHECK_EQ(1, exception_event_count);
6640}
6641
6642
6643// Tests after compile event is sent when there are some provisional
6644// breakpoints out of the scripts lines range.
6645TEST(ProvisionalBreakpointOnLineOutOfRange) {
6646 v8::HandleScope scope;
6647 DebugLocalContext env;
6648 env.ExposeDebug();
6649 const char* script = "function f() {};";
6650 const char* resource_name = "test_resource";
6651
6652 // Set a couple of provisional breakpoint on lines out of the script lines
6653 // range.
6654 int sbp1 = SetScriptBreakPointByNameFromJS(resource_name, 3,
6655 -1 /* no column */);
6656 int sbp2 = SetScriptBreakPointByNameFromJS(resource_name, 5, 5);
6657
6658 after_compile_message_count = 0;
6659 v8::Debug::SetMessageHandler2(AfterCompileMessageHandler);
6660
6661 v8::ScriptOrigin origin(
6662 v8::String::New(resource_name),
6663 v8::Integer::New(10),
6664 v8::Integer::New(1));
6665 // Compile a script whose first line number is greater than the breakpoints'
6666 // lines.
6667 v8::Script::Compile(v8::String::New(script), &origin)->Run();
6668
6669 // If the script is compiled successfully there is exactly one after compile
6670 // event. In case of an exception in debugger code after compile event is not
6671 // sent.
6672 CHECK_EQ(1, after_compile_message_count);
6673
6674 ClearBreakPointFromJS(sbp1);
6675 ClearBreakPointFromJS(sbp2);
6676 v8::Debug::SetMessageHandler2(NULL);
6677}
6678
6679
6680static void BreakMessageHandler(const v8::Debug::Message& message) {
Steve Block44f0eee2011-05-26 01:26:41 +01006681 i::Isolate* isolate = i::Isolate::Current();
Steve Blocka7e24c12009-10-30 11:49:00 +00006682 if (message.IsEvent() && message.GetEvent() == v8::Break) {
6683 // Count the number of breaks.
6684 break_point_hit_count++;
6685
6686 v8::HandleScope scope;
6687 v8::Handle<v8::String> json = message.GetJSON();
6688
6689 SendContinueCommand();
6690 } else if (message.IsEvent() && message.GetEvent() == v8::AfterCompile) {
6691 v8::HandleScope scope;
6692
Steve Block44f0eee2011-05-26 01:26:41 +01006693 bool is_debug_break = isolate->stack_guard()->IsDebugBreak();
Steve Blocka7e24c12009-10-30 11:49:00 +00006694 // Force DebugBreak flag while serializer is working.
Steve Block44f0eee2011-05-26 01:26:41 +01006695 isolate->stack_guard()->DebugBreak();
Steve Blocka7e24c12009-10-30 11:49:00 +00006696
6697 // Force serialization to trigger some internal JS execution.
6698 v8::Handle<v8::String> json = message.GetJSON();
6699
6700 // Restore previous state.
6701 if (is_debug_break) {
Steve Block44f0eee2011-05-26 01:26:41 +01006702 isolate->stack_guard()->DebugBreak();
Steve Blocka7e24c12009-10-30 11:49:00 +00006703 } else {
Steve Block44f0eee2011-05-26 01:26:41 +01006704 isolate->stack_guard()->Continue(i::DEBUGBREAK);
Steve Blocka7e24c12009-10-30 11:49:00 +00006705 }
6706 }
6707}
6708
6709
6710// Test that if DebugBreak is forced it is ignored when code from
6711// debug-delay.js is executed.
6712TEST(NoDebugBreakInAfterCompileMessageHandler) {
6713 v8::HandleScope scope;
6714 DebugLocalContext env;
6715
6716 // Register a debug event listener which sets the break flag and counts.
6717 v8::Debug::SetMessageHandler2(BreakMessageHandler);
6718
6719 // Set the debug break flag.
6720 v8::Debug::DebugBreak();
6721
6722 // Create a function for testing stepping.
6723 const char* src = "function f() { eval('var x = 10;'); } ";
6724 v8::Local<v8::Function> f = CompileFunction(&env, src, "f");
6725
6726 // There should be only one break event.
6727 CHECK_EQ(1, break_point_hit_count);
6728
6729 // Set the debug break flag again.
6730 v8::Debug::DebugBreak();
6731 f->Call(env->Global(), 0, NULL);
6732 // There should be one more break event when the script is evaluated in 'f'.
6733 CHECK_EQ(2, break_point_hit_count);
6734
6735 // Get rid of the debug message handler.
6736 v8::Debug::SetMessageHandler2(NULL);
6737 CheckDebuggerUnloaded();
6738}
6739
6740
Leon Clarkee46be812010-01-19 14:06:41 +00006741static int counting_message_handler_counter;
6742
6743static void CountingMessageHandler(const v8::Debug::Message& message) {
6744 counting_message_handler_counter++;
6745}
6746
6747// Test that debug messages get processed when ProcessDebugMessages is called.
6748TEST(ProcessDebugMessages) {
6749 v8::HandleScope scope;
6750 DebugLocalContext env;
6751
6752 counting_message_handler_counter = 0;
6753
6754 v8::Debug::SetMessageHandler2(CountingMessageHandler);
6755
6756 const int kBufferSize = 1000;
6757 uint16_t buffer[kBufferSize];
6758 const char* scripts_command =
6759 "{\"seq\":0,"
6760 "\"type\":\"request\","
6761 "\"command\":\"scripts\"}";
6762
6763 // Send scripts command.
6764 v8::Debug::SendCommand(buffer, AsciiToUtf16(scripts_command, buffer));
6765
6766 CHECK_EQ(0, counting_message_handler_counter);
6767 v8::Debug::ProcessDebugMessages();
6768 // At least one message should come
6769 CHECK_GE(counting_message_handler_counter, 1);
6770
6771 counting_message_handler_counter = 0;
6772
6773 v8::Debug::SendCommand(buffer, AsciiToUtf16(scripts_command, buffer));
6774 v8::Debug::SendCommand(buffer, AsciiToUtf16(scripts_command, buffer));
6775 CHECK_EQ(0, counting_message_handler_counter);
6776 v8::Debug::ProcessDebugMessages();
6777 // At least two messages should come
6778 CHECK_GE(counting_message_handler_counter, 2);
6779
6780 // Get rid of the debug message handler.
6781 v8::Debug::SetMessageHandler2(NULL);
6782 CheckDebuggerUnloaded();
6783}
6784
6785
Steve Block6ded16b2010-05-10 14:33:55 +01006786struct BacktraceData {
Leon Clarked91b9f72010-01-27 17:25:45 +00006787 static int frame_counter;
6788 static void MessageHandler(const v8::Debug::Message& message) {
6789 char print_buffer[1000];
6790 v8::String::Value json(message.GetJSON());
6791 Utf16ToAscii(*json, json.length(), print_buffer, 1000);
6792
6793 if (strstr(print_buffer, "backtrace") == NULL) {
6794 return;
6795 }
6796 frame_counter = GetTotalFramesInt(print_buffer);
6797 }
6798};
6799
Steve Block6ded16b2010-05-10 14:33:55 +01006800int BacktraceData::frame_counter;
Leon Clarked91b9f72010-01-27 17:25:45 +00006801
6802
6803// Test that debug messages get processed when ProcessDebugMessages is called.
6804TEST(Backtrace) {
6805 v8::HandleScope scope;
6806 DebugLocalContext env;
6807
Steve Block6ded16b2010-05-10 14:33:55 +01006808 v8::Debug::SetMessageHandler2(BacktraceData::MessageHandler);
Leon Clarked91b9f72010-01-27 17:25:45 +00006809
6810 const int kBufferSize = 1000;
6811 uint16_t buffer[kBufferSize];
6812 const char* scripts_command =
6813 "{\"seq\":0,"
6814 "\"type\":\"request\","
6815 "\"command\":\"backtrace\"}";
6816
6817 // Check backtrace from ProcessDebugMessages.
Steve Block6ded16b2010-05-10 14:33:55 +01006818 BacktraceData::frame_counter = -10;
Leon Clarked91b9f72010-01-27 17:25:45 +00006819 v8::Debug::SendCommand(buffer, AsciiToUtf16(scripts_command, buffer));
6820 v8::Debug::ProcessDebugMessages();
Steve Block6ded16b2010-05-10 14:33:55 +01006821 CHECK_EQ(BacktraceData::frame_counter, 0);
Leon Clarked91b9f72010-01-27 17:25:45 +00006822
6823 v8::Handle<v8::String> void0 = v8::String::New("void(0)");
6824 v8::Handle<v8::Script> script = v8::Script::Compile(void0, void0);
6825
6826 // Check backtrace from "void(0)" script.
Steve Block6ded16b2010-05-10 14:33:55 +01006827 BacktraceData::frame_counter = -10;
Leon Clarked91b9f72010-01-27 17:25:45 +00006828 v8::Debug::SendCommand(buffer, AsciiToUtf16(scripts_command, buffer));
6829 script->Run();
Steve Block6ded16b2010-05-10 14:33:55 +01006830 CHECK_EQ(BacktraceData::frame_counter, 1);
Leon Clarked91b9f72010-01-27 17:25:45 +00006831
6832 // Get rid of the debug message handler.
6833 v8::Debug::SetMessageHandler2(NULL);
6834 CheckDebuggerUnloaded();
6835}
6836
6837
Steve Blocka7e24c12009-10-30 11:49:00 +00006838TEST(GetMirror) {
6839 v8::HandleScope scope;
6840 DebugLocalContext env;
6841 v8::Handle<v8::Value> obj = v8::Debug::GetMirror(v8::String::New("hodja"));
6842 v8::Handle<v8::Function> run_test = v8::Handle<v8::Function>::Cast(
6843 v8::Script::New(
6844 v8::String::New(
6845 "function runTest(mirror) {"
6846 " return mirror.isString() && (mirror.length() == 5);"
6847 "}"
6848 ""
6849 "runTest;"))->Run());
6850 v8::Handle<v8::Value> result = run_test->Call(env->Global(), 1, &obj);
6851 CHECK(result->IsTrue());
6852}
Steve Blockd0582a62009-12-15 09:54:21 +00006853
6854
6855// Test that the debug break flag works with function.apply.
6856TEST(DebugBreakFunctionApply) {
6857 v8::HandleScope scope;
6858 DebugLocalContext env;
6859
6860 // Create a function for testing breaking in apply.
6861 v8::Local<v8::Function> foo = CompileFunction(
6862 &env,
6863 "function baz(x) { }"
6864 "function bar(x) { baz(); }"
6865 "function foo(){ bar.apply(this, [1]); }",
6866 "foo");
6867
6868 // Register a debug event listener which steps and counts.
6869 v8::Debug::SetDebugEventListener(DebugEventBreakMax);
6870
6871 // Set the debug break flag before calling the code using function.apply.
6872 v8::Debug::DebugBreak();
6873
6874 // Limit the number of debug breaks. This is a regression test for issue 493
6875 // where this test would enter an infinite loop.
6876 break_point_hit_count = 0;
6877 max_break_point_hit_count = 10000; // 10000 => infinite loop.
6878 foo->Call(env->Global(), 0, NULL);
6879
6880 // When keeping the debug break several break will happen.
6881 CHECK_EQ(3, break_point_hit_count);
6882
6883 v8::Debug::SetDebugEventListener(NULL);
6884 CheckDebuggerUnloaded();
6885}
6886
6887
6888v8::Handle<v8::Context> debugee_context;
6889v8::Handle<v8::Context> debugger_context;
6890
6891
6892// Property getter that checks that current and calling contexts
6893// are both the debugee contexts.
6894static v8::Handle<v8::Value> NamedGetterWithCallingContextCheck(
6895 v8::Local<v8::String> name,
6896 const v8::AccessorInfo& info) {
6897 CHECK_EQ(0, strcmp(*v8::String::AsciiValue(name), "a"));
6898 v8::Handle<v8::Context> current = v8::Context::GetCurrent();
6899 CHECK(current == debugee_context);
6900 CHECK(current != debugger_context);
6901 v8::Handle<v8::Context> calling = v8::Context::GetCalling();
6902 CHECK(calling == debugee_context);
6903 CHECK(calling != debugger_context);
6904 return v8::Int32::New(1);
6905}
6906
6907
6908// Debug event listener that checks if the first argument of a function is
6909// an object with property 'a' == 1. If the property has custom accessor
6910// this handler will eventually invoke it.
6911static void DebugEventGetAtgumentPropertyValue(
6912 v8::DebugEvent event,
6913 v8::Handle<v8::Object> exec_state,
6914 v8::Handle<v8::Object> event_data,
6915 v8::Handle<v8::Value> data) {
6916 if (event == v8::Break) {
6917 break_point_hit_count++;
6918 CHECK(debugger_context == v8::Context::GetCurrent());
6919 v8::Handle<v8::Function> func(v8::Function::Cast(*CompileRun(
6920 "(function(exec_state) {\n"
6921 " return (exec_state.frame(0).argumentValue(0).property('a').\n"
6922 " value().value() == 1);\n"
6923 "})")));
6924 const int argc = 1;
6925 v8::Handle<v8::Value> argv[argc] = { exec_state };
6926 v8::Handle<v8::Value> result = func->Call(exec_state, argc, argv);
6927 CHECK(result->IsTrue());
6928 }
6929}
6930
6931
6932TEST(CallingContextIsNotDebugContext) {
Steve Block44f0eee2011-05-26 01:26:41 +01006933 v8::internal::Debug* debug = v8::internal::Isolate::Current()->debug();
Steve Blockd0582a62009-12-15 09:54:21 +00006934 // Create and enter a debugee context.
6935 v8::HandleScope scope;
6936 DebugLocalContext env;
6937 env.ExposeDebug();
6938
6939 // Save handles to the debugger and debugee contexts to be used in
6940 // NamedGetterWithCallingContextCheck.
6941 debugee_context = v8::Local<v8::Context>(*env);
Steve Block44f0eee2011-05-26 01:26:41 +01006942 debugger_context = v8::Utils::ToLocal(debug->debug_context());
Steve Blockd0582a62009-12-15 09:54:21 +00006943
6944 // Create object with 'a' property accessor.
6945 v8::Handle<v8::ObjectTemplate> named = v8::ObjectTemplate::New();
6946 named->SetAccessor(v8::String::New("a"),
6947 NamedGetterWithCallingContextCheck);
6948 env->Global()->Set(v8::String::New("obj"),
6949 named->NewInstance());
6950
6951 // Register the debug event listener
6952 v8::Debug::SetDebugEventListener(DebugEventGetAtgumentPropertyValue);
6953
6954 // Create a function that invokes debugger.
6955 v8::Local<v8::Function> foo = CompileFunction(
6956 &env,
6957 "function bar(x) { debugger; }"
6958 "function foo(){ bar(obj); }",
6959 "foo");
6960
6961 break_point_hit_count = 0;
6962 foo->Call(env->Global(), 0, NULL);
6963 CHECK_EQ(1, break_point_hit_count);
6964
6965 v8::Debug::SetDebugEventListener(NULL);
6966 debugee_context = v8::Handle<v8::Context>();
6967 debugger_context = v8::Handle<v8::Context>();
6968 CheckDebuggerUnloaded();
6969}
Steve Block6ded16b2010-05-10 14:33:55 +01006970
6971
6972TEST(DebugContextIsPreservedBetweenAccesses) {
6973 v8::HandleScope scope;
6974 v8::Local<v8::Context> context1 = v8::Debug::GetDebugContext();
6975 v8::Local<v8::Context> context2 = v8::Debug::GetDebugContext();
6976 CHECK_EQ(*context1, *context2);
Leon Clarkef7060e22010-06-03 12:02:55 +01006977}
6978
6979
6980static v8::Handle<v8::Value> expected_callback_data;
6981static void DebugEventContextChecker(const v8::Debug::EventDetails& details) {
6982 CHECK(details.GetEventContext() == expected_context);
6983 CHECK_EQ(expected_callback_data, details.GetCallbackData());
6984}
6985
6986// Check that event details contain context where debug event occured.
6987TEST(DebugEventContext) {
6988 v8::HandleScope scope;
6989 expected_callback_data = v8::Int32::New(2010);
6990 v8::Debug::SetDebugEventListener2(DebugEventContextChecker,
6991 expected_callback_data);
6992 expected_context = v8::Context::New();
6993 v8::Context::Scope context_scope(expected_context);
6994 v8::Script::Compile(v8::String::New("(function(){debugger;})();"))->Run();
6995 expected_context.Dispose();
6996 expected_context.Clear();
6997 v8::Debug::SetDebugEventListener(NULL);
6998 expected_context_data = v8::Handle<v8::Value>();
Steve Block6ded16b2010-05-10 14:33:55 +01006999 CheckDebuggerUnloaded();
7000}
Leon Clarkef7060e22010-06-03 12:02:55 +01007001
Ben Murdoch3bec4d22010-07-22 14:51:16 +01007002
7003static void* expected_break_data;
7004static bool was_debug_break_called;
7005static bool was_debug_event_called;
7006static void DebugEventBreakDataChecker(const v8::Debug::EventDetails& details) {
7007 if (details.GetEvent() == v8::BreakForCommand) {
7008 CHECK_EQ(expected_break_data, details.GetClientData());
7009 was_debug_event_called = true;
7010 } else if (details.GetEvent() == v8::Break) {
7011 was_debug_break_called = true;
7012 }
7013}
7014
Ben Murdochb0fe1622011-05-05 13:52:32 +01007015
Ben Murdoch3bec4d22010-07-22 14:51:16 +01007016// Check that event details contain context where debug event occured.
7017TEST(DebugEventBreakData) {
7018 v8::HandleScope scope;
7019 DebugLocalContext env;
7020 v8::Debug::SetDebugEventListener2(DebugEventBreakDataChecker);
7021
7022 TestClientData::constructor_call_counter = 0;
7023 TestClientData::destructor_call_counter = 0;
7024
7025 expected_break_data = NULL;
7026 was_debug_event_called = false;
7027 was_debug_break_called = false;
7028 v8::Debug::DebugBreakForCommand();
7029 v8::Script::Compile(v8::String::New("(function(x){return x;})(1);"))->Run();
7030 CHECK(was_debug_event_called);
7031 CHECK(!was_debug_break_called);
7032
7033 TestClientData* data1 = new TestClientData();
7034 expected_break_data = data1;
7035 was_debug_event_called = false;
7036 was_debug_break_called = false;
7037 v8::Debug::DebugBreakForCommand(data1);
7038 v8::Script::Compile(v8::String::New("(function(x){return x+1;})(1);"))->Run();
7039 CHECK(was_debug_event_called);
7040 CHECK(!was_debug_break_called);
7041
7042 expected_break_data = NULL;
7043 was_debug_event_called = false;
7044 was_debug_break_called = false;
7045 v8::Debug::DebugBreak();
7046 v8::Script::Compile(v8::String::New("(function(x){return x+2;})(1);"))->Run();
7047 CHECK(!was_debug_event_called);
7048 CHECK(was_debug_break_called);
7049
7050 TestClientData* data2 = new TestClientData();
7051 expected_break_data = data2;
7052 was_debug_event_called = false;
7053 was_debug_break_called = false;
7054 v8::Debug::DebugBreak();
7055 v8::Debug::DebugBreakForCommand(data2);
7056 v8::Script::Compile(v8::String::New("(function(x){return x+3;})(1);"))->Run();
7057 CHECK(was_debug_event_called);
7058 CHECK(was_debug_break_called);
7059
7060 CHECK_EQ(2, TestClientData::constructor_call_counter);
7061 CHECK_EQ(TestClientData::constructor_call_counter,
7062 TestClientData::destructor_call_counter);
7063
7064 v8::Debug::SetDebugEventListener(NULL);
7065 CheckDebuggerUnloaded();
7066}
7067
Ben Murdochb0fe1622011-05-05 13:52:32 +01007068static bool debug_event_break_deoptimize_done = false;
7069
7070static void DebugEventBreakDeoptimize(v8::DebugEvent event,
7071 v8::Handle<v8::Object> exec_state,
7072 v8::Handle<v8::Object> event_data,
7073 v8::Handle<v8::Value> data) {
7074 if (event == v8::Break) {
7075 if (!frame_function_name.IsEmpty()) {
7076 // Get the name of the function.
7077 const int argc = 2;
7078 v8::Handle<v8::Value> argv[argc] = { exec_state, v8::Integer::New(0) };
7079 v8::Handle<v8::Value> result =
7080 frame_function_name->Call(exec_state, argc, argv);
7081 if (!result->IsUndefined()) {
7082 char fn[80];
7083 CHECK(result->IsString());
7084 v8::Handle<v8::String> function_name(result->ToString());
7085 function_name->WriteAscii(fn);
7086 if (strcmp(fn, "bar") == 0) {
7087 i::Deoptimizer::DeoptimizeAll();
7088 debug_event_break_deoptimize_done = true;
7089 }
7090 }
7091 }
7092
7093 v8::Debug::DebugBreak();
7094 }
7095}
7096
7097
7098// Test deoptimization when execution is broken using the debug break stack
7099// check interrupt.
7100TEST(DeoptimizeDuringDebugBreak) {
7101 v8::HandleScope scope;
7102 DebugLocalContext env;
7103 env.ExposeDebug();
7104
7105 // Create a function for checking the function when hitting a break point.
7106 frame_function_name = CompileFunction(&env,
7107 frame_function_name_source,
7108 "frame_function_name");
7109
7110
7111 // Set a debug event listener which will keep interrupting execution until
7112 // debug break. When inside function bar it will deoptimize all functions.
7113 // This tests lazy deoptimization bailout for the stack check, as the first
7114 // time in function bar when using debug break and no break points will be at
7115 // the initial stack check.
7116 v8::Debug::SetDebugEventListener(DebugEventBreakDeoptimize,
7117 v8::Undefined());
7118
7119 // Compile and run function bar which will optimize it for some flag settings.
7120 v8::Script::Compile(v8::String::New("function bar(){}; bar()"))->Run();
7121
7122 // Set debug break and call bar again.
7123 v8::Debug::DebugBreak();
7124 v8::Script::Compile(v8::String::New("bar()"))->Run();
7125
7126 CHECK(debug_event_break_deoptimize_done);
7127
7128 v8::Debug::SetDebugEventListener(NULL);
7129}
7130
7131
7132static void DebugEventBreakWithOptimizedStack(v8::DebugEvent event,
7133 v8::Handle<v8::Object> exec_state,
7134 v8::Handle<v8::Object> event_data,
7135 v8::Handle<v8::Value> data) {
7136 if (event == v8::Break) {
7137 if (!frame_function_name.IsEmpty()) {
7138 for (int i = 0; i < 2; i++) {
7139 const int argc = 2;
7140 v8::Handle<v8::Value> argv[argc] = { exec_state, v8::Integer::New(i) };
7141 // Get the name of the function in frame i.
7142 v8::Handle<v8::Value> result =
7143 frame_function_name->Call(exec_state, argc, argv);
7144 CHECK(result->IsString());
7145 v8::Handle<v8::String> function_name(result->ToString());
7146 CHECK(function_name->Equals(v8::String::New("loop")));
7147 // Get the name of the first argument in frame i.
7148 result = frame_argument_name->Call(exec_state, argc, argv);
7149 CHECK(result->IsString());
7150 v8::Handle<v8::String> argument_name(result->ToString());
7151 CHECK(argument_name->Equals(v8::String::New("count")));
7152 // Get the value of the first argument in frame i. If the
7153 // funtion is optimized the value will be undefined, otherwise
7154 // the value will be '1 - i'.
7155 //
7156 // TODO(3141533): We should be able to get the real value for
7157 // optimized frames.
7158 result = frame_argument_value->Call(exec_state, argc, argv);
7159 CHECK(result->IsUndefined() || (result->Int32Value() == 1 - i));
7160 // Get the name of the first local variable.
7161 result = frame_local_name->Call(exec_state, argc, argv);
7162 CHECK(result->IsString());
7163 v8::Handle<v8::String> local_name(result->ToString());
7164 CHECK(local_name->Equals(v8::String::New("local")));
7165 // Get the value of the first local variable. If the function
7166 // is optimized the value will be undefined, otherwise it will
7167 // be 42.
7168 //
7169 // TODO(3141533): We should be able to get the real value for
7170 // optimized frames.
7171 result = frame_local_value->Call(exec_state, argc, argv);
7172 CHECK(result->IsUndefined() || (result->Int32Value() == 42));
7173 }
7174 }
7175 }
7176}
7177
7178
7179static v8::Handle<v8::Value> ScheduleBreak(const v8::Arguments& args) {
7180 v8::Debug::SetDebugEventListener(DebugEventBreakWithOptimizedStack,
7181 v8::Undefined());
7182 v8::Debug::DebugBreak();
7183 return v8::Undefined();
7184}
7185
7186
7187TEST(DebugBreakStackInspection) {
7188 v8::HandleScope scope;
7189 DebugLocalContext env;
7190
7191 frame_function_name =
7192 CompileFunction(&env, frame_function_name_source, "frame_function_name");
7193 frame_argument_name =
7194 CompileFunction(&env, frame_argument_name_source, "frame_argument_name");
7195 frame_argument_value = CompileFunction(&env,
7196 frame_argument_value_source,
7197 "frame_argument_value");
7198 frame_local_name =
7199 CompileFunction(&env, frame_local_name_source, "frame_local_name");
7200 frame_local_value =
7201 CompileFunction(&env, frame_local_value_source, "frame_local_value");
7202
7203 v8::Handle<v8::FunctionTemplate> schedule_break_template =
7204 v8::FunctionTemplate::New(ScheduleBreak);
7205 v8::Handle<v8::Function> schedule_break =
7206 schedule_break_template->GetFunction();
7207 env->Global()->Set(v8_str("scheduleBreak"), schedule_break);
7208
7209 const char* src =
7210 "function loop(count) {"
7211 " var local = 42;"
7212 " if (count < 1) { scheduleBreak(); loop(count + 1); }"
7213 "}"
7214 "loop(0);";
7215 v8::Script::Compile(v8::String::New(src))->Run();
7216}
7217
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -08007218
7219// Test that setting the terminate execution flag during debug break processing.
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -08007220static void TestDebugBreakInLoop(const char* loop_head,
7221 const char** loop_bodies,
7222 const char* loop_tail) {
7223 // Receive 100 breaks for each test and then terminate JavaScript execution.
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00007224 static const int kBreaksPerTest = 100;
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -08007225
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00007226 for (int i = 0; i < 1 && loop_bodies[i] != NULL; i++) {
7227 // Perform a lazy deoptimization after various numbers of breaks
7228 // have been hit.
7229 for (int j = 0; j < 10; j++) {
7230 break_point_hit_count_deoptimize = j;
7231 if (j == 10) {
7232 break_point_hit_count_deoptimize = kBreaksPerTest;
7233 }
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -08007234
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00007235 break_point_hit_count = 0;
7236 max_break_point_hit_count = kBreaksPerTest;
7237 terminate_after_max_break_point_hit = true;
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -08007238
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00007239 EmbeddedVector<char, 1024> buffer;
7240 OS::SNPrintF(buffer,
7241 "function f() {%s%s%s}",
7242 loop_head, loop_bodies[i], loop_tail);
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -08007243
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00007244 // Function with infinite loop.
7245 CompileRun(buffer.start());
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -08007246
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00007247 // Set the debug break to enter the debugger as soon as possible.
7248 v8::Debug::DebugBreak();
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -08007249
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00007250 // Call function with infinite loop.
7251 CompileRun("f();");
7252 CHECK_EQ(kBreaksPerTest, break_point_hit_count);
7253
7254 CHECK(!v8::V8::IsExecutionTerminating());
7255 }
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -08007256 }
7257}
7258
7259
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -08007260TEST(DebugBreakLoop) {
7261 v8::HandleScope scope;
7262 DebugLocalContext env;
7263
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -08007264 // Register a debug event listener which sets the break flag and counts.
7265 v8::Debug::SetDebugEventListener(DebugEventBreakMax);
7266
Ben Murdoch3fb3ca82011-12-02 17:19:32 +00007267 // Create a function for getting the frame count when hitting the break.
7268 frame_count = CompileFunction(&env, frame_count_source, "frame_count");
7269
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -08007270 CompileRun("var a = 1;");
7271 CompileRun("function g() { }");
7272 CompileRun("function h() { }");
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -08007273
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -08007274 const char* loop_bodies[] = {
7275 "",
7276 "g()",
7277 "if (a == 0) { g() }",
7278 "if (a == 1) { g() }",
7279 "if (a == 0) { g() } else { h() }",
7280 "if (a == 0) { continue }",
7281 "if (a == 1) { continue }",
7282 "switch (a) { case 1: g(); }",
7283 "switch (a) { case 1: continue; }",
7284 "switch (a) { case 1: g(); break; default: h() }",
7285 "switch (a) { case 1: continue; break; default: h() }",
7286 NULL
7287 };
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -08007288
Shimeng (Simon) Wang8a31eba2010-12-06 19:01:33 -08007289 TestDebugBreakInLoop("while (true) {", loop_bodies, "}");
7290 TestDebugBreakInLoop("while (a == 1) {", loop_bodies, "}");
7291
7292 TestDebugBreakInLoop("do {", loop_bodies, "} while (true)");
7293 TestDebugBreakInLoop("do {", loop_bodies, "} while (a == 1)");
7294
7295 TestDebugBreakInLoop("for (;;) {", loop_bodies, "}");
7296 TestDebugBreakInLoop("for (;a == 1;) {", loop_bodies, "}");
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -08007297
7298 // Get rid of the debug event listener.
7299 v8::Debug::SetDebugEventListener(NULL);
7300 CheckDebuggerUnloaded();
7301}
7302
7303
Kristian Monsen9dcf7e22010-06-28 14:14:28 +01007304#endif // ENABLE_DEBUGGER_SUPPORT