test-debug.cc 254 KB
Newer Older
1
// Copyright 2012 the V8 project authors. All rights reserved.
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
//     * Redistributions of source code must retain the above copyright
//       notice, this list of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above
//       copyright notice, this list of conditions and the following
//       disclaimer in the documentation and/or other materials provided
//       with the distribution.
//     * Neither the name of Google Inc. nor the names of its
//       contributors may be used to endorse or promote products derived
//       from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

#include <stdlib.h>

30
#include "src/v8.h"
31

32
#include "src/api.h"
33 34
#include "src/base/platform/condition-variable.h"
#include "src/base/platform/platform.h"
35
#include "src/compilation-cache.h"
36
#include "src/debug/debug.h"
37 38 39 40
#include "src/deoptimizer.h"
#include "src/frames.h"
#include "src/utils.h"
#include "test/cctest/cctest.h"
41

42

43 44 45 46 47
using ::v8::base::Mutex;
using ::v8::base::LockGuard;
using ::v8::base::ConditionVariable;
using ::v8::base::OS;
using ::v8::base::Semaphore;
48
using ::v8::internal::EmbeddedVector;
49 50 51
using ::v8::internal::Object;
using ::v8::internal::Handle;
using ::v8::internal::Heap;
52
using ::v8::internal::JSGlobalProxy;
53 54
using ::v8::internal::Code;
using ::v8::internal::Debug;
55 56
using ::v8::internal::CommandMessage;
using ::v8::internal::CommandMessageQueue;
57
using ::v8::internal::StackFrame;
58 59 60 61
using ::v8::internal::StepAction;
using ::v8::internal::StepIn;  // From StepAction enum
using ::v8::internal::StepNext;  // From StepAction enum
using ::v8::internal::StepOut;  // From StepAction enum
62
using ::v8::internal::Vector;
63
using ::v8::internal::StrLength;
64 65 66 67 68 69 70 71

// Size of temp buffer for formatting small strings.
#define SMALL_STRING_BUFFER_SIZE 80

// --- H e l p e r   C l a s s e s


// Helper class for creating a V8 enviromnent for running tests
72
class DebugLocalContext {
73
 public:
74 75 76 77 78 79 80 81 82 83
  inline DebugLocalContext(
      v8::Isolate* isolate, v8::ExtensionConfiguration* extensions = 0,
      v8::Handle<v8::ObjectTemplate> global_template =
          v8::Handle<v8::ObjectTemplate>(),
      v8::Handle<v8::Value> global_object = v8::Handle<v8::Value>())
      : scope_(isolate),
        context_(v8::Context::New(isolate, extensions, global_template,
                                  global_object)) {
    context_->Enter();
  }
84
  inline DebugLocalContext(
85 86 87 88
      v8::ExtensionConfiguration* extensions = 0,
      v8::Handle<v8::ObjectTemplate> global_template =
          v8::Handle<v8::ObjectTemplate>(),
      v8::Handle<v8::Value> global_object = v8::Handle<v8::Value>())
89
      : scope_(CcTest::isolate()),
90 91
        context_(v8::Context::New(CcTest::isolate(), extensions,
                                  global_template, global_object)) {
92 93
    context_->Enter();
  }
94
  inline ~DebugLocalContext() {
95 96
    context_->Exit();
  }
97
  inline v8::Local<v8::Context> context() { return context_; }
98 99
  inline v8::Context* operator->() { return *context_; }
  inline v8::Context* operator*() { return *context_; }
100
  inline v8::Isolate* GetIsolate() { return context_->GetIsolate(); }
101 102
  inline bool IsReady() { return !context_.IsEmpty(); }
  void ExposeDebug() {
103 104
    v8::internal::Isolate* isolate =
        reinterpret_cast<v8::internal::Isolate*>(context_->GetIsolate());
105
    v8::internal::Factory* factory = isolate->factory();
106
    // Expose the debug context global object in the global object for testing.
107 108 109 110
    CHECK(isolate->debug()->Load());
    Handle<v8::internal::Context> debug_context =
        isolate->debug()->debug_context();
    debug_context->set_security_token(
111 112 113
        v8::Utils::OpenHandle(*context_)->security_token());

    Handle<JSGlobalProxy> global(Handle<JSGlobalProxy>::cast(
114 115
        v8::Utils::OpenHandle(*context_->Global())));
    Handle<v8::internal::String> debug_string =
116
        factory->InternalizeOneByteString(STATIC_CHAR_VECTOR("debug"));
117 118 119
    v8::internal::JSObject::SetOwnPropertyIgnoreAttributes(
        global, debug_string, handle(debug_context->global_proxy()), DONT_ENUM)
        .Check();
120
  }
121

122
 private:
123 124
  v8::HandleScope scope_;
  v8::Local<v8::Context> context_;
125 126 127 128 129 130 131
};


// --- H e l p e r   F u n c t i o n s


// Compile and run the supplied source and return the fequested function.
132
static v8::Local<v8::Function> CompileFunction(DebugLocalContext* env,
133 134
                                               const char* source,
                                               const char* function_name) {
135 136 137 138
  v8::Script::Compile(v8::String::NewFromUtf8(env->GetIsolate(), source))
      ->Run();
  return v8::Local<v8::Function>::Cast((*env)->Global()->Get(
      v8::String::NewFromUtf8(env->GetIsolate(), function_name)));
139 140
}

141 142

// Compile and run the supplied source and return the requested function.
143 144
static v8::Local<v8::Function> CompileFunction(v8::Isolate* isolate,
                                               const char* source,
145
                                               const char* function_name) {
146
  v8::Script::Compile(v8::String::NewFromUtf8(isolate, source))->Run();
147
  v8::Local<v8::Object> global = isolate->GetCurrentContext()->Global();
148
  return v8::Local<v8::Function>::Cast(
149
      global->Get(v8::String::NewFromUtf8(isolate, function_name)));
150 151 152
}


153 154 155 156
// Is there any debug info for the function?
static bool HasDebugInfo(v8::Handle<v8::Function> fun) {
  Handle<v8::internal::JSFunction> f = v8::Utils::OpenHandle(*fun);
  Handle<v8::internal::SharedFunctionInfo> shared(f->shared());
157
  return shared->HasDebugInfo();
158 159 160 161 162 163 164
}


// Set a break point in a function and return the associated break point
// number.
static int SetBreakPoint(Handle<v8::internal::JSFunction> fun, int position) {
  static int break_point = 0;
165 166
  v8::internal::Isolate* isolate = fun->GetIsolate();
  v8::internal::Debug* debug = isolate->debug();
167
  debug->SetBreakPoint(
168
      fun,
169
      Handle<Object>(v8::internal::Smi::FromInt(++break_point), isolate),
170
      &position);
171 172 173 174 175 176 177 178 179 180 181 182 183
  return break_point;
}


// Set a break point in a function and return the associated break point
// number.
static int SetBreakPoint(v8::Handle<v8::Function> fun, int position) {
  return SetBreakPoint(v8::Utils::OpenHandle(*fun), position);
}


// Set a break point in a function using the Debug object and return the
// associated break point number.
184 185
static int SetBreakPointFromJS(v8::Isolate* isolate,
                               const char* function_name,
186
                               int line, int position) {
187
  EmbeddedVector<char, SMALL_STRING_BUFFER_SIZE> buffer;
188 189 190
  SNPrintF(buffer,
           "debug.Debug.setBreakPoint(%s,%d,%d)",
           function_name, line, position);
191
  buffer[SMALL_STRING_BUFFER_SIZE - 1] = '\0';
192
  v8::Handle<v8::String> str = v8::String::NewFromUtf8(isolate, buffer.start());
193
  return v8::Script::Compile(str)->Run()->Int32Value();
194 195 196
}


197
// Set a break point in a script identified by id using the global Debug object.
198 199
static int SetScriptBreakPointByIdFromJS(v8::Isolate* isolate, int script_id,
                                         int line, int column) {
200
  EmbeddedVector<char, SMALL_STRING_BUFFER_SIZE> buffer;
201 202
  if (column >= 0) {
    // Column specified set script break point on precise location.
203 204 205
    SNPrintF(buffer,
             "debug.Debug.setScriptBreakPointById(%d,%d,%d)",
             script_id, line, column);
206 207
  } else {
    // Column not specified set script break point on line.
208 209 210
    SNPrintF(buffer,
             "debug.Debug.setScriptBreakPointById(%d,%d)",
             script_id, line);
211 212 213
  }
  buffer[SMALL_STRING_BUFFER_SIZE - 1] = '\0';
  {
214
    v8::TryCatch try_catch(isolate);
215 216
    v8::Handle<v8::String> str =
        v8::String::NewFromUtf8(isolate, buffer.start());
217
    v8::Handle<v8::Value> value = v8::Script::Compile(str)->Run();
218
    CHECK(!try_catch.HasCaught());
219 220 221 222 223 224 225
    return value->Int32Value();
  }
}


// Set a break point in a script identified by name using the global Debug
// object.
226 227 228
static int SetScriptBreakPointByNameFromJS(v8::Isolate* isolate,
                                           const char* script_name, int line,
                                           int column) {
229 230 231
  EmbeddedVector<char, SMALL_STRING_BUFFER_SIZE> buffer;
  if (column >= 0) {
    // Column specified set script break point on precise location.
232 233 234
    SNPrintF(buffer,
             "debug.Debug.setScriptBreakPointByName(\"%s\",%d,%d)",
             script_name, line, column);
235 236
  } else {
    // Column not specified set script break point on line.
237 238 239
    SNPrintF(buffer,
             "debug.Debug.setScriptBreakPointByName(\"%s\",%d)",
             script_name, line);
240 241
  }
  buffer[SMALL_STRING_BUFFER_SIZE - 1] = '\0';
242
  {
243
    v8::TryCatch try_catch(isolate);
244 245
    v8::Handle<v8::String> str =
        v8::String::NewFromUtf8(isolate, buffer.start());
246
    v8::Handle<v8::Value> value = v8::Script::Compile(str)->Run();
247
    CHECK(!try_catch.HasCaught());
248 249
    return value->Int32Value();
  }
250 251 252 253 254
}


// Clear a break point.
static void ClearBreakPoint(int break_point) {
255
  v8::internal::Isolate* isolate = CcTest::i_isolate();
256
  v8::internal::Debug* debug = isolate->debug();
257
  debug->ClearBreakPoint(
258
      Handle<Object>(v8::internal::Smi::FromInt(break_point), isolate));
259 260 261 262
}


// Clear a break point using the global Debug object.
263 264
static void ClearBreakPointFromJS(v8::Isolate* isolate,
                                  int break_point_number) {
265
  EmbeddedVector<char, SMALL_STRING_BUFFER_SIZE> buffer;
266 267 268
  SNPrintF(buffer,
           "debug.Debug.clearBreakPoint(%d)",
           break_point_number);
269
  buffer[SMALL_STRING_BUFFER_SIZE - 1] = '\0';
270
  v8::Script::Compile(v8::String::NewFromUtf8(isolate, buffer.start()))->Run();
271 272 273
}


274 275
static void EnableScriptBreakPointFromJS(v8::Isolate* isolate,
                                         int break_point_number) {
276
  EmbeddedVector<char, SMALL_STRING_BUFFER_SIZE> buffer;
277 278 279
  SNPrintF(buffer,
           "debug.Debug.enableScriptBreakPoint(%d)",
           break_point_number);
280
  buffer[SMALL_STRING_BUFFER_SIZE - 1] = '\0';
281
  v8::Script::Compile(v8::String::NewFromUtf8(isolate, buffer.start()))->Run();
282 283 284
}


285 286
static void DisableScriptBreakPointFromJS(v8::Isolate* isolate,
                                          int break_point_number) {
287
  EmbeddedVector<char, SMALL_STRING_BUFFER_SIZE> buffer;
288 289 290
  SNPrintF(buffer,
           "debug.Debug.disableScriptBreakPoint(%d)",
           break_point_number);
291
  buffer[SMALL_STRING_BUFFER_SIZE - 1] = '\0';
292
  v8::Script::Compile(v8::String::NewFromUtf8(isolate, buffer.start()))->Run();
293 294 295
}


296 297
static void ChangeScriptBreakPointConditionFromJS(v8::Isolate* isolate,
                                                  int break_point_number,
298
                                                  const char* condition) {
299
  EmbeddedVector<char, SMALL_STRING_BUFFER_SIZE> buffer;
300 301 302
  SNPrintF(buffer,
           "debug.Debug.changeScriptBreakPointCondition(%d, \"%s\")",
           break_point_number, condition);
303
  buffer[SMALL_STRING_BUFFER_SIZE - 1] = '\0';
304
  v8::Script::Compile(v8::String::NewFromUtf8(isolate, buffer.start()))->Run();
305 306 307
}


308 309
static void ChangeScriptBreakPointIgnoreCountFromJS(v8::Isolate* isolate,
                                                    int break_point_number,
310
                                                    int ignoreCount) {
311
  EmbeddedVector<char, SMALL_STRING_BUFFER_SIZE> buffer;
312 313 314
  SNPrintF(buffer,
           "debug.Debug.changeScriptBreakPointIgnoreCount(%d, %d)",
           break_point_number, ignoreCount);
315
  buffer[SMALL_STRING_BUFFER_SIZE - 1] = '\0';
316
  v8::Script::Compile(v8::String::NewFromUtf8(isolate, buffer.start()))->Run();
317 318 319 320 321
}


// Change break on exception.
static void ChangeBreakOnException(bool caught, bool uncaught) {
322
  v8::internal::Debug* debug = CcTest::i_isolate()->debug();
323 324
  debug->ChangeBreakOnException(v8::internal::BreakException, caught);
  debug->ChangeBreakOnException(v8::internal::BreakUncaughtException, uncaught);
325 326 327 328
}


// Change break on exception using the global Debug object.
329 330
static void ChangeBreakOnExceptionFromJS(v8::Isolate* isolate, bool caught,
                                         bool uncaught) {
331 332
  if (caught) {
    v8::Script::Compile(
333 334
        v8::String::NewFromUtf8(isolate, "debug.Debug.setBreakOnException()"))
        ->Run();
335 336
  } else {
    v8::Script::Compile(
337 338
        v8::String::NewFromUtf8(isolate, "debug.Debug.clearBreakOnException()"))
        ->Run();
339 340 341
  }
  if (uncaught) {
    v8::Script::Compile(
342 343
        v8::String::NewFromUtf8(
            isolate, "debug.Debug.setBreakOnUncaughtException()"))->Run();
344 345
  } else {
    v8::Script::Compile(
346 347
        v8::String::NewFromUtf8(
            isolate, "debug.Debug.clearBreakOnUncaughtException()"))->Run();
348 349 350 351 352 353
  }
}


// Prepare to step to next break location.
static void PrepareStep(StepAction step_action) {
354
  v8::internal::Debug* debug = CcTest::i_isolate()->debug();
355
  debug->PrepareStep(step_action, 1, StackFrame::NO_ID);
356 357 358 359 360
}


// This function is in namespace v8::internal to be friend with class
// v8::internal::Debug.
361 362
namespace v8 {
namespace internal {
363 364 365

// Collect the currently debugged functions.
Handle<FixedArray> GetDebuggedFunctions() {
366
  Debug* debug = CcTest::i_isolate()->debug();
367 368

  v8::internal::DebugInfoListNode* node = debug->debug_info_list_;
369 370 371 372 373 374 375 376 377 378

  // Find the number of debugged functions.
  int count = 0;
  while (node) {
    count++;
    node = node->next();
  }

  // Allocate array for the debugged functions
  Handle<FixedArray> debugged_functions =
379
      CcTest::i_isolate()->factory()->NewFixedArray(count);
380 381 382 383 384 385 386 387 388 389 390 391

  // Run through the debug info objects and collect all functions.
  count = 0;
  while (node) {
    debugged_functions->set(count++, *node->debug_info());
    node = node->next();
  }

  return debugged_functions;
}


392 393
// Check that the debugger has been fully unloaded.
void CheckDebuggerUnloaded(bool check_functions) {
394 395
  // Check that the debugger context is cleared and that there is no debug
  // information stored for the debugger.
396
  CHECK(CcTest::i_isolate()->debug()->debug_context().is_null());
397
  CHECK(!CcTest::i_isolate()->debug()->debug_info_list_);
398 399

  // Collect garbage to ensure weak handles are cleared.
400
  CcTest::heap()->CollectAllGarbage();
401
  CcTest::heap()->CollectAllGarbage(Heap::kMakeHeapIterableMask);
402 403

  // Iterate the head and check that there are no debugger related objects left.
404
  HeapIterator iterator(CcTest::heap());
405
  for (HeapObject* obj = iterator.next(); obj != NULL; obj = iterator.next()) {
406 407 408 409 410 411 412 413
    CHECK(!obj->IsDebugInfo());
    CHECK(!obj->IsBreakPointInfo());

    // If deep check of functions is requested check that no debug break code
    // is left in all functions.
    if (check_functions) {
      if (obj->IsJSFunction()) {
        JSFunction* fun = JSFunction::cast(obj);
414 415 416 417
        for (RelocIterator it(fun->shared()->code(),
                              RelocInfo::kDebugBreakSlotMask);
             !it.done(); it.next()) {
          CHECK(!it.rinfo()->IsPatchedDebugBreakSlotSequence());
418 419 420 421 422 423 424
        }
      }
    }
  }
}


425 426
}  // namespace internal
}  // namespace v8
427

428 429 430

// Check that the debugger has been fully unloaded.
static void CheckDebuggerUnloaded(bool check_functions = false) {
431 432 433
  // Let debugger to unload itself synchronously
  v8::Debug::ProcessDebugMessages();

434 435 436 437
  v8::internal::CheckDebuggerUnloaded(check_functions);
}


438 439 440 441 442 443
// --- D e b u g   E v e n t   H a n d l e r s
// ---
// --- The different tests uses a number of debug event handlers.
// ---


444 445
// Source for the JavaScript function which picks out the function
// name of a frame.
446
const char* frame_function_name_source =
447 448
    "function frame_function_name(exec_state, frame_number) {"
    "  return exec_state.frame(frame_number).func().name();"
449 450 451
    "}";
v8::Local<v8::Function> frame_function_name;

452

453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489
// Source for the JavaScript function which pick out the name of the
// first argument of a frame.
const char* frame_argument_name_source =
    "function frame_argument_name(exec_state, frame_number) {"
    "  return exec_state.frame(frame_number).argumentName(0);"
    "}";
v8::Local<v8::Function> frame_argument_name;


// Source for the JavaScript function which pick out the value of the
// first argument of a frame.
const char* frame_argument_value_source =
    "function frame_argument_value(exec_state, frame_number) {"
    "  return exec_state.frame(frame_number).argumentValue(0).value_;"
    "}";
v8::Local<v8::Function> frame_argument_value;


// Source for the JavaScript function which pick out the name of the
// first argument of a frame.
const char* frame_local_name_source =
    "function frame_local_name(exec_state, frame_number) {"
    "  return exec_state.frame(frame_number).localName(0);"
    "}";
v8::Local<v8::Function> frame_local_name;


// Source for the JavaScript function which pick out the value of the
// first argument of a frame.
const char* frame_local_value_source =
    "function frame_local_value(exec_state, frame_number) {"
    "  return exec_state.frame(frame_number).localValue(0).value_;"
    "}";
v8::Local<v8::Function> frame_local_value;


// Source for the JavaScript function which picks out the source line for the
490 491 492 493 494 495 496 497
// top frame.
const char* frame_source_line_source =
    "function frame_source_line(exec_state) {"
    "  return exec_state.frame(0).sourceLine();"
    "}";
v8::Local<v8::Function> frame_source_line;


498
// Source for the JavaScript function which picks out the source column for the
499 500 501 502 503 504 505 506
// top frame.
const char* frame_source_column_source =
    "function frame_source_column(exec_state) {"
    "  return exec_state.frame(0).sourceColumn();"
    "}";
v8::Local<v8::Function> frame_source_column;


507
// Source for the JavaScript function which picks out the script name for the
508 509 510 511 512 513 514 515
// top frame.
const char* frame_script_name_source =
    "function frame_script_name(exec_state) {"
    "  return exec_state.frame(0).func().script().name();"
    "}";
v8::Local<v8::Function> frame_script_name;


516
// Source for the JavaScript function which returns the number of frames.
517 518 519 520 521 522 523
static const char* frame_count_source =
    "function frame_count(exec_state) {"
    "  return exec_state.frameCount();"
    "}";
v8::Handle<v8::Function> frame_count;


524 525 526
// Global variable to store the last function hit - used by some tests.
char last_function_hit[80];

527
// Global variable to store the name for last script hit - used by some tests.
528 529
char last_script_name_hit[80];

530 531 532 533
// Global variables to store the last source position - used by some tests.
int last_source_line = -1;
int last_source_column = -1;

534 535
// Debug event handler which counts the break points which have been hit.
int break_point_hit_count = 0;
536
int break_point_hit_count_deoptimize = 0;
537 538 539 540
static void DebugEventBreakPointHitCount(
    const v8::Debug::EventDetails& event_details) {
  v8::DebugEvent event = event_details.GetEvent();
  v8::Handle<v8::Object> exec_state = event_details.GetExecutionState();
541
  v8::internal::Isolate* isolate = CcTest::i_isolate();
542
  Debug* debug = isolate->debug();
543
  // When hitting a debug event listener there must be a break set.
544
  CHECK_NE(debug->break_id(), 0);
545

546 547 548 549 550
  // Count the number of breaks.
  if (event == v8::Break) {
    break_point_hit_count++;
    if (!frame_function_name.IsEmpty()) {
      // Get the name of the function.
551
      const int argc = 2;
552 553 554
      v8::Handle<v8::Value> argv[argc] = {
        exec_state, v8::Integer::New(CcTest::isolate(), 0)
      };
555 556 557 558 559 560
      v8::Handle<v8::Value> result = frame_function_name->Call(exec_state,
                                                               argc, argv);
      if (result->IsUndefined()) {
        last_function_hit[0] = '\0';
      } else {
        CHECK(result->IsString());
561
        v8::Handle<v8::String> function_name(result.As<v8::String>());
562
        function_name->WriteUtf8(last_function_hit);
563 564
      }
    }
565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584

    if (!frame_source_line.IsEmpty()) {
      // Get the source line.
      const int argc = 1;
      v8::Handle<v8::Value> argv[argc] = { exec_state };
      v8::Handle<v8::Value> result = frame_source_line->Call(exec_state,
                                                             argc, argv);
      CHECK(result->IsNumber());
      last_source_line = result->Int32Value();
    }

    if (!frame_source_column.IsEmpty()) {
      // Get the source column.
      const int argc = 1;
      v8::Handle<v8::Value> argv[argc] = { exec_state };
      v8::Handle<v8::Value> result = frame_source_column->Call(exec_state,
                                                               argc, argv);
      CHECK(result->IsNumber());
      last_source_column = result->Int32Value();
    }
585 586 587 588 589 590 591 592 593 594 595

    if (!frame_script_name.IsEmpty()) {
      // Get the script name of the function script.
      const int argc = 1;
      v8::Handle<v8::Value> argv[argc] = { exec_state };
      v8::Handle<v8::Value> result = frame_script_name->Call(exec_state,
                                                             argc, argv);
      if (result->IsUndefined()) {
        last_script_name_hit[0] = '\0';
      } else {
        CHECK(result->IsString());
596
        v8::Handle<v8::String> script_name(result.As<v8::String>());
597
        script_name->WriteUtf8(last_script_name_hit);
598 599 600
      }
    }

601 602 603
    // Perform a full deoptimization when the specified number of
    // breaks have been hit.
    if (break_point_hit_count == break_point_hit_count_deoptimize) {
604
      i::Deoptimizer::DeoptimizeAll(isolate);
605
    }
606 607 608 609
  }
}


610 611
// Debug event handler which counts a number of events and collects the stack
// height if there is a function compiled for that.
612 613
int exception_hit_count = 0;
int uncaught_exception_hit_count = 0;
614
int last_js_stack_height = -1;
615 616
v8::Handle<v8::Function> debug_event_listener_callback;
int debug_event_listener_callback_result;
617 618 619 620 621 622 623

static void DebugEventCounterClear() {
  break_point_hit_count = 0;
  exception_hit_count = 0;
  uncaught_exception_hit_count = 0;
}

624 625 626 627 628
static void DebugEventCounter(
    const v8::Debug::EventDetails& event_details) {
  v8::DebugEvent event = event_details.GetEvent();
  v8::Handle<v8::Object> exec_state = event_details.GetExecutionState();
  v8::Handle<v8::Object> event_data = event_details.GetEventData();
629
  v8::internal::Debug* debug = CcTest::i_isolate()->debug();
630

631
  // When hitting a debug event listener there must be a break set.
632
  CHECK_NE(debug->break_id(), 0);
633

634 635 636 637 638 639 640
  // Count the number of breaks.
  if (event == v8::Break) {
    break_point_hit_count++;
  } else if (event == v8::Exception) {
    exception_hit_count++;

    // Check whether the exception was uncaught.
641 642
    v8::Local<v8::String> fun_name =
        v8::String::NewFromUtf8(CcTest::isolate(), "uncaught");
643
    v8::Local<v8::Function> fun =
644 645
        v8::Local<v8::Function>::Cast(event_data->Get(fun_name));
    v8::Local<v8::Value> result = fun->Call(event_data, 0, NULL);
646 647 648 649
    if (result->IsTrue()) {
      uncaught_exception_hit_count++;
    }
  }
650 651 652 653 654 655 656

  // Collect the JavsScript stack height if the function frame_count is
  // compiled.
  if (!frame_count.IsEmpty()) {
    static const int kArgc = 1;
    v8::Handle<v8::Value> argv[kArgc] = { exec_state };
    // Using exec_state as receiver is just to have a receiver.
657
    v8::Handle<v8::Value> result = frame_count->Call(exec_state, kArgc, argv);
658 659
    last_js_stack_height = result->Int32Value();
  }
660 661 662 663 664 665 666 667

  // Run callback from DebugEventListener and check the result.
  if (!debug_event_listener_callback.IsEmpty()) {
    v8::Handle<v8::Value> result =
        debug_event_listener_callback->Call(event_data, 0, NULL);
    CHECK(!result.IsEmpty());
    CHECK_EQ(debug_event_listener_callback_result, result->Int32Value());
  }
668 669 670 671 672 673 674 675 676 677 678 679 680 681 682
}


// Debug event handler which evaluates a number of expressions when a break
// point is hit. Each evaluated expression is compared with an expected value.
// For this debug event handler to work the following two global varaibles
// must be initialized.
//   checks: An array of expressions and expected results
//   evaluate_check_function: A JavaScript function (see below)

// Structure for holding checks to do.
struct EvaluateCheck {
  const char* expr;  // An expression to evaluate when a break point is hit.
  v8::Handle<v8::Value> expected;  // The expected result.
};
683 684


685 686 687 688 689 690 691 692 693 694 695
// Array of checks to do.
struct EvaluateCheck* checks = NULL;
// Source for The JavaScript function which can do the evaluation when a break
// point is hit.
const char* evaluate_check_source =
    "function evaluate_check(exec_state, expr, expected) {"
    "  return exec_state.frame(0).evaluate(expr).value() === expected;"
    "}";
v8::Local<v8::Function> evaluate_check_function;

// The actual debug event described by the longer comment above.
696 697 698 699
static void DebugEventEvaluate(
    const v8::Debug::EventDetails& event_details) {
  v8::DebugEvent event = event_details.GetEvent();
  v8::Handle<v8::Object> exec_state = event_details.GetExecutionState();
700
  v8::internal::Debug* debug = CcTest::i_isolate()->debug();
701
  // When hitting a debug event listener there must be a break set.
702
  CHECK_NE(debug->break_id(), 0);
703

704
  if (event == v8::Break) {
705
    break_point_hit_count++;
706 707
    for (int i = 0; checks[i].expr != NULL; i++) {
      const int argc = 3;
708 709 710 711
      v8::Handle<v8::Value> argv[argc] = {
          exec_state,
          v8::String::NewFromUtf8(CcTest::isolate(), checks[i].expr),
          checks[i].expected};
712 713 714
      v8::Handle<v8::Value> result =
          evaluate_check_function->Call(exec_state, argc, argv);
      if (!result->IsTrue()) {
715
        v8::String::Utf8Value utf8(checks[i].expected);
716
        V8_Fatal(__FILE__, __LINE__, "%s != %s", checks[i].expr, *utf8);
717 718 719 720 721 722 723 724
      }
    }
  }
}


// This debug event listener removes a breakpoint in a function
int debug_event_remove_break_point = 0;
725 726 727 728
static void DebugEventRemoveBreakPoint(
    const v8::Debug::EventDetails& event_details) {
  v8::DebugEvent event = event_details.GetEvent();
  v8::Handle<v8::Value> data = event_details.GetCallbackData();
729
  v8::internal::Debug* debug = CcTest::i_isolate()->debug();
730
  // When hitting a debug event listener there must be a break set.
731
  CHECK_NE(debug->break_id(), 0);
732

733 734
  if (event == v8::Break) {
    break_point_hit_count++;
735
    CHECK(data->IsFunction());
736 737 738 739 740 741 742 743
    ClearBreakPoint(debug_event_remove_break_point);
  }
}


// Debug event handler which counts break points hit and performs a step
// afterwards.
StepAction step_action = StepIn;  // Step action to perform when stepping.
744 745 746
static void DebugEventStep(
    const v8::Debug::EventDetails& event_details) {
  v8::DebugEvent event = event_details.GetEvent();
747
  v8::internal::Debug* debug = CcTest::i_isolate()->debug();
748
  // When hitting a debug event listener there must be a break set.
749
  CHECK_NE(debug->break_id(), 0);
750

751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769
  if (event == v8::Break) {
    break_point_hit_count++;
    PrepareStep(step_action);
  }
}


// Debug event handler which counts break points hit and performs a step
// afterwards. For each call the expected function is checked.
// For this debug event handler to work the following two global varaibles
// must be initialized.
//   expected_step_sequence: An array of the expected function call sequence.
//   frame_function_name: A JavaScript function (see below).

// String containing the expected function call sequence. Note: this only works
// if functions have name length of one.
const char* expected_step_sequence = NULL;

// The actual debug event described by the longer comment above.
770 771 772 773
static void DebugEventStepSequence(
    const v8::Debug::EventDetails& event_details) {
  v8::DebugEvent event = event_details.GetEvent();
  v8::Handle<v8::Object> exec_state = event_details.GetExecutionState();
774
  v8::internal::Debug* debug = CcTest::i_isolate()->debug();
775
  // When hitting a debug event listener there must be a break set.
776
  CHECK_NE(debug->break_id(), 0);
777

778 779 780
  if (event == v8::Break || event == v8::Exception) {
    // Check that the current function is the expected.
    CHECK(break_point_hit_count <
781
          StrLength(expected_step_sequence));
782
    const int argc = 2;
783 784 785
    v8::Handle<v8::Value> argv[argc] = {
      exec_state, v8::Integer::New(CcTest::isolate(), 0)
    };
786 787 788
    v8::Handle<v8::Value> result = frame_function_name->Call(exec_state,
                                                             argc, argv);
    CHECK(result->IsString());
789
    v8::String::Utf8Value function_name(result->ToString(CcTest::isolate()));
790
    CHECK_EQ(1, StrLength(*function_name));
791 792 793 794 795 796 797 798 799 800 801 802
    CHECK_EQ((*function_name)[0],
              expected_step_sequence[break_point_hit_count]);

    // Perform step.
    break_point_hit_count++;
    PrepareStep(step_action);
  }
}


// Debug event handler which performs a garbage collection.
static void DebugEventBreakPointCollectGarbage(
803 804
    const v8::Debug::EventDetails& event_details) {
  v8::DebugEvent event = event_details.GetEvent();
805
  v8::internal::Debug* debug = CcTest::i_isolate()->debug();
806
  // When hitting a debug event listener there must be a break set.
807
  CHECK_NE(debug->break_id(), 0);
808

809 810 811 812 813 814 815
  // Perform a garbage collection when break point is hit and continue. Based
  // on the number of break points hit either scavenge or mark compact
  // collector is used.
  if (event == v8::Break) {
    break_point_hit_count++;
    if (break_point_hit_count % 2 == 0) {
      // Scavenge.
816
      CcTest::heap()->CollectGarbage(v8::internal::NEW_SPACE);
817
    } else {
818
      // Mark sweep compact.
819
      CcTest::heap()->CollectAllGarbage();
820 821 822 823 824 825 826
    }
  }
}


// Debug event handler which re-issues a debug break and calls the garbage
// collector to have the heap verified.
827 828 829
static void DebugEventBreak(
    const v8::Debug::EventDetails& event_details) {
  v8::DebugEvent event = event_details.GetEvent();
830
  v8::internal::Debug* debug = CcTest::i_isolate()->debug();
831
  // When hitting a debug event listener there must be a break set.
832
  CHECK_NE(debug->break_id(), 0);
833

834 835 836 837 838 839
  if (event == v8::Break) {
    // Count the number of breaks.
    break_point_hit_count++;

    // Run the garbage collector to enforce heap verification if option
    // --verify-heap is set.
840
    CcTest::heap()->CollectGarbage(v8::internal::NEW_SPACE);
841 842

    // Set the break flag again to come back here as soon as possible.
843
    v8::Debug::DebugBreak(CcTest::isolate());
844 845 846 847
  }
}


848 849 850
// Debug event handler which re-issues a debug break until a limit has been
// reached.
int max_break_point_hit_count = 0;
851
bool terminate_after_max_break_point_hit = false;
852 853 854
static void DebugEventBreakMax(
    const v8::Debug::EventDetails& event_details) {
  v8::DebugEvent event = event_details.GetEvent();
855 856
  v8::Isolate* v8_isolate = CcTest::isolate();
  v8::internal::Isolate* isolate = CcTest::i_isolate();
857
  v8::internal::Debug* debug = isolate->debug();
858
  // When hitting a debug event listener there must be a break set.
859
  CHECK_NE(debug->break_id(), 0);
860

861 862 863 864
  if (event == v8::Break) {
    if (break_point_hit_count < max_break_point_hit_count) {
      // Count the number of breaks.
      break_point_hit_count++;
865

866
      // Set the break flag again to come back here as soon as possible.
867
      v8::Debug::DebugBreak(v8_isolate);
868

869 870
    } else if (terminate_after_max_break_point_hit) {
      // Terminate execution after the last break if requested.
871
      v8::V8::TerminateExecution(v8_isolate);
872
    }
873 874 875 876

    // Perform a full deoptimization when the specified number of
    // breaks have been hit.
    if (break_point_hit_count == break_point_hit_count_deoptimize) {
877
      i::Deoptimizer::DeoptimizeAll(isolate);
878
    }
879 880 881 882
  }
}


883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903
// --- M e s s a g e   C a l l b a c k


// Message callback which counts the number of messages.
int message_callback_count = 0;

static void MessageCallbackCountClear() {
  message_callback_count = 0;
}

static void MessageCallbackCount(v8::Handle<v8::Message> message,
                                 v8::Handle<v8::Value> data) {
  message_callback_count++;
}


// --- T h e   A c t u a l   T e s t s

// Test that the debug info in the VM is in sync with the functions being
// debugged.
TEST(DebugInfo) {
904
  DebugLocalContext env;
905
  v8::HandleScope scope(env->GetIsolate());
906 907 908 909 910 911 912 913 914
  // Create a couple of functions for the test.
  v8::Local<v8::Function> foo =
      CompileFunction(&env, "function foo(){}", "foo");
  v8::Local<v8::Function> bar =
      CompileFunction(&env, "function bar(){}", "bar");
  // Initially no functions are debugged.
  CHECK_EQ(0, v8::internal::GetDebuggedFunctions()->length());
  CHECK(!HasDebugInfo(foo));
  CHECK(!HasDebugInfo(bar));
915
  EnableDebugger();
916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932
  // One function (foo) is debugged.
  int bp1 = SetBreakPoint(foo, 0);
  CHECK_EQ(1, v8::internal::GetDebuggedFunctions()->length());
  CHECK(HasDebugInfo(foo));
  CHECK(!HasDebugInfo(bar));
  // Two functions are debugged.
  int bp2 = SetBreakPoint(bar, 0);
  CHECK_EQ(2, v8::internal::GetDebuggedFunctions()->length());
  CHECK(HasDebugInfo(foo));
  CHECK(HasDebugInfo(bar));
  // One function (bar) is debugged.
  ClearBreakPoint(bp1);
  CHECK_EQ(1, v8::internal::GetDebuggedFunctions()->length());
  CHECK(!HasDebugInfo(foo));
  CHECK(HasDebugInfo(bar));
  // No functions are debugged.
  ClearBreakPoint(bp2);
933
  DisableDebugger();
934 935 936 937 938 939 940 941 942
  CHECK_EQ(0, v8::internal::GetDebuggedFunctions()->length());
  CHECK(!HasDebugInfo(foo));
  CHECK(!HasDebugInfo(bar));
}


// Test that a break point can be set at an IC store location.
TEST(BreakPointICStore) {
  break_point_hit_count = 0;
943
  DebugLocalContext env;
944
  v8::HandleScope scope(env->GetIsolate());
945

946
  v8::Debug::SetDebugEventListener(DebugEventBreakPointHitCount);
947 948 949 950
  v8::Script::Compile(v8::String::NewFromUtf8(env->GetIsolate(),
                                              "function foo(){bar=0;}"))->Run();
  v8::Local<v8::Function> foo = v8::Local<v8::Function>::Cast(
      env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "foo")));
951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967

  // Run without breakpoints.
  foo->Call(env->Global(), 0, NULL);
  CHECK_EQ(0, break_point_hit_count);

  // Run with breakpoint
  int bp = SetBreakPoint(foo, 0);
  foo->Call(env->Global(), 0, NULL);
  CHECK_EQ(1, break_point_hit_count);
  foo->Call(env->Global(), 0, NULL);
  CHECK_EQ(2, break_point_hit_count);

  // Run without breakpoints.
  ClearBreakPoint(bp);
  foo->Call(env->Global(), 0, NULL);
  CHECK_EQ(2, break_point_hit_count);

968
  v8::Debug::SetDebugEventListener(NULL);
969
  CheckDebuggerUnloaded();
970 971 972 973 974 975
}


// Test that a break point can be set at an IC load location.
TEST(BreakPointICLoad) {
  break_point_hit_count = 0;
976
  DebugLocalContext env;
977
  v8::HandleScope scope(env->GetIsolate());
978
  v8::Debug::SetDebugEventListener(DebugEventBreakPointHitCount);
979 980 981 982 983 984 985
  v8::Script::Compile(v8::String::NewFromUtf8(env->GetIsolate(), "bar=1"))
      ->Run();
  v8::Script::Compile(
      v8::String::NewFromUtf8(env->GetIsolate(), "function foo(){var x=bar;}"))
      ->Run();
  v8::Local<v8::Function> foo = v8::Local<v8::Function>::Cast(
      env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "foo")));
986 987 988 989 990

  // Run without breakpoints.
  foo->Call(env->Global(), 0, NULL);
  CHECK_EQ(0, break_point_hit_count);

991
  // Run with breakpoint.
992 993 994 995 996 997 998 999 1000 1001 1002
  int bp = SetBreakPoint(foo, 0);
  foo->Call(env->Global(), 0, NULL);
  CHECK_EQ(1, break_point_hit_count);
  foo->Call(env->Global(), 0, NULL);
  CHECK_EQ(2, break_point_hit_count);

  // Run without breakpoints.
  ClearBreakPoint(bp);
  foo->Call(env->Global(), 0, NULL);
  CHECK_EQ(2, break_point_hit_count);

1003
  v8::Debug::SetDebugEventListener(NULL);
1004
  CheckDebuggerUnloaded();
1005 1006 1007 1008 1009 1010
}


// Test that a break point can be set at an IC call location.
TEST(BreakPointICCall) {
  break_point_hit_count = 0;
1011
  DebugLocalContext env;
1012
  v8::HandleScope scope(env->GetIsolate());
1013
  v8::Debug::SetDebugEventListener(DebugEventBreakPointHitCount);
1014 1015 1016 1017 1018 1019
  v8::Script::Compile(
      v8::String::NewFromUtf8(env->GetIsolate(), "function bar(){}"))->Run();
  v8::Script::Compile(v8::String::NewFromUtf8(env->GetIsolate(),
                                              "function foo(){bar();}"))->Run();
  v8::Local<v8::Function> foo = v8::Local<v8::Function>::Cast(
      env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "foo")));
1020 1021 1022 1023 1024

  // Run without breakpoints.
  foo->Call(env->Global(), 0, NULL);
  CHECK_EQ(0, break_point_hit_count);

1025
  // Run with breakpoint
1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036
  int bp = SetBreakPoint(foo, 0);
  foo->Call(env->Global(), 0, NULL);
  CHECK_EQ(1, break_point_hit_count);
  foo->Call(env->Global(), 0, NULL);
  CHECK_EQ(2, break_point_hit_count);

  // Run without breakpoints.
  ClearBreakPoint(bp);
  foo->Call(env->Global(), 0, NULL);
  CHECK_EQ(2, break_point_hit_count);

1037
  v8::Debug::SetDebugEventListener(NULL);
1038
  CheckDebuggerUnloaded();
1039 1040 1041
}


1042 1043 1044 1045
// Test that a break point can be set at an IC call location and survive a GC.
TEST(BreakPointICCallWithGC) {
  break_point_hit_count = 0;
  DebugLocalContext env;
1046
  v8::HandleScope scope(env->GetIsolate());
1047
  v8::Debug::SetDebugEventListener(DebugEventBreakPointCollectGarbage);
1048 1049 1050 1051 1052 1053 1054 1055
  v8::Script::Compile(
      v8::String::NewFromUtf8(env->GetIsolate(), "function bar(){return 1;}"))
      ->Run();
  v8::Script::Compile(v8::String::NewFromUtf8(env->GetIsolate(),
                                              "function foo(){return bar();}"))
      ->Run();
  v8::Local<v8::Function> foo = v8::Local<v8::Function>::Cast(
      env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "foo")));
1056 1057 1058

  // Run without breakpoints.
  CHECK_EQ(1, foo->Call(env->Global(), 0, NULL)->Int32Value());
1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072
  CHECK_EQ(0, break_point_hit_count);

  // Run with breakpoint.
  int bp = SetBreakPoint(foo, 0);
  CHECK_EQ(1, foo->Call(env->Global(), 0, NULL)->Int32Value());
  CHECK_EQ(1, break_point_hit_count);
  CHECK_EQ(1, foo->Call(env->Global(), 0, NULL)->Int32Value());
  CHECK_EQ(2, break_point_hit_count);

  // Run without breakpoints.
  ClearBreakPoint(bp);
  foo->Call(env->Global(), 0, NULL);
  CHECK_EQ(2, break_point_hit_count);

1073
  v8::Debug::SetDebugEventListener(NULL);
1074 1075 1076 1077 1078 1079 1080 1081
  CheckDebuggerUnloaded();
}


// Test that a break point can be set at an IC call location and survive a GC.
TEST(BreakPointConstructCallWithGC) {
  break_point_hit_count = 0;
  DebugLocalContext env;
1082
  v8::HandleScope scope(env->GetIsolate());
1083
  v8::Debug::SetDebugEventListener(DebugEventBreakPointCollectGarbage);
1084 1085 1086 1087 1088 1089 1090 1091
  v8::Script::Compile(v8::String::NewFromUtf8(env->GetIsolate(),
                                              "function bar(){ this.x = 1;}"))
      ->Run();
  v8::Script::Compile(
      v8::String::NewFromUtf8(env->GetIsolate(),
                              "function foo(){return new bar(1).x;}"))->Run();
  v8::Local<v8::Function> foo = v8::Local<v8::Function>::Cast(
      env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "foo")));
1092 1093 1094

  // Run without breakpoints.
  CHECK_EQ(1, foo->Call(env->Global(), 0, NULL)->Int32Value());
1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108
  CHECK_EQ(0, break_point_hit_count);

  // Run with breakpoint.
  int bp = SetBreakPoint(foo, 0);
  CHECK_EQ(1, foo->Call(env->Global(), 0, NULL)->Int32Value());
  CHECK_EQ(1, break_point_hit_count);
  CHECK_EQ(1, foo->Call(env->Global(), 0, NULL)->Int32Value());
  CHECK_EQ(2, break_point_hit_count);

  // Run without breakpoints.
  ClearBreakPoint(bp);
  foo->Call(env->Global(), 0, NULL);
  CHECK_EQ(2, break_point_hit_count);

1109
  v8::Debug::SetDebugEventListener(NULL);
1110 1111 1112 1113
  CheckDebuggerUnloaded();
}


1114 1115 1116
// Test that a break point can be set at a return store location.
TEST(BreakPointReturn) {
  break_point_hit_count = 0;
1117
  DebugLocalContext env;
1118
  v8::HandleScope scope(env->GetIsolate());
1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129

  // Create a functions for checking the source line and column when hitting
  // a break point.
  frame_source_line = CompileFunction(&env,
                                      frame_source_line_source,
                                      "frame_source_line");
  frame_source_column = CompileFunction(&env,
                                        frame_source_column_source,
                                        "frame_source_column");


1130
  v8::Debug::SetDebugEventListener(DebugEventBreakPointHitCount);
1131 1132 1133 1134
  v8::Script::Compile(
      v8::String::NewFromUtf8(env->GetIsolate(), "function foo(){}"))->Run();
  v8::Local<v8::Function> foo = v8::Local<v8::Function>::Cast(
      env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "foo")));
1135 1136 1137 1138 1139 1140 1141 1142 1143

  // Run without breakpoints.
  foo->Call(env->Global(), 0, NULL);
  CHECK_EQ(0, break_point_hit_count);

  // Run with breakpoint
  int bp = SetBreakPoint(foo, 0);
  foo->Call(env->Global(), 0, NULL);
  CHECK_EQ(1, break_point_hit_count);
1144
  CHECK_EQ(0, last_source_line);
1145
  CHECK_EQ(15, last_source_column);
1146 1147
  foo->Call(env->Global(), 0, NULL);
  CHECK_EQ(2, break_point_hit_count);
1148
  CHECK_EQ(0, last_source_line);
1149
  CHECK_EQ(15, last_source_column);
1150 1151 1152 1153 1154 1155

  // Run without breakpoints.
  ClearBreakPoint(bp);
  foo->Call(env->Global(), 0, NULL);
  CHECK_EQ(2, break_point_hit_count);

1156
  v8::Debug::SetDebugEventListener(NULL);
1157
  CheckDebuggerUnloaded();
1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171
}


static void CallWithBreakPoints(v8::Local<v8::Object> recv,
                                v8::Local<v8::Function> f,
                                int break_point_count,
                                int call_count) {
  break_point_hit_count = 0;
  for (int i = 0; i < call_count; i++) {
    f->Call(recv, 0, NULL);
    CHECK_EQ((i + 1) * break_point_count, break_point_hit_count);
  }
}

1172

1173 1174 1175
// Test GC during break point processing.
TEST(GCDuringBreakPointProcessing) {
  break_point_hit_count = 0;
1176
  DebugLocalContext env;
1177
  v8::HandleScope scope(env->GetIsolate());
1178

1179
  v8::Debug::SetDebugEventListener(DebugEventBreakPointCollectGarbage);
1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201
  v8::Local<v8::Function> foo;

  // Test IC store break point with garbage collection.
  foo = CompileFunction(&env, "function foo(){bar=0;}", "foo");
  SetBreakPoint(foo, 0);
  CallWithBreakPoints(env->Global(), foo, 1, 10);

  // Test IC load break point with garbage collection.
  foo = CompileFunction(&env, "bar=1;function foo(){var x=bar;}", "foo");
  SetBreakPoint(foo, 0);
  CallWithBreakPoints(env->Global(), foo, 1, 10);

  // Test IC call break point with garbage collection.
  foo = CompileFunction(&env, "function bar(){};function foo(){bar();}", "foo");
  SetBreakPoint(foo, 0);
  CallWithBreakPoints(env->Global(), foo, 1, 10);

  // Test return break point with garbage collection.
  foo = CompileFunction(&env, "function foo(){}", "foo");
  SetBreakPoint(foo, 0);
  CallWithBreakPoints(env->Global(), foo, 1, 25);

1202 1203 1204 1205 1206
  // Test debug break slot break point with garbage collection.
  foo = CompileFunction(&env, "function foo(){var a;}", "foo");
  SetBreakPoint(foo, 0);
  CallWithBreakPoints(env->Global(), foo, 1, 25);

1207
  v8::Debug::SetDebugEventListener(NULL);
1208
  CheckDebuggerUnloaded();
1209 1210 1211 1212 1213
}


// Call the function three times with different garbage collections in between
// and make sure that the break point survives.
1214
static void CallAndGC(v8::Local<v8::Object> recv,
1215
                      v8::Local<v8::Function> f) {
1216 1217 1218 1219 1220 1221 1222 1223
  break_point_hit_count = 0;

  for (int i = 0; i < 3; i++) {
    // Call function.
    f->Call(recv, 0, NULL);
    CHECK_EQ(1 + i * 3, break_point_hit_count);

    // Scavenge and call function.
1224
    CcTest::heap()->CollectGarbage(v8::internal::NEW_SPACE);
1225 1226 1227 1228
    f->Call(recv, 0, NULL);
    CHECK_EQ(2 + i * 3, break_point_hit_count);

    // Mark sweep (and perhaps compact) and call function.
1229
    CcTest::heap()->CollectAllGarbage();
1230 1231 1232 1233 1234 1235
    f->Call(recv, 0, NULL);
    CHECK_EQ(3 + i * 3, break_point_hit_count);
  }
}


1236 1237
// Test that a break point can be set at a return store location.
TEST(BreakPointSurviveGC) {
1238
  break_point_hit_count = 0;
1239
  DebugLocalContext env;
1240
  v8::HandleScope scope(env->GetIsolate());
1241

1242
  v8::Debug::SetDebugEventListener(DebugEventBreakPointHitCount);
1243 1244 1245
  v8::Local<v8::Function> foo;

  // Test IC store break point with garbage collection.
1246
  {
1247
    CompileFunction(&env, "function foo(){}", "foo");
1248 1249 1250
    foo = CompileFunction(&env, "function foo(){bar=0;}", "foo");
    SetBreakPoint(foo, 0);
  }
1251
  CallAndGC(env->Global(), foo);
1252 1253

  // Test IC load break point with garbage collection.
1254
  {
1255
    CompileFunction(&env, "function foo(){}", "foo");
1256 1257 1258
    foo = CompileFunction(&env, "bar=1;function foo(){var x=bar;}", "foo");
    SetBreakPoint(foo, 0);
  }
1259
  CallAndGC(env->Global(), foo);
1260 1261

  // Test IC call break point with garbage collection.
1262
  {
1263
    CompileFunction(&env, "function foo(){}", "foo");
1264 1265 1266 1267 1268
    foo = CompileFunction(&env,
                          "function bar(){};function foo(){bar();}",
                          "foo");
    SetBreakPoint(foo, 0);
  }
1269
  CallAndGC(env->Global(), foo);
1270 1271

  // Test return break point with garbage collection.
1272
  {
1273
    CompileFunction(&env, "function foo(){}", "foo");
1274 1275 1276
    foo = CompileFunction(&env, "function foo(){}", "foo");
    SetBreakPoint(foo, 0);
  }
1277
  CallAndGC(env->Global(), foo);
1278

1279 1280
  // Test non IC break point with garbage collection.
  {
1281
    CompileFunction(&env, "function foo(){}", "foo");
1282 1283 1284
    foo = CompileFunction(&env, "function foo(){var bar=0;}", "foo");
    SetBreakPoint(foo, 0);
  }
1285
  CallAndGC(env->Global(), foo);
1286 1287


1288
  v8::Debug::SetDebugEventListener(NULL);
1289
  CheckDebuggerUnloaded();
1290 1291 1292 1293 1294 1295
}


// Test that break points can be set using the global Debug object.
TEST(BreakPointThroughJavaScript) {
  break_point_hit_count = 0;
1296
  DebugLocalContext env;
1297
  v8::HandleScope scope(env->GetIsolate());
1298 1299
  env.ExposeDebug();

1300
  v8::Debug::SetDebugEventListener(DebugEventBreakPointHitCount);
1301 1302 1303 1304 1305
  v8::Script::Compile(
      v8::String::NewFromUtf8(env->GetIsolate(), "function bar(){}"))->Run();
  v8::Script::Compile(v8::String::NewFromUtf8(env->GetIsolate(),
                                              "function foo(){bar();bar();}"))
      ->Run();
1306 1307 1308
  //                                               012345678901234567890
  //                                                         1         2
  // Break points are set at position 3 and 9
1309 1310
  v8::Local<v8::Script> foo =
      v8::Script::Compile(v8::String::NewFromUtf8(env->GetIsolate(), "foo()"));
1311 1312 1313 1314 1315 1316

  // Run without breakpoints.
  foo->Run();
  CHECK_EQ(0, break_point_hit_count);

  // Run with one breakpoint
1317
  int bp1 = SetBreakPointFromJS(env->GetIsolate(), "foo", 0, 3);
1318 1319 1320 1321 1322 1323
  foo->Run();
  CHECK_EQ(1, break_point_hit_count);
  foo->Run();
  CHECK_EQ(2, break_point_hit_count);

  // Run with two breakpoints
1324
  int bp2 = SetBreakPointFromJS(env->GetIsolate(), "foo", 0, 9);
1325 1326 1327 1328 1329 1330
  foo->Run();
  CHECK_EQ(4, break_point_hit_count);
  foo->Run();
  CHECK_EQ(6, break_point_hit_count);

  // Run with one breakpoint
1331
  ClearBreakPointFromJS(env->GetIsolate(), bp2);
1332 1333 1334 1335 1336 1337
  foo->Run();
  CHECK_EQ(7, break_point_hit_count);
  foo->Run();
  CHECK_EQ(8, break_point_hit_count);

  // Run without breakpoints.
1338
  ClearBreakPointFromJS(env->GetIsolate(), bp1);
1339 1340 1341
  foo->Run();
  CHECK_EQ(8, break_point_hit_count);

1342
  v8::Debug::SetDebugEventListener(NULL);
1343
  CheckDebuggerUnloaded();
1344 1345 1346 1347 1348 1349 1350

  // Make sure that the break point numbers are consecutive.
  CHECK_EQ(1, bp1);
  CHECK_EQ(2, bp2);
}


1351 1352 1353
// Test that break points on scripts identified by name can be set using the
// global Debug object.
TEST(ScriptBreakPointByNameThroughJavaScript) {
1354
  break_point_hit_count = 0;
1355
  DebugLocalContext env;
1356
  v8::HandleScope scope(env->GetIsolate());
1357 1358
  env.ExposeDebug();

1359
  v8::Debug::SetDebugEventListener(DebugEventBreakPointHitCount);
1360

1361 1362
  v8::Local<v8::String> script = v8::String::NewFromUtf8(
    env->GetIsolate(),
1363 1364 1365 1366 1367 1368 1369 1370 1371 1372 1373 1374 1375 1376 1377 1378 1379 1380 1381 1382
    "function f() {\n"
    "  function h() {\n"
    "    a = 0;  // line 2\n"
    "  }\n"
    "  b = 1;  // line 4\n"
    "  return h();\n"
    "}\n"
    "\n"
    "function g() {\n"
    "  function h() {\n"
    "    a = 0;\n"
    "  }\n"
    "  b = 2;  // line 12\n"
    "  h();\n"
    "  b = 3;  // line 14\n"
    "  f();    // line 15\n"
    "}");

  // Compile the script and get the two functions.
  v8::ScriptOrigin origin =
1383
      v8::ScriptOrigin(v8::String::NewFromUtf8(env->GetIsolate(), "test"));
1384
  v8::Script::Compile(script, &origin)->Run();
1385 1386 1387 1388
  v8::Local<v8::Function> f = v8::Local<v8::Function>::Cast(
      env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "f")));
  v8::Local<v8::Function> g = v8::Local<v8::Function>::Cast(
      env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "g")));
1389 1390 1391 1392 1393 1394 1395 1396 1397

  // Call f and g without break points.
  break_point_hit_count = 0;
  f->Call(env->Global(), 0, NULL);
  CHECK_EQ(0, break_point_hit_count);
  g->Call(env->Global(), 0, NULL);
  CHECK_EQ(0, break_point_hit_count);

  // Call f and g with break point on line 12.
1398
  int sbp1 = SetScriptBreakPointByNameFromJS(env->GetIsolate(), "test", 12, 0);
1399 1400 1401 1402 1403 1404 1405 1406
  break_point_hit_count = 0;
  f->Call(env->Global(), 0, NULL);
  CHECK_EQ(0, break_point_hit_count);
  g->Call(env->Global(), 0, NULL);
  CHECK_EQ(1, break_point_hit_count);

  // Remove the break point again.
  break_point_hit_count = 0;
1407
  ClearBreakPointFromJS(env->GetIsolate(), sbp1);
1408 1409 1410 1411 1412 1413
  f->Call(env->Global(), 0, NULL);
  CHECK_EQ(0, break_point_hit_count);
  g->Call(env->Global(), 0, NULL);
  CHECK_EQ(0, break_point_hit_count);

  // Call f and g with break point on line 2.
1414
  int sbp2 = SetScriptBreakPointByNameFromJS(env->GetIsolate(), "test", 2, 0);
1415 1416 1417 1418 1419 1420 1421
  break_point_hit_count = 0;
  f->Call(env->Global(), 0, NULL);
  CHECK_EQ(1, break_point_hit_count);
  g->Call(env->Global(), 0, NULL);
  CHECK_EQ(2, break_point_hit_count);

  // Call f and g with break point on line 2, 4, 12, 14 and 15.
1422 1423 1424 1425
  int sbp3 = SetScriptBreakPointByNameFromJS(env->GetIsolate(), "test", 4, 0);
  int sbp4 = SetScriptBreakPointByNameFromJS(env->GetIsolate(), "test", 12, 0);
  int sbp5 = SetScriptBreakPointByNameFromJS(env->GetIsolate(), "test", 14, 0);
  int sbp6 = SetScriptBreakPointByNameFromJS(env->GetIsolate(), "test", 15, 0);
1426 1427 1428 1429 1430 1431
  break_point_hit_count = 0;
  f->Call(env->Global(), 0, NULL);
  CHECK_EQ(2, break_point_hit_count);
  g->Call(env->Global(), 0, NULL);
  CHECK_EQ(7, break_point_hit_count);

1432
  // Remove all the break points again.
1433
  break_point_hit_count = 0;
1434 1435 1436 1437 1438
  ClearBreakPointFromJS(env->GetIsolate(), sbp2);
  ClearBreakPointFromJS(env->GetIsolate(), sbp3);
  ClearBreakPointFromJS(env->GetIsolate(), sbp4);
  ClearBreakPointFromJS(env->GetIsolate(), sbp5);
  ClearBreakPointFromJS(env->GetIsolate(), sbp6);
1439 1440 1441 1442 1443
  f->Call(env->Global(), 0, NULL);
  CHECK_EQ(0, break_point_hit_count);
  g->Call(env->Global(), 0, NULL);
  CHECK_EQ(0, break_point_hit_count);

1444
  v8::Debug::SetDebugEventListener(NULL);
1445 1446 1447 1448 1449 1450 1451 1452 1453 1454 1455 1456 1457 1458 1459
  CheckDebuggerUnloaded();

  // Make sure that the break point numbers are consecutive.
  CHECK_EQ(1, sbp1);
  CHECK_EQ(2, sbp2);
  CHECK_EQ(3, sbp3);
  CHECK_EQ(4, sbp4);
  CHECK_EQ(5, sbp5);
  CHECK_EQ(6, sbp6);
}


TEST(ScriptBreakPointByIdThroughJavaScript) {
  break_point_hit_count = 0;
  DebugLocalContext env;
1460
  v8::HandleScope scope(env->GetIsolate());
1461 1462
  env.ExposeDebug();

1463
  v8::Debug::SetDebugEventListener(DebugEventBreakPointHitCount);
1464

1465 1466
  v8::Local<v8::String> source = v8::String::NewFromUtf8(
    env->GetIsolate(),
1467 1468 1469 1470 1471 1472 1473 1474 1475 1476 1477 1478 1479 1480 1481 1482 1483 1484 1485 1486
    "function f() {\n"
    "  function h() {\n"
    "    a = 0;  // line 2\n"
    "  }\n"
    "  b = 1;  // line 4\n"
    "  return h();\n"
    "}\n"
    "\n"
    "function g() {\n"
    "  function h() {\n"
    "    a = 0;\n"
    "  }\n"
    "  b = 2;  // line 12\n"
    "  h();\n"
    "  b = 3;  // line 14\n"
    "  f();    // line 15\n"
    "}");

  // Compile the script and get the two functions.
  v8::ScriptOrigin origin =
1487
      v8::ScriptOrigin(v8::String::NewFromUtf8(env->GetIsolate(), "test"));
1488 1489
  v8::Local<v8::Script> script = v8::Script::Compile(source, &origin);
  script->Run();
1490 1491 1492 1493
  v8::Local<v8::Function> f = v8::Local<v8::Function>::Cast(
      env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "f")));
  v8::Local<v8::Function> g = v8::Local<v8::Function>::Cast(
      env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "g")));
1494 1495

  // Get the script id knowing that internally it is a 32 integer.
1496
  int script_id = script->GetUnboundScript()->GetId();
1497 1498 1499 1500 1501 1502 1503 1504 1505

  // Call f and g without break points.
  break_point_hit_count = 0;
  f->Call(env->Global(), 0, NULL);
  CHECK_EQ(0, break_point_hit_count);
  g->Call(env->Global(), 0, NULL);
  CHECK_EQ(0, break_point_hit_count);

  // Call f and g with break point on line 12.
1506
  int sbp1 = SetScriptBreakPointByIdFromJS(env->GetIsolate(), script_id, 12, 0);
1507 1508 1509
  break_point_hit_count = 0;
  f->Call(env->Global(), 0, NULL);
  CHECK_EQ(0, break_point_hit_count);
1510 1511 1512
  g->Call(env->Global(), 0, NULL);
  CHECK_EQ(1, break_point_hit_count);

1513 1514
  // Remove the break point again.
  break_point_hit_count = 0;
1515
  ClearBreakPointFromJS(env->GetIsolate(), sbp1);
1516 1517 1518 1519 1520 1521
  f->Call(env->Global(), 0, NULL);
  CHECK_EQ(0, break_point_hit_count);
  g->Call(env->Global(), 0, NULL);
  CHECK_EQ(0, break_point_hit_count);

  // Call f and g with break point on line 2.
1522
  int sbp2 = SetScriptBreakPointByIdFromJS(env->GetIsolate(), script_id, 2, 0);
1523 1524 1525
  break_point_hit_count = 0;
  f->Call(env->Global(), 0, NULL);
  CHECK_EQ(1, break_point_hit_count);
1526 1527 1528
  g->Call(env->Global(), 0, NULL);
  CHECK_EQ(2, break_point_hit_count);

1529
  // Call f and g with break point on line 2, 4, 12, 14 and 15.
1530 1531 1532 1533
  int sbp3 = SetScriptBreakPointByIdFromJS(env->GetIsolate(), script_id, 4, 0);
  int sbp4 = SetScriptBreakPointByIdFromJS(env->GetIsolate(), script_id, 12, 0);
  int sbp5 = SetScriptBreakPointByIdFromJS(env->GetIsolate(), script_id, 14, 0);
  int sbp6 = SetScriptBreakPointByIdFromJS(env->GetIsolate(), script_id, 15, 0);
1534 1535 1536 1537 1538 1539 1540 1541
  break_point_hit_count = 0;
  f->Call(env->Global(), 0, NULL);
  CHECK_EQ(2, break_point_hit_count);
  g->Call(env->Global(), 0, NULL);
  CHECK_EQ(7, break_point_hit_count);

  // Remove all the break points again.
  break_point_hit_count = 0;
1542 1543 1544 1545 1546
  ClearBreakPointFromJS(env->GetIsolate(), sbp2);
  ClearBreakPointFromJS(env->GetIsolate(), sbp3);
  ClearBreakPointFromJS(env->GetIsolate(), sbp4);
  ClearBreakPointFromJS(env->GetIsolate(), sbp5);
  ClearBreakPointFromJS(env->GetIsolate(), sbp6);
1547 1548 1549 1550 1551
  f->Call(env->Global(), 0, NULL);
  CHECK_EQ(0, break_point_hit_count);
  g->Call(env->Global(), 0, NULL);
  CHECK_EQ(0, break_point_hit_count);

1552
  v8::Debug::SetDebugEventListener(NULL);
1553
  CheckDebuggerUnloaded();
1554 1555 1556 1557 1558 1559 1560 1561 1562 1563 1564 1565 1566 1567

  // Make sure that the break point numbers are consecutive.
  CHECK_EQ(1, sbp1);
  CHECK_EQ(2, sbp2);
  CHECK_EQ(3, sbp3);
  CHECK_EQ(4, sbp4);
  CHECK_EQ(5, sbp5);
  CHECK_EQ(6, sbp6);
}


// Test conditional script break points.
TEST(EnableDisableScriptBreakPoint) {
  break_point_hit_count = 0;
1568
  DebugLocalContext env;
1569
  v8::HandleScope scope(env->GetIsolate());
1570 1571
  env.ExposeDebug();

1572
  v8::Debug::SetDebugEventListener(DebugEventBreakPointHitCount);
1573

1574 1575
  v8::Local<v8::String> script = v8::String::NewFromUtf8(
    env->GetIsolate(),
1576 1577 1578 1579 1580 1581
    "function f() {\n"
    "  a = 0;  // line 1\n"
    "};");

  // Compile the script and get function f.
  v8::ScriptOrigin origin =
1582
      v8::ScriptOrigin(v8::String::NewFromUtf8(env->GetIsolate(), "test"));
1583
  v8::Script::Compile(script, &origin)->Run();
1584 1585
  v8::Local<v8::Function> f = v8::Local<v8::Function>::Cast(
      env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "f")));
1586 1587

  // Set script break point on line 1 (in function f).
1588
  int sbp = SetScriptBreakPointByNameFromJS(env->GetIsolate(), "test", 1, 0);
1589 1590 1591 1592 1593 1594

  // Call f while enabeling and disabling the script break point.
  break_point_hit_count = 0;
  f->Call(env->Global(), 0, NULL);
  CHECK_EQ(1, break_point_hit_count);

1595
  DisableScriptBreakPointFromJS(env->GetIsolate(), sbp);
1596 1597 1598
  f->Call(env->Global(), 0, NULL);
  CHECK_EQ(1, break_point_hit_count);

1599
  EnableScriptBreakPointFromJS(env->GetIsolate(), sbp);
1600 1601 1602
  f->Call(env->Global(), 0, NULL);
  CHECK_EQ(2, break_point_hit_count);

1603
  DisableScriptBreakPointFromJS(env->GetIsolate(), sbp);
1604 1605 1606 1607 1608
  f->Call(env->Global(), 0, NULL);
  CHECK_EQ(2, break_point_hit_count);

  // Reload the script and get f again checking that the disabeling survives.
  v8::Script::Compile(script, &origin)->Run();
1609 1610
  f = v8::Local<v8::Function>::Cast(
      env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "f")));
1611 1612 1613
  f->Call(env->Global(), 0, NULL);
  CHECK_EQ(2, break_point_hit_count);

1614
  EnableScriptBreakPointFromJS(env->GetIsolate(), sbp);
1615 1616 1617
  f->Call(env->Global(), 0, NULL);
  CHECK_EQ(3, break_point_hit_count);

1618
  v8::Debug::SetDebugEventListener(NULL);
1619
  CheckDebuggerUnloaded();
1620 1621 1622 1623 1624 1625
}


// Test conditional script break points.
TEST(ConditionalScriptBreakPoint) {
  break_point_hit_count = 0;
1626
  DebugLocalContext env;
1627
  v8::HandleScope scope(env->GetIsolate());
1628 1629
  env.ExposeDebug();

1630
  v8::Debug::SetDebugEventListener(DebugEventBreakPointHitCount);
1631

1632 1633
  v8::Local<v8::String> script = v8::String::NewFromUtf8(
    env->GetIsolate(),
1634 1635 1636 1637 1638 1639 1640 1641 1642 1643
    "count = 0;\n"
    "function f() {\n"
    "  g(count++);  // line 2\n"
    "};\n"
    "function g(x) {\n"
    "  var a=x;  // line 5\n"
    "};");

  // Compile the script and get function f.
  v8::ScriptOrigin origin =
1644
      v8::ScriptOrigin(v8::String::NewFromUtf8(env->GetIsolate(), "test"));
1645
  v8::Script::Compile(script, &origin)->Run();
1646 1647
  v8::Local<v8::Function> f = v8::Local<v8::Function>::Cast(
      env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "f")));
1648 1649

  // Set script break point on line 5 (in function g).
1650
  int sbp1 = SetScriptBreakPointByNameFromJS(env->GetIsolate(), "test", 5, 0);
1651 1652 1653

  // Call f with different conditions on the script break point.
  break_point_hit_count = 0;
1654
  ChangeScriptBreakPointConditionFromJS(env->GetIsolate(), sbp1, "false");
1655 1656 1657
  f->Call(env->Global(), 0, NULL);
  CHECK_EQ(0, break_point_hit_count);

1658
  ChangeScriptBreakPointConditionFromJS(env->GetIsolate(), sbp1, "true");
1659 1660 1661 1662
  break_point_hit_count = 0;
  f->Call(env->Global(), 0, NULL);
  CHECK_EQ(1, break_point_hit_count);

1663
  ChangeScriptBreakPointConditionFromJS(env->GetIsolate(), sbp1, "x % 2 == 0");
1664 1665 1666 1667 1668 1669 1670 1671
  break_point_hit_count = 0;
  for (int i = 0; i < 10; i++) {
    f->Call(env->Global(), 0, NULL);
  }
  CHECK_EQ(5, break_point_hit_count);

  // Reload the script and get f again checking that the condition survives.
  v8::Script::Compile(script, &origin)->Run();
1672 1673
  f = v8::Local<v8::Function>::Cast(
      env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "f")));
1674 1675 1676 1677 1678 1679 1680

  break_point_hit_count = 0;
  for (int i = 0; i < 10; i++) {
    f->Call(env->Global(), 0, NULL);
  }
  CHECK_EQ(5, break_point_hit_count);

1681
  v8::Debug::SetDebugEventListener(NULL);
1682
  CheckDebuggerUnloaded();
1683 1684 1685 1686 1687 1688
}


// Test ignore count on script break points.
TEST(ScriptBreakPointIgnoreCount) {
  break_point_hit_count = 0;
1689
  DebugLocalContext env;
1690
  v8::HandleScope scope(env->GetIsolate());
1691 1692
  env.ExposeDebug();

1693
  v8::Debug::SetDebugEventListener(DebugEventBreakPointHitCount);
1694

1695 1696
  v8::Local<v8::String> script = v8::String::NewFromUtf8(
    env->GetIsolate(),
1697 1698 1699 1700 1701 1702
    "function f() {\n"
    "  a = 0;  // line 1\n"
    "};");

  // Compile the script and get function f.
  v8::ScriptOrigin origin =
1703
      v8::ScriptOrigin(v8::String::NewFromUtf8(env->GetIsolate(), "test"));
1704
  v8::Script::Compile(script, &origin)->Run();
1705 1706
  v8::Local<v8::Function> f = v8::Local<v8::Function>::Cast(
      env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "f")));
1707 1708

  // Set script break point on line 1 (in function f).
1709
  int sbp = SetScriptBreakPointByNameFromJS(env->GetIsolate(), "test", 1, 0);
1710 1711 1712

  // Call f with different ignores on the script break point.
  break_point_hit_count = 0;
1713
  ChangeScriptBreakPointIgnoreCountFromJS(env->GetIsolate(), sbp, 1);
1714 1715 1716 1717 1718
  f->Call(env->Global(), 0, NULL);
  CHECK_EQ(0, break_point_hit_count);
  f->Call(env->Global(), 0, NULL);
  CHECK_EQ(1, break_point_hit_count);

1719
  ChangeScriptBreakPointIgnoreCountFromJS(env->GetIsolate(), sbp, 5);
1720 1721 1722 1723 1724 1725 1726 1727
  break_point_hit_count = 0;
  for (int i = 0; i < 10; i++) {
    f->Call(env->Global(), 0, NULL);
  }
  CHECK_EQ(5, break_point_hit_count);

  // Reload the script and get f again checking that the ignore survives.
  v8::Script::Compile(script, &origin)->Run();
1728 1729
  f = v8::Local<v8::Function>::Cast(
      env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "f")));
1730 1731 1732 1733 1734 1735 1736

  break_point_hit_count = 0;
  for (int i = 0; i < 10; i++) {
    f->Call(env->Global(), 0, NULL);
  }
  CHECK_EQ(5, break_point_hit_count);

1737
  v8::Debug::SetDebugEventListener(NULL);
1738
  CheckDebuggerUnloaded();
1739 1740 1741 1742 1743 1744
}


// Test that script break points survive when a script is reloaded.
TEST(ScriptBreakPointReload) {
  break_point_hit_count = 0;
1745
  DebugLocalContext env;
1746
  v8::HandleScope scope(env->GetIsolate());
1747 1748
  env.ExposeDebug();

1749
  v8::Debug::SetDebugEventListener(DebugEventBreakPointHitCount);
1750 1751

  v8::Local<v8::Function> f;
1752 1753
  v8::Local<v8::String> script = v8::String::NewFromUtf8(
    env->GetIsolate(),
1754 1755 1756 1757 1758 1759 1760 1761
    "function f() {\n"
    "  function h() {\n"
    "    a = 0;  // line 2\n"
    "  }\n"
    "  b = 1;  // line 4\n"
    "  return h();\n"
    "}");

1762 1763 1764 1765
  v8::ScriptOrigin origin_1 =
      v8::ScriptOrigin(v8::String::NewFromUtf8(env->GetIsolate(), "1"));
  v8::ScriptOrigin origin_2 =
      v8::ScriptOrigin(v8::String::NewFromUtf8(env->GetIsolate(), "2"));
1766 1767

  // Set a script break point before the script is loaded.
1768
  SetScriptBreakPointByNameFromJS(env->GetIsolate(), "1", 2, 0);
1769 1770 1771

  // Compile the script and get the function.
  v8::Script::Compile(script, &origin_1)->Run();
1772 1773
  f = v8::Local<v8::Function>::Cast(
      env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "f")));
1774 1775 1776 1777 1778 1779 1780 1781 1782

  // Call f and check that the script break point is active.
  break_point_hit_count = 0;
  f->Call(env->Global(), 0, NULL);
  CHECK_EQ(1, break_point_hit_count);

  // Compile the script again with a different script data and get the
  // function.
  v8::Script::Compile(script, &origin_2)->Run();
1783 1784
  f = v8::Local<v8::Function>::Cast(
      env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "f")));
1785 1786 1787 1788 1789 1790 1791 1792

  // Call f and check that no break points are set.
  break_point_hit_count = 0;
  f->Call(env->Global(), 0, NULL);
  CHECK_EQ(0, break_point_hit_count);

  // Compile the script again and get the function.
  v8::Script::Compile(script, &origin_1)->Run();
1793 1794
  f = v8::Local<v8::Function>::Cast(
      env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "f")));
1795 1796 1797 1798 1799 1800

  // Call f and check that the script break point is active.
  break_point_hit_count = 0;
  f->Call(env->Global(), 0, NULL);
  CHECK_EQ(1, break_point_hit_count);

1801
  v8::Debug::SetDebugEventListener(NULL);
1802
  CheckDebuggerUnloaded();
1803 1804 1805 1806 1807 1808
}


// Test when several scripts has the same script data
TEST(ScriptBreakPointMultiple) {
  break_point_hit_count = 0;
1809
  DebugLocalContext env;
1810
  v8::HandleScope scope(env->GetIsolate());
1811 1812
  env.ExposeDebug();

1813
  v8::Debug::SetDebugEventListener(DebugEventBreakPointHitCount);
1814 1815

  v8::Local<v8::Function> f;
1816 1817 1818 1819 1820
  v8::Local<v8::String> script_f =
      v8::String::NewFromUtf8(env->GetIsolate(),
                              "function f() {\n"
                              "  a = 0;  // line 1\n"
                              "}");
1821 1822

  v8::Local<v8::Function> g;
1823 1824 1825 1826 1827
  v8::Local<v8::String> script_g =
      v8::String::NewFromUtf8(env->GetIsolate(),
                              "function g() {\n"
                              "  b = 0;  // line 1\n"
                              "}");
1828 1829

  v8::ScriptOrigin origin =
1830
      v8::ScriptOrigin(v8::String::NewFromUtf8(env->GetIsolate(), "test"));
1831 1832

  // Set a script break point before the scripts are loaded.
1833
  int sbp = SetScriptBreakPointByNameFromJS(env->GetIsolate(), "test", 1, 0);
1834 1835 1836

  // Compile the scripts with same script data and get the functions.
  v8::Script::Compile(script_f, &origin)->Run();
1837 1838
  f = v8::Local<v8::Function>::Cast(
      env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "f")));
1839
  v8::Script::Compile(script_g, &origin)->Run();
1840 1841
  g = v8::Local<v8::Function>::Cast(
      env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "g")));
1842 1843 1844 1845 1846 1847 1848 1849 1850

  // Call f and g and check that the script break point is active.
  break_point_hit_count = 0;
  f->Call(env->Global(), 0, NULL);
  CHECK_EQ(1, break_point_hit_count);
  g->Call(env->Global(), 0, NULL);
  CHECK_EQ(2, break_point_hit_count);

  // Clear the script break point.
1851
  ClearBreakPointFromJS(env->GetIsolate(), sbp);
1852 1853 1854 1855 1856 1857 1858 1859 1860

  // Call f and g and check that the script break point is no longer active.
  break_point_hit_count = 0;
  f->Call(env->Global(), 0, NULL);
  CHECK_EQ(0, break_point_hit_count);
  g->Call(env->Global(), 0, NULL);
  CHECK_EQ(0, break_point_hit_count);

  // Set script break point with the scripts loaded.
1861
  sbp = SetScriptBreakPointByNameFromJS(env->GetIsolate(), "test", 1, 0);
1862 1863 1864 1865 1866 1867 1868 1869

  // Call f and g and check that the script break point is active.
  break_point_hit_count = 0;
  f->Call(env->Global(), 0, NULL);
  CHECK_EQ(1, break_point_hit_count);
  g->Call(env->Global(), 0, NULL);
  CHECK_EQ(2, break_point_hit_count);

1870
  v8::Debug::SetDebugEventListener(NULL);
1871
  CheckDebuggerUnloaded();
1872 1873 1874 1875 1876 1877
}


// Test the script origin which has both name and line offset.
TEST(ScriptBreakPointLineOffset) {
  break_point_hit_count = 0;
1878
  DebugLocalContext env;
1879
  v8::HandleScope scope(env->GetIsolate());
1880 1881
  env.ExposeDebug();

1882
  v8::Debug::SetDebugEventListener(DebugEventBreakPointHitCount);
1883 1884

  v8::Local<v8::Function> f;
1885 1886 1887 1888 1889 1890
  v8::Local<v8::String> script = v8::String::NewFromUtf8(
      env->GetIsolate(),
      "function f() {\n"
      "  a = 0;  // line 8 as this script has line offset 7\n"
      "  b = 0;  // line 9 as this script has line offset 7\n"
      "}");
1891 1892

  // Create script origin both name and line offset.
1893 1894
  v8::ScriptOrigin origin(
      v8::String::NewFromUtf8(env->GetIsolate(), "test.html"),
1895
      v8::Integer::New(env->GetIsolate(), 7));
1896 1897

  // Set two script break points before the script is loaded.
1898 1899 1900 1901
  int sbp1 =
      SetScriptBreakPointByNameFromJS(env->GetIsolate(), "test.html", 8, 0);
  int sbp2 =
      SetScriptBreakPointByNameFromJS(env->GetIsolate(), "test.html", 9, 0);
1902 1903 1904

  // Compile the script and get the function.
  v8::Script::Compile(script, &origin)->Run();
1905 1906
  f = v8::Local<v8::Function>::Cast(
      env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "f")));
1907 1908 1909 1910 1911 1912 1913

  // Call f and check that the script break point is active.
  break_point_hit_count = 0;
  f->Call(env->Global(), 0, NULL);
  CHECK_EQ(2, break_point_hit_count);

  // Clear the script break points.
1914 1915
  ClearBreakPointFromJS(env->GetIsolate(), sbp1);
  ClearBreakPointFromJS(env->GetIsolate(), sbp2);
1916 1917 1918 1919 1920 1921 1922

  // Call f and check that no script break points are active.
  break_point_hit_count = 0;
  f->Call(env->Global(), 0, NULL);
  CHECK_EQ(0, break_point_hit_count);

  // Set a script break point with the script loaded.
1923
  sbp1 = SetScriptBreakPointByNameFromJS(env->GetIsolate(), "test.html", 9, 0);
1924 1925 1926 1927 1928 1929

  // Call f and check that the script break point is active.
  break_point_hit_count = 0;
  f->Call(env->Global(), 0, NULL);
  CHECK_EQ(1, break_point_hit_count);

1930
  v8::Debug::SetDebugEventListener(NULL);
1931
  CheckDebuggerUnloaded();
1932 1933 1934 1935 1936
}


// Test script break points set on lines.
TEST(ScriptBreakPointLine) {
1937
  DebugLocalContext env;
1938
  v8::HandleScope scope(env->GetIsolate());
1939 1940 1941 1942 1943 1944 1945
  env.ExposeDebug();

  // Create a function for checking the function when hitting a break point.
  frame_function_name = CompileFunction(&env,
                                        frame_function_name_source,
                                        "frame_function_name");

1946
  v8::Debug::SetDebugEventListener(DebugEventBreakPointHitCount);
1947 1948 1949

  v8::Local<v8::Function> f;
  v8::Local<v8::Function> g;
1950 1951 1952 1953 1954 1955 1956 1957 1958 1959 1960 1961 1962 1963 1964
  v8::Local<v8::String> script =
      v8::String::NewFromUtf8(env->GetIsolate(),
                              "a = 0                      // line 0\n"
                              "function f() {\n"
                              "  a = 1;                   // line 2\n"
                              "}\n"
                              " a = 2;                    // line 4\n"
                              "  /* xx */ function g() {  // line 5\n"
                              "    function h() {         // line 6\n"
                              "      a = 3;               // line 7\n"
                              "    }\n"
                              "    h();                   // line 9\n"
                              "    a = 4;                 // line 10\n"
                              "  }\n"
                              " a=5;                      // line 12");
1965 1966

  // Set a couple script break point before the script is loaded.
1967 1968 1969 1970 1971 1972
  int sbp1 =
      SetScriptBreakPointByNameFromJS(env->GetIsolate(), "test.html", 0, -1);
  int sbp2 =
      SetScriptBreakPointByNameFromJS(env->GetIsolate(), "test.html", 1, -1);
  int sbp3 =
      SetScriptBreakPointByNameFromJS(env->GetIsolate(), "test.html", 5, -1);
1973 1974 1975

  // Compile the script and get the function.
  break_point_hit_count = 0;
1976 1977
  v8::ScriptOrigin origin(
      v8::String::NewFromUtf8(env->GetIsolate(), "test.html"),
1978
      v8::Integer::New(env->GetIsolate(), 0));
1979
  v8::Script::Compile(script, &origin)->Run();
1980 1981 1982 1983
  f = v8::Local<v8::Function>::Cast(
      env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "f")));
  g = v8::Local<v8::Function>::Cast(
      env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "g")));
1984

1985
  // Check that a break point was hit when the script was run.
1986
  CHECK_EQ(1, break_point_hit_count);
1987
  CHECK_EQ(0, StrLength(last_function_hit));
1988 1989 1990 1991

  // Call f and check that the script break point.
  f->Call(env->Global(), 0, NULL);
  CHECK_EQ(2, break_point_hit_count);
1992
  CHECK_EQ(0, strcmp("f", last_function_hit));
1993 1994 1995 1996

  // Call g and check that the script break point.
  g->Call(env->Global(), 0, NULL);
  CHECK_EQ(3, break_point_hit_count);
1997
  CHECK_EQ(0, strcmp("g", last_function_hit));
1998 1999

  // Clear the script break point on g and set one on h.
2000 2001 2002
  ClearBreakPointFromJS(env->GetIsolate(), sbp3);
  int sbp4 =
      SetScriptBreakPointByNameFromJS(env->GetIsolate(), "test.html", 6, -1);
2003 2004 2005 2006

  // Call g and check that the script break point in h is hit.
  g->Call(env->Global(), 0, NULL);
  CHECK_EQ(4, break_point_hit_count);
2007
  CHECK_EQ(0, strcmp("h", last_function_hit));
2008 2009 2010 2011

  // Clear break points in f and h. Set a new one in the script between
  // functions f and g and test that there is no break points in f and g any
  // more.
2012 2013 2014 2015
  ClearBreakPointFromJS(env->GetIsolate(), sbp2);
  ClearBreakPointFromJS(env->GetIsolate(), sbp4);
  int sbp5 =
      SetScriptBreakPointByNameFromJS(env->GetIsolate(), "test.html", 4, -1);
2016 2017 2018 2019 2020 2021 2022 2023 2024
  break_point_hit_count = 0;
  f->Call(env->Global(), 0, NULL);
  g->Call(env->Global(), 0, NULL);
  CHECK_EQ(0, break_point_hit_count);

  // Reload the script which should hit two break points.
  break_point_hit_count = 0;
  v8::Script::Compile(script, &origin)->Run();
  CHECK_EQ(2, break_point_hit_count);
2025
  CHECK_EQ(0, StrLength(last_function_hit));
2026 2027

  // Set a break point in the code after the last function decleration.
2028 2029
  int sbp6 =
      SetScriptBreakPointByNameFromJS(env->GetIsolate(), "test.html", 12, -1);
2030 2031 2032 2033 2034

  // Reload the script which should hit three break points.
  break_point_hit_count = 0;
  v8::Script::Compile(script, &origin)->Run();
  CHECK_EQ(3, break_point_hit_count);
2035
  CHECK_EQ(0, StrLength(last_function_hit));
2036 2037 2038

  // Clear the last break points, and reload the script which should not hit any
  // break points.
2039 2040 2041
  ClearBreakPointFromJS(env->GetIsolate(), sbp1);
  ClearBreakPointFromJS(env->GetIsolate(), sbp5);
  ClearBreakPointFromJS(env->GetIsolate(), sbp6);
2042 2043 2044 2045
  break_point_hit_count = 0;
  v8::Script::Compile(script, &origin)->Run();
  CHECK_EQ(0, break_point_hit_count);

2046
  v8::Debug::SetDebugEventListener(NULL);
2047
  CheckDebuggerUnloaded();
2048 2049 2050
}


2051 2052 2053
// Test top level script break points set on lines.
TEST(ScriptBreakPointLineTopLevel) {
  DebugLocalContext env;
2054
  v8::HandleScope scope(env->GetIsolate());
2055 2056
  env.ExposeDebug();

2057
  v8::Debug::SetDebugEventListener(DebugEventBreakPointHitCount);
2058

2059 2060 2061 2062 2063 2064
  v8::Local<v8::String> script =
      v8::String::NewFromUtf8(env->GetIsolate(),
                              "function f() {\n"
                              "  a = 1;                   // line 1\n"
                              "}\n"
                              "a = 2;                     // line 3\n");
2065 2066
  v8::Local<v8::Function> f;
  {
2067
    v8::HandleScope scope(env->GetIsolate());
2068
    CompileRunWithOrigin(script, "test.html");
2069
  }
2070 2071
  f = v8::Local<v8::Function>::Cast(
      env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "f")));
2072

2073
  CcTest::heap()->CollectAllGarbage();
2074

2075
  SetScriptBreakPointByNameFromJS(env->GetIsolate(), "test.html", 3, -1);
2076 2077 2078 2079 2080 2081 2082 2083

  // Call f and check that there was no break points.
  break_point_hit_count = 0;
  f->Call(env->Global(), 0, NULL);
  CHECK_EQ(0, break_point_hit_count);

  // Recompile and run script and check that break point was hit.
  break_point_hit_count = 0;
2084
  CompileRunWithOrigin(script, "test.html");
2085 2086 2087 2088
  CHECK_EQ(1, break_point_hit_count);

  // Call f and check that there are still no break points.
  break_point_hit_count = 0;
2089 2090
  f = v8::Local<v8::Function>::Cast(
      env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "f")));
2091 2092
  CHECK_EQ(0, break_point_hit_count);

2093
  v8::Debug::SetDebugEventListener(NULL);
2094 2095 2096 2097
  CheckDebuggerUnloaded();
}


2098 2099 2100 2101
// Test that it is possible to add and remove break points in a top level
// function which has no references but has not been collected yet.
TEST(ScriptBreakPointTopLevelCrash) {
  DebugLocalContext env;
2102
  v8::HandleScope scope(env->GetIsolate());
2103 2104
  env.ExposeDebug();

2105
  v8::Debug::SetDebugEventListener(DebugEventBreakPointHitCount);
2106

2107 2108 2109 2110 2111 2112
  v8::Local<v8::String> script_source =
      v8::String::NewFromUtf8(env->GetIsolate(),
                              "function f() {\n"
                              "  return 0;\n"
                              "}\n"
                              "f()");
2113

2114 2115
  int sbp1 =
      SetScriptBreakPointByNameFromJS(env->GetIsolate(), "test.html", 3, -1);
2116
  {
2117
    v8::HandleScope scope(env->GetIsolate());
2118
    break_point_hit_count = 0;
2119
    CompileRunWithOrigin(script_source, "test.html");
2120 2121 2122
    CHECK_EQ(1, break_point_hit_count);
  }

2123 2124 2125 2126
  int sbp2 =
      SetScriptBreakPointByNameFromJS(env->GetIsolate(), "test.html", 3, -1);
  ClearBreakPointFromJS(env->GetIsolate(), sbp1);
  ClearBreakPointFromJS(env->GetIsolate(), sbp2);
2127

2128
  v8::Debug::SetDebugEventListener(NULL);
2129 2130 2131 2132
  CheckDebuggerUnloaded();
}


2133 2134 2135
// Test that it is possible to remove the last break point for a function
// inside the break handling of that break point.
TEST(RemoveBreakPointInBreak) {
2136
  DebugLocalContext env;
2137
  v8::HandleScope scope(env->GetIsolate());
2138 2139 2140 2141 2142

  v8::Local<v8::Function> foo =
      CompileFunction(&env, "function foo(){a=1;}", "foo");

  // Register the debug event listener pasing the function
2143
  v8::Debug::SetDebugEventListener(DebugEventRemoveBreakPoint, foo);
2144

2145 2146
  debug_event_remove_break_point = SetBreakPoint(foo, 0);

2147 2148 2149 2150 2151 2152 2153 2154
  break_point_hit_count = 0;
  foo->Call(env->Global(), 0, NULL);
  CHECK_EQ(1, break_point_hit_count);

  break_point_hit_count = 0;
  foo->Call(env->Global(), 0, NULL);
  CHECK_EQ(0, break_point_hit_count);

2155
  v8::Debug::SetDebugEventListener(NULL);
2156
  CheckDebuggerUnloaded();
2157 2158 2159 2160 2161 2162
}


// Test that the debugger statement causes a break.
TEST(DebuggerStatement) {
  break_point_hit_count = 0;
2163
  DebugLocalContext env;
2164
  v8::HandleScope scope(env->GetIsolate());
2165
  v8::Debug::SetDebugEventListener(DebugEventBreakPointHitCount);
2166 2167 2168 2169 2170 2171 2172 2173 2174 2175
  v8::Script::Compile(
      v8::String::NewFromUtf8(env->GetIsolate(), "function bar(){debugger}"))
      ->Run();
  v8::Script::Compile(
      v8::String::NewFromUtf8(env->GetIsolate(),
                              "function foo(){debugger;debugger;}"))->Run();
  v8::Local<v8::Function> foo = v8::Local<v8::Function>::Cast(
      env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "foo")));
  v8::Local<v8::Function> bar = v8::Local<v8::Function>::Cast(
      env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "bar")));
2176 2177 2178 2179 2180 2181 2182 2183 2184

  // Run function with debugger statement
  bar->Call(env->Global(), 0, NULL);
  CHECK_EQ(1, break_point_hit_count);

  // Run function with two debugger statement
  foo->Call(env->Global(), 0, NULL);
  CHECK_EQ(3, break_point_hit_count);

2185
  v8::Debug::SetDebugEventListener(NULL);
2186
  CheckDebuggerUnloaded();
2187 2188 2189
}


2190
// Test setting a breakpoint on the debugger statement.
2191 2192 2193
TEST(DebuggerStatementBreakpoint) {
    break_point_hit_count = 0;
    DebugLocalContext env;
2194
    v8::HandleScope scope(env->GetIsolate());
2195
    v8::Debug::SetDebugEventListener(DebugEventBreakPointHitCount);
2196 2197 2198 2199 2200
    v8::Script::Compile(
        v8::String::NewFromUtf8(env->GetIsolate(), "function foo(){debugger;}"))
        ->Run();
    v8::Local<v8::Function> foo = v8::Local<v8::Function>::Cast(
        env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "foo")));
2201

2202
    // The debugger statement triggers breakpoint hit
2203 2204 2205 2206 2207 2208 2209 2210 2211 2212
    foo->Call(env->Global(), 0, NULL);
    CHECK_EQ(1, break_point_hit_count);

    int bp = SetBreakPoint(foo, 0);

    // Set breakpoint does not duplicate hits
    foo->Call(env->Global(), 0, NULL);
    CHECK_EQ(2, break_point_hit_count);

    ClearBreakPoint(bp);
2213
    v8::Debug::SetDebugEventListener(NULL);
2214 2215 2216 2217
    CheckDebuggerUnloaded();
}


2218
// Test that the evaluation of expressions when a break point is hit generates
2219 2220
// the correct results.
TEST(DebugEvaluate) {
2221
  DebugLocalContext env;
2222 2223
  v8::Isolate* isolate = env->GetIsolate();
  v8::HandleScope scope(isolate);
2224 2225 2226 2227 2228 2229 2230
  env.ExposeDebug();

  // Create a function for checking the evaluation when hitting a break point.
  evaluate_check_function = CompileFunction(&env,
                                            evaluate_check_source,
                                            "evaluate_check");
  // Register the debug event listener
2231
  v8::Debug::SetDebugEventListener(DebugEventEvaluate);
2232 2233 2234 2235

  // Different expected vaules of x and a when in a break point (u = undefined,
  // d = Hello, world!).
  struct EvaluateCheck checks_uu[] = {
2236 2237
    {"x", v8::Undefined(isolate)},
    {"a", v8::Undefined(isolate)},
2238 2239 2240
    {NULL, v8::Handle<v8::Value>()}
  };
  struct EvaluateCheck checks_hu[] = {
2241
    {"x", v8::String::NewFromUtf8(env->GetIsolate(), "Hello, world!")},
2242
    {"a", v8::Undefined(isolate)},
2243 2244 2245
    {NULL, v8::Handle<v8::Value>()}
  };
  struct EvaluateCheck checks_hh[] = {
2246 2247
    {"x", v8::String::NewFromUtf8(env->GetIsolate(), "Hello, world!")},
    {"a", v8::String::NewFromUtf8(env->GetIsolate(), "Hello, world!")},
2248 2249 2250 2251
    {NULL, v8::Handle<v8::Value>()}
  };

  // Simple test function. The "y=0" is in the function foo to provide a break
2252
  // location. For "y=0" the "y" is at position 15 in the foo function
2253 2254 2255 2256 2257
  // therefore setting breakpoint at position 15 will break at "y=0" and
  // setting it higher will break after.
  v8::Local<v8::Function> foo = CompileFunction(&env,
    "function foo(x) {"
    "  var a;"
2258
    "  y=0;"  // To ensure break location 1.
2259
    "  a=x;"
2260
    "  y=0;"  // To ensure break location 2.
2261 2262
    "}",
    "foo");
2263 2264
  const int foo_break_position_1 = 15;
  const int foo_break_position_2 = 29;
2265 2266

  // Arguments with one parameter "Hello, world!"
2267 2268
  v8::Handle<v8::Value> argv_foo[1] = {
      v8::String::NewFromUtf8(env->GetIsolate(), "Hello, world!")};
2269 2270

  // Call foo with breakpoint set before a=x and undefined as parameter.
2271
  int bp = SetBreakPoint(foo, foo_break_position_1);
2272 2273 2274 2275 2276 2277 2278 2279 2280
  checks = checks_uu;
  foo->Call(env->Global(), 0, NULL);

  // Call foo with breakpoint set before a=x and parameter "Hello, world!".
  checks = checks_hu;
  foo->Call(env->Global(), 1, argv_foo);

  // Call foo with breakpoint set after a=x and parameter "Hello, world!".
  ClearBreakPoint(bp);
2281
  SetBreakPoint(foo, foo_break_position_2);
2282 2283 2284
  checks = checks_hh;
  foo->Call(env->Global(), 1, argv_foo);

2285 2286 2287 2288 2289 2290 2291 2292 2293 2294 2295 2296 2297 2298 2299 2300 2301 2302 2303 2304 2305 2306 2307 2308 2309 2310 2311 2312
  // Test that overriding Object.prototype will not interfere into evaluation
  // on call frame.
  v8::Local<v8::Function> zoo =
      CompileFunction(&env,
                      "x = undefined;"
                      "function zoo(t) {"
                      "  var a=x;"
                      "  Object.prototype.x = 42;"
                      "  x=t;"
                      "  y=0;"  // To ensure break location.
                      "  delete Object.prototype.x;"
                      "  x=a;"
                      "}",
                      "zoo");
  const int zoo_break_position = 50;

  // Arguments with one parameter "Hello, world!"
  v8::Handle<v8::Value> argv_zoo[1] = {
      v8::String::NewFromUtf8(env->GetIsolate(), "Hello, world!")};

  // Call zoo with breakpoint set at y=0.
  DebugEventCounterClear();
  bp = SetBreakPoint(zoo, zoo_break_position);
  checks = checks_hu;
  zoo->Call(env->Global(), 1, argv_zoo);
  CHECK_EQ(1, break_point_hit_count);
  ClearBreakPoint(bp);

2313 2314 2315 2316 2317 2318 2319 2320 2321 2322 2323 2324 2325 2326 2327 2328 2329 2330 2331 2332 2333 2334 2335 2336
  // Test function with an inner function. The "y=0" is in function barbar
  // to provide a break location. For "y=0" the "y" is at position 8 in the
  // barbar function therefore setting breakpoint at position 8 will break at
  // "y=0" and setting it higher will break after.
  v8::Local<v8::Function> bar = CompileFunction(&env,
    "y = 0;"
    "x = 'Goodbye, world!';"
    "function bar(x, b) {"
    "  var a;"
    "  function barbar() {"
    "    y=0; /* To ensure break location.*/"
    "    a=x;"
    "  };"
    "  debug.Debug.clearAllBreakPoints();"
    "  barbar();"
    "  y=0;a=x;"
    "}",
    "bar");
  const int barbar_break_position = 8;

  // Call bar setting breakpoint before a=x in barbar and undefined as
  // parameter.
  checks = checks_uu;
  v8::Handle<v8::Value> argv_bar_1[2] = {
2337
    v8::Undefined(isolate),
2338
    v8::Number::New(isolate, barbar_break_position)
2339 2340 2341 2342 2343 2344 2345
  };
  bar->Call(env->Global(), 2, argv_bar_1);

  // Call bar setting breakpoint before a=x in barbar and parameter
  // "Hello, world!".
  checks = checks_hu;
  v8::Handle<v8::Value> argv_bar_2[2] = {
2346
    v8::String::NewFromUtf8(env->GetIsolate(), "Hello, world!"),
2347
    v8::Number::New(env->GetIsolate(), barbar_break_position)
2348 2349 2350 2351 2352 2353 2354
  };
  bar->Call(env->Global(), 2, argv_bar_2);

  // Call bar setting breakpoint after a=x in barbar and parameter
  // "Hello, world!".
  checks = checks_hh;
  v8::Handle<v8::Value> argv_bar_3[2] = {
2355
    v8::String::NewFromUtf8(env->GetIsolate(), "Hello, world!"),
2356
    v8::Number::New(env->GetIsolate(), barbar_break_position + 1)
2357 2358 2359
  };
  bar->Call(env->Global(), 2, argv_bar_3);

2360
  v8::Debug::SetDebugEventListener(NULL);
2361
  CheckDebuggerUnloaded();
2362 2363
}

2364 2365 2366 2367 2368 2369

int debugEventCount = 0;
static void CheckDebugEvent(const v8::Debug::EventDetails& eventDetails) {
  if (eventDetails.GetEvent() == v8::Break) ++debugEventCount;
}

2370

2371 2372 2373 2374
// Test that the conditional breakpoints work event if code generation from
// strings is prohibited in the debugee context.
TEST(ConditionalBreakpointWithCodeGenerationDisallowed) {
  DebugLocalContext env;
2375
  v8::HandleScope scope(env->GetIsolate());
2376 2377
  env.ExposeDebug();

2378
  v8::Debug::SetDebugEventListener(CheckDebugEvent);
2379 2380 2381 2382 2383 2384 2385 2386 2387 2388 2389 2390 2391 2392 2393 2394

  v8::Local<v8::Function> foo = CompileFunction(&env,
    "function foo(x) {\n"
    "  var s = 'String value2';\n"
    "  return s + x;\n"
    "}",
    "foo");

  // Set conditional breakpoint with condition 'true'.
  CompileRun("debug.Debug.setBreakPoint(foo, 2, 0, 'true')");

  debugEventCount = 0;
  env->AllowCodeGenerationFromStrings(false);
  foo->Call(env->Global(), 0, NULL);
  CHECK_EQ(1, debugEventCount);

2395
  v8::Debug::SetDebugEventListener(NULL);
2396 2397 2398 2399 2400 2401 2402 2403 2404 2405
  CheckDebuggerUnloaded();
}


bool checkedDebugEvals = true;
v8::Handle<v8::Function> checkGlobalEvalFunction;
v8::Handle<v8::Function> checkFrameEvalFunction;
static void CheckDebugEval(const v8::Debug::EventDetails& eventDetails) {
  if (eventDetails.GetEvent() == v8::Break) {
    ++debugEventCount;
2406
    v8::HandleScope handleScope(CcTest::isolate());
2407 2408 2409 2410 2411 2412 2413 2414 2415

    v8::Handle<v8::Value> args[] = { eventDetails.GetExecutionState() };
    CHECK(checkGlobalEvalFunction->Call(
        eventDetails.GetEventContext()->Global(), 1, args)->IsTrue());
    CHECK(checkFrameEvalFunction->Call(
        eventDetails.GetEventContext()->Global(), 1, args)->IsTrue());
  }
}

2416

2417 2418 2419 2420 2421
// Test that the evaluation of expressions when a break point is hit generates
// the correct results in case code generation from strings is disallowed in the
// debugee context.
TEST(DebugEvaluateWithCodeGenerationDisallowed) {
  DebugLocalContext env;
2422
  v8::HandleScope scope(env->GetIsolate());
2423 2424
  env.ExposeDebug();

2425
  v8::Debug::SetDebugEventListener(CheckDebugEval);
2426 2427 2428 2429 2430 2431 2432 2433 2434 2435 2436 2437 2438 2439 2440 2441 2442 2443 2444 2445 2446 2447 2448 2449 2450 2451 2452

  v8::Local<v8::Function> foo = CompileFunction(&env,
    "var global = 'Global';\n"
    "function foo(x) {\n"
    "  var local = 'Local';\n"
    "  debugger;\n"
    "  return local + x;\n"
    "}",
    "foo");
  checkGlobalEvalFunction = CompileFunction(&env,
    "function checkGlobalEval(exec_state) {\n"
    "  return exec_state.evaluateGlobal('global').value() === 'Global';\n"
    "}",
    "checkGlobalEval");

  checkFrameEvalFunction = CompileFunction(&env,
    "function checkFrameEval(exec_state) {\n"
    "  return exec_state.frame(0).evaluate('local').value() === 'Local';\n"
    "}",
    "checkFrameEval");
  debugEventCount = 0;
  env->AllowCodeGenerationFromStrings(false);
  foo->Call(env->Global(), 0, NULL);
  CHECK_EQ(1, debugEventCount);

  checkGlobalEvalFunction.Clear();
  checkFrameEvalFunction.Clear();
2453
  v8::Debug::SetDebugEventListener(NULL);
2454 2455 2456 2457
  CheckDebuggerUnloaded();
}


2458 2459 2460 2461 2462 2463 2464 2465 2466 2467 2468 2469 2470
// Copies a C string to a 16-bit string.  Does not check for buffer overflow.
// Does not use the V8 engine to convert strings, so it can be used
// in any thread.  Returns the length of the string.
int AsciiToUtf16(const char* input_buffer, uint16_t* output_buffer) {
  int i;
  for (i = 0; input_buffer[i] != '\0'; ++i) {
    // ASCII does not use chars > 127, but be careful anyway.
    output_buffer[i] = static_cast<unsigned char>(input_buffer[i]);
  }
  output_buffer[i] = 0;
  return i;
}

2471

2472 2473 2474 2475 2476 2477 2478 2479 2480 2481 2482 2483 2484 2485 2486 2487 2488 2489 2490 2491 2492
// Copies a 16-bit string to a C string by dropping the high byte of
// each character.  Does not check for buffer overflow.
// Can be used in any thread.  Requires string length as an input.
int Utf16ToAscii(const uint16_t* input_buffer, int length,
                 char* output_buffer, int output_len = -1) {
  if (output_len >= 0) {
    if (length > output_len - 1) {
      length = output_len - 1;
    }
  }

  for (int i = 0; i < length; ++i) {
    output_buffer[i] = static_cast<char>(input_buffer[i]);
  }
  output_buffer[length] = '\0';
  return length;
}


// We match parts of the message to get evaluate result int value.
bool GetEvaluateStringResult(char *message, char* buffer, int buffer_size) {
2493 2494 2495 2496 2497 2498 2499 2500 2501 2502 2503
  if (strstr(message, "\"command\":\"evaluate\"") == NULL) {
    return false;
  }
  const char* prefix = "\"text\":\"";
  char* pos1 = strstr(message, prefix);
  if (pos1 == NULL) {
    return false;
  }
  pos1 += strlen(prefix);
  char* pos2 = strchr(pos1, '"');
  if (pos2 == NULL) {
2504 2505
    return false;
  }
2506
  Vector<char> buf(buffer, buffer_size);
2507
  int len = static_cast<int>(pos2 - pos1);
2508 2509 2510
  if (len > buffer_size - 1) {
    len = buffer_size - 1;
  }
2511
  StrNCpy(buf, pos1, len);
2512
  buffer[buffer_size - 1] = '\0';
2513 2514 2515 2516 2517 2518 2519 2520 2521 2522 2523 2524 2525 2526 2527 2528 2529 2530 2531 2532 2533 2534 2535 2536 2537 2538 2539 2540
  return true;
}


struct EvaluateResult {
  static const int kBufferSize = 20;
  char buffer[kBufferSize];
};

struct DebugProcessDebugMessagesData {
  static const int kArraySize = 5;
  int counter;
  EvaluateResult results[kArraySize];

  void reset() {
    counter = 0;
  }
  EvaluateResult* current() {
    return &results[counter % kArraySize];
  }
  void next() {
    counter++;
  }
};

DebugProcessDebugMessagesData process_debug_messages_data;

static void DebugProcessDebugMessagesHandler(
2541 2542
    const v8::Debug::Message& message) {
  v8::Handle<v8::String> json = message.GetJSON();
2543
  v8::String::Utf8Value utf8(json);
2544 2545
  EvaluateResult* array_item = process_debug_messages_data.current();

2546
  bool res = GetEvaluateStringResult(*utf8,
2547 2548 2549 2550 2551 2552 2553
                                     array_item->buffer,
                                     EvaluateResult::kBufferSize);
  if (res) {
    process_debug_messages_data.next();
  }
}

2554

2555 2556 2557
// Test that the evaluation of expressions works even from ProcessDebugMessages
// i.e. with empty stack.
TEST(DebugEvaluateWithoutStack) {
2558
  v8::Debug::SetMessageHandler(DebugProcessDebugMessagesHandler);
2559 2560

  DebugLocalContext env;
2561
  v8::HandleScope scope(env->GetIsolate());
2562 2563 2564 2565

  const char* source =
      "var v1 = 'Pinguin';\n function getAnimal() { return 'Capy' + 'bara'; }";

2566 2567
  v8::Script::Compile(v8::String::NewFromUtf8(env->GetIsolate(), source))
      ->Run();
2568 2569 2570 2571 2572 2573 2574 2575 2576 2577 2578 2579 2580 2581

  v8::Debug::ProcessDebugMessages();

  const int kBufferSize = 1000;
  uint16_t buffer[kBufferSize];

  const char* command_111 = "{\"seq\":111,"
      "\"type\":\"request\","
      "\"command\":\"evaluate\","
      "\"arguments\":{"
      "    \"global\":true,"
      "    \"expression\":\"v1\",\"disable_break\":true"
      "}}";

2582
  v8::Isolate* isolate = CcTest::isolate();
2583
  v8::Debug::SendCommand(isolate, buffer, AsciiToUtf16(command_111, buffer));
2584 2585 2586 2587 2588 2589 2590 2591 2592

  const char* command_112 = "{\"seq\":112,"
      "\"type\":\"request\","
      "\"command\":\"evaluate\","
      "\"arguments\":{"
      "    \"global\":true,"
      "    \"expression\":\"getAnimal()\",\"disable_break\":true"
      "}}";

2593
  v8::Debug::SendCommand(isolate, buffer, AsciiToUtf16(command_112, buffer));
2594 2595 2596 2597 2598 2599 2600 2601 2602

  const char* command_113 = "{\"seq\":113,"
     "\"type\":\"request\","
     "\"command\":\"evaluate\","
     "\"arguments\":{"
     "    \"global\":true,"
     "    \"expression\":\"239 + 566\",\"disable_break\":true"
     "}}";

2603
  v8::Debug::SendCommand(isolate, buffer, AsciiToUtf16(command_113, buffer));
2604 2605 2606 2607 2608

  v8::Debug::ProcessDebugMessages();

  CHECK_EQ(3, process_debug_messages_data.counter);

peter.rybin@gmail.com's avatar
peter.rybin@gmail.com committed
2609 2610 2611 2612
  CHECK_EQ(strcmp("Pinguin", process_debug_messages_data.results[0].buffer), 0);
  CHECK_EQ(strcmp("Capybara", process_debug_messages_data.results[1].buffer),
           0);
  CHECK_EQ(strcmp("805", process_debug_messages_data.results[2].buffer), 0);
2613

2614 2615
  v8::Debug::SetMessageHandler(NULL);
  v8::Debug::SetDebugEventListener(NULL);
2616 2617 2618
  CheckDebuggerUnloaded();
}

2619 2620 2621

// Simple test of the stepping mechanism using only store ICs.
TEST(DebugStepLinear) {
2622
  DebugLocalContext env;
2623
  v8::HandleScope scope(env->GetIsolate());
2624 2625 2626 2627 2628

  // Create a function for testing stepping.
  v8::Local<v8::Function> foo = CompileFunction(&env,
                                                "function foo(){a=1;b=1;c=1;}",
                                                "foo");
2629 2630 2631 2632

  // Run foo to allow it to get optimized.
  CompileRun("a=0; b=0; c=0; foo();");

2633
  // Register a debug event listener which steps and counts.
2634
  v8::Debug::SetDebugEventListener(DebugEventStep);
2635

2636 2637
  SetBreakPoint(foo, 3);

2638 2639 2640 2641 2642 2643 2644
  step_action = StepIn;
  break_point_hit_count = 0;
  foo->Call(env->Global(), 0, NULL);

  // With stepping all break locations are hit.
  CHECK_EQ(4, break_point_hit_count);

2645
  v8::Debug::SetDebugEventListener(NULL);
2646
  CheckDebuggerUnloaded();
2647 2648

  // Register a debug event listener which just counts.
2649
  v8::Debug::SetDebugEventListener(DebugEventBreakPointHitCount);
2650

2651
  SetBreakPoint(foo, 3);
2652 2653 2654 2655 2656 2657
  break_point_hit_count = 0;
  foo->Call(env->Global(), 0, NULL);

  // Without stepping only active break points are hit.
  CHECK_EQ(1, break_point_hit_count);

2658
  v8::Debug::SetDebugEventListener(NULL);
2659
  CheckDebuggerUnloaded();
2660 2661 2662
}


2663 2664 2665
// Test of the stepping mechanism for keyed load in a loop.
TEST(DebugStepKeyedLoadLoop) {
  DebugLocalContext env;
2666
  v8::HandleScope scope(env->GetIsolate());
2667

2668
  // Register a debug event listener which steps and counts.
2669
  v8::Debug::SetDebugEventListener(DebugEventStep);
2670

2671 2672 2673 2674 2675 2676 2677 2678 2679 2680 2681
  // Create a function for testing stepping of keyed load. The statement 'y=1'
  // is there to have more than one breakable statement in the loop, TODO(315).
  v8::Local<v8::Function> foo = CompileFunction(
      &env,
      "function foo(a) {\n"
      "  var x;\n"
      "  var len = a.length;\n"
      "  for (var i = 0; i < len; i++) {\n"
      "    y = 1;\n"
      "    x = a[i];\n"
      "  }\n"
2682 2683
      "}\n"
      "y=0\n",
2684 2685 2686
      "foo");

  // Create array [0,1,2,3,4,5,6,7,8,9]
2687
  v8::Local<v8::Array> a = v8::Array::New(env->GetIsolate(), 10);
2688
  for (int i = 0; i < 10; i++) {
2689 2690
    a->Set(v8::Number::New(env->GetIsolate(), i),
           v8::Number::New(env->GetIsolate(), i));
2691 2692 2693 2694 2695 2696 2697
  }

  // Call function without any break points to ensure inlining is in place.
  const int kArgc = 1;
  v8::Handle<v8::Value> args[kArgc] = { a };
  foo->Call(env->Global(), kArgc, args);

2698
  // Set up break point and step through the function.
2699 2700 2701 2702 2703 2704
  SetBreakPoint(foo, 3);
  step_action = StepNext;
  break_point_hit_count = 0;
  foo->Call(env->Global(), kArgc, args);

  // With stepping all break locations are hit.
2705
  CHECK_EQ(45, break_point_hit_count);
2706

2707
  v8::Debug::SetDebugEventListener(NULL);
2708 2709 2710 2711
  CheckDebuggerUnloaded();
}


2712 2713 2714
// Test of the stepping mechanism for keyed store in a loop.
TEST(DebugStepKeyedStoreLoop) {
  DebugLocalContext env;
2715
  v8::HandleScope scope(env->GetIsolate());
2716

2717
  // Register a debug event listener which steps and counts.
2718
  v8::Debug::SetDebugEventListener(DebugEventStep);
2719

2720 2721 2722 2723 2724 2725 2726 2727 2728 2729
  // Create a function for testing stepping of keyed store. The statement 'y=1'
  // is there to have more than one breakable statement in the loop, TODO(315).
  v8::Local<v8::Function> foo = CompileFunction(
      &env,
      "function foo(a) {\n"
      "  var len = a.length;\n"
      "  for (var i = 0; i < len; i++) {\n"
      "    y = 1;\n"
      "    a[i] = 42;\n"
      "  }\n"
2730 2731
      "}\n"
      "y=0\n",
2732 2733 2734
      "foo");

  // Create array [0,1,2,3,4,5,6,7,8,9]
2735
  v8::Local<v8::Array> a = v8::Array::New(env->GetIsolate(), 10);
2736
  for (int i = 0; i < 10; i++) {
2737 2738
    a->Set(v8::Number::New(env->GetIsolate(), i),
           v8::Number::New(env->GetIsolate(), i));
2739 2740 2741 2742 2743 2744 2745
  }

  // Call function without any break points to ensure inlining is in place.
  const int kArgc = 1;
  v8::Handle<v8::Value> args[kArgc] = { a };
  foo->Call(env->Global(), kArgc, args);

2746
  // Set up break point and step through the function.
2747 2748 2749 2750 2751 2752
  SetBreakPoint(foo, 3);
  step_action = StepNext;
  break_point_hit_count = 0;
  foo->Call(env->Global(), kArgc, args);

  // With stepping all break locations are hit.
2753
  CHECK_EQ(44, break_point_hit_count);
2754

2755
  v8::Debug::SetDebugEventListener(NULL);
2756 2757 2758 2759
  CheckDebuggerUnloaded();
}


2760 2761 2762
// Test of the stepping mechanism for named load in a loop.
TEST(DebugStepNamedLoadLoop) {
  DebugLocalContext env;
2763
  v8::HandleScope scope(env->GetIsolate());
2764

2765
  // Register a debug event listener which steps and counts.
2766
  v8::Debug::SetDebugEventListener(DebugEventStep);
2767

2768 2769 2770 2771 2772 2773 2774 2775 2776 2777 2778 2779 2780 2781 2782 2783 2784 2785 2786 2787 2788 2789
  // Create a function for testing stepping of named load.
  v8::Local<v8::Function> foo = CompileFunction(
      &env,
      "function foo() {\n"
          "  var a = [];\n"
          "  var s = \"\";\n"
          "  for (var i = 0; i < 10; i++) {\n"
          "    var v = new V(i, i + 1);\n"
          "    v.y;\n"
          "    a.length;\n"  // Special case: array length.
          "    s.length;\n"  // Special case: string length.
          "  }\n"
          "}\n"
          "function V(x, y) {\n"
          "  this.x = x;\n"
          "  this.y = y;\n"
          "}\n",
          "foo");

  // Call function without any break points to ensure inlining is in place.
  foo->Call(env->Global(), 0, NULL);

2790
  // Set up break point and step through the function.
2791 2792 2793 2794 2795 2796
  SetBreakPoint(foo, 4);
  step_action = StepNext;
  break_point_hit_count = 0;
  foo->Call(env->Global(), 0, NULL);

  // With stepping all break locations are hit.
2797
  CHECK_EQ(65, break_point_hit_count);
2798

2799
  v8::Debug::SetDebugEventListener(NULL);
2800 2801 2802 2803
  CheckDebuggerUnloaded();
}


2804
static void DoDebugStepNamedStoreLoop(int expected) {
2805
  DebugLocalContext env;
2806
  v8::HandleScope scope(env->GetIsolate());
2807

2808
  // Register a debug event listener which steps and counts.
2809
  v8::Debug::SetDebugEventListener(DebugEventStep);
2810 2811 2812 2813 2814 2815 2816 2817 2818 2819 2820 2821 2822 2823 2824

  // Create a function for testing stepping of named store.
  v8::Local<v8::Function> foo = CompileFunction(
      &env,
      "function foo() {\n"
          "  var a = {a:1};\n"
          "  for (var i = 0; i < 10; i++) {\n"
          "    a.a = 2\n"
          "  }\n"
          "}\n",
          "foo");

  // Call function without any break points to ensure inlining is in place.
  foo->Call(env->Global(), 0, NULL);

2825
  // Set up break point and step through the function.
2826 2827 2828 2829 2830 2831 2832 2833
  SetBreakPoint(foo, 3);
  step_action = StepNext;
  break_point_hit_count = 0;
  foo->Call(env->Global(), 0, NULL);

  // With stepping all expected break locations are hit.
  CHECK_EQ(expected, break_point_hit_count);

2834
  v8::Debug::SetDebugEventListener(NULL);
2835 2836 2837 2838 2839
  CheckDebuggerUnloaded();
}


// Test of the stepping mechanism for named load in a loop.
2840
TEST(DebugStepNamedStoreLoop) { DoDebugStepNamedStoreLoop(34); }
2841 2842


2843 2844
// Test the stepping mechanism with different ICs.
TEST(DebugStepLinearMixedICs) {
2845
  DebugLocalContext env;
2846
  v8::HandleScope scope(env->GetIsolate());
2847

2848
  // Register a debug event listener which steps and counts.
2849
  v8::Debug::SetDebugEventListener(DebugEventStep);
2850

2851 2852 2853 2854 2855 2856 2857 2858
  // Create a function for testing stepping.
  v8::Local<v8::Function> foo = CompileFunction(&env,
      "function bar() {};"
      "function foo() {"
      "  var x;"
      "  var index='name';"
      "  var y = {};"
      "  a=1;b=2;x=a;y[index]=3;x=y[index];bar();}", "foo");
2859 2860 2861 2862

  // Run functions to allow them to get optimized.
  CompileRun("a=0; b=0; bar(); foo();");

2863 2864 2865 2866 2867 2868
  SetBreakPoint(foo, 0);

  step_action = StepIn;
  break_point_hit_count = 0;
  foo->Call(env->Global(), 0, NULL);

2869
  // With stepping all break locations are hit.
2870
  CHECK_EQ(11, break_point_hit_count);
2871

2872
  v8::Debug::SetDebugEventListener(NULL);
2873
  CheckDebuggerUnloaded();
2874 2875

  // Register a debug event listener which just counts.
2876
  v8::Debug::SetDebugEventListener(DebugEventBreakPointHitCount);
2877

2878
  SetBreakPoint(foo, 0);
2879 2880 2881 2882 2883 2884
  break_point_hit_count = 0;
  foo->Call(env->Global(), 0, NULL);

  // Without stepping only active break points are hit.
  CHECK_EQ(1, break_point_hit_count);

2885
  v8::Debug::SetDebugEventListener(NULL);
2886
  CheckDebuggerUnloaded();
2887 2888 2889
}


2890 2891
TEST(DebugStepDeclarations) {
  DebugLocalContext env;
2892
  v8::HandleScope scope(env->GetIsolate());
2893 2894

  // Register a debug event listener which steps and counts.
2895
  v8::Debug::SetDebugEventListener(DebugEventStep);
2896

2897 2898
  // Create a function for testing stepping. Run it to allow it to get
  // optimized.
2899 2900 2901 2902 2903 2904
  const char* src = "function foo() { "
                    "  var a;"
                    "  var b = 1;"
                    "  var c = foo;"
                    "  var d = Math.floor;"
                    "  var e = b + d(1.2);"
2905 2906
                    "}"
                    "foo()";
2907
  v8::Local<v8::Function> foo = CompileFunction(&env, src, "foo");
2908

2909 2910 2911 2912 2913 2914 2915 2916 2917
  SetBreakPoint(foo, 0);

  // Stepping through the declarations.
  step_action = StepIn;
  break_point_hit_count = 0;
  foo->Call(env->Global(), 0, NULL);
  CHECK_EQ(6, break_point_hit_count);

  // Get rid of the debug event listener.
2918
  v8::Debug::SetDebugEventListener(NULL);
2919 2920 2921 2922 2923 2924
  CheckDebuggerUnloaded();
}


TEST(DebugStepLocals) {
  DebugLocalContext env;
2925
  v8::HandleScope scope(env->GetIsolate());
2926 2927

  // Register a debug event listener which steps and counts.
2928
  v8::Debug::SetDebugEventListener(DebugEventStep);
2929

2930 2931
  // Create a function for testing stepping. Run it to allow it to get
  // optimized.
2932 2933 2934 2935 2936 2937
  const char* src = "function foo() { "
                    "  var a,b;"
                    "  a = 1;"
                    "  b = a + 2;"
                    "  b = 1 + 2 + 3;"
                    "  a = Math.floor(b);"
2938 2939
                    "}"
                    "foo()";
2940
  v8::Local<v8::Function> foo = CompileFunction(&env, src, "foo");
2941

2942 2943 2944 2945 2946 2947 2948 2949 2950
  SetBreakPoint(foo, 0);

  // Stepping through the declarations.
  step_action = StepIn;
  break_point_hit_count = 0;
  foo->Call(env->Global(), 0, NULL);
  CHECK_EQ(6, break_point_hit_count);

  // Get rid of the debug event listener.
2951
  v8::Debug::SetDebugEventListener(NULL);
2952 2953 2954 2955
  CheckDebuggerUnloaded();
}


2956
TEST(DebugStepIf) {
2957
  DebugLocalContext env;
2958 2959
  v8::Isolate* isolate = env->GetIsolate();
  v8::HandleScope scope(isolate);
2960 2961

  // Register a debug event listener which steps and counts.
2962
  v8::Debug::SetDebugEventListener(DebugEventStep);
2963

2964 2965
  // Create a function for testing stepping. Run it to allow it to get
  // optimized.
2966 2967 2968 2969 2970 2971 2972 2973 2974
  const int argc = 1;
  const char* src = "function foo(x) { "
                    "  a = 1;"
                    "  if (x) {"
                    "    b = 1;"
                    "  } else {"
                    "    c = 1;"
                    "    d = 1;"
                    "  }"
2975 2976
                    "}"
                    "a=0; b=0; c=0; d=0; foo()";
2977 2978 2979 2980 2981 2982
  v8::Local<v8::Function> foo = CompileFunction(&env, src, "foo");
  SetBreakPoint(foo, 0);

  // Stepping through the true part.
  step_action = StepIn;
  break_point_hit_count = 0;
2983
  v8::Handle<v8::Value> argv_true[argc] = { v8::True(isolate) };
2984
  foo->Call(env->Global(), argc, argv_true);
2985
  CHECK_EQ(4, break_point_hit_count);
2986 2987 2988 2989

  // Stepping through the false part.
  step_action = StepIn;
  break_point_hit_count = 0;
2990
  v8::Handle<v8::Value> argv_false[argc] = { v8::False(isolate) };
2991
  foo->Call(env->Global(), argc, argv_false);
2992
  CHECK_EQ(5, break_point_hit_count);
2993 2994

  // Get rid of the debug event listener.
2995
  v8::Debug::SetDebugEventListener(NULL);
2996
  CheckDebuggerUnloaded();
2997 2998 2999 3000
}


TEST(DebugStepSwitch) {
3001
  DebugLocalContext env;
3002 3003
  v8::Isolate* isolate = env->GetIsolate();
  v8::HandleScope scope(isolate);
3004 3005

  // Register a debug event listener which steps and counts.
3006
  v8::Debug::SetDebugEventListener(DebugEventStep);
3007

3008 3009
  // Create a function for testing stepping. Run it to allow it to get
  // optimized.
3010 3011 3012 3013 3014 3015 3016 3017 3018 3019 3020 3021
  const int argc = 1;
  const char* src = "function foo(x) { "
                    "  a = 1;"
                    "  switch (x) {"
                    "    case 1:"
                    "      b = 1;"
                    "    case 2:"
                    "      c = 1;"
                    "      break;"
                    "    case 3:"
                    "      d = 1;"
                    "      e = 1;"
3022
                    "      f = 1;"
3023 3024
                    "      break;"
                    "  }"
3025 3026
                    "}"
                    "a=0; b=0; c=0; d=0; e=0; f=0; foo()";
3027 3028 3029 3030 3031 3032
  v8::Local<v8::Function> foo = CompileFunction(&env, src, "foo");
  SetBreakPoint(foo, 0);

  // One case with fall-through.
  step_action = StepIn;
  break_point_hit_count = 0;
3033
  v8::Handle<v8::Value> argv_1[argc] = { v8::Number::New(isolate, 1) };
3034
  foo->Call(env->Global(), argc, argv_1);
3035
  CHECK_EQ(6, break_point_hit_count);
3036 3037 3038 3039

  // Another case.
  step_action = StepIn;
  break_point_hit_count = 0;
3040
  v8::Handle<v8::Value> argv_2[argc] = { v8::Number::New(isolate, 2) };
3041
  foo->Call(env->Global(), argc, argv_2);
3042
  CHECK_EQ(5, break_point_hit_count);
3043 3044 3045 3046

  // Last case.
  step_action = StepIn;
  break_point_hit_count = 0;
3047
  v8::Handle<v8::Value> argv_3[argc] = { v8::Number::New(isolate, 3) };
3048
  foo->Call(env->Global(), argc, argv_3);
3049 3050 3051
  CHECK_EQ(7, break_point_hit_count);

  // Get rid of the debug event listener.
3052
  v8::Debug::SetDebugEventListener(NULL);
3053 3054 3055 3056 3057 3058
  CheckDebuggerUnloaded();
}


TEST(DebugStepWhile) {
  DebugLocalContext env;
3059 3060
  v8::Isolate* isolate = env->GetIsolate();
  v8::HandleScope scope(isolate);
3061 3062

  // Register a debug event listener which steps and counts.
3063
  v8::Debug::SetDebugEventListener(DebugEventStep);
3064

3065 3066
  // Create a function for testing stepping. Run it to allow it to get
  // optimized.
3067 3068 3069 3070 3071 3072
  const int argc = 1;
  const char* src = "function foo(x) { "
                    "  var a = 0;"
                    "  while (a < x) {"
                    "    a++;"
                    "  }"
3073 3074
                    "}"
                    "foo()";
3075 3076 3077
  v8::Local<v8::Function> foo = CompileFunction(&env, src, "foo");
  SetBreakPoint(foo, 8);  // "var a = 0;"

3078 3079 3080 3081 3082 3083 3084
  // Looping 0 times.  We still should break at the while-condition once.
  step_action = StepIn;
  break_point_hit_count = 0;
  v8::Handle<v8::Value> argv_0[argc] = { v8::Number::New(isolate, 0) };
  foo->Call(env->Global(), argc, argv_0);
  CHECK_EQ(3, break_point_hit_count);

3085 3086 3087
  // Looping 10 times.
  step_action = StepIn;
  break_point_hit_count = 0;
3088
  v8::Handle<v8::Value> argv_10[argc] = { v8::Number::New(isolate, 10) };
3089
  foo->Call(env->Global(), argc, argv_10);
3090
  CHECK_EQ(23, break_point_hit_count);
3091 3092 3093 3094

  // Looping 100 times.
  step_action = StepIn;
  break_point_hit_count = 0;
3095
  v8::Handle<v8::Value> argv_100[argc] = { v8::Number::New(isolate, 100) };
3096
  foo->Call(env->Global(), argc, argv_100);
3097
  CHECK_EQ(203, break_point_hit_count);
3098 3099

  // Get rid of the debug event listener.
3100
  v8::Debug::SetDebugEventListener(NULL);
3101 3102 3103 3104 3105 3106
  CheckDebuggerUnloaded();
}


TEST(DebugStepDoWhile) {
  DebugLocalContext env;
3107 3108
  v8::Isolate* isolate = env->GetIsolate();
  v8::HandleScope scope(isolate);
3109 3110

  // Register a debug event listener which steps and counts.
3111
  v8::Debug::SetDebugEventListener(DebugEventStep);
3112

3113 3114
  // Create a function for testing stepping. Run it to allow it to get
  // optimized.
3115 3116 3117 3118 3119 3120
  const int argc = 1;
  const char* src = "function foo(x) { "
                    "  var a = 0;"
                    "  do {"
                    "    a++;"
                    "  } while (a < x)"
3121 3122
                    "}"
                    "foo()";
3123 3124 3125
  v8::Local<v8::Function> foo = CompileFunction(&env, src, "foo");
  SetBreakPoint(foo, 8);  // "var a = 0;"

3126 3127 3128 3129 3130 3131 3132
  // Looping 0 times.
  step_action = StepIn;
  break_point_hit_count = 0;
  v8::Handle<v8::Value> argv_0[argc] = {v8::Number::New(isolate, 0)};
  foo->Call(env->Global(), argc, argv_0);
  CHECK_EQ(4, break_point_hit_count);

3133 3134 3135
  // Looping 10 times.
  step_action = StepIn;
  break_point_hit_count = 0;
3136
  v8::Handle<v8::Value> argv_10[argc] = { v8::Number::New(isolate, 10) };
3137 3138 3139 3140 3141 3142
  foo->Call(env->Global(), argc, argv_10);
  CHECK_EQ(22, break_point_hit_count);

  // Looping 100 times.
  step_action = StepIn;
  break_point_hit_count = 0;
3143
  v8::Handle<v8::Value> argv_100[argc] = { v8::Number::New(isolate, 100) };
3144 3145
  foo->Call(env->Global(), argc, argv_100);
  CHECK_EQ(202, break_point_hit_count);
3146 3147

  // Get rid of the debug event listener.
3148
  v8::Debug::SetDebugEventListener(NULL);
3149
  CheckDebuggerUnloaded();
3150 3151 3152 3153
}


TEST(DebugStepFor) {
3154
  DebugLocalContext env;
3155 3156
  v8::Isolate* isolate = env->GetIsolate();
  v8::HandleScope scope(isolate);
3157 3158

  // Register a debug event listener which steps and counts.
3159
  v8::Debug::SetDebugEventListener(DebugEventStep);
3160

3161 3162
  // Create a function for testing stepping. Run it to allow it to get
  // optimized.
3163 3164 3165 3166 3167 3168
  const int argc = 1;
  const char* src = "function foo(x) { "
                    "  a = 1;"
                    "  for (i = 0; i < x; i++) {"
                    "    b = 1;"
                    "  }"
3169 3170
                    "}"
                    "a=0; b=0; i=0; foo()";
3171
  v8::Local<v8::Function> foo = CompileFunction(&env, src, "foo");
3172

3173 3174
  SetBreakPoint(foo, 8);  // "a = 1;"

3175 3176 3177 3178 3179 3180 3181
  // Looping 0 times.
  step_action = StepIn;
  break_point_hit_count = 0;
  v8::Handle<v8::Value> argv_0[argc] = {v8::Number::New(isolate, 0)};
  foo->Call(env->Global(), argc, argv_0);
  CHECK_EQ(4, break_point_hit_count);

3182 3183 3184
  // Looping 10 times.
  step_action = StepIn;
  break_point_hit_count = 0;
3185
  v8::Handle<v8::Value> argv_10[argc] = { v8::Number::New(isolate, 10) };
3186
  foo->Call(env->Global(), argc, argv_10);
3187
  CHECK_EQ(34, break_point_hit_count);
3188 3189 3190 3191

  // Looping 100 times.
  step_action = StepIn;
  break_point_hit_count = 0;
3192
  v8::Handle<v8::Value> argv_100[argc] = { v8::Number::New(isolate, 100) };
3193
  foo->Call(env->Global(), argc, argv_100);
3194
  CHECK_EQ(304, break_point_hit_count);
3195 3196

  // Get rid of the debug event listener.
3197
  v8::Debug::SetDebugEventListener(NULL);
3198
  CheckDebuggerUnloaded();
3199 3200 3201
}


3202 3203
TEST(DebugStepForContinue) {
  DebugLocalContext env;
3204 3205
  v8::Isolate* isolate = env->GetIsolate();
  v8::HandleScope scope(isolate);
3206 3207

  // Register a debug event listener which steps and counts.
3208
  v8::Debug::SetDebugEventListener(DebugEventStep);
3209

3210 3211
  // Create a function for testing stepping. Run it to allow it to get
  // optimized.
3212 3213 3214 3215 3216 3217 3218 3219 3220 3221 3222 3223
  const int argc = 1;
  const char* src = "function foo(x) { "
                    "  var a = 0;"
                    "  var b = 0;"
                    "  var c = 0;"
                    "  for (var i = 0; i < x; i++) {"
                    "    a++;"
                    "    if (a % 2 == 0) continue;"
                    "    b++;"
                    "    c++;"
                    "  }"
                    "  return b;"
3224 3225
                    "}"
                    "foo()";
3226 3227 3228 3229 3230 3231 3232 3233 3234
  v8::Local<v8::Function> foo = CompileFunction(&env, src, "foo");
  v8::Handle<v8::Value> result;
  SetBreakPoint(foo, 8);  // "var a = 0;"

  // Each loop generates 4 or 5 steps depending on whether a is equal.

  // Looping 10 times.
  step_action = StepIn;
  break_point_hit_count = 0;
3235
  v8::Handle<v8::Value> argv_10[argc] = { v8::Number::New(isolate, 10) };
3236 3237
  result = foo->Call(env->Global(), argc, argv_10);
  CHECK_EQ(5, result->Int32Value());
3238
  CHECK_EQ(62, break_point_hit_count);
3239 3240 3241 3242

  // Looping 100 times.
  step_action = StepIn;
  break_point_hit_count = 0;
3243
  v8::Handle<v8::Value> argv_100[argc] = { v8::Number::New(isolate, 100) };
3244 3245
  result = foo->Call(env->Global(), argc, argv_100);
  CHECK_EQ(50, result->Int32Value());
3246
  CHECK_EQ(557, break_point_hit_count);
3247 3248

  // Get rid of the debug event listener.
3249
  v8::Debug::SetDebugEventListener(NULL);
3250 3251 3252 3253 3254 3255
  CheckDebuggerUnloaded();
}


TEST(DebugStepForBreak) {
  DebugLocalContext env;
3256 3257
  v8::Isolate* isolate = env->GetIsolate();
  v8::HandleScope scope(isolate);
3258 3259

  // Register a debug event listener which steps and counts.
3260
  v8::Debug::SetDebugEventListener(DebugEventStep);
3261

3262 3263
  // Create a function for testing stepping. Run it to allow it to get
  // optimized.
3264 3265 3266 3267 3268 3269 3270 3271 3272 3273 3274 3275
  const int argc = 1;
  const char* src = "function foo(x) { "
                    "  var a = 0;"
                    "  var b = 0;"
                    "  var c = 0;"
                    "  for (var i = 0; i < 1000; i++) {"
                    "    a++;"
                    "    if (a == x) break;"
                    "    b++;"
                    "    c++;"
                    "  }"
                    "  return b;"
3276 3277
                    "}"
                    "foo()";
3278 3279 3280 3281 3282 3283 3284 3285 3286 3287
  v8::Local<v8::Function> foo = CompileFunction(&env, src, "foo");
  v8::Handle<v8::Value> result;
  SetBreakPoint(foo, 8);  // "var a = 0;"

  // Each loop generates 5 steps except for the last (when break is executed)
  // which only generates 4.

  // Looping 10 times.
  step_action = StepIn;
  break_point_hit_count = 0;
3288
  v8::Handle<v8::Value> argv_10[argc] = { v8::Number::New(isolate, 10) };
3289 3290
  result = foo->Call(env->Global(), argc, argv_10);
  CHECK_EQ(9, result->Int32Value());
3291
  CHECK_EQ(64, break_point_hit_count);
3292 3293 3294 3295

  // Looping 100 times.
  step_action = StepIn;
  break_point_hit_count = 0;
3296
  v8::Handle<v8::Value> argv_100[argc] = { v8::Number::New(isolate, 100) };
3297 3298
  result = foo->Call(env->Global(), argc, argv_100);
  CHECK_EQ(99, result->Int32Value());
3299
  CHECK_EQ(604, break_point_hit_count);
3300 3301

  // Get rid of the debug event listener.
3302
  v8::Debug::SetDebugEventListener(NULL);
3303 3304 3305 3306 3307 3308
  CheckDebuggerUnloaded();
}


TEST(DebugStepForIn) {
  DebugLocalContext env;
3309
  v8::HandleScope scope(env->GetIsolate());
3310 3311

  // Register a debug event listener which steps and counts.
3312
  v8::Debug::SetDebugEventListener(DebugEventStep);
3313

3314 3315
  // Create a function for testing stepping. Run it to allow it to get
  // optimized.
3316 3317 3318 3319 3320 3321
  v8::Local<v8::Function> foo;
  const char* src_1 = "function foo() { "
                      "  var a = [1, 2];"
                      "  for (x in a) {"
                      "    b = 0;"
                      "  }"
3322 3323
                      "}"
                      "foo()";
3324 3325 3326 3327 3328 3329
  foo = CompileFunction(&env, src_1, "foo");
  SetBreakPoint(foo, 0);  // "var a = ..."

  step_action = StepIn;
  break_point_hit_count = 0;
  foo->Call(env->Global(), 0, NULL);
3330
  CHECK_EQ(8, break_point_hit_count);
3331

3332 3333
  // Create a function for testing stepping. Run it to allow it to get
  // optimized.
3334 3335 3336 3337 3338
  const char* src_2 = "function foo() { "
                      "  var a = {a:[1, 2, 3]};"
                      "  for (x in a.a) {"
                      "    b = 0;"
                      "  }"
3339 3340
                      "}"
                      "foo()";
3341 3342 3343 3344 3345 3346
  foo = CompileFunction(&env, src_2, "foo");
  SetBreakPoint(foo, 0);  // "var a = ..."

  step_action = StepIn;
  break_point_hit_count = 0;
  foo->Call(env->Global(), 0, NULL);
3347
  CHECK_EQ(10, break_point_hit_count);
3348 3349

  // Get rid of the debug event listener.
3350
  v8::Debug::SetDebugEventListener(NULL);
3351 3352 3353 3354 3355 3356
  CheckDebuggerUnloaded();
}


TEST(DebugStepWith) {
  DebugLocalContext env;
3357
  v8::HandleScope scope(env->GetIsolate());
3358 3359

  // Register a debug event listener which steps and counts.
3360
  v8::Debug::SetDebugEventListener(DebugEventStep);
3361

3362 3363
  // Create a function for testing stepping. Run it to allow it to get
  // optimized.
3364 3365 3366 3367
  const char* src = "function foo(x) { "
                    "  var a = {};"
                    "  with (a) {}"
                    "  with (b) {}"
3368 3369
                    "}"
                    "foo()";
3370
  env->Global()->Set(v8::String::NewFromUtf8(env->GetIsolate(), "b"),
3371
                     v8::Object::New(env->GetIsolate()));
3372 3373 3374 3375 3376 3377 3378 3379 3380 3381
  v8::Local<v8::Function> foo = CompileFunction(&env, src, "foo");
  v8::Handle<v8::Value> result;
  SetBreakPoint(foo, 8);  // "var a = {};"

  step_action = StepIn;
  break_point_hit_count = 0;
  foo->Call(env->Global(), 0, NULL);
  CHECK_EQ(4, break_point_hit_count);

  // Get rid of the debug event listener.
3382
  v8::Debug::SetDebugEventListener(NULL);
3383 3384 3385 3386 3387 3388
  CheckDebuggerUnloaded();
}


TEST(DebugConditional) {
  DebugLocalContext env;
3389 3390
  v8::Isolate* isolate = env->GetIsolate();
  v8::HandleScope scope(isolate);
3391 3392

  // Register a debug event listener which steps and counts.
3393
  v8::Debug::SetDebugEventListener(DebugEventStep);
3394

3395 3396
  // Create a function for testing stepping. Run it to allow it to get
  // optimized.
3397 3398 3399 3400
  const char* src = "function foo(x) { "
                    "  var a;"
                    "  a = x ? 1 : 2;"
                    "  return a;"
3401 3402
                    "}"
                    "foo()";
3403 3404 3405 3406 3407 3408
  v8::Local<v8::Function> foo = CompileFunction(&env, src, "foo");
  SetBreakPoint(foo, 0);  // "var a;"

  step_action = StepIn;
  break_point_hit_count = 0;
  foo->Call(env->Global(), 0, NULL);
3409
  CHECK_EQ(4, break_point_hit_count);
3410 3411 3412 3413

  step_action = StepIn;
  break_point_hit_count = 0;
  const int argc = 1;
3414
  v8::Handle<v8::Value> argv_true[argc] = { v8::True(isolate) };
3415
  foo->Call(env->Global(), argc, argv_true);
3416
  CHECK_EQ(4, break_point_hit_count);
3417 3418

  // Get rid of the debug event listener.
3419
  v8::Debug::SetDebugEventListener(NULL);
3420 3421 3422 3423
  CheckDebuggerUnloaded();
}


3424
TEST(StepInOutSimple) {
3425
  DebugLocalContext env;
3426
  v8::HandleScope scope(env->GetIsolate());
3427 3428 3429 3430 3431 3432 3433

  // Create a function for checking the function when hitting a break point.
  frame_function_name = CompileFunction(&env,
                                        frame_function_name_source,
                                        "frame_function_name");

  // Register a debug event listener which steps and counts.
3434
  v8::Debug::SetDebugEventListener(DebugEventStepSequence);
3435

3436 3437
  // Create a function for testing stepping. Run it to allow it to get
  // optimized.
3438 3439
  const char* src = "function a() {b();c();}; "
                    "function b() {c();}; "
3440 3441
                    "function c() {}; "
                    "a(); b(); c()";
3442 3443 3444 3445 3446 3447 3448 3449
  v8::Local<v8::Function> a = CompileFunction(&env, src, "a");
  SetBreakPoint(a, 0);

  // Step through invocation of a with step in.
  step_action = StepIn;
  break_point_hit_count = 0;
  expected_step_sequence = "abcbaca";
  a->Call(env->Global(), 0, NULL);
3450 3451
  CHECK_EQ(StrLength(expected_step_sequence),
           break_point_hit_count);
3452 3453 3454 3455 3456 3457

  // Step through invocation of a with step next.
  step_action = StepNext;
  break_point_hit_count = 0;
  expected_step_sequence = "aaa";
  a->Call(env->Global(), 0, NULL);
3458 3459
  CHECK_EQ(StrLength(expected_step_sequence),
           break_point_hit_count);
3460 3461 3462 3463 3464 3465

  // Step through invocation of a with step out.
  step_action = StepOut;
  break_point_hit_count = 0;
  expected_step_sequence = "a";
  a->Call(env->Global(), 0, NULL);
3466 3467
  CHECK_EQ(StrLength(expected_step_sequence),
           break_point_hit_count);
3468 3469

  // Get rid of the debug event listener.
3470
  v8::Debug::SetDebugEventListener(NULL);
3471
  CheckDebuggerUnloaded();
3472 3473 3474 3475
}


TEST(StepInOutTree) {
3476
  DebugLocalContext env;
3477
  v8::HandleScope scope(env->GetIsolate());
3478 3479 3480 3481 3482 3483 3484

  // Create a function for checking the function when hitting a break point.
  frame_function_name = CompileFunction(&env,
                                        frame_function_name_source,
                                        "frame_function_name");

  // Register a debug event listener which steps and counts.
3485
  v8::Debug::SetDebugEventListener(DebugEventStepSequence);
3486

3487 3488
  // Create a function for testing stepping. Run it to allow it to get
  // optimized.
3489 3490 3491
  const char* src = "function a() {b(c(d()),d());c(d());d()}; "
                    "function b(x,y) {c();}; "
                    "function c(x) {}; "
3492 3493
                    "function d() {}; "
                    "a(); b(); c(); d()";
3494 3495 3496 3497 3498 3499 3500 3501
  v8::Local<v8::Function> a = CompileFunction(&env, src, "a");
  SetBreakPoint(a, 0);

  // Step through invocation of a with step in.
  step_action = StepIn;
  break_point_hit_count = 0;
  expected_step_sequence = "adacadabcbadacada";
  a->Call(env->Global(), 0, NULL);
3502 3503
  CHECK_EQ(StrLength(expected_step_sequence),
           break_point_hit_count);
3504 3505 3506 3507 3508 3509

  // Step through invocation of a with step next.
  step_action = StepNext;
  break_point_hit_count = 0;
  expected_step_sequence = "aaaa";
  a->Call(env->Global(), 0, NULL);
3510 3511
  CHECK_EQ(StrLength(expected_step_sequence),
           break_point_hit_count);
3512 3513 3514 3515 3516 3517

  // Step through invocation of a with step out.
  step_action = StepOut;
  break_point_hit_count = 0;
  expected_step_sequence = "a";
  a->Call(env->Global(), 0, NULL);
3518 3519
  CHECK_EQ(StrLength(expected_step_sequence),
           break_point_hit_count);
3520 3521

  // Get rid of the debug event listener.
3522
  v8::Debug::SetDebugEventListener(NULL);
3523
  CheckDebuggerUnloaded(true);
3524 3525 3526 3527
}


TEST(StepInOutBranch) {
3528
  DebugLocalContext env;
3529
  v8::HandleScope scope(env->GetIsolate());
3530 3531 3532 3533 3534 3535 3536

  // Create a function for checking the function when hitting a break point.
  frame_function_name = CompileFunction(&env,
                                        frame_function_name_source,
                                        "frame_function_name");

  // Register a debug event listener which steps and counts.
3537
  v8::Debug::SetDebugEventListener(DebugEventStepSequence);
3538

3539 3540
  // Create a function for testing stepping. Run it to allow it to get
  // optimized.
3541 3542
  const char* src = "function a() {b(false);c();}; "
                    "function b(x) {if(x){c();};}; "
3543 3544
                    "function c() {}; "
                    "a(); b(); c()";
3545 3546 3547 3548 3549 3550
  v8::Local<v8::Function> a = CompileFunction(&env, src, "a");
  SetBreakPoint(a, 0);

  // Step through invocation of a.
  step_action = StepIn;
  break_point_hit_count = 0;
3551
  expected_step_sequence = "abbaca";
3552
  a->Call(env->Global(), 0, NULL);
3553 3554
  CHECK_EQ(StrLength(expected_step_sequence),
           break_point_hit_count);
3555 3556

  // Get rid of the debug event listener.
3557
  v8::Debug::SetDebugEventListener(NULL);
3558
  CheckDebuggerUnloaded();
3559 3560 3561 3562 3563
}


// Test that step in does not step into native functions.
TEST(DebugStepNatives) {
3564
  DebugLocalContext env;
3565
  v8::HandleScope scope(env->GetIsolate());
3566 3567 3568 3569 3570 3571 3572 3573

  // Create a function for testing stepping.
  v8::Local<v8::Function> foo = CompileFunction(
      &env,
      "function foo(){debugger;Math.sin(1);}",
      "foo");

  // Register a debug event listener which steps and counts.
3574
  v8::Debug::SetDebugEventListener(DebugEventStep);
3575 3576 3577 3578 3579 3580 3581 3582

  step_action = StepIn;
  break_point_hit_count = 0;
  foo->Call(env->Global(), 0, NULL);

  // With stepping all break locations are hit.
  CHECK_EQ(3, break_point_hit_count);

3583
  v8::Debug::SetDebugEventListener(NULL);
3584
  CheckDebuggerUnloaded();
3585 3586

  // Register a debug event listener which just counts.
3587
  v8::Debug::SetDebugEventListener(DebugEventBreakPointHitCount);
3588 3589 3590 3591 3592 3593 3594

  break_point_hit_count = 0;
  foo->Call(env->Global(), 0, NULL);

  // Without stepping only active break points are hit.
  CHECK_EQ(1, break_point_hit_count);

3595
  v8::Debug::SetDebugEventListener(NULL);
3596
  CheckDebuggerUnloaded();
3597 3598 3599
}


3600 3601 3602
// Test that step in works with function.apply.
TEST(DebugStepFunctionApply) {
  DebugLocalContext env;
3603
  v8::HandleScope scope(env->GetIsolate());
3604 3605 3606 3607 3608 3609 3610 3611 3612

  // Create a function for testing stepping.
  v8::Local<v8::Function> foo = CompileFunction(
      &env,
      "function bar(x, y, z) { if (x == 1) { a = y; b = z; } }"
      "function foo(){ debugger; bar.apply(this, [1,2,3]); }",
      "foo");

  // Register a debug event listener which steps and counts.
3613
  v8::Debug::SetDebugEventListener(DebugEventStep);
3614 3615 3616 3617 3618 3619

  step_action = StepIn;
  break_point_hit_count = 0;
  foo->Call(env->Global(), 0, NULL);

  // With stepping all break locations are hit.
3620
  CHECK_EQ(7, break_point_hit_count);
3621

3622
  v8::Debug::SetDebugEventListener(NULL);
3623 3624 3625
  CheckDebuggerUnloaded();

  // Register a debug event listener which just counts.
3626
  v8::Debug::SetDebugEventListener(DebugEventBreakPointHitCount);
3627 3628 3629 3630 3631 3632 3633

  break_point_hit_count = 0;
  foo->Call(env->Global(), 0, NULL);

  // Without stepping only the debugger statement is hit.
  CHECK_EQ(1, break_point_hit_count);

3634
  v8::Debug::SetDebugEventListener(NULL);
3635 3636 3637 3638
  CheckDebuggerUnloaded();
}


3639 3640 3641
// Test that step in works with function.call.
TEST(DebugStepFunctionCall) {
  DebugLocalContext env;
3642 3643
  v8::Isolate* isolate = env->GetIsolate();
  v8::HandleScope scope(isolate);
3644 3645 3646 3647 3648 3649 3650 3651 3652 3653 3654 3655 3656 3657 3658

  // Create a function for testing stepping.
  v8::Local<v8::Function> foo = CompileFunction(
      &env,
      "function bar(x, y, z) { if (x == 1) { a = y; b = z; } }"
      "function foo(a){ debugger;"
      "                 if (a) {"
      "                   bar.call(this, 1, 2, 3);"
      "                 } else {"
      "                   bar.call(this, 0);"
      "                 }"
      "}",
      "foo");

  // Register a debug event listener which steps and counts.
3659
  v8::Debug::SetDebugEventListener(DebugEventStep);
3660 3661 3662 3663 3664
  step_action = StepIn;

  // Check stepping where the if condition in bar is false.
  break_point_hit_count = 0;
  foo->Call(env->Global(), 0, NULL);
3665
  CHECK_EQ(6, break_point_hit_count);
3666 3667 3668 3669

  // Check stepping where the if condition in bar is true.
  break_point_hit_count = 0;
  const int argc = 1;
3670
  v8::Handle<v8::Value> argv[argc] = { v8::True(isolate) };
3671
  foo->Call(env->Global(), argc, argv);
3672
  CHECK_EQ(8, break_point_hit_count);
3673

3674
  v8::Debug::SetDebugEventListener(NULL);
3675 3676 3677
  CheckDebuggerUnloaded();

  // Register a debug event listener which just counts.
3678
  v8::Debug::SetDebugEventListener(DebugEventBreakPointHitCount);
3679 3680 3681 3682 3683 3684 3685

  break_point_hit_count = 0;
  foo->Call(env->Global(), 0, NULL);

  // Without stepping only the debugger statement is hit.
  CHECK_EQ(1, break_point_hit_count);

3686
  v8::Debug::SetDebugEventListener(NULL);
3687 3688 3689 3690
  CheckDebuggerUnloaded();
}


3691 3692 3693 3694 3695 3696 3697 3698 3699 3700 3701 3702 3703 3704 3705 3706 3707 3708 3709 3710 3711 3712 3713 3714 3715 3716 3717 3718 3719 3720 3721 3722 3723 3724 3725 3726 3727 3728 3729 3730 3731 3732
// Test that step in works with Function.call.apply.
TEST(DebugStepFunctionCallApply) {
  DebugLocalContext env;
  v8::Isolate* isolate = env->GetIsolate();
  v8::HandleScope scope(isolate);

  // Create a function for testing stepping.
  v8::Local<v8::Function> foo =
      CompileFunction(&env,
                      "function bar() { }"
                      "function foo(){ debugger;"
                      "                Function.call.apply(bar);"
                      "                Function.call.apply(Function.call, "
                      "[Function.call, bar]);"
                      "}",
                      "foo");

  // Register a debug event listener which steps and counts.
  v8::Debug::SetDebugEventListener(DebugEventStep);
  step_action = StepIn;

  break_point_hit_count = 0;
  foo->Call(env->Global(), 0, NULL);
  CHECK_EQ(5, break_point_hit_count);

  v8::Debug::SetDebugEventListener(NULL);
  CheckDebuggerUnloaded();

  // Register a debug event listener which just counts.
  v8::Debug::SetDebugEventListener(DebugEventBreakPointHitCount);

  break_point_hit_count = 0;
  foo->Call(env->Global(), 0, NULL);

  // Without stepping only the debugger statement is hit.
  CHECK_EQ(1, break_point_hit_count);

  v8::Debug::SetDebugEventListener(NULL);
  CheckDebuggerUnloaded();
}


3733 3734 3735
// Tests that breakpoint will be hit if it's set in script.
TEST(PauseInScript) {
  DebugLocalContext env;
3736
  v8::HandleScope scope(env->GetIsolate());
3737 3738 3739
  env.ExposeDebug();

  // Register a debug event listener which counts.
3740
  v8::Debug::SetDebugEventListener(DebugEventCounter);
3741 3742 3743 3744 3745 3746

  // Create a script that returns a function.
  const char* src = "(function (evt) {})";
  const char* script_name = "StepInHandlerTest";

  // Set breakpoint in the script.
3747
  SetScriptBreakPointByNameFromJS(env->GetIsolate(), script_name, 0, -1);
3748
  break_point_hit_count = 0;
3749

3750 3751
  v8::ScriptOrigin origin(
      v8::String::NewFromUtf8(env->GetIsolate(), script_name),
3752
      v8::Integer::New(env->GetIsolate(), 0));
3753 3754
  v8::Handle<v8::Script> script = v8::Script::Compile(
      v8::String::NewFromUtf8(env->GetIsolate(), src), &origin);
3755 3756 3757
  v8::Local<v8::Value> r = script->Run();

  CHECK(r->IsFunction());
3758
  CHECK_EQ(1, break_point_hit_count);
3759 3760

  // Get rid of the debug event listener.
3761
  v8::Debug::SetDebugEventListener(NULL);
3762 3763 3764 3765
  CheckDebuggerUnloaded();
}


3766 3767 3768 3769 3770 3771 3772
static void DebugEventCounterCheck(int caught, int uncaught, int message) {
  CHECK_EQ(caught, exception_hit_count);
  CHECK_EQ(uncaught, uncaught_exception_hit_count);
  CHECK_EQ(message, message_callback_count);
}


3773 3774
// Test break on exceptions. For each exception break combination the number
// of debug event exception callbacks and message callbacks are collected. The
3775
// number of debug event exception callbacks are used to check that the
3776 3777 3778 3779
// debugger is called correctly and the number of message callbacks is used to
// check that uncaught exceptions are still returned even if there is a break
// for them.
TEST(BreakOnException) {
3780
  DebugLocalContext env;
3781
  v8::HandleScope scope(env->GetIsolate());
3782 3783 3784
  env.ExposeDebug();

  // Create functions for testing break on exception.
3785
  CompileFunction(&env, "function throws(){throw 1;}", "throws");
3786 3787 3788 3789 3790 3791
  v8::Local<v8::Function> caught =
      CompileFunction(&env,
                      "function caught(){try {throws();} catch(e) {};}",
                      "caught");
  v8::Local<v8::Function> notCaught =
      CompileFunction(&env, "function notCaught(){throws();}", "notCaught");
3792 3793 3794 3795 3796 3797 3798 3799 3800
  v8::Local<v8::Function> notCaughtFinally = CompileFunction(
      &env, "function notCaughtFinally(){try{throws();}finally{}}",
      "notCaughtFinally");
  // In this edge case, even though this finally does not propagate the
  // exception, the debugger considers this uncaught, since we want to break
  // at the first throw for the general case where finally implicitly rethrows.
  v8::Local<v8::Function> edgeCaseFinally = CompileFunction(
      &env, "function caughtFinally(){L:try{throws();}finally{break L;}}",
      "caughtFinally");
3801 3802

  v8::V8::AddMessageListener(MessageCallbackCount);
3803
  v8::Debug::SetDebugEventListener(DebugEventCounter);
3804

3805
  // Initial state should be no break on exceptions.
3806 3807 3808
  DebugEventCounterClear();
  MessageCallbackCountClear();
  caught->Call(env->Global(), 0, NULL);
3809
  DebugEventCounterCheck(0, 0, 0);
3810
  notCaught->Call(env->Global(), 0, NULL);
3811 3812 3813 3814 3815
  DebugEventCounterCheck(0, 0, 1);
  notCaughtFinally->Call(env->Global(), 0, NULL);
  DebugEventCounterCheck(0, 0, 2);
  edgeCaseFinally->Call(env->Global(), 0, NULL);
  DebugEventCounterCheck(0, 0, 2);
3816 3817 3818 3819 3820 3821

  // No break on exception
  DebugEventCounterClear();
  MessageCallbackCountClear();
  ChangeBreakOnException(false, false);
  caught->Call(env->Global(), 0, NULL);
3822
  DebugEventCounterCheck(0, 0, 0);
3823
  notCaught->Call(env->Global(), 0, NULL);
3824 3825 3826 3827 3828
  DebugEventCounterCheck(0, 0, 1);
  notCaughtFinally->Call(env->Global(), 0, NULL);
  DebugEventCounterCheck(0, 0, 2);
  edgeCaseFinally->Call(env->Global(), 0, NULL);
  DebugEventCounterCheck(0, 0, 2);
3829 3830 3831 3832 3833 3834

  // Break on uncaught exception
  DebugEventCounterClear();
  MessageCallbackCountClear();
  ChangeBreakOnException(false, true);
  caught->Call(env->Global(), 0, NULL);
3835
  DebugEventCounterCheck(0, 0, 0);
3836
  notCaught->Call(env->Global(), 0, NULL);
3837 3838 3839 3840 3841
  DebugEventCounterCheck(1, 1, 1);
  notCaughtFinally->Call(env->Global(), 0, NULL);
  DebugEventCounterCheck(2, 2, 2);
  edgeCaseFinally->Call(env->Global(), 0, NULL);
  DebugEventCounterCheck(3, 3, 2);
3842 3843 3844 3845 3846 3847

  // Break on exception and uncaught exception
  DebugEventCounterClear();
  MessageCallbackCountClear();
  ChangeBreakOnException(true, true);
  caught->Call(env->Global(), 0, NULL);
3848
  DebugEventCounterCheck(1, 0, 0);
3849
  notCaught->Call(env->Global(), 0, NULL);
3850 3851 3852 3853 3854
  DebugEventCounterCheck(2, 1, 1);
  notCaughtFinally->Call(env->Global(), 0, NULL);
  DebugEventCounterCheck(3, 2, 2);
  edgeCaseFinally->Call(env->Global(), 0, NULL);
  DebugEventCounterCheck(4, 3, 2);
3855 3856 3857 3858 3859 3860

  // Break on exception
  DebugEventCounterClear();
  MessageCallbackCountClear();
  ChangeBreakOnException(true, false);
  caught->Call(env->Global(), 0, NULL);
3861
  DebugEventCounterCheck(1, 0, 0);
3862
  notCaught->Call(env->Global(), 0, NULL);
3863 3864 3865 3866 3867
  DebugEventCounterCheck(2, 1, 1);
  notCaughtFinally->Call(env->Global(), 0, NULL);
  DebugEventCounterCheck(3, 2, 2);
  edgeCaseFinally->Call(env->Global(), 0, NULL);
  DebugEventCounterCheck(4, 3, 2);
3868 3869 3870 3871

  // No break on exception using JavaScript
  DebugEventCounterClear();
  MessageCallbackCountClear();
3872
  ChangeBreakOnExceptionFromJS(env->GetIsolate(), false, false);
3873
  caught->Call(env->Global(), 0, NULL);
3874
  DebugEventCounterCheck(0, 0, 0);
3875
  notCaught->Call(env->Global(), 0, NULL);
3876 3877 3878 3879 3880
  DebugEventCounterCheck(0, 0, 1);
  notCaughtFinally->Call(env->Global(), 0, NULL);
  DebugEventCounterCheck(0, 0, 2);
  edgeCaseFinally->Call(env->Global(), 0, NULL);
  DebugEventCounterCheck(0, 0, 2);
3881 3882 3883 3884

  // Break on uncaught exception using JavaScript
  DebugEventCounterClear();
  MessageCallbackCountClear();
3885
  ChangeBreakOnExceptionFromJS(env->GetIsolate(), false, true);
3886
  caught->Call(env->Global(), 0, NULL);
3887
  DebugEventCounterCheck(0, 0, 0);
3888
  notCaught->Call(env->Global(), 0, NULL);
3889 3890 3891 3892 3893
  DebugEventCounterCheck(1, 1, 1);
  notCaughtFinally->Call(env->Global(), 0, NULL);
  DebugEventCounterCheck(2, 2, 2);
  edgeCaseFinally->Call(env->Global(), 0, NULL);
  DebugEventCounterCheck(3, 3, 2);
3894 3895 3896 3897

  // Break on exception and uncaught exception using JavaScript
  DebugEventCounterClear();
  MessageCallbackCountClear();
3898
  ChangeBreakOnExceptionFromJS(env->GetIsolate(), true, true);
3899
  caught->Call(env->Global(), 0, NULL);
3900
  DebugEventCounterCheck(1, 0, 0);
3901
  notCaught->Call(env->Global(), 0, NULL);
3902 3903 3904 3905 3906
  DebugEventCounterCheck(2, 1, 1);
  notCaughtFinally->Call(env->Global(), 0, NULL);
  DebugEventCounterCheck(3, 2, 2);
  edgeCaseFinally->Call(env->Global(), 0, NULL);
  DebugEventCounterCheck(4, 3, 2);
3907 3908 3909 3910

  // Break on exception using JavaScript
  DebugEventCounterClear();
  MessageCallbackCountClear();
3911
  ChangeBreakOnExceptionFromJS(env->GetIsolate(), true, false);
3912
  caught->Call(env->Global(), 0, NULL);
3913
  DebugEventCounterCheck(1, 0, 0);
3914
  notCaught->Call(env->Global(), 0, NULL);
3915 3916 3917 3918 3919
  DebugEventCounterCheck(2, 1, 1);
  notCaughtFinally->Call(env->Global(), 0, NULL);
  DebugEventCounterCheck(3, 2, 2);
  edgeCaseFinally->Call(env->Global(), 0, NULL);
  DebugEventCounterCheck(4, 3, 2);
3920

3921
  v8::Debug::SetDebugEventListener(NULL);
3922
  CheckDebuggerUnloaded();
3923 3924 3925 3926
  v8::V8::RemoveMessageListeners(MessageCallbackCount);
}


3927 3928 3929 3930 3931 3932 3933 3934 3935 3936 3937 3938 3939 3940 3941 3942 3943 3944 3945 3946 3947 3948 3949 3950 3951 3952 3953 3954 3955
static void try_finally_original_message(v8::Handle<v8::Message> message,
                                         v8::Handle<v8::Value> data) {
  CHECK_EQ(2, message->GetLineNumber());
  CHECK_EQ(2, message->GetStartColumn());
  message_callback_count++;
}


TEST(TryFinallyOriginalMessage) {
  // Test that the debugger plays nicely with the pending message.
  message_callback_count = 0;
  DebugEventCounterClear();
  v8::V8::AddMessageListener(try_finally_original_message);
  v8::Debug::SetDebugEventListener(DebugEventCounter);
  ChangeBreakOnException(true, true);
  DebugLocalContext env;
  v8::Isolate* isolate = CcTest::isolate();
  v8::HandleScope scope(isolate);
  CompileRun(
      "try {\n"
      "  throw 1;\n"
      "} finally {\n"
      "}\n");
  DebugEventCounterCheck(1, 1, 1);
  v8::Debug::SetDebugEventListener(NULL);
  v8::V8::RemoveMessageListeners(try_finally_original_message);
}


3956 3957 3958 3959 3960 3961 3962 3963 3964 3965 3966 3967 3968 3969 3970 3971 3972 3973 3974 3975 3976 3977
TEST(EvalJSInDebugEventListenerOnNativeReThrownException) {
  DebugLocalContext env;
  v8::HandleScope scope(env->GetIsolate());
  env.ExposeDebug();

  // Create functions for testing break on exception.
  v8::Local<v8::Function> noThrowJS = CompileFunction(
      &env, "function noThrowJS(){var a=[1]; a.push(2); return a.length;}",
      "noThrowJS");

  debug_event_listener_callback = noThrowJS;
  debug_event_listener_callback_result = 2;

  v8::V8::AddMessageListener(MessageCallbackCount);
  v8::Debug::SetDebugEventListener(DebugEventCounter);
  // Break on uncaught exception
  ChangeBreakOnException(false, true);
  DebugEventCounterClear();
  MessageCallbackCountClear();

  // ReThrow native error
  {
3978
    v8::TryCatch tryCatch(env->GetIsolate());
3979 3980 3981 3982 3983 3984 3985 3986 3987 3988 3989 3990 3991 3992
    env->GetIsolate()->ThrowException(v8::Exception::TypeError(
        v8::String::NewFromUtf8(env->GetIsolate(), "Type error")));
    CHECK(tryCatch.HasCaught());
    tryCatch.ReThrow();
  }
  CHECK_EQ(1, exception_hit_count);
  CHECK_EQ(1, uncaught_exception_hit_count);
  CHECK_EQ(0, message_callback_count);  // FIXME: Should it be 1 ?
  CHECK(!debug_event_listener_callback.IsEmpty());

  debug_event_listener_callback.Clear();
}


3993 3994 3995 3996 3997
// Test break on exception from compiler errors. When compiling using
// v8::Script::Compile there is no JavaScript stack whereas when compiling using
// eval there are JavaScript frames.
TEST(BreakOnCompileException) {
  DebugLocalContext env;
3998
  v8::HandleScope scope(env->GetIsolate());
3999

4000 4001 4002
  // For this test, we want to break on uncaught exceptions:
  ChangeBreakOnException(false, true);

4003 4004 4005 4006
  // Create a function for checking the function when hitting a break point.
  frame_count = CompileFunction(&env, frame_count_source, "frame_count");

  v8::V8::AddMessageListener(MessageCallbackCount);
4007
  v8::Debug::SetDebugEventListener(DebugEventCounter);
4008 4009 4010 4011 4012 4013 4014 4015 4016 4017 4018

  DebugEventCounterClear();
  MessageCallbackCountClear();

  // Check initial state.
  CHECK_EQ(0, exception_hit_count);
  CHECK_EQ(0, uncaught_exception_hit_count);
  CHECK_EQ(0, message_callback_count);
  CHECK_EQ(-1, last_js_stack_height);

  // Throws SyntaxError: Unexpected end of input
4019
  v8::Script::Compile(v8::String::NewFromUtf8(env->GetIsolate(), "+++"));
4020 4021 4022 4023 4024 4025
  CHECK_EQ(1, exception_hit_count);
  CHECK_EQ(1, uncaught_exception_hit_count);
  CHECK_EQ(1, message_callback_count);
  CHECK_EQ(0, last_js_stack_height);  // No JavaScript stack.

  // Throws SyntaxError: Unexpected identifier
4026
  v8::Script::Compile(v8::String::NewFromUtf8(env->GetIsolate(), "x x"));
4027 4028 4029 4030 4031 4032
  CHECK_EQ(2, exception_hit_count);
  CHECK_EQ(2, uncaught_exception_hit_count);
  CHECK_EQ(2, message_callback_count);
  CHECK_EQ(0, last_js_stack_height);  // No JavaScript stack.

  // Throws SyntaxError: Unexpected end of input
4033 4034
  v8::Script::Compile(v8::String::NewFromUtf8(env->GetIsolate(), "eval('+++')"))
      ->Run();
4035 4036 4037 4038 4039 4040
  CHECK_EQ(3, exception_hit_count);
  CHECK_EQ(3, uncaught_exception_hit_count);
  CHECK_EQ(3, message_callback_count);
  CHECK_EQ(1, last_js_stack_height);

  // Throws SyntaxError: Unexpected identifier
4041 4042
  v8::Script::Compile(v8::String::NewFromUtf8(env->GetIsolate(), "eval('x x')"))
      ->Run();
4043 4044 4045 4046 4047 4048 4049
  CHECK_EQ(4, exception_hit_count);
  CHECK_EQ(4, uncaught_exception_hit_count);
  CHECK_EQ(4, message_callback_count);
  CHECK_EQ(1, last_js_stack_height);
}


4050
TEST(StepWithException) {
4051
  DebugLocalContext env;
4052
  v8::HandleScope scope(env->GetIsolate());
4053

4054 4055 4056
  // For this test, we want to break on uncaught exceptions:
  ChangeBreakOnException(false, true);

4057 4058 4059 4060 4061 4062
  // Create a function for checking the function when hitting a break point.
  frame_function_name = CompileFunction(&env,
                                        frame_function_name_source,
                                        "frame_function_name");

  // Register a debug event listener which steps and counts.
4063
  v8::Debug::SetDebugEventListener(DebugEventStepSequence);
4064 4065 4066 4067 4068 4069 4070 4071 4072 4073 4074 4075 4076 4077 4078 4079 4080 4081

  // Create functions for testing stepping.
  const char* src = "function a() { n(); }; "
                    "function b() { c(); }; "
                    "function c() { n(); }; "
                    "function d() { x = 1; try { e(); } catch(x) { x = 2; } }; "
                    "function e() { n(); }; "
                    "function f() { x = 1; try { g(); } catch(x) { x = 2; } }; "
                    "function g() { h(); }; "
                    "function h() { x = 1; throw 1; }; ";

  // Step through invocation of a.
  v8::Local<v8::Function> a = CompileFunction(&env, src, "a");
  SetBreakPoint(a, 0);
  step_action = StepIn;
  break_point_hit_count = 0;
  expected_step_sequence = "aa";
  a->Call(env->Global(), 0, NULL);
4082 4083
  CHECK_EQ(StrLength(expected_step_sequence),
           break_point_hit_count);
4084 4085 4086 4087 4088 4089 4090 4091

  // Step through invocation of b + c.
  v8::Local<v8::Function> b = CompileFunction(&env, src, "b");
  SetBreakPoint(b, 0);
  step_action = StepIn;
  break_point_hit_count = 0;
  expected_step_sequence = "bcc";
  b->Call(env->Global(), 0, NULL);
4092 4093
  CHECK_EQ(StrLength(expected_step_sequence),
           break_point_hit_count);
4094 4095 4096 4097 4098 4099
  // Step through invocation of d + e.
  v8::Local<v8::Function> d = CompileFunction(&env, src, "d");
  SetBreakPoint(d, 0);
  ChangeBreakOnException(false, true);
  step_action = StepIn;
  break_point_hit_count = 0;
4100
  expected_step_sequence = "ddedd";
4101
  d->Call(env->Global(), 0, NULL);
4102 4103
  CHECK_EQ(StrLength(expected_step_sequence),
           break_point_hit_count);
4104 4105 4106 4107 4108

  // Step through invocation of d + e now with break on caught exceptions.
  ChangeBreakOnException(true, true);
  step_action = StepIn;
  break_point_hit_count = 0;
4109
  expected_step_sequence = "ddeedd";
4110
  d->Call(env->Global(), 0, NULL);
4111 4112
  CHECK_EQ(StrLength(expected_step_sequence),
           break_point_hit_count);
4113 4114 4115 4116 4117 4118 4119

  // Step through invocation of f + g + h.
  v8::Local<v8::Function> f = CompileFunction(&env, src, "f");
  SetBreakPoint(f, 0);
  ChangeBreakOnException(false, true);
  step_action = StepIn;
  break_point_hit_count = 0;
4120
  expected_step_sequence = "ffghhff";
4121
  f->Call(env->Global(), 0, NULL);
4122 4123
  CHECK_EQ(StrLength(expected_step_sequence),
           break_point_hit_count);
4124 4125 4126 4127 4128

  // Step through invocation of f + g + h now with break on caught exceptions.
  ChangeBreakOnException(true, true);
  step_action = StepIn;
  break_point_hit_count = 0;
4129
  expected_step_sequence = "ffghhhff";
4130
  f->Call(env->Global(), 0, NULL);
4131 4132
  CHECK_EQ(StrLength(expected_step_sequence),
           break_point_hit_count);
4133 4134

  // Get rid of the debug event listener.
4135
  v8::Debug::SetDebugEventListener(NULL);
4136
  CheckDebuggerUnloaded();
4137 4138 4139 4140
}


TEST(DebugBreak) {
4141
  i::FLAG_stress_compaction = false;
4142 4143 4144
#ifdef VERIFY_HEAP
  i::FLAG_verify_heap = true;
#endif
4145
  DebugLocalContext env;
4146 4147
  v8::Isolate* isolate = env->GetIsolate();
  v8::HandleScope scope(isolate);
4148 4149

  // Register a debug event listener which sets the break flag and counts.
4150
  v8::Debug::SetDebugEventListener(DebugEventBreak);
4151 4152 4153 4154 4155 4156 4157 4158 4159 4160 4161 4162

  // Create a function for testing stepping.
  const char* src = "function f0() {}"
                    "function f1(x1) {}"
                    "function f2(x1,x2) {}"
                    "function f3(x1,x2,x3) {}";
  v8::Local<v8::Function> f0 = CompileFunction(&env, src, "f0");
  v8::Local<v8::Function> f1 = CompileFunction(&env, src, "f1");
  v8::Local<v8::Function> f2 = CompileFunction(&env, src, "f2");
  v8::Local<v8::Function> f3 = CompileFunction(&env, src, "f3");

  // Call the function to make sure it is compiled.
4163 4164 4165 4166
  v8::Handle<v8::Value> argv[] = { v8::Number::New(isolate, 1),
                                   v8::Number::New(isolate, 1),
                                   v8::Number::New(isolate, 1),
                                   v8::Number::New(isolate, 1) };
4167 4168 4169 4170 4171 4172 4173 4174

  // Call all functions to make sure that they are compiled.
  f0->Call(env->Global(), 0, NULL);
  f1->Call(env->Global(), 0, NULL);
  f2->Call(env->Global(), 0, NULL);
  f3->Call(env->Global(), 0, NULL);

  // Set the debug break flag.
4175
  v8::Debug::DebugBreak(env->GetIsolate());
4176
  CHECK(v8::Debug::CheckDebugBreak(env->GetIsolate()));
4177 4178 4179

  // Call all functions with different argument count.
  break_point_hit_count = 0;
4180
  for (unsigned int i = 0; i < arraysize(argv); i++) {
4181 4182 4183 4184 4185 4186 4187
    f0->Call(env->Global(), i, argv);
    f1->Call(env->Global(), i, argv);
    f2->Call(env->Global(), i, argv);
    f3->Call(env->Global(), i, argv);
  }

  // One break for each function called.
4188
  CHECK(4 * arraysize(argv) == break_point_hit_count);
4189 4190

  // Get rid of the debug event listener.
4191
  v8::Debug::SetDebugEventListener(NULL);
4192
  CheckDebuggerUnloaded();
4193 4194 4195 4196 4197 4198
}


// Test to ensure that JavaScript code keeps running while the debug break
// through the stack limit flag is set but breaks are disabled.
TEST(DisableBreak) {
4199
  DebugLocalContext env;
4200
  v8::HandleScope scope(env->GetIsolate());
4201 4202

  // Register a debug event listener which sets the break flag and counts.
4203
  v8::Debug::SetDebugEventListener(DebugEventCounter);
4204 4205 4206 4207 4208

  // Create a function for testing stepping.
  const char* src = "function f() {g()};function g(){i=0; while(i<10){i++}}";
  v8::Local<v8::Function> f = CompileFunction(&env, src, "f");

4209 4210 4211 4212 4213 4214
  // Set, test and cancel debug break.
  v8::Debug::DebugBreak(env->GetIsolate());
  CHECK(v8::Debug::CheckDebugBreak(env->GetIsolate()));
  v8::Debug::CancelDebugBreak(env->GetIsolate());
  CHECK(!v8::Debug::CheckDebugBreak(env->GetIsolate()));

4215
  // Set the debug break flag.
4216
  v8::Debug::DebugBreak(env->GetIsolate());
4217 4218 4219 4220 4221 4222 4223

  // Call all functions with different argument count.
  break_point_hit_count = 0;
  f->Call(env->Global(), 0, NULL);
  CHECK_EQ(1, break_point_hit_count);

  {
4224
    v8::Debug::DebugBreak(env->GetIsolate());
4225
    i::Isolate* isolate = reinterpret_cast<i::Isolate*>(env->GetIsolate());
4226
    v8::internal::DisableBreak disable_break(isolate->debug(), true);
4227 4228 4229 4230 4231 4232 4233 4234
    f->Call(env->Global(), 0, NULL);
    CHECK_EQ(1, break_point_hit_count);
  }

  f->Call(env->Global(), 0, NULL);
  CHECK_EQ(2, break_point_hit_count);

  // Get rid of the debug event listener.
4235
  v8::Debug::SetDebugEventListener(NULL);
4236
  CheckDebuggerUnloaded();
4237 4238
}

4239 4240 4241 4242 4243 4244 4245 4246
static const char* kSimpleExtensionSource =
  "(function Foo() {"
  "  return 4;"
  "})() ";

// http://crbug.com/28933
// Test that debug break is disabled when bootstrapper is active.
TEST(NoBreakWhenBootstrapping) {
4247
  v8::Isolate* isolate = CcTest::isolate();
4248
  v8::HandleScope scope(isolate);
4249 4250

  // Register a debug event listener which sets the break flag and counts.
4251
  v8::Debug::SetDebugEventListener(DebugEventCounter);
4252 4253

  // Set the debug break flag.
4254
  v8::Debug::DebugBreak(isolate);
4255 4256 4257 4258 4259 4260 4261 4262
  break_point_hit_count = 0;
  {
    // Create a context with an extension to make sure that some JavaScript
    // code is executed during bootstrapping.
    v8::RegisterExtension(new v8::Extension("simpletest",
                                            kSimpleExtensionSource));
    const char* extension_names[] = { "simpletest" };
    v8::ExtensionConfiguration extensions(1, extension_names);
4263 4264
    v8::HandleScope handle_scope(isolate);
    v8::Context::New(isolate, &extensions);
4265 4266 4267
  }
  // Check that no DebugBreak events occured during the context creation.
  CHECK_EQ(0, break_point_hit_count);
4268

4269
  // Get rid of the debug event listener.
4270
  v8::Debug::SetDebugEventListener(NULL);
4271 4272
  CheckDebuggerUnloaded();
}
4273

4274

4275
static void NamedEnum(const v8::PropertyCallbackInfo<v8::Array>& info) {
4276
  v8::Handle<v8::Array> result = v8::Array::New(info.GetIsolate(), 3);
4277
  result->Set(v8::Integer::New(info.GetIsolate(), 0),
4278
              v8::String::NewFromUtf8(info.GetIsolate(), "a"));
4279
  result->Set(v8::Integer::New(info.GetIsolate(), 1),
4280
              v8::String::NewFromUtf8(info.GetIsolate(), "b"));
4281
  result->Set(v8::Integer::New(info.GetIsolate(), 2),
4282
              v8::String::NewFromUtf8(info.GetIsolate(), "c"));
4283
  info.GetReturnValue().Set(result);
4284 4285 4286
}


4287
static void IndexedEnum(const v8::PropertyCallbackInfo<v8::Array>& info) {
4288 4289 4290 4291
  v8::Isolate* isolate = info.GetIsolate();
  v8::Handle<v8::Array> result = v8::Array::New(isolate, 2);
  result->Set(v8::Integer::New(isolate, 0), v8::Number::New(isolate, 1));
  result->Set(v8::Integer::New(isolate, 1), v8::Number::New(isolate, 10));
4292
  info.GetReturnValue().Set(result);
4293 4294 4295
}


4296
static void NamedGetter(v8::Local<v8::Name> name,
4297
                        const v8::PropertyCallbackInfo<v8::Value>& info) {
4298 4299
  if (name->IsSymbol()) return;
  v8::String::Utf8Value n(v8::Local<v8::String>::Cast(name));
4300
  if (strcmp(*n, "a") == 0) {
4301
    info.GetReturnValue().Set(v8::String::NewFromUtf8(info.GetIsolate(), "AA"));
4302
    return;
4303
  } else if (strcmp(*n, "b") == 0) {
4304
    info.GetReturnValue().Set(v8::String::NewFromUtf8(info.GetIsolate(), "BB"));
4305
    return;
4306
  } else if (strcmp(*n, "c") == 0) {
4307
    info.GetReturnValue().Set(v8::String::NewFromUtf8(info.GetIsolate(), "CC"));
4308
    return;
4309
  } else {
4310 4311
    info.GetReturnValue().SetUndefined();
    return;
4312
  }
4313
  info.GetReturnValue().Set(name);
4314 4315 4316
}


4317 4318 4319
static void IndexedGetter(uint32_t index,
                          const v8::PropertyCallbackInfo<v8::Value>& info) {
  info.GetReturnValue().Set(static_cast<double>(index + 1));
4320 4321 4322 4323 4324
}


TEST(InterceptorPropertyMirror) {
  // Create a V8 environment with debug access.
4325
  DebugLocalContext env;
4326 4327
  v8::Isolate* isolate = env->GetIsolate();
  v8::HandleScope scope(isolate);
4328 4329 4330
  env.ExposeDebug();

  // Create object with named interceptor.
4331
  v8::Handle<v8::ObjectTemplate> named = v8::ObjectTemplate::New(isolate);
4332 4333
  named->SetHandler(v8::NamedPropertyHandlerConfiguration(
      NamedGetter, NULL, NULL, NULL, NamedEnum));
4334
  env->Global()->Set(
4335
      v8::String::NewFromUtf8(isolate, "intercepted_named"),
4336
      named->NewInstance());
4337 4338

  // Create object with indexed interceptor.
4339
  v8::Handle<v8::ObjectTemplate> indexed = v8::ObjectTemplate::New(isolate);
4340 4341
  indexed->SetHandler(v8::IndexedPropertyHandlerConfiguration(
      IndexedGetter, NULL, NULL, NULL, IndexedEnum));
4342
  env->Global()->Set(
4343
      v8::String::NewFromUtf8(isolate, "intercepted_indexed"),
4344
      indexed->NewInstance());
4345 4346

  // Create object with both named and indexed interceptor.
4347
  v8::Handle<v8::ObjectTemplate> both = v8::ObjectTemplate::New(isolate);
4348 4349
  both->SetHandler(v8::NamedPropertyHandlerConfiguration(
      NamedGetter, NULL, NULL, NULL, NamedEnum));
4350 4351
  both->SetHandler(v8::IndexedPropertyHandlerConfiguration(
      IndexedGetter, NULL, NULL, NULL, IndexedEnum));
4352
  env->Global()->Set(
4353
      v8::String::NewFromUtf8(isolate, "intercepted_both"),
4354
      both->NewInstance());
4355 4356 4357

  // Get mirrors for the three objects with interceptor.
  CompileRun(
4358 4359 4360
      "var named_mirror = debug.MakeMirror(intercepted_named);"
      "var indexed_mirror = debug.MakeMirror(intercepted_indexed);"
      "var both_mirror = debug.MakeMirror(intercepted_both)");
4361 4362 4363 4364 4365 4366 4367 4368 4369
  CHECK(CompileRun(
       "named_mirror instanceof debug.ObjectMirror")->BooleanValue());
  CHECK(CompileRun(
        "indexed_mirror instanceof debug.ObjectMirror")->BooleanValue());
  CHECK(CompileRun(
        "both_mirror instanceof debug.ObjectMirror")->BooleanValue());

  // Get the property names from the interceptors
  CompileRun(
4370 4371 4372
      "named_names = named_mirror.propertyNames();"
      "indexed_names = indexed_mirror.propertyNames();"
      "both_names = both_mirror.propertyNames()");
4373 4374 4375 4376 4377 4378
  CHECK_EQ(3, CompileRun("named_names.length")->Int32Value());
  CHECK_EQ(2, CompileRun("indexed_names.length")->Int32Value());
  CHECK_EQ(5, CompileRun("both_names.length")->Int32Value());

  // Check the expected number of properties.
  const char* source;
4379
  source = "named_mirror.properties().length";
4380 4381
  CHECK_EQ(3, CompileRun(source)->Int32Value());

4382
  source = "indexed_mirror.properties().length";
4383 4384
  CHECK_EQ(2, CompileRun(source)->Int32Value());

4385
  source = "both_mirror.properties().length";
4386 4387
  CHECK_EQ(5, CompileRun(source)->Int32Value());

4388 4389
  // 1 is PropertyKind.Named;
  source = "both_mirror.properties(1).length";
4390 4391
  CHECK_EQ(3, CompileRun(source)->Int32Value());

4392 4393
  // 2 is PropertyKind.Indexed;
  source = "both_mirror.properties(2).length";
4394 4395
  CHECK_EQ(2, CompileRun(source)->Int32Value());

4396 4397
  // 3 is PropertyKind.Named  | PropertyKind.Indexed;
  source = "both_mirror.properties(3).length";
4398 4399
  CHECK_EQ(5, CompileRun(source)->Int32Value());

4400
  // Get the interceptor properties for the object with only named interceptor.
4401
  CompileRun("var named_values = named_mirror.properties()");
4402

4403 4404 4405
  // Check that the properties are interceptor properties.
  for (int i = 0; i < 3; i++) {
    EmbeddedVector<char, SMALL_STRING_BUFFER_SIZE> buffer;
4406 4407
    SNPrintF(buffer,
             "named_values[%d] instanceof debug.PropertyMirror", i);
4408
    CHECK(CompileRun(buffer.start())->BooleanValue());
4409

4410
    SNPrintF(buffer, "named_values[%d].isNative()", i);
4411 4412
    CHECK(CompileRun(buffer.start())->BooleanValue());
  }
4413

4414 4415
  // Get the interceptor properties for the object with only indexed
  // interceptor.
4416
  CompileRun("var indexed_values = indexed_mirror.properties()");
4417

4418 4419 4420
  // Check that the properties are interceptor properties.
  for (int i = 0; i < 2; i++) {
    EmbeddedVector<char, SMALL_STRING_BUFFER_SIZE> buffer;
4421 4422
    SNPrintF(buffer,
             "indexed_values[%d] instanceof debug.PropertyMirror", i);
4423 4424
    CHECK(CompileRun(buffer.start())->BooleanValue());
  }
4425

4426 4427
  // Get the interceptor properties for the object with both types of
  // interceptors.
4428
  CompileRun("var both_values = both_mirror.properties()");
4429

4430 4431 4432
  // Check that the properties are interceptor properties.
  for (int i = 0; i < 5; i++) {
    EmbeddedVector<char, SMALL_STRING_BUFFER_SIZE> buffer;
4433
    SNPrintF(buffer, "both_values[%d] instanceof debug.PropertyMirror", i);
4434 4435
    CHECK(CompileRun(buffer.start())->BooleanValue());
  }
4436 4437 4438 4439 4440 4441 4442 4443 4444 4445 4446 4447 4448 4449 4450 4451 4452 4453 4454

  // Check the property names.
  source = "both_values[0].name() == 'a'";
  CHECK(CompileRun(source)->BooleanValue());

  source = "both_values[1].name() == 'b'";
  CHECK(CompileRun(source)->BooleanValue());

  source = "both_values[2].name() == 'c'";
  CHECK(CompileRun(source)->BooleanValue());

  source = "both_values[3].name() == 1";
  CHECK(CompileRun(source)->BooleanValue());

  source = "both_values[4].name() == 10";
  CHECK(CompileRun(source)->BooleanValue());
}


4455 4456 4457
TEST(HiddenPrototypePropertyMirror) {
  // Create a V8 environment with debug access.
  DebugLocalContext env;
4458 4459
  v8::Isolate* isolate = env->GetIsolate();
  v8::HandleScope scope(isolate);
4460 4461
  env.ExposeDebug();

4462 4463
  v8::Handle<v8::FunctionTemplate> t0 = v8::FunctionTemplate::New(isolate);
  t0->InstanceTemplate()->Set(v8::String::NewFromUtf8(isolate, "x"),
4464
                              v8::Number::New(isolate, 0));
4465
  v8::Handle<v8::FunctionTemplate> t1 = v8::FunctionTemplate::New(isolate);
4466
  t1->SetHiddenPrototype(true);
4467
  t1->InstanceTemplate()->Set(v8::String::NewFromUtf8(isolate, "y"),
4468
                              v8::Number::New(isolate, 1));
4469
  v8::Handle<v8::FunctionTemplate> t2 = v8::FunctionTemplate::New(isolate);
4470
  t2->SetHiddenPrototype(true);
4471
  t2->InstanceTemplate()->Set(v8::String::NewFromUtf8(isolate, "z"),
4472
                              v8::Number::New(isolate, 2));
4473 4474
  v8::Handle<v8::FunctionTemplate> t3 = v8::FunctionTemplate::New(isolate);
  t3->InstanceTemplate()->Set(v8::String::NewFromUtf8(isolate, "u"),
4475
                              v8::Number::New(isolate, 3));
4476 4477 4478

  // Create object and set them on the global object.
  v8::Handle<v8::Object> o0 = t0->GetFunction()->NewInstance();
4479
  env->Global()->Set(v8::String::NewFromUtf8(isolate, "o0"), o0);
4480
  v8::Handle<v8::Object> o1 = t1->GetFunction()->NewInstance();
4481
  env->Global()->Set(v8::String::NewFromUtf8(isolate, "o1"), o1);
4482
  v8::Handle<v8::Object> o2 = t2->GetFunction()->NewInstance();
4483
  env->Global()->Set(v8::String::NewFromUtf8(isolate, "o2"), o2);
4484
  v8::Handle<v8::Object> o3 = t3->GetFunction()->NewInstance();
4485
  env->Global()->Set(v8::String::NewFromUtf8(isolate, "o3"), o3);
4486 4487 4488

  // Get mirrors for the four objects.
  CompileRun(
4489 4490 4491 4492
      "var o0_mirror = debug.MakeMirror(o0);"
      "var o1_mirror = debug.MakeMirror(o1);"
      "var o2_mirror = debug.MakeMirror(o2);"
      "var o3_mirror = debug.MakeMirror(o3)");
4493 4494 4495 4496 4497 4498 4499 4500 4501 4502 4503 4504 4505 4506 4507 4508 4509
  CHECK(CompileRun("o0_mirror instanceof debug.ObjectMirror")->BooleanValue());
  CHECK(CompileRun("o1_mirror instanceof debug.ObjectMirror")->BooleanValue());
  CHECK(CompileRun("o2_mirror instanceof debug.ObjectMirror")->BooleanValue());
  CHECK(CompileRun("o3_mirror instanceof debug.ObjectMirror")->BooleanValue());

  // Check that each object has one property.
  CHECK_EQ(1, CompileRun(
              "o0_mirror.propertyNames().length")->Int32Value());
  CHECK_EQ(1, CompileRun(
              "o1_mirror.propertyNames().length")->Int32Value());
  CHECK_EQ(1, CompileRun(
              "o2_mirror.propertyNames().length")->Int32Value());
  CHECK_EQ(1, CompileRun(
              "o3_mirror.propertyNames().length")->Int32Value());

  // Set o1 as prototype for o0. o1 has the hidden prototype flag so all
  // properties on o1 should be seen on o0.
4510
  o0->Set(v8::String::NewFromUtf8(isolate, "__proto__"), o1);
4511 4512 4513 4514 4515 4516 4517 4518 4519 4520
  CHECK_EQ(2, CompileRun(
              "o0_mirror.propertyNames().length")->Int32Value());
  CHECK_EQ(0, CompileRun(
              "o0_mirror.property('x').value().value()")->Int32Value());
  CHECK_EQ(1, CompileRun(
              "o0_mirror.property('y').value().value()")->Int32Value());

  // Set o2 as prototype for o0 (it will end up after o1 as o1 has the hidden
  // prototype flag. o2 also has the hidden prototype flag so all properties
  // on o2 should be seen on o0 as well as properties on o1.
4521
  o0->Set(v8::String::NewFromUtf8(isolate, "__proto__"), o2);
4522 4523 4524 4525 4526 4527 4528 4529 4530 4531 4532 4533 4534 4535 4536
  CHECK_EQ(3, CompileRun(
              "o0_mirror.propertyNames().length")->Int32Value());
  CHECK_EQ(0, CompileRun(
              "o0_mirror.property('x').value().value()")->Int32Value());
  CHECK_EQ(1, CompileRun(
              "o0_mirror.property('y').value().value()")->Int32Value());
  CHECK_EQ(2, CompileRun(
              "o0_mirror.property('z').value().value()")->Int32Value());

  // Set o3 as prototype for o0 (it will end up after o1 and o2 as both o1 and
  // o2 has the hidden prototype flag. o3 does not have the hidden prototype
  // flag so properties on o3 should not be seen on o0 whereas the properties
  // from o1 and o2 should still be seen on o0.
  // Final prototype chain: o0 -> o1 -> o2 -> o3
  // Hidden prototypes:           ^^    ^^
4537
  o0->Set(v8::String::NewFromUtf8(isolate, "__proto__"), o3);
4538 4539 4540 4541 4542 4543 4544 4545 4546 4547 4548 4549 4550 4551 4552 4553 4554
  CHECK_EQ(3, CompileRun(
              "o0_mirror.propertyNames().length")->Int32Value());
  CHECK_EQ(1, CompileRun(
              "o3_mirror.propertyNames().length")->Int32Value());
  CHECK_EQ(0, CompileRun(
              "o0_mirror.property('x').value().value()")->Int32Value());
  CHECK_EQ(1, CompileRun(
              "o0_mirror.property('y').value().value()")->Int32Value());
  CHECK_EQ(2, CompileRun(
              "o0_mirror.property('z').value().value()")->Int32Value());
  CHECK(CompileRun("o0_mirror.property('u').isUndefined()")->BooleanValue());

  // The prototype (__proto__) for o0 should be o3 as o1 and o2 are hidden.
  CHECK(CompileRun("o0_mirror.protoObject() == o3_mirror")->BooleanValue());
}


4555 4556 4557 4558
static void ProtperyXNativeGetter(
    v8::Local<v8::String> property,
    const v8::PropertyCallbackInfo<v8::Value>& info) {
  info.GetReturnValue().Set(10);
4559 4560 4561 4562 4563 4564
}


TEST(NativeGetterPropertyMirror) {
  // Create a V8 environment with debug access.
  DebugLocalContext env;
4565 4566
  v8::Isolate* isolate = env->GetIsolate();
  v8::HandleScope scope(isolate);
4567 4568
  env.ExposeDebug();

4569
  v8::Handle<v8::String> name = v8::String::NewFromUtf8(isolate, "x");
4570
  // Create object with named accessor.
4571
  v8::Handle<v8::ObjectTemplate> named = v8::ObjectTemplate::New(isolate);
4572 4573 4574 4575
  named->SetAccessor(name, &ProtperyXNativeGetter, NULL,
      v8::Handle<v8::Value>(), v8::DEFAULT, v8::None);

  // Create object with named property getter.
4576
  env->Global()->Set(v8::String::NewFromUtf8(isolate, "instance"),
4577
                     named->NewInstance());
4578 4579 4580
  CHECK_EQ(10, CompileRun("instance.x")->Int32Value());

  // Get mirror for the object with property getter.
4581
  CompileRun("var instance_mirror = debug.MakeMirror(instance);");
4582 4583 4584
  CHECK(CompileRun(
      "instance_mirror instanceof debug.ObjectMirror")->BooleanValue());

4585
  CompileRun("var named_names = instance_mirror.propertyNames();");
4586 4587 4588 4589 4590 4591 4592 4593 4594
  CHECK_EQ(1, CompileRun("named_names.length")->Int32Value());
  CHECK(CompileRun("named_names[0] == 'x'")->BooleanValue());
  CHECK(CompileRun(
      "instance_mirror.property('x').value().isNumber()")->BooleanValue());
  CHECK(CompileRun(
      "instance_mirror.property('x').value().value() == 10")->BooleanValue());
}


4595 4596 4597 4598
static void ProtperyXNativeGetterThrowingError(
    v8::Local<v8::String> property,
    const v8::PropertyCallbackInfo<v8::Value>& info) {
  CompileRun("throw new Error('Error message');");
4599 4600 4601 4602 4603 4604
}


TEST(NativeGetterThrowingErrorPropertyMirror) {
  // Create a V8 environment with debug access.
  DebugLocalContext env;
4605 4606
  v8::Isolate* isolate = env->GetIsolate();
  v8::HandleScope scope(isolate);
4607 4608
  env.ExposeDebug();

4609
  v8::Handle<v8::String> name = v8::String::NewFromUtf8(isolate, "x");
4610
  // Create object with named accessor.
4611
  v8::Handle<v8::ObjectTemplate> named = v8::ObjectTemplate::New(isolate);
4612 4613 4614 4615
  named->SetAccessor(name, &ProtperyXNativeGetterThrowingError, NULL,
      v8::Handle<v8::Value>(), v8::DEFAULT, v8::None);

  // Create object with named property getter.
4616
  env->Global()->Set(v8::String::NewFromUtf8(isolate, "instance"),
4617
                     named->NewInstance());
4618 4619

  // Get mirror for the object with property getter.
4620
  CompileRun("var instance_mirror = debug.MakeMirror(instance);");
4621 4622 4623 4624 4625 4626 4627 4628 4629 4630 4631 4632 4633 4634 4635
  CHECK(CompileRun(
      "instance_mirror instanceof debug.ObjectMirror")->BooleanValue());
  CompileRun("named_names = instance_mirror.propertyNames();");
  CHECK_EQ(1, CompileRun("named_names.length")->Int32Value());
  CHECK(CompileRun("named_names[0] == 'x'")->BooleanValue());
  CHECK(CompileRun(
      "instance_mirror.property('x').value().isError()")->BooleanValue());

  // Check that the message is that passed to the Error constructor.
  CHECK(CompileRun(
      "instance_mirror.property('x').value().message() == 'Error message'")->
          BooleanValue());
}


4636 4637 4638 4639 4640 4641
// Test that hidden properties object is not returned as an unnamed property
// among regular properties.
// See http://crbug.com/26491
TEST(NoHiddenProperties) {
  // Create a V8 environment with debug access.
  DebugLocalContext env;
4642 4643
  v8::Isolate* isolate = env->GetIsolate();
  v8::HandleScope scope(isolate);
4644 4645 4646 4647
  env.ExposeDebug();

  // Create an object in the global scope.
  const char* source = "var obj = {a: 1};";
4648
  v8::Script::Compile(v8::String::NewFromUtf8(isolate, source))
4649
      ->Run();
4650
  v8::Local<v8::Object> obj = v8::Local<v8::Object>::Cast(
4651
      env->Global()->Get(v8::String::NewFromUtf8(isolate, "obj")));
4652
  // Set a hidden property on the object.
4653
  obj->SetHiddenValue(
4654
      v8::String::NewFromUtf8(isolate, "v8::test-debug::a"),
4655
      v8::Int32::New(isolate, 11));
4656 4657 4658 4659 4660 4661 4662 4663 4664 4665 4666 4667 4668 4669 4670

  // Get mirror for the object with property getter.
  CompileRun("var obj_mirror = debug.MakeMirror(obj);");
  CHECK(CompileRun(
      "obj_mirror instanceof debug.ObjectMirror")->BooleanValue());
  CompileRun("var named_names = obj_mirror.propertyNames();");
  // There should be exactly one property. But there is also an unnamed
  // property whose value is hidden properties dictionary. The latter
  // property should not be in the list of reguar properties.
  CHECK_EQ(1, CompileRun("named_names.length")->Int32Value());
  CHECK(CompileRun("named_names[0] == 'a'")->BooleanValue());
  CHECK(CompileRun(
      "obj_mirror.property('a').value().value() == 1")->BooleanValue());

  // Object created by t0 will become hidden prototype of object 'obj'.
4671 4672
  v8::Handle<v8::FunctionTemplate> t0 = v8::FunctionTemplate::New(isolate);
  t0->InstanceTemplate()->Set(v8::String::NewFromUtf8(isolate, "b"),
4673
                              v8::Number::New(isolate, 2));
4674
  t0->SetHiddenPrototype(true);
4675 4676
  v8::Handle<v8::FunctionTemplate> t1 = v8::FunctionTemplate::New(isolate);
  t1->InstanceTemplate()->Set(v8::String::NewFromUtf8(isolate, "c"),
4677
                              v8::Number::New(isolate, 3));
4678 4679 4680 4681

  // Create proto objects, add hidden properties to them and set them on
  // the global object.
  v8::Handle<v8::Object> protoObj = t0->GetFunction()->NewInstance();
4682
  protoObj->SetHiddenValue(
4683
      v8::String::NewFromUtf8(isolate, "v8::test-debug::b"),
4684
      v8::Int32::New(isolate, 12));
4685
  env->Global()->Set(v8::String::NewFromUtf8(isolate, "protoObj"),
4686
                     protoObj);
4687
  v8::Handle<v8::Object> grandProtoObj = t1->GetFunction()->NewInstance();
4688
  grandProtoObj->SetHiddenValue(
4689
      v8::String::NewFromUtf8(isolate, "v8::test-debug::c"),
4690
      v8::Int32::New(isolate, 13));
4691
  env->Global()->Set(
4692
      v8::String::NewFromUtf8(isolate, "grandProtoObj"),
4693
      grandProtoObj);
4694

4695
  // Setting prototypes: obj->protoObj->grandProtoObj
4696
  protoObj->Set(v8::String::NewFromUtf8(isolate, "__proto__"),
4697
                grandProtoObj);
4698
  obj->Set(v8::String::NewFromUtf8(isolate, "__proto__"), protoObj);
4699 4700 4701 4702 4703 4704 4705 4706 4707 4708 4709 4710 4711 4712 4713 4714 4715

  // Get mirror for the object with property getter.
  CompileRun("var obj_mirror = debug.MakeMirror(obj);");
  CHECK(CompileRun(
      "obj_mirror instanceof debug.ObjectMirror")->BooleanValue());
  CompileRun("var named_names = obj_mirror.propertyNames();");
  // There should be exactly two properties - one from the object itself and
  // another from its hidden prototype.
  CHECK_EQ(2, CompileRun("named_names.length")->Int32Value());
  CHECK(CompileRun("named_names.sort(); named_names[0] == 'a' &&"
                   "named_names[1] == 'b'")->BooleanValue());
  CHECK(CompileRun(
      "obj_mirror.property('a').value().value() == 1")->BooleanValue());
  CHECK(CompileRun(
      "obj_mirror.property('b').value().value() == 2")->BooleanValue());
}

4716

4717 4718 4719 4720
// Multithreaded tests of JSON debugger protocol

// Support classes

4721 4722 4723 4724
// Provides synchronization between N threads, where N is a template parameter.
// The Wait() call blocks a thread until it is called for the Nth time, then all
// calls return.  Each ThreadBarrier object can only be used once.
template <int N>
4725
class ThreadBarrier final {
4726
 public:
4727
  ThreadBarrier() : num_blocked_(0) {}
4728

4729 4730 4731 4732 4733 4734
  ~ThreadBarrier() {
    LockGuard<Mutex> lock_guard(&mutex_);
    if (num_blocked_ != 0) {
      CHECK_EQ(N, num_blocked_);
    }
  }
4735

4736 4737 4738 4739 4740 4741 4742 4743 4744 4745 4746 4747 4748 4749 4750 4751
  void Wait() {
    LockGuard<Mutex> lock_guard(&mutex_);
    CHECK_LT(num_blocked_, N);
    num_blocked_++;
    if (N == num_blocked_) {
      // Signal and unblock all waiting threads.
      cv_.NotifyAll();
      printf("BARRIER\n\n");
      fflush(stdout);
    } else {  // Wait for the semaphore.
      while (num_blocked_ < N) {
        cv_.Wait(&mutex_);
      }
    }
    CHECK_EQ(N, num_blocked_);
  }
4752

4753 4754 4755 4756
 private:
  ConditionVariable cv_;
  Mutex mutex_;
  int num_blocked_;
4757

4758
  STATIC_ASSERT(N > 0);
4759

4760 4761
  DISALLOW_COPY_AND_ASSIGN(ThreadBarrier);
};
4762

4763

4764 4765 4766
// A set containing enough barriers and semaphores for any of the tests.
class Barriers {
 public:
4767 4768 4769 4770 4771 4772
  Barriers() : semaphore_1(0), semaphore_2(0) {}
  ThreadBarrier<2> barrier_1;
  ThreadBarrier<2> barrier_2;
  ThreadBarrier<2> barrier_3;
  ThreadBarrier<2> barrier_4;
  ThreadBarrier<2> barrier_5;
4773 4774
  v8::base::Semaphore semaphore_1;
  v8::base::Semaphore semaphore_2;
4775 4776 4777
};


4778
// We match parts of the message to decide if it is a break message.
4779
bool IsBreakEventMessage(char *message) {
4780 4781 4782 4783 4784
  const char* type_event = "\"type\":\"event\"";
  const char* event_break = "\"event\":\"break\"";
  // Does the message contain both type:event and event:break?
  return strstr(message, type_event) != NULL &&
         strstr(message, event_break) != NULL;
4785 4786 4787
}


4788 4789 4790 4791 4792 4793 4794 4795 4796 4797 4798 4799 4800 4801 4802 4803 4804 4805 4806 4807
// We match parts of the message to decide if it is a exception message.
bool IsExceptionEventMessage(char *message) {
  const char* type_event = "\"type\":\"event\"";
  const char* event_exception = "\"event\":\"exception\"";
  // Does the message contain both type:event and event:exception?
  return strstr(message, type_event) != NULL &&
      strstr(message, event_exception) != NULL;
}


// We match the message wether it is an evaluate response message.
bool IsEvaluateResponseMessage(char* message) {
  const char* type_response = "\"type\":\"response\"";
  const char* command_evaluate = "\"command\":\"evaluate\"";
  // Does the message contain both type:response and command:evaluate?
  return strstr(message, type_response) != NULL &&
         strstr(message, command_evaluate) != NULL;
}


antonm@chromium.org's avatar
antonm@chromium.org committed
4808 4809 4810 4811 4812
static int StringToInt(const char* s) {
  return atoi(s);  // NOLINT
}


4813 4814 4815 4816 4817 4818 4819 4820
// We match parts of the message to get evaluate result int value.
int GetEvaluateIntResult(char *message) {
  const char* value = "\"value\":";
  char* pos = strstr(message, value);
  if (pos == NULL) {
    return -1;
  }
  int res = -1;
antonm@chromium.org's avatar
antonm@chromium.org committed
4821
  res = StringToInt(pos + strlen(value));
4822 4823 4824 4825 4826 4827 4828 4829 4830 4831 4832 4833
  return res;
}


// We match parts of the message to get hit breakpoint id.
int GetBreakpointIdFromBreakEventMessage(char *message) {
  const char* breakpoints = "\"breakpoints\":[";
  char* pos = strstr(message, breakpoints);
  if (pos == NULL) {
    return -1;
  }
  int res = -1;
antonm@chromium.org's avatar
antonm@chromium.org committed
4834
  res = StringToInt(pos + strlen(breakpoints));
4835 4836 4837 4838
  return res;
}


4839 4840 4841 4842 4843 4844 4845 4846
// We match parts of the message to get total frames number.
int GetTotalFramesInt(char *message) {
  const char* prefix = "\"totalFrames\":";
  char* pos = strstr(message, prefix);
  if (pos == NULL) {
    return -1;
  }
  pos += strlen(prefix);
antonm@chromium.org's avatar
antonm@chromium.org committed
4847
  int res = StringToInt(pos);
4848
  return res;
4849 4850 4851
}


4852 4853 4854 4855 4856 4857 4858 4859 4860 4861 4862 4863
// We match parts of the message to get source line.
int GetSourceLineFromBreakEventMessage(char *message) {
  const char* source_line = "\"sourceLine\":";
  char* pos = strstr(message, source_line);
  if (pos == NULL) {
    return -1;
  }
  int res = -1;
  res = StringToInt(pos + strlen(source_line));
  return res;
}

4864

4865 4866 4867 4868 4869 4870 4871 4872 4873
/* Test MessageQueues */
/* Tests the message queues that hold debugger commands and
 * response messages to the debugger.  Fills queues and makes
 * them grow.
 */
Barriers message_queue_barriers;

// This is the debugger thread, that executes no v8 calls except
// placing JSON debugger commands in the queue.
4874
class MessageQueueDebuggerThread : public v8::base::Thread {
4875
 public:
4876
  MessageQueueDebuggerThread()
4877
      : Thread(Options("MessageQueueDebuggerThread")) {}
4878 4879 4880
  void Run();
};

4881 4882 4883

static void MessageHandler(const v8::Debug::Message& message) {
  v8::Handle<v8::String> json = message.GetJSON();
4884 4885
  v8::String::Utf8Value utf8(json);
  if (IsBreakEventMessage(*utf8)) {
4886 4887
    // Lets test script wait until break occurs to send commands.
    // Signals when a break is reported.
4888
    message_queue_barriers.semaphore_2.Signal();
4889
  }
4890

4891 4892
  // Allow message handler to block on a semaphore, to test queueing of
  // messages while blocked.
4893
  message_queue_barriers.semaphore_1.Wait();
4894 4895
}

4896

4897 4898 4899 4900 4901 4902 4903 4904 4905 4906 4907 4908 4909 4910 4911 4912 4913 4914 4915 4916 4917 4918 4919 4920 4921 4922 4923 4924 4925 4926 4927
void MessageQueueDebuggerThread::Run() {
  const int kBufferSize = 1000;
  uint16_t buffer_1[kBufferSize];
  uint16_t buffer_2[kBufferSize];
  const char* command_1 =
      "{\"seq\":117,"
       "\"type\":\"request\","
       "\"command\":\"evaluate\","
       "\"arguments\":{\"expression\":\"1+2\"}}";
  const char* command_2 =
    "{\"seq\":118,"
     "\"type\":\"request\","
     "\"command\":\"evaluate\","
     "\"arguments\":{\"expression\":\"1+a\"}}";
  const char* command_3 =
    "{\"seq\":119,"
     "\"type\":\"request\","
     "\"command\":\"evaluate\","
     "\"arguments\":{\"expression\":\"c.d * b\"}}";
  const char* command_continue =
    "{\"seq\":106,"
     "\"type\":\"request\","
     "\"command\":\"continue\"}";
  const char* command_single_step =
    "{\"seq\":107,"
     "\"type\":\"request\","
     "\"command\":\"continue\","
     "\"arguments\":{\"stepaction\":\"next\"}}";

  /* Interleaved sequence of actions by the two threads:*/
  // Main thread compiles and runs source_1
4928
  message_queue_barriers.semaphore_1.Signal();
4929 4930 4931 4932 4933 4934
  message_queue_barriers.barrier_1.Wait();
  // Post 6 commands, filling the command queue and making it expand.
  // These calls return immediately, but the commands stay on the queue
  // until the execution of source_2.
  // Note: AsciiToUtf16 executes before SendCommand, so command is copied
  // to buffer before buffer is sent to SendCommand.
4935
  v8::Isolate* isolate = CcTest::isolate();
4936 4937 4938 4939 4940
  v8::Debug::SendCommand(isolate, buffer_1, AsciiToUtf16(command_1, buffer_1));
  v8::Debug::SendCommand(isolate, buffer_2, AsciiToUtf16(command_2, buffer_2));
  v8::Debug::SendCommand(isolate, buffer_2, AsciiToUtf16(command_3, buffer_2));
  v8::Debug::SendCommand(isolate, buffer_2, AsciiToUtf16(command_3, buffer_2));
  v8::Debug::SendCommand(isolate, buffer_2, AsciiToUtf16(command_3, buffer_2));
4941 4942
  message_queue_barriers.barrier_2.Wait();
  // Main thread compiles and runs source_2.
4943 4944 4945 4946 4947 4948 4949
  // Queued commands are executed at the start of compilation of source_2(
  // beforeCompile event).
  // Free the message handler to process all the messages from the queue. 7
  // messages are expected: 2 afterCompile events and 5 responses.
  // All the commands added so far will fail to execute as long as call stack
  // is empty on beforeCompile event.
  for (int i = 0; i < 6 ; ++i) {
4950
    message_queue_barriers.semaphore_1.Signal();
4951
  }
4952
  message_queue_barriers.barrier_3.Wait();
4953
  // Main thread compiles and runs source_3.
4954
  // Don't stop in the afterCompile handler.
4955
  message_queue_barriers.semaphore_1.Signal();
4956 4957
  // source_3 includes a debugger statement, which causes a break event.
  // Wait on break event from hitting "debugger" statement
4958
  message_queue_barriers.semaphore_2.Wait();
4959
  // These should execute after the "debugger" statement in source_2
4960 4961 4962 4963 4964
  v8::Debug::SendCommand(isolate, buffer_1, AsciiToUtf16(command_1, buffer_1));
  v8::Debug::SendCommand(isolate, buffer_2, AsciiToUtf16(command_2, buffer_2));
  v8::Debug::SendCommand(isolate, buffer_2, AsciiToUtf16(command_3, buffer_2));
  v8::Debug::SendCommand(
      isolate, buffer_2, AsciiToUtf16(command_single_step, buffer_2));
4965 4966
  // Run after 2 break events, 4 responses.
  for (int i = 0; i < 6 ; ++i) {
4967
    message_queue_barriers.semaphore_1.Signal();
4968
  }
4969
  // Wait on break event after a single step executes.
4970
  message_queue_barriers.semaphore_2.Wait();
4971 4972 4973
  v8::Debug::SendCommand(isolate, buffer_1, AsciiToUtf16(command_2, buffer_1));
  v8::Debug::SendCommand(
      isolate, buffer_2, AsciiToUtf16(command_continue, buffer_2));
4974 4975
  // Run after 2 responses.
  for (int i = 0; i < 2 ; ++i) {
4976
    message_queue_barriers.semaphore_1.Signal();
4977
  }
4978 4979 4980 4981 4982
  // Main thread continues running source_3 to end, waits for this thread.
}


// This thread runs the v8 engine.
4983
TEST(MessageQueues) {
4984
  MessageQueueDebuggerThread message_queue_debugger_thread;
4985

4986
  // Create a V8 environment
4987
  DebugLocalContext env;
4988
  v8::HandleScope scope(env->GetIsolate());
4989
  v8::Debug::SetMessageHandler(MessageHandler);
4990 4991 4992 4993 4994 4995 4996 4997 4998 4999 5000 5001 5002 5003 5004 5005 5006 5007
  message_queue_debugger_thread.Start();

  const char* source_1 = "a = 3; b = 4; c = new Object(); c.d = 5;";
  const char* source_2 = "e = 17;";
  const char* source_3 = "a = 4; debugger; a = 5; a = 6; a = 7;";

  // See MessageQueueDebuggerThread::Run for interleaved sequence of
  // API calls and events in the two threads.
  CompileRun(source_1);
  message_queue_barriers.barrier_1.Wait();
  message_queue_barriers.barrier_2.Wait();
  CompileRun(source_2);
  message_queue_barriers.barrier_3.Wait();
  CompileRun(source_3);
  message_queue_debugger_thread.Join();
  fflush(stdout);
}

5008 5009 5010 5011 5012 5013 5014 5015 5016 5017 5018 5019 5020 5021 5022 5023 5024 5025 5026 5027 5028 5029 5030 5031 5032 5033 5034 5035

class TestClientData : public v8::Debug::ClientData {
 public:
  TestClientData() {
    constructor_call_counter++;
  }
  virtual ~TestClientData() {
    destructor_call_counter++;
  }

  static void ResetCounters() {
    constructor_call_counter = 0;
    destructor_call_counter = 0;
  }

  static int constructor_call_counter;
  static int destructor_call_counter;
};

int TestClientData::constructor_call_counter = 0;
int TestClientData::destructor_call_counter = 0;


// Tests that MessageQueue doesn't destroy client data when expands and
// does destroy when it dies.
TEST(MessageQueueExpandAndDestroy) {
  TestClientData::ResetCounters();
  { // Create a scope for the queue.
5036 5037
    CommandMessageQueue queue(1);
    queue.Put(CommandMessage::New(Vector<uint16_t>::empty(),
5038
                                  new TestClientData()));
5039
    queue.Put(CommandMessage::New(Vector<uint16_t>::empty(),
5040
                                  new TestClientData()));
5041
    queue.Put(CommandMessage::New(Vector<uint16_t>::empty(),
5042
                                  new TestClientData()));
5043
    CHECK_EQ(0, TestClientData::destructor_call_counter);
5044
    queue.Get().Dispose();
5045
    CHECK_EQ(1, TestClientData::destructor_call_counter);
5046
    queue.Put(CommandMessage::New(Vector<uint16_t>::empty(),
5047
                                  new TestClientData()));
5048
    queue.Put(CommandMessage::New(Vector<uint16_t>::empty(),
5049
                                  new TestClientData()));
5050 5051 5052 5053 5054
    queue.Put(CommandMessage::New(Vector<uint16_t>::empty(),
                                  new TestClientData()));
    queue.Put(CommandMessage::New(Vector<uint16_t>::empty(),
                                  new TestClientData()));
    queue.Put(CommandMessage::New(Vector<uint16_t>::empty(),
5055
                                  new TestClientData()));
5056
    CHECK_EQ(1, TestClientData::destructor_call_counter);
5057
    queue.Get().Dispose();
5058
    CHECK_EQ(2, TestClientData::destructor_call_counter);
5059 5060
  }
  // All the client data should be destroyed when the queue is destroyed.
5061 5062
  CHECK_EQ(TestClientData::destructor_call_counter,
           TestClientData::destructor_call_counter);
5063 5064 5065 5066 5067
}


static int handled_client_data_instances_count = 0;
static void MessageHandlerCountingClientData(
5068 5069
    const v8::Debug::Message& message) {
  if (message.GetClientData() != NULL) {
5070 5071 5072 5073 5074 5075 5076 5077 5078
    handled_client_data_instances_count++;
  }
}


// Tests that all client data passed to the debugger are sent to the handler.
TEST(SendClientDataToHandler) {
  // Create a V8 environment
  DebugLocalContext env;
5079 5080
  v8::Isolate* isolate = env->GetIsolate();
  v8::HandleScope scope(isolate);
5081 5082
  TestClientData::ResetCounters();
  handled_client_data_instances_count = 0;
5083
  v8::Debug::SetMessageHandler(MessageHandlerCountingClientData);
5084
  const char* source_1 = "a = 3; b = 4; c = new Object(); c.d = 5;";
5085 5086 5087 5088 5089 5090 5091 5092 5093 5094 5095 5096 5097 5098 5099 5100 5101
  const int kBufferSize = 1000;
  uint16_t buffer[kBufferSize];
  const char* command_1 =
      "{\"seq\":117,"
       "\"type\":\"request\","
       "\"command\":\"evaluate\","
       "\"arguments\":{\"expression\":\"1+2\"}}";
  const char* command_2 =
    "{\"seq\":118,"
     "\"type\":\"request\","
     "\"command\":\"evaluate\","
     "\"arguments\":{\"expression\":\"1+a\"}}";
  const char* command_continue =
    "{\"seq\":106,"
     "\"type\":\"request\","
     "\"command\":\"continue\"}";

5102
  v8::Debug::SendCommand(isolate, buffer, AsciiToUtf16(command_1, buffer),
5103
                         new TestClientData());
5104 5105 5106
  v8::Debug::SendCommand(
      isolate, buffer, AsciiToUtf16(command_2, buffer), NULL);
  v8::Debug::SendCommand(isolate, buffer, AsciiToUtf16(command_2, buffer),
5107
                         new TestClientData());
5108
  v8::Debug::SendCommand(isolate, buffer, AsciiToUtf16(command_2, buffer),
5109
                         new TestClientData());
5110
  // All the messages will be processed on beforeCompile event.
5111
  CompileRun(source_1);
5112 5113
  v8::Debug::SendCommand(
      isolate, buffer, AsciiToUtf16(command_continue, buffer));
5114 5115 5116 5117 5118
  CHECK_EQ(3, TestClientData::constructor_call_counter);
  CHECK_EQ(TestClientData::constructor_call_counter,
           handled_client_data_instances_count);
  CHECK_EQ(TestClientData::constructor_call_counter,
           TestClientData::destructor_call_counter);
5119 5120 5121
}


5122 5123 5124 5125 5126 5127 5128 5129 5130
/* Test ThreadedDebugging */
/* This test interrupts a running infinite loop that is
 * occupying the v8 thread by a break command from the
 * debugger thread.  It then changes the value of a
 * global object, to make the loop terminate.
 */

Barriers threaded_debugging_barriers;

5131
class V8Thread : public v8::base::Thread {
5132
 public:
5133
  V8Thread() : Thread(Options("V8Thread")) {}
5134
  void Run();
5135 5136 5137 5138
  v8::Isolate* isolate() { return isolate_; }

 private:
  v8::Isolate* isolate_;
5139 5140
};

5141
class DebuggerThread : public v8::base::Thread {
5142
 public:
5143 5144
  explicit DebuggerThread(v8::Isolate* isolate)
      : Thread(Options("DebuggerThread")), isolate_(isolate) {}
5145
  void Run();
5146 5147 5148

 private:
  v8::Isolate* isolate_;
5149 5150 5151
};


5152 5153
static void ThreadedAtBarrier1(
    const v8::FunctionCallbackInfo<v8::Value>& args) {
5154 5155 5156 5157
  threaded_debugging_barriers.barrier_1.Wait();
}


5158
static void ThreadedMessageHandler(const v8::Debug::Message& message) {
5159
  static char print_buffer[1000];
5160 5161
  v8::String::Value json(message.GetJSON());
  Utf16ToAscii(*json, json.length(), print_buffer);
5162
  if (IsBreakEventMessage(print_buffer)) {
5163 5164
    // Check that we are inside the while loop.
    int source_line = GetSourceLineFromBreakEventMessage(print_buffer);
5165
    CHECK(8 <= source_line && source_line <= 13);
5166 5167 5168 5169 5170 5171
    threaded_debugging_barriers.barrier_2.Wait();
  }
}


void V8Thread::Run() {
5172
  const char* source =
5173 5174 5175 5176 5177 5178 5179 5180 5181
      "flag = true;\n"
      "function bar( new_value ) {\n"
      "  flag = new_value;\n"
      "  return \"Return from bar(\" + new_value + \")\";\n"
      "}\n"
      "\n"
      "function foo() {\n"
      "  var x = 1;\n"
      "  while ( flag == true ) {\n"
5182 5183 5184
      "    if ( x == 1 ) {\n"
      "      ThreadedAtBarrier1();\n"
      "    }\n"
5185 5186 5187
      "    x = x + 1;\n"
      "  }\n"
      "}\n"
5188 5189
      "\n"
      "foo();\n";
5190

5191 5192 5193
  v8::Isolate::CreateParams create_params;
  create_params.array_buffer_allocator = CcTest::array_buffer_allocator();
  isolate_ = v8::Isolate::New(create_params);
5194 5195 5196 5197 5198 5199 5200 5201 5202 5203 5204 5205 5206 5207 5208 5209 5210
  threaded_debugging_barriers.barrier_3.Wait();
  {
    v8::Isolate::Scope isolate_scope(isolate_);
    DebugLocalContext env(isolate_);
    v8::HandleScope scope(isolate_);
    v8::Debug::SetMessageHandler(&ThreadedMessageHandler);
    v8::Handle<v8::ObjectTemplate> global_template =
        v8::ObjectTemplate::New(env->GetIsolate());
    global_template->Set(
        v8::String::NewFromUtf8(env->GetIsolate(), "ThreadedAtBarrier1"),
        v8::FunctionTemplate::New(isolate_, ThreadedAtBarrier1));
    v8::Handle<v8::Context> context =
        v8::Context::New(isolate_, NULL, global_template);
    v8::Context::Scope context_scope(context);

    CompileRun(source);
  }
5211
  threaded_debugging_barriers.barrier_4.Wait();
5212
  isolate_->Dispose();
5213 5214
}

5215

5216 5217 5218 5219
void DebuggerThread::Run() {
  const int kBufSize = 1000;
  uint16_t buffer[kBufSize];

5220
  const char* command_1 = "{\"seq\":102,"
5221 5222 5223
      "\"type\":\"request\","
      "\"command\":\"evaluate\","
      "\"arguments\":{\"expression\":\"bar(false)\"}}";
5224
  const char* command_2 = "{\"seq\":103,"
5225 5226 5227 5228
      "\"type\":\"request\","
      "\"command\":\"continue\"}";

  threaded_debugging_barriers.barrier_1.Wait();
5229
  v8::Debug::DebugBreak(isolate_);
5230
  threaded_debugging_barriers.barrier_2.Wait();
5231 5232
  v8::Debug::SendCommand(isolate_, buffer, AsciiToUtf16(command_1, buffer));
  v8::Debug::SendCommand(isolate_, buffer, AsciiToUtf16(command_2, buffer));
5233
  threaded_debugging_barriers.barrier_4.Wait();
5234 5235 5236
}


5237
TEST(ThreadedDebugging) {
5238
  V8Thread v8_thread;
5239

5240 5241
  // Create a V8 environment
  v8_thread.Start();
5242 5243
  threaded_debugging_barriers.barrier_3.Wait();
  DebuggerThread debugger_thread(v8_thread.isolate());
5244 5245 5246 5247 5248 5249
  debugger_thread.Start();

  v8_thread.Join();
  debugger_thread.Join();
}

5250

5251 5252 5253 5254 5255 5256 5257
/* Test RecursiveBreakpoints */
/* In this test, the debugger evaluates a function with a breakpoint, after
 * hitting a breakpoint in another function.  We do this with both values
 * of the flag enabling recursive breakpoints, and verify that the second
 * breakpoint is hit when enabled, and missed when disabled.
 */

5258
class BreakpointsV8Thread : public v8::base::Thread {
5259
 public:
5260
  BreakpointsV8Thread() : Thread(Options("BreakpointsV8Thread")) {}
5261
  void Run();
5262 5263 5264 5265 5266

  v8::Isolate* isolate() { return isolate_; }

 private:
  v8::Isolate* isolate_;
5267 5268
};

5269
class BreakpointsDebuggerThread : public v8::base::Thread {
5270
 public:
5271
  BreakpointsDebuggerThread(bool global_evaluate, v8::Isolate* isolate)
5272
      : Thread(Options("BreakpointsDebuggerThread")),
5273 5274
        global_evaluate_(global_evaluate),
        isolate_(isolate) {}
5275
  void Run();
5276 5277 5278

 private:
  bool global_evaluate_;
5279
  v8::Isolate* isolate_;
5280 5281 5282 5283
};


Barriers* breakpoints_barriers;
5284 5285
int break_event_breakpoint_id;
int evaluate_int_result;
5286

5287
static void BreakpointsMessageHandler(const v8::Debug::Message& message) {
5288
  static char print_buffer[1000];
5289 5290
  v8::String::Value json(message.GetJSON());
  Utf16ToAscii(*json, json.length(), print_buffer);
5291

5292
  if (IsBreakEventMessage(print_buffer)) {
5293 5294
    break_event_breakpoint_id =
        GetBreakpointIdFromBreakEventMessage(print_buffer);
5295
    breakpoints_barriers->semaphore_1.Signal();
5296 5297
  } else if (IsEvaluateResponseMessage(print_buffer)) {
    evaluate_int_result = GetEvaluateIntResult(print_buffer);
5298
    breakpoints_barriers->semaphore_1.Signal();
5299 5300 5301 5302 5303 5304 5305 5306
  }
}


void BreakpointsV8Thread::Run() {
  const char* source_1 = "var y_global = 3;\n"
    "function cat( new_value ) {\n"
    "  var x = new_value;\n"
5307
    "  y_global = y_global + 4;\n"
5308
    "  x = 3 * x + 1;\n"
5309
    "  y_global = y_global + 5;\n"
5310 5311 5312 5313 5314 5315 5316 5317 5318 5319 5320 5321 5322 5323
    "  return x;\n"
    "}\n"
    "\n"
    "function dog() {\n"
    "  var x = 1;\n"
    "  x = y_global;"
    "  var z = 3;"
    "  x += 100;\n"
    "  return x;\n"
    "}\n"
    "\n";
  const char* source_2 = "cat(17);\n"
    "cat(19);\n";

5324 5325 5326
  v8::Isolate::CreateParams create_params;
  create_params.array_buffer_allocator = CcTest::array_buffer_allocator();
  isolate_ = v8::Isolate::New(create_params);
5327 5328 5329 5330 5331 5332 5333 5334 5335 5336 5337 5338
  breakpoints_barriers->barrier_3.Wait();
  {
    v8::Isolate::Scope isolate_scope(isolate_);
    DebugLocalContext env(isolate_);
    v8::HandleScope scope(isolate_);
    v8::Debug::SetMessageHandler(&BreakpointsMessageHandler);

    CompileRun(source_1);
    breakpoints_barriers->barrier_1.Wait();
    breakpoints_barriers->barrier_2.Wait();
    CompileRun(source_2);
  }
5339
  breakpoints_barriers->barrier_4.Wait();
5340
  isolate_->Dispose();
5341 5342 5343 5344 5345 5346 5347 5348 5349 5350 5351 5352 5353 5354 5355
}


void BreakpointsDebuggerThread::Run() {
  const int kBufSize = 1000;
  uint16_t buffer[kBufSize];

  const char* command_1 = "{\"seq\":101,"
      "\"type\":\"request\","
      "\"command\":\"setbreakpoint\","
      "\"arguments\":{\"type\":\"function\",\"target\":\"cat\",\"line\":3}}";
  const char* command_2 = "{\"seq\":102,"
      "\"type\":\"request\","
      "\"command\":\"setbreakpoint\","
      "\"arguments\":{\"type\":\"function\",\"target\":\"dog\",\"line\":3}}";
5356 5357 5358 5359 5360 5361 5362 5363 5364 5365 5366 5367 5368 5369 5370 5371 5372 5373 5374 5375 5376 5377 5378 5379 5380 5381
  const char* command_3;
  if (this->global_evaluate_) {
    command_3 = "{\"seq\":103,"
        "\"type\":\"request\","
        "\"command\":\"evaluate\","
        "\"arguments\":{\"expression\":\"dog()\",\"disable_break\":false,"
        "\"global\":true}}";
  } else {
    command_3 = "{\"seq\":103,"
        "\"type\":\"request\","
        "\"command\":\"evaluate\","
        "\"arguments\":{\"expression\":\"dog()\",\"disable_break\":false}}";
  }
  const char* command_4;
  if (this->global_evaluate_) {
    command_4 = "{\"seq\":104,"
        "\"type\":\"request\","
        "\"command\":\"evaluate\","
        "\"arguments\":{\"expression\":\"100 + 8\",\"disable_break\":true,"
        "\"global\":true}}";
  } else {
    command_4 = "{\"seq\":104,"
        "\"type\":\"request\","
        "\"command\":\"evaluate\","
        "\"arguments\":{\"expression\":\"x + 1\",\"disable_break\":true}}";
  }
5382
  const char* command_5 = "{\"seq\":105,"
5383 5384
      "\"type\":\"request\","
      "\"command\":\"continue\"}";
5385
  const char* command_6 = "{\"seq\":106,"
5386 5387
      "\"type\":\"request\","
      "\"command\":\"continue\"}";
5388 5389 5390 5391 5392 5393 5394 5395 5396 5397 5398 5399 5400
  const char* command_7;
  if (this->global_evaluate_) {
    command_7 = "{\"seq\":107,"
        "\"type\":\"request\","
        "\"command\":\"evaluate\","
        "\"arguments\":{\"expression\":\"dog()\",\"disable_break\":true,"
        "\"global\":true}}";
  } else {
    command_7 = "{\"seq\":107,"
        "\"type\":\"request\","
        "\"command\":\"evaluate\","
        "\"arguments\":{\"expression\":\"dog()\",\"disable_break\":true}}";
  }
5401
  const char* command_8 = "{\"seq\":108,"
5402 5403 5404 5405 5406 5407
      "\"type\":\"request\","
      "\"command\":\"continue\"}";


  // v8 thread initializes, runs source_1
  breakpoints_barriers->barrier_1.Wait();
5408
  // 1:Set breakpoint in cat() (will get id 1).
5409
  v8::Debug::SendCommand(isolate_, buffer, AsciiToUtf16(command_1, buffer));
5410
  // 2:Set breakpoint in dog() (will get id 2).
5411
  v8::Debug::SendCommand(isolate_, buffer, AsciiToUtf16(command_2, buffer));
5412
  breakpoints_barriers->barrier_2.Wait();
5413
  // V8 thread starts compiling source_2.
5414
  // Automatic break happens, to run queued commands
5415
  // breakpoints_barriers->semaphore_1.Wait();
5416 5417 5418
  // Commands 1 through 3 run, thread continues.
  // v8 thread runs source_2 to breakpoint in cat().
  // message callback receives break event.
5419
  breakpoints_barriers->semaphore_1.Wait();
5420 5421
  // Must have hit breakpoint #1.
  CHECK_EQ(1, break_event_breakpoint_id);
5422
  // 4:Evaluate dog() (which has a breakpoint).
5423
  v8::Debug::SendCommand(isolate_, buffer, AsciiToUtf16(command_3, buffer));
5424
  // V8 thread hits breakpoint in dog().
5425
  breakpoints_barriers->semaphore_1.Wait();  // wait for break event
5426 5427 5428
  // Must have hit breakpoint #2.
  CHECK_EQ(2, break_event_breakpoint_id);
  // 5:Evaluate (x + 1).
5429
  v8::Debug::SendCommand(isolate_, buffer, AsciiToUtf16(command_4, buffer));
5430
  // Evaluate (x + 1) finishes.
5431
  breakpoints_barriers->semaphore_1.Wait();
5432 5433 5434
  // Must have result 108.
  CHECK_EQ(108, evaluate_int_result);
  // 6:Continue evaluation of dog().
5435
  v8::Debug::SendCommand(isolate_, buffer, AsciiToUtf16(command_5, buffer));
5436
  // Evaluate dog() finishes.
5437
  breakpoints_barriers->semaphore_1.Wait();
5438 5439
  // Must have result 107.
  CHECK_EQ(107, evaluate_int_result);
5440 5441
  // 7:Continue evaluation of source_2, finish cat(17), hit breakpoint
  // in cat(19).
5442
  v8::Debug::SendCommand(isolate_, buffer, AsciiToUtf16(command_6, buffer));
5443
  // Message callback gets break event.
5444
  breakpoints_barriers->semaphore_1.Wait();  // wait for break event
5445 5446 5447
  // Must have hit breakpoint #1.
  CHECK_EQ(1, break_event_breakpoint_id);
  // 8: Evaluate dog() with breaks disabled.
5448
  v8::Debug::SendCommand(isolate_, buffer, AsciiToUtf16(command_7, buffer));
5449
  // Evaluate dog() finishes.
5450
  breakpoints_barriers->semaphore_1.Wait();
5451 5452
  // Must have result 116.
  CHECK_EQ(116, evaluate_int_result);
5453
  // 9: Continue evaluation of source2, reach end.
5454
  v8::Debug::SendCommand(isolate_, buffer, AsciiToUtf16(command_8, buffer));
5455
  breakpoints_barriers->barrier_4.Wait();
5456 5457
}

5458

5459
void TestRecursiveBreakpointsGeneric(bool global_evaluate) {
5460
  BreakpointsV8Thread breakpoints_v8_thread;
5461

5462 5463 5464 5465 5466
  // Create a V8 environment
  Barriers stack_allocated_breakpoints_barriers;
  breakpoints_barriers = &stack_allocated_breakpoints_barriers;

  breakpoints_v8_thread.Start();
5467 5468 5469
  breakpoints_barriers->barrier_3.Wait();
  BreakpointsDebuggerThread breakpoints_debugger_thread(
      global_evaluate, breakpoints_v8_thread.isolate());
5470 5471 5472 5473 5474
  breakpoints_debugger_thread.Start();

  breakpoints_v8_thread.Join();
  breakpoints_debugger_thread.Join();
}
5475

5476

5477
TEST(RecursiveBreakpoints) {
5478 5479 5480
  TestRecursiveBreakpointsGeneric(false);
}

5481

5482
TEST(RecursiveBreakpointsGlobal) {
5483 5484 5485
  TestRecursiveBreakpointsGeneric(true);
}

5486

5487
TEST(SetDebugEventListenerOnUninitializedVM) {
5488
  v8::Debug::SetDebugEventListener(DummyDebugEventListener);
5489 5490 5491
}


5492
static void DummyMessageHandler(const v8::Debug::Message& message) {
5493 5494 5495 5496
}


TEST(SetMessageHandlerOnUninitializedVM) {
5497
  v8::Debug::SetMessageHandler(DummyMessageHandler);
5498 5499 5500
}


5501 5502 5503 5504 5505 5506 5507 5508 5509 5510 5511 5512 5513 5514 5515 5516
// Source for a JavaScript function which returns the data parameter of a
// function called in the context of the debugger. If no data parameter is
// passed it throws an exception.
static const char* debugger_call_with_data_source =
    "function debugger_call_with_data(exec_state, data) {"
    "  if (data) return data;"
    "  throw 'No data!'"
    "}";
v8::Handle<v8::Function> debugger_call_with_data;


// Source for a JavaScript function which returns the data parameter of a
// function called in the context of the debugger. If no data parameter is
// passed it throws an exception.
static const char* debugger_call_with_closure_source =
    "var x = 3;"
5517
    "(function (exec_state) {"
5518 5519 5520
    "  if (exec_state.y) return x - 1;"
    "  exec_state.y = x;"
    "  return exec_state.y"
5521
    "})";
5522 5523 5524 5525
v8::Handle<v8::Function> debugger_call_with_closure;

// Function to retrieve the number of JavaScript frames by calling a JavaScript
// in the debugger.
5526
static void CheckFrameCount(const v8::FunctionCallbackInfo<v8::Value>& args) {
5527 5528 5529 5530 5531 5532 5533 5534
  CHECK(v8::Debug::Call(frame_count)->IsNumber());
  CHECK_EQ(args[0]->Int32Value(),
           v8::Debug::Call(frame_count)->Int32Value());
}


// Function to retrieve the source line of the top JavaScript frame by calling a
// JavaScript function in the debugger.
5535
static void CheckSourceLine(const v8::FunctionCallbackInfo<v8::Value>& args) {
5536 5537 5538 5539 5540 5541 5542 5543 5544
  CHECK(v8::Debug::Call(frame_source_line)->IsNumber());
  CHECK_EQ(args[0]->Int32Value(),
           v8::Debug::Call(frame_source_line)->Int32Value());
}


// Function to test passing an additional parameter to a JavaScript function
// called in the debugger. It also tests that functions called in the debugger
// can throw exceptions.
5545 5546
static void CheckDataParameter(
    const v8::FunctionCallbackInfo<v8::Value>& args) {
5547 5548
  v8::Handle<v8::String> data =
      v8::String::NewFromUtf8(args.GetIsolate(), "Test");
5549 5550
  CHECK(v8::Debug::Call(debugger_call_with_data, data)->IsString());

5551
  for (int i = 0; i < 3; i++) {
5552
    v8::TryCatch catcher(args.GetIsolate());
5553 5554 5555 5556
    CHECK(v8::Debug::Call(debugger_call_with_data).IsEmpty());
    CHECK(catcher.HasCaught());
    CHECK(catcher.Exception()->IsString());
  }
5557 5558 5559 5560
}


// Function to test using a JavaScript with closure in the debugger.
5561
static void CheckClosure(const v8::FunctionCallbackInfo<v8::Value>& args) {
5562 5563 5564 5565 5566 5567 5568 5569 5570
  CHECK(v8::Debug::Call(debugger_call_with_closure)->IsNumber());
  CHECK_EQ(3, v8::Debug::Call(debugger_call_with_closure)->Int32Value());
}


// Test functions called through the debugger.
TEST(CallFunctionInDebugger) {
  // Create and enter a context with the functions CheckFrameCount,
  // CheckSourceLine and CheckDataParameter installed.
5571 5572 5573 5574
  v8::Isolate* isolate = CcTest::isolate();
  v8::HandleScope scope(isolate);
  v8::Handle<v8::ObjectTemplate> global_template =
      v8::ObjectTemplate::New(isolate);
5575
  global_template->Set(
5576 5577
      v8::String::NewFromUtf8(isolate, "CheckFrameCount"),
      v8::FunctionTemplate::New(isolate, CheckFrameCount));
5578
  global_template->Set(
5579 5580
      v8::String::NewFromUtf8(isolate, "CheckSourceLine"),
      v8::FunctionTemplate::New(isolate, CheckSourceLine));
5581
  global_template->Set(
5582 5583
      v8::String::NewFromUtf8(isolate, "CheckDataParameter"),
      v8::FunctionTemplate::New(isolate, CheckDataParameter));
5584
  global_template->Set(
5585 5586 5587
      v8::String::NewFromUtf8(isolate, "CheckClosure"),
      v8::FunctionTemplate::New(isolate, CheckClosure));
  v8::Handle<v8::Context> context = v8::Context::New(isolate,
5588 5589
                                                     NULL,
                                                     global_template);
5590 5591 5592
  v8::Context::Scope context_scope(context);

  // Compile a function for checking the number of JavaScript frames.
5593
  v8::Script::Compile(
5594
      v8::String::NewFromUtf8(isolate, frame_count_source))->Run();
5595
  frame_count = v8::Local<v8::Function>::Cast(context->Global()->Get(
5596
      v8::String::NewFromUtf8(isolate, "frame_count")));
5597 5598

  // Compile a function for returning the source line for the top frame.
5599
  v8::Script::Compile(v8::String::NewFromUtf8(isolate,
5600 5601
                                              frame_source_line_source))->Run();
  frame_source_line = v8::Local<v8::Function>::Cast(context->Global()->Get(
5602
      v8::String::NewFromUtf8(isolate, "frame_source_line")));
5603 5604

  // Compile a function returning the data parameter.
5605
  v8::Script::Compile(v8::String::NewFromUtf8(isolate,
5606 5607
                                              debugger_call_with_data_source))
      ->Run();
5608
  debugger_call_with_data = v8::Local<v8::Function>::Cast(
5609
      context->Global()->Get(v8::String::NewFromUtf8(
5610
          isolate, "debugger_call_with_data")));
5611 5612

  // Compile a function capturing closure.
5613 5614
  debugger_call_with_closure =
      v8::Local<v8::Function>::Cast(v8::Script::Compile(
5615
          v8::String::NewFromUtf8(isolate,
5616
                                  debugger_call_with_closure_source))->Run());
5617

5618 5619
  // Calling a function through the debugger returns 0 frames if there are
  // no JavaScript frames.
5620
  CHECK(v8::Integer::New(isolate, 0)->Equals(v8::Debug::Call(frame_count)));
5621 5622

  // Test that the number of frames can be retrieved.
5623
  v8::Script::Compile(
5624 5625
      v8::String::NewFromUtf8(isolate, "CheckFrameCount(1)"))->Run();
  v8::Script::Compile(v8::String::NewFromUtf8(isolate,
5626 5627 5628
                                              "function f() {"
                                              "  CheckFrameCount(2);"
                                              "}; f()"))->Run();
5629 5630

  // Test that the source line can be retrieved.
5631
  v8::Script::Compile(
5632 5633
      v8::String::NewFromUtf8(isolate, "CheckSourceLine(0)"))->Run();
  v8::Script::Compile(v8::String::NewFromUtf8(isolate,
5634 5635 5636 5637 5638
                                              "function f() {\n"
                                              "  CheckSourceLine(1)\n"
                                              "  CheckSourceLine(2)\n"
                                              "  CheckSourceLine(3)\n"
                                              "}; f()"))->Run();
5639 5640

  // Test that a parameter can be passed to a function called in the debugger.
5641
  v8::Script::Compile(v8::String::NewFromUtf8(isolate,
5642
                                              "CheckDataParameter()"))->Run();
5643 5644

  // Test that a function with closure can be run in the debugger.
5645
  v8::Script::Compile(
5646
      v8::String::NewFromUtf8(isolate, "CheckClosure()"))->Run();
5647 5648

  // Test that the source line is correct when there is a line offset.
5649 5650
  v8::ScriptOrigin origin(v8::String::NewFromUtf8(isolate, "test"),
                          v8::Integer::New(isolate, 7));
5651
  v8::Script::Compile(
5652
      v8::String::NewFromUtf8(isolate, "CheckSourceLine(7)"), &origin)
5653
      ->Run();
5654
  v8::Script::Compile(v8::String::NewFromUtf8(isolate,
5655 5656 5657 5658 5659 5660
                                              "function f() {\n"
                                              "  CheckSourceLine(8)\n"
                                              "  CheckSourceLine(9)\n"
                                              "  CheckSourceLine(10)\n"
                                              "}; f()"),
                      &origin)->Run();
5661
}
5662 5663


5664 5665 5666 5667 5668 5669 5670 5671 5672 5673 5674 5675 5676
// Debugger message handler which counts the number of breaks.
static void SendContinueCommand();
static void MessageHandlerBreakPointHitCount(
    const v8::Debug::Message& message) {
  if (message.IsEvent() && message.GetEvent() == v8::Break) {
    // Count the number of breaks.
    break_point_hit_count++;

    SendContinueCommand();
  }
}


5677 5678 5679 5680 5681 5682 5683 5684
// Test that clearing the debug event listener actually clears all break points
// and related information.
TEST(DebuggerUnload) {
  DebugLocalContext env;

  // Check debugger is unloaded before it is used.
  CheckDebuggerUnloaded();

5685 5686
  // Set a debug event listener.
  break_point_hit_count = 0;
5687
  v8::Debug::SetDebugEventListener(DebugEventBreakPointHitCount);
5688
  {
5689
    v8::HandleScope scope(env->GetIsolate());
5690 5691 5692 5693 5694 5695 5696 5697 5698 5699 5700 5701 5702 5703 5704 5705 5706 5707 5708
    // Create a couple of functions for the test.
    v8::Local<v8::Function> foo =
        CompileFunction(&env, "function foo(){x=1}", "foo");
    v8::Local<v8::Function> bar =
        CompileFunction(&env, "function bar(){y=2}", "bar");

    // Set some break points.
    SetBreakPoint(foo, 0);
    SetBreakPoint(foo, 4);
    SetBreakPoint(bar, 0);
    SetBreakPoint(bar, 4);

    // Make sure that the break points are there.
    break_point_hit_count = 0;
    foo->Call(env->Global(), 0, NULL);
    CHECK_EQ(2, break_point_hit_count);
    bar->Call(env->Global(), 0, NULL);
    CHECK_EQ(4, break_point_hit_count);
  }
sgjesse@chromium.org's avatar
sgjesse@chromium.org committed
5709

5710 5711
  // Remove the debug event listener without clearing breakpoints. Do this
  // outside a handle scope.
5712
  v8::Debug::SetDebugEventListener(NULL);
5713 5714
  CheckDebuggerUnloaded(true);

5715
  // Now set a debug message handler.
5716
  break_point_hit_count = 0;
5717
  v8::Debug::SetMessageHandler(MessageHandlerBreakPointHitCount);
5718
  {
5719
    v8::HandleScope scope(env->GetIsolate());
5720

5721
    // Get the test functions again.
5722
    v8::Local<v8::Function> foo(v8::Local<v8::Function>::Cast(
5723
        env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "foo"))));
5724

5725 5726 5727 5728 5729 5730 5731 5732 5733 5734 5735 5736
    foo->Call(env->Global(), 0, NULL);
    CHECK_EQ(0, break_point_hit_count);

    // Set break points and run again.
    SetBreakPoint(foo, 0);
    SetBreakPoint(foo, 4);
    foo->Call(env->Global(), 0, NULL);
    CHECK_EQ(2, break_point_hit_count);
  }

  // Remove the debug message handler without clearing breakpoints. Do this
  // outside a handle scope.
5737
  v8::Debug::SetMessageHandler(NULL);
5738 5739
  CheckDebuggerUnloaded(true);
}
5740 5741


5742 5743
// Sends continue command to the debugger.
static void SendContinueCommand() {
5744 5745 5746 5747 5748 5749 5750
  const int kBufferSize = 1000;
  uint16_t buffer[kBufferSize];
  const char* command_continue =
    "{\"seq\":0,"
     "\"type\":\"request\","
     "\"command\":\"continue\"}";

5751 5752
  v8::Debug::SendCommand(
      CcTest::isolate(), buffer, AsciiToUtf16(command_continue, buffer));
5753 5754 5755
}


5756 5757 5758 5759 5760
// Debugger message handler which counts the number of times it is called.
static int message_handler_hit_count = 0;
static void MessageHandlerHitCount(const v8::Debug::Message& message) {
  message_handler_hit_count++;

5761 5762 5763 5764 5765 5766 5767
  static char print_buffer[1000];
  v8::String::Value json(message.GetJSON());
  Utf16ToAscii(*json, json.length(), print_buffer);
  if (IsExceptionEventMessage(print_buffer)) {
    // Send a continue command for exception events.
    SendContinueCommand();
  }
5768 5769 5770
}


5771 5772 5773
// Test clearing the debug message handler.
TEST(DebuggerClearMessageHandler) {
  DebugLocalContext env;
5774
  v8::HandleScope scope(env->GetIsolate());
5775 5776 5777 5778 5779

  // Check debugger is unloaded before it is used.
  CheckDebuggerUnloaded();

  // Set a debug message handler.
5780
  v8::Debug::SetMessageHandler(MessageHandlerHitCount);
5781 5782 5783 5784 5785 5786 5787 5788 5789 5790

  // Run code to throw a unhandled exception. This should end up in the message
  // handler.
  CompileRun("throw 1");

  // The message handler should be called.
  CHECK_GT(message_handler_hit_count, 0);

  // Clear debug message handler.
  message_handler_hit_count = 0;
5791
  v8::Debug::SetMessageHandler(NULL);
5792 5793 5794 5795 5796 5797 5798 5799 5800 5801 5802 5803 5804

  // Run code to throw a unhandled exception. This should end up in the message
  // handler.
  CompileRun("throw 1");

  // The message handler should not be called more.
  CHECK_EQ(0, message_handler_hit_count);

  CheckDebuggerUnloaded(true);
}


// Debugger message handler which clears the message handler while active.
5805
static void MessageHandlerClearingMessageHandler(
5806
    const v8::Debug::Message& message) {
5807 5808 5809
  message_handler_hit_count++;

  // Clear debug message handler.
5810
  v8::Debug::SetMessageHandler(NULL);
5811 5812 5813 5814 5815 5816
}


// Test clearing the debug message handler while processing a debug event.
TEST(DebuggerClearMessageHandlerWhileActive) {
  DebugLocalContext env;
5817
  v8::HandleScope scope(env->GetIsolate());
5818 5819 5820 5821 5822

  // Check debugger is unloaded before it is used.
  CheckDebuggerUnloaded();

  // Set a debug message handler.
5823
  v8::Debug::SetMessageHandler(MessageHandlerClearingMessageHandler);
5824 5825 5826 5827 5828 5829 5830 5831 5832 5833 5834 5835

  // Run code to throw a unhandled exception. This should end up in the message
  // handler.
  CompileRun("throw 1");

  // The message handler should be called.
  CHECK_EQ(1, message_handler_hit_count);

  CheckDebuggerUnloaded(true);
}


5836 5837 5838 5839 5840 5841
// Test for issue http://code.google.com/p/v8/issues/detail?id=289.
// Make sure that DebugGetLoadedScripts doesn't return scripts
// with disposed external source.
class EmptyExternalStringResource : public v8::String::ExternalStringResource {
 public:
  EmptyExternalStringResource() { empty_[0] = 0; }
5842
  virtual ~EmptyExternalStringResource() {}
5843 5844 5845
  virtual size_t length() const { return empty_.length(); }
  virtual const uint16_t* data() const { return empty_.start(); }
 private:
5846
  ::v8::internal::EmbeddedVector<uint16_t, 1> empty_;
5847 5848 5849 5850 5851
};


TEST(DebugGetLoadedScripts) {
  DebugLocalContext env;
5852
  v8::HandleScope scope(env->GetIsolate());
5853 5854
  env.ExposeDebug();

5855
  EmptyExternalStringResource source_ext_str;
5856 5857
  v8::Local<v8::String> source =
      v8::String::NewExternal(env->GetIsolate(), &source_ext_str);
5858
  v8::Handle<v8::Script> evil_script(v8::Script::Compile(source));
5859
  // "use" evil_script to make the compiler happy.
5860
  USE(evil_script);
5861 5862 5863 5864 5865 5866 5867 5868
  Handle<i::ExternalTwoByteString> i_source(
      i::ExternalTwoByteString::cast(*v8::Utils::OpenHandle(*source)));
  // This situation can happen if source was an external string disposed
  // by its owner.
  i_source->set_resource(0);

  bool allow_natives_syntax = i::FLAG_allow_natives_syntax;
  i::FLAG_allow_natives_syntax = true;
5869
  EnableDebugger();
5870 5871 5872 5873 5874 5875 5876 5877 5878 5879 5880 5881 5882 5883 5884
  v8::MaybeLocal<v8::Value> result =
      CompileRun(env.context(),
                 "var scripts = %DebugGetLoadedScripts();"
                 "var count = scripts.length;"
                 "for (var i = 0; i < count; ++i) {"
                 "  var lines = scripts[i].lineCount();"
                 "  if (lines < 1) throw 'lineCount';"
                 "  var last = -1;"
                 "  for (var j = 0; j < lines; ++j) {"
                 "    var end = scripts[i].lineEnd(j);"
                 "    if (last >= end) throw 'lineEnd';"
                 "    last = end;"
                 "  }"
                 "}");
  CHECK(!result.IsEmpty());
5885
  DisableDebugger();
5886 5887
  // Must not crash while accessing line_ends.
  i::FLAG_allow_natives_syntax = allow_natives_syntax;
5888 5889

  // Some scripts are retrieved - at least the number of native scripts.
5890 5891 5892 5893 5894
  CHECK_GT((*env)
               ->Global()
               ->Get(v8::String::NewFromUtf8(env->GetIsolate(), "count"))
               ->Int32Value(),
           8);
5895
}
5896 5897 5898 5899 5900


// Test script break points set on lines.
TEST(ScriptNameAndData) {
  DebugLocalContext env;
5901
  v8::HandleScope scope(env->GetIsolate());
5902 5903 5904 5905 5906 5907 5908 5909
  env.ExposeDebug();

  // Create functions for retrieving script name and data for the function on
  // the top frame when hitting a break point.
  frame_script_name = CompileFunction(&env,
                                      frame_script_name_source,
                                      "frame_script_name");

5910
  v8::Debug::SetDebugEventListener(DebugEventBreakPointHitCount);
5911 5912

  // Test function source.
5913 5914 5915 5916
  v8::Local<v8::String> script = v8::String::NewFromUtf8(env->GetIsolate(),
                                                         "function f() {\n"
                                                         "  debugger;\n"
                                                         "}\n");
5917

5918 5919
  v8::ScriptOrigin origin1 =
      v8::ScriptOrigin(v8::String::NewFromUtf8(env->GetIsolate(), "name"));
5920 5921 5922
  v8::Handle<v8::Script> script1 = v8::Script::Compile(script, &origin1);
  script1->Run();
  v8::Local<v8::Function> f;
5923 5924
  f = v8::Local<v8::Function>::Cast(
      env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "f")));
5925 5926 5927

  f->Call(env->Global(), 0, NULL);
  CHECK_EQ(1, break_point_hit_count);
5928
  CHECK_EQ(0, strcmp("name", last_script_name_hit));
5929

5930 5931 5932
  // Compile the same script again without setting data. As the compilation
  // cache is disabled when debugging expect the data to be missing.
  v8::Script::Compile(script, &origin1)->Run();
5933 5934
  f = v8::Local<v8::Function>::Cast(
      env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "f")));
5935 5936
  f->Call(env->Global(), 0, NULL);
  CHECK_EQ(2, break_point_hit_count);
5937
  CHECK_EQ(0, strcmp("name", last_script_name_hit));
5938

5939 5940 5941 5942 5943 5944
  v8::Local<v8::String> data_obj_source = v8::String::NewFromUtf8(
      env->GetIsolate(),
      "({ a: 'abc',\n"
      "  b: 123,\n"
      "  toString: function() { return this.a + ' ' + this.b; }\n"
      "})\n");
5945
  v8::Script::Compile(data_obj_source)->Run();
5946 5947
  v8::ScriptOrigin origin2 =
      v8::ScriptOrigin(v8::String::NewFromUtf8(env->GetIsolate(), "new name"));
5948 5949
  v8::Handle<v8::Script> script2 = v8::Script::Compile(script, &origin2);
  script2->Run();
5950 5951
  f = v8::Local<v8::Function>::Cast(
      env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "f")));
5952
  f->Call(env->Global(), 0, NULL);
5953
  CHECK_EQ(3, break_point_hit_count);
5954
  CHECK_EQ(0, strcmp("new name", last_script_name_hit));
5955

5956
  v8::Handle<v8::Script> script3 = v8::Script::Compile(script, &origin2);
5957
  script3->Run();
5958 5959
  f = v8::Local<v8::Function>::Cast(
      env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "f")));
5960 5961
  f->Call(env->Global(), 0, NULL);
  CHECK_EQ(4, break_point_hit_count);
5962
}
5963 5964


5965
static v8::Handle<v8::Context> expected_context;
5966 5967 5968 5969 5970 5971
static v8::Handle<v8::Value> expected_context_data;


// Check that the expected context is the one generating the debug event.
static void ContextCheckMessageHandler(const v8::Debug::Message& message) {
  CHECK(message.GetEventContext() == expected_context);
5972
  CHECK(message.GetEventContext()->GetEmbedderData(0)->StrictEquals(
5973 5974 5975
      expected_context_data));
  message_handler_hit_count++;

5976 5977 5978 5979
  static char print_buffer[1000];
  v8::String::Value json(message.GetJSON());
  Utf16ToAscii(*json, json.length(), print_buffer);

5980
  // Send a continue command for break events.
5981
  if (IsBreakEventMessage(print_buffer)) {
5982
    SendContinueCommand();
5983 5984 5985 5986 5987 5988 5989 5990
  }
}


// Test which creates two contexts and sets different embedder data on each.
// Checks that this data is set correctly and that when the debug message
// handler is called the expected context is the one active.
TEST(ContextData) {
5991
  v8::Isolate* isolate = CcTest::isolate();
5992
  v8::HandleScope scope(isolate);
5993 5994

  // Create two contexts.
5995 5996
  v8::Handle<v8::Context> context_1;
  v8::Handle<v8::Context> context_2;
5997 5998 5999
  v8::Handle<v8::ObjectTemplate> global_template =
      v8::Handle<v8::ObjectTemplate>();
  v8::Handle<v8::Value> global_object = v8::Handle<v8::Value>();
6000 6001
  context_1 = v8::Context::New(isolate, NULL, global_template, global_object);
  context_2 = v8::Context::New(isolate, NULL, global_template, global_object);
6002

6003
  v8::Debug::SetMessageHandler(ContextCheckMessageHandler);
6004

6005
  // Default data value is undefined.
6006 6007
  CHECK(context_1->GetEmbedderData(0)->IsUndefined());
  CHECK(context_2->GetEmbedderData(0)->IsUndefined());
6008 6009

  // Set and check different data values.
6010 6011
  v8::Handle<v8::String> data_1 = v8::String::NewFromUtf8(isolate, "1");
  v8::Handle<v8::String> data_2 = v8::String::NewFromUtf8(isolate, "2");
6012 6013 6014 6015
  context_1->SetEmbedderData(0, data_1);
  context_2->SetEmbedderData(0, data_2);
  CHECK(context_1->GetEmbedderData(0)->StrictEquals(data_1));
  CHECK(context_2->GetEmbedderData(0)->StrictEquals(data_2));
6016 6017

  // Simple test function which causes a break.
6018
  const char* source = "function f() { debugger; }";
6019 6020 6021 6022

  // Enter and run function in the first context.
  {
    v8::Context::Scope context_scope(context_1);
6023
    expected_context = context_1;
6024
    expected_context_data = data_1;
6025
    v8::Local<v8::Function> f = CompileFunction(isolate, source, "f");
6026 6027 6028 6029 6030 6031 6032
    f->Call(context_1->Global(), 0, NULL);
  }


  // Enter and run function in the second context.
  {
    v8::Context::Scope context_scope(context_2);
6033
    expected_context = context_2;
6034
    expected_context_data = data_2;
6035
    v8::Local<v8::Function> f = CompileFunction(isolate, source, "f");
6036 6037 6038 6039 6040
    f->Call(context_2->Global(), 0, NULL);
  }

  // Two times compile event and two times break event.
  CHECK_GT(message_handler_hit_count, 4);
6041

6042
  v8::Debug::SetMessageHandler(NULL);
6043
  CheckDebuggerUnloaded();
6044
}
6045 6046


6047 6048 6049 6050 6051 6052 6053
// Debug message handler which issues a debug break when it hits a break event.
static int message_handler_break_hit_count = 0;
static void DebugBreakMessageHandler(const v8::Debug::Message& message) {
  // Schedule a debug break for break events.
  if (message.IsEvent() && message.GetEvent() == v8::Break) {
    message_handler_break_hit_count++;
    if (message_handler_break_hit_count == 1) {
6054
      v8::Debug::DebugBreak(message.GetIsolate());
6055 6056 6057 6058 6059 6060 6061 6062 6063 6064 6065 6066 6067 6068
    }
  }

  // Issue a continue command if this event will not cause the VM to start
  // running.
  if (!message.WillStartRunning()) {
    SendContinueCommand();
  }
}


// Test that a debug break can be scheduled while in a message handler.
TEST(DebugBreakInMessageHandler) {
  DebugLocalContext env;
6069
  v8::HandleScope scope(env->GetIsolate());
6070

6071
  v8::Debug::SetMessageHandler(DebugBreakMessageHandler);
6072 6073

  // Test functions.
6074
  const char* script = "function f() { debugger; g(); } function g() { }";
6075
  CompileRun(script);
6076 6077 6078 6079
  v8::Local<v8::Function> f = v8::Local<v8::Function>::Cast(
      env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "f")));
  v8::Local<v8::Function> g = v8::Local<v8::Function>::Cast(
      env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "g")));
6080 6081 6082 6083 6084 6085 6086 6087 6088 6089 6090

  // Call f then g. The debugger statement in f will casue a break which will
  // cause another break.
  f->Call(env->Global(), 0, NULL);
  CHECK_EQ(2, message_handler_break_hit_count);
  // Calling g will not cause any additional breaks.
  g->Call(env->Global(), 0, NULL);
  CHECK_EQ(2, message_handler_break_hit_count);
}


6091
#ifndef V8_INTERPRETED_REGEXP
6092 6093 6094
// Debug event handler which gets the function on the top frame and schedules a
// break a number of times.
static void DebugEventDebugBreak(
6095 6096 6097
    const v8::Debug::EventDetails& event_details) {
  v8::DebugEvent event = event_details.GetEvent();
  v8::Handle<v8::Object> exec_state = event_details.GetExecutionState();
6098 6099 6100 6101 6102 6103 6104

  if (event == v8::Break) {
    break_point_hit_count++;

    // Get the name of the top frame function.
    if (!frame_function_name.IsEmpty()) {
      // Get the name of the function.
6105
      const int argc = 2;
6106 6107 6108
      v8::Handle<v8::Value> argv[argc] = {
        exec_state, v8::Integer::New(CcTest::isolate(), 0)
      };
6109 6110 6111 6112 6113 6114
      v8::Handle<v8::Value> result = frame_function_name->Call(exec_state,
                                                               argc, argv);
      if (result->IsUndefined()) {
        last_function_hit[0] = '\0';
      } else {
        CHECK(result->IsString());
6115 6116
        v8::Handle<v8::String> function_name(
            result->ToString(CcTest::isolate()));
6117
        function_name->WriteUtf8(last_function_hit);
6118 6119 6120 6121 6122
      }
    }

    // Keep forcing breaks.
    if (break_point_hit_count < 20) {
6123
      v8::Debug::DebugBreak(CcTest::isolate());
6124 6125 6126 6127 6128
    }
  }
}


6129
TEST(RegExpDebugBreak) {
6130
  // This test only applies to native regexps.
6131
  DebugLocalContext env;
6132
  v8::HandleScope scope(env->GetIsolate());
6133 6134 6135 6136 6137 6138 6139 6140 6141 6142 6143 6144

  // Create a function for checking the function when hitting a break point.
  frame_function_name = CompileFunction(&env,
                                        frame_function_name_source,
                                        "frame_function_name");

  // Test RegExp which matches white spaces and comments at the begining of a
  // source line.
  const char* script =
    "var sourceLineBeginningSkip = /^(?:[ \\v\\h]*(?:\\/\\*.*?\\*\\/)*)*/;\n"
    "function f(s) { return s.match(sourceLineBeginningSkip)[0].length; }";

6145
  v8::Local<v8::Function> f = CompileFunction(env->GetIsolate(), script, "f");
6146
  const int argc = 1;
6147 6148
  v8::Handle<v8::Value> argv[argc] = {
      v8::String::NewFromUtf8(env->GetIsolate(), "  /* xxx */ a=0;")};
6149 6150 6151
  v8::Local<v8::Value> result = f->Call(env->Global(), argc, argv);
  CHECK_EQ(12, result->Int32Value());

6152
  v8::Debug::SetDebugEventListener(DebugEventDebugBreak);
6153
  v8::Debug::DebugBreak(env->GetIsolate());
6154 6155
  result = f->Call(env->Global(), argc, argv);

6156 6157 6158
  // Check that there was only one break event. Matching RegExp should not
  // cause Break events.
  CHECK_EQ(1, break_point_hit_count);
6159
  CHECK_EQ(0, strcmp("f", last_function_hit));
6160
}
6161
#endif  // V8_INTERPRETED_REGEXP
6162 6163


6164
// Common part of EvalContextData and NestedBreakEventContextData tests.
6165
static void ExecuteScriptForContextCheck(
6166
    v8::Debug::MessageHandler message_handler) {
6167
  // Create a context.
6168
  v8::Handle<v8::Context> context_1;
6169 6170
  v8::Handle<v8::ObjectTemplate> global_template =
      v8::Handle<v8::ObjectTemplate>();
6171
  context_1 =
6172
      v8::Context::New(CcTest::isolate(), NULL, global_template);
6173

6174
  v8::Debug::SetMessageHandler(message_handler);
6175

6176
  // Default data value is undefined.
6177
  CHECK(context_1->GetEmbedderData(0)->IsUndefined());
6178 6179

  // Set and check a data value.
6180 6181
  v8::Handle<v8::String> data_1 =
      v8::String::NewFromUtf8(CcTest::isolate(), "1");
6182 6183
  context_1->SetEmbedderData(0, data_1);
  CHECK(context_1->GetEmbedderData(0)->StrictEquals(data_1));
6184 6185 6186 6187 6188 6189 6190

  // Simple test function with eval that causes a break.
  const char* source = "function f() { eval('debugger;'); }";

  // Enter and run function in the context.
  {
    v8::Context::Scope context_scope(context_1);
6191
    expected_context = context_1;
6192
    expected_context_data = data_1;
6193
    v8::Local<v8::Function> f = CompileFunction(CcTest::isolate(), source, "f");
6194 6195
    f->Call(context_1->Global(), 0, NULL);
  }
6196

6197
  v8::Debug::SetMessageHandler(NULL);
6198 6199 6200 6201 6202 6203 6204 6205
}


// Test which creates a context and sets embedder data on it. Checks that this
// data is set correctly and that when the debug message handler is called for
// break event in an eval statement the expected context is the one returned by
// Message.GetEventContext.
TEST(EvalContextData) {
6206
  v8::HandleScope scope(CcTest::isolate());
6207

6208
  ExecuteScriptForContextCheck(ContextCheckMessageHandler);
6209 6210 6211

  // One time compile event and one time break event.
  CHECK_GT(message_handler_hit_count, 2);
6212
  CheckDebuggerUnloaded();
6213 6214 6215 6216 6217
}


static bool sent_eval = false;
static int break_count = 0;
6218
static int continue_command_send_count = 0;
6219 6220 6221 6222 6223
// Check that the expected context is the one generating the debug event
// including the case of nested break event.
static void DebugEvalContextCheckMessageHandler(
    const v8::Debug::Message& message) {
  CHECK(message.GetEventContext() == expected_context);
6224
  CHECK(message.GetEventContext()->GetEmbedderData(0)->StrictEquals(
6225 6226 6227
      expected_context_data));
  message_handler_hit_count++;

6228 6229 6230 6231
  static char print_buffer[1000];
  v8::String::Value json(message.GetJSON());
  Utf16ToAscii(*json, json.length(), print_buffer);

6232
  v8::Isolate* isolate = message.GetIsolate();
6233
  if (IsBreakEventMessage(print_buffer)) {
6234 6235 6236 6237 6238 6239 6240
    break_count++;
    if (!sent_eval) {
      sent_eval = true;

      const int kBufferSize = 1000;
      uint16_t buffer[kBufferSize];
      const char* eval_command =
6241 6242 6243 6244 6245
          "{\"seq\":0,"
          "\"type\":\"request\","
          "\"command\":\"evaluate\","
          "\"arguments\":{\"expression\":\"debugger;\","
          "\"global\":true,\"disable_break\":false}}";
6246 6247

      // Send evaluate command.
6248 6249
      v8::Debug::SendCommand(
          isolate, buffer, AsciiToUtf16(eval_command, buffer));
6250 6251 6252 6253
      return;
    } else {
      // It's a break event caused by the evaluation request above.
      SendContinueCommand();
6254
      continue_command_send_count++;
6255
    }
6256 6257
  } else if (IsEvaluateResponseMessage(print_buffer) &&
      continue_command_send_count < 2) {
6258 6259 6260
    // Response to the evaluation request. We're still on the breakpoint so
    // send continue.
    SendContinueCommand();
6261
    continue_command_send_count++;
6262 6263 6264 6265 6266 6267 6268
  }
}


// Tests that context returned for break event is correct when the event occurs
// in 'evaluate' debugger request.
TEST(NestedBreakEventContextData) {
6269
  v8::HandleScope scope(CcTest::isolate());
6270 6271
  break_count = 0;
  message_handler_hit_count = 0;
6272

6273
  ExecuteScriptForContextCheck(DebugEvalContextCheckMessageHandler);
6274 6275 6276 6277 6278 6279

  // One time compile event and two times break event.
  CHECK_GT(message_handler_hit_count, 3);

  // One break from the source and another from the evaluate request.
  CHECK_EQ(break_count, 2);
6280
  CheckDebuggerUnloaded();
6281 6282 6283
}


6284 6285 6286 6287 6288 6289 6290 6291 6292 6293 6294 6295 6296 6297 6298 6299 6300 6301
// Debug event listener which counts the after compile events.
int after_compile_message_count = 0;
static void AfterCompileMessageHandler(const v8::Debug::Message& message) {
  // Count the number of scripts collected.
  if (message.IsEvent()) {
    if (message.GetEvent() == v8::AfterCompile) {
      after_compile_message_count++;
    } else if (message.GetEvent() == v8::Break) {
      SendContinueCommand();
    }
  }
}


// Tests that after compile event is sent as many times as there are scripts
// compiled.
TEST(AfterCompileMessageWhenMessageHandlerIsReset) {
  DebugLocalContext env;
6302
  v8::HandleScope scope(env->GetIsolate());
6303 6304 6305
  after_compile_message_count = 0;
  const char* script = "var a=1";

6306
  v8::Debug::SetMessageHandler(AfterCompileMessageHandler);
6307 6308
  v8::Script::Compile(v8::String::NewFromUtf8(env->GetIsolate(), script))
      ->Run();
6309
  v8::Debug::SetMessageHandler(NULL);
6310

6311
  v8::Debug::SetMessageHandler(AfterCompileMessageHandler);
6312
  v8::Debug::DebugBreak(env->GetIsolate());
6313 6314
  v8::Script::Compile(v8::String::NewFromUtf8(env->GetIsolate(), script))
      ->Run();
6315 6316

  // Setting listener to NULL should cause debugger unload.
6317
  v8::Debug::SetMessageHandler(NULL);
6318 6319 6320 6321 6322 6323 6324
  CheckDebuggerUnloaded();

  // Compilation cache should be disabled when debugger is active.
  CHECK_EQ(2, after_compile_message_count);
}


6325 6326 6327 6328 6329 6330 6331 6332 6333 6334 6335 6336 6337 6338 6339 6340 6341 6342 6343 6344 6345 6346 6347 6348 6349 6350 6351 6352 6353 6354 6355 6356 6357 6358 6359 6360 6361 6362 6363 6364 6365
// Syntax error event handler which counts a number of events.
int compile_error_event_count = 0;

static void CompileErrorEventCounterClear() {
  compile_error_event_count = 0;
}

static void CompileErrorEventCounter(
    const v8::Debug::EventDetails& event_details) {
  v8::DebugEvent event = event_details.GetEvent();

  if (event == v8::CompileError) {
    compile_error_event_count++;
  }
}


// Tests that syntax error event is sent as many times as there are scripts
// with syntax error compiled.
TEST(SyntaxErrorMessageOnSyntaxException) {
  DebugLocalContext env;
  v8::HandleScope scope(env->GetIsolate());

  // For this test, we want to break on uncaught exceptions:
  ChangeBreakOnException(false, true);

  v8::Debug::SetDebugEventListener(CompileErrorEventCounter);

  CompileErrorEventCounterClear();

  // Check initial state.
  CHECK_EQ(0, compile_error_event_count);

  // Throws SyntaxError: Unexpected end of input
  v8::Script::Compile(v8::String::NewFromUtf8(env->GetIsolate(), "+++"));
  CHECK_EQ(1, compile_error_event_count);

  v8::Script::Compile(
    v8::String::NewFromUtf8(env->GetIsolate(), "/sel\\/: \\"));
  CHECK_EQ(2, compile_error_event_count);

6366 6367
  v8::Local<v8::Script> script = v8::Script::Compile(
      v8::String::NewFromUtf8(env->GetIsolate(), "JSON.parse('1234:')"));
6368
  CHECK_EQ(2, compile_error_event_count);
6369 6370
  script->Run();
  CHECK_EQ(3, compile_error_event_count);
6371 6372 6373

  v8::Script::Compile(
    v8::String::NewFromUtf8(env->GetIsolate(), "new RegExp('/\\/\\\\');"));
6374
  CHECK_EQ(3, compile_error_event_count);
6375 6376

  v8::Script::Compile(v8::String::NewFromUtf8(env->GetIsolate(), "throw 1;"));
6377
  CHECK_EQ(3, compile_error_event_count);
6378 6379 6380
}


6381 6382 6383
// Tests that break event is sent when message handler is reset.
TEST(BreakMessageWhenMessageHandlerIsReset) {
  DebugLocalContext env;
6384
  v8::HandleScope scope(env->GetIsolate());
6385 6386 6387
  after_compile_message_count = 0;
  const char* script = "function f() {};";

6388
  v8::Debug::SetMessageHandler(AfterCompileMessageHandler);
6389 6390
  v8::Script::Compile(v8::String::NewFromUtf8(env->GetIsolate(), script))
      ->Run();
6391
  v8::Debug::SetMessageHandler(NULL);
6392

6393
  v8::Debug::SetMessageHandler(AfterCompileMessageHandler);
6394
  v8::Debug::DebugBreak(env->GetIsolate());
6395 6396
  v8::Local<v8::Function> f = v8::Local<v8::Function>::Cast(
      env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "f")));
6397 6398 6399
  f->Call(env->Global(), 0, NULL);

  // Setting message handler to NULL should cause debugger unload.
6400
  v8::Debug::SetMessageHandler(NULL);
6401 6402 6403 6404 6405 6406 6407 6408 6409 6410 6411 6412 6413 6414 6415 6416 6417 6418 6419
  CheckDebuggerUnloaded();

  // Compilation cache should be disabled when debugger is active.
  CHECK_EQ(1, after_compile_message_count);
}


static int exception_event_count = 0;
static void ExceptionMessageHandler(const v8::Debug::Message& message) {
  if (message.IsEvent() && message.GetEvent() == v8::Exception) {
    exception_event_count++;
    SendContinueCommand();
  }
}


// Tests that exception event is sent when message handler is reset.
TEST(ExceptionMessageWhenMessageHandlerIsReset) {
  DebugLocalContext env;
6420
  v8::HandleScope scope(env->GetIsolate());
6421 6422 6423 6424

  // For this test, we want to break on uncaught exceptions:
  ChangeBreakOnException(false, true);

6425 6426 6427
  exception_event_count = 0;
  const char* script = "function f() {throw new Error()};";

6428
  v8::Debug::SetMessageHandler(AfterCompileMessageHandler);
6429 6430
  v8::Script::Compile(v8::String::NewFromUtf8(env->GetIsolate(), script))
      ->Run();
6431
  v8::Debug::SetMessageHandler(NULL);
6432

6433
  v8::Debug::SetMessageHandler(ExceptionMessageHandler);
6434 6435
  v8::Local<v8::Function> f = v8::Local<v8::Function>::Cast(
      env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "f")));
6436 6437 6438
  f->Call(env->Global(), 0, NULL);

  // Setting message handler to NULL should cause debugger unload.
6439
  v8::Debug::SetMessageHandler(NULL);
6440 6441 6442 6443
  CheckDebuggerUnloaded();

  CHECK_EQ(1, exception_event_count);
}
6444 6445 6446 6447 6448 6449


// Tests after compile event is sent when there are some provisional
// breakpoints out of the scripts lines range.
TEST(ProvisionalBreakpointOnLineOutOfRange) {
  DebugLocalContext env;
6450
  v8::HandleScope scope(env->GetIsolate());
6451 6452 6453 6454
  env.ExposeDebug();
  const char* script = "function f() {};";
  const char* resource_name = "test_resource";

6455 6456
  v8::Debug::SetMessageHandler(AfterCompileMessageHandler);

6457 6458
  // Set a couple of provisional breakpoint on lines out of the script lines
  // range.
6459 6460 6461 6462
  int sbp1 = SetScriptBreakPointByNameFromJS(env->GetIsolate(), resource_name,
                                             3, -1 /* no column */);
  int sbp2 =
      SetScriptBreakPointByNameFromJS(env->GetIsolate(), resource_name, 5, 5);
6463 6464 6465 6466

  after_compile_message_count = 0;

  v8::ScriptOrigin origin(
6467
      v8::String::NewFromUtf8(env->GetIsolate(), resource_name),
6468 6469
      v8::Integer::New(env->GetIsolate(), 10),
      v8::Integer::New(env->GetIsolate(), 1));
6470 6471
  // Compile a script whose first line number is greater than the breakpoints'
  // lines.
6472 6473
  v8::Script::Compile(v8::String::NewFromUtf8(env->GetIsolate(), script),
                      &origin)->Run();
6474 6475 6476 6477 6478 6479

  // If the script is compiled successfully there is exactly one after compile
  // event. In case of an exception in debugger code after compile event is not
  // sent.
  CHECK_EQ(1, after_compile_message_count);

6480 6481
  ClearBreakPointFromJS(env->GetIsolate(), sbp1);
  ClearBreakPointFromJS(env->GetIsolate(), sbp2);
6482
  v8::Debug::SetMessageHandler(NULL);
6483
}
6484 6485 6486


static void BreakMessageHandler(const v8::Debug::Message& message) {
6487
  i::Isolate* isolate = CcTest::i_isolate();
6488 6489 6490 6491
  if (message.IsEvent() && message.GetEvent() == v8::Break) {
    // Count the number of breaks.
    break_point_hit_count++;

6492
    i::HandleScope scope(isolate);
6493
    message.GetJSON();
6494 6495 6496

    SendContinueCommand();
  } else if (message.IsEvent() && message.GetEvent() == v8::AfterCompile) {
6497
    i::HandleScope scope(isolate);
6498

6499
    int current_count = break_point_hit_count;
6500 6501

    // Force serialization to trigger some internal JS execution.
6502
    message.GetJSON();
6503

6504
    CHECK_EQ(current_count, break_point_hit_count);
6505 6506 6507 6508 6509
  }
}


// Test that if DebugBreak is forced it is ignored when code from
6510
// debug-delay.js is executed.
6511
TEST(NoDebugBreakInAfterCompileMessageHandler) {
6512
  DebugLocalContext env;
6513
  v8::HandleScope scope(env->GetIsolate());
6514 6515

  // Register a debug event listener which sets the break flag and counts.
6516
  v8::Debug::SetMessageHandler(BreakMessageHandler);
6517 6518

  // Set the debug break flag.
6519
  v8::Debug::DebugBreak(env->GetIsolate());
6520 6521 6522 6523 6524 6525 6526 6527 6528

  // Create a function for testing stepping.
  const char* src = "function f() { eval('var x = 10;'); } ";
  v8::Local<v8::Function> f = CompileFunction(&env, src, "f");

  // There should be only one break event.
  CHECK_EQ(1, break_point_hit_count);

  // Set the debug break flag again.
6529
  v8::Debug::DebugBreak(env->GetIsolate());
6530 6531 6532 6533 6534
  f->Call(env->Global(), 0, NULL);
  // There should be one more break event when the script is evaluated in 'f'.
  CHECK_EQ(2, break_point_hit_count);

  // Get rid of the debug message handler.
6535
  v8::Debug::SetMessageHandler(NULL);
6536 6537
  CheckDebuggerUnloaded();
}
6538 6539


6540 6541 6542
static int counting_message_handler_counter;

static void CountingMessageHandler(const v8::Debug::Message& message) {
6543
  if (message.IsResponse()) counting_message_handler_counter++;
6544 6545
}

6546

6547 6548 6549
// Test that debug messages get processed when ProcessDebugMessages is called.
TEST(ProcessDebugMessages) {
  DebugLocalContext env;
6550 6551
  v8::Isolate* isolate = env->GetIsolate();
  v8::HandleScope scope(isolate);
6552 6553 6554

  counting_message_handler_counter = 0;

6555
  v8::Debug::SetMessageHandler(CountingMessageHandler);
6556 6557 6558 6559 6560 6561 6562 6563 6564

  const int kBufferSize = 1000;
  uint16_t buffer[kBufferSize];
  const char* scripts_command =
    "{\"seq\":0,"
     "\"type\":\"request\","
     "\"command\":\"scripts\"}";

  // Send scripts command.
6565 6566
  v8::Debug::SendCommand(
      isolate, buffer, AsciiToUtf16(scripts_command, buffer));
6567 6568 6569 6570 6571 6572 6573 6574

  CHECK_EQ(0, counting_message_handler_counter);
  v8::Debug::ProcessDebugMessages();
  // At least one message should come
  CHECK_GE(counting_message_handler_counter, 1);

  counting_message_handler_counter = 0;

6575 6576 6577 6578
  v8::Debug::SendCommand(
      isolate, buffer, AsciiToUtf16(scripts_command, buffer));
  v8::Debug::SendCommand(
      isolate, buffer, AsciiToUtf16(scripts_command, buffer));
6579 6580 6581 6582 6583 6584
  CHECK_EQ(0, counting_message_handler_counter);
  v8::Debug::ProcessDebugMessages();
  // At least two messages should come
  CHECK_GE(counting_message_handler_counter, 2);

  // Get rid of the debug message handler.
6585
  v8::Debug::SetMessageHandler(NULL);
6586 6587 6588 6589
  CheckDebuggerUnloaded();
}


6590 6591 6592 6593
class SendCommandThread;
static SendCommandThread* send_command_thread_ = NULL;


6594
class SendCommandThread : public v8::base::Thread {
6595 6596
 public:
  explicit SendCommandThread(v8::Isolate* isolate)
6597
      : Thread(Options("SendCommandThread")),
6598
        semaphore_(0),
6599
        isolate_(isolate) {}
6600

6601 6602 6603 6604
  static void CountingAndSignallingMessageHandler(
      const v8::Debug::Message& message) {
    if (message.IsResponse()) {
      counting_message_handler_counter++;
6605
      send_command_thread_->semaphore_.Signal();
6606
    }
6607 6608 6609 6610 6611 6612 6613 6614 6615 6616 6617 6618 6619
  }

  virtual void Run() {
    semaphore_.Wait();
    const int kBufferSize = 1000;
    uint16_t buffer[kBufferSize];
    const char* scripts_command =
      "{\"seq\":0,"
       "\"type\":\"request\","
       "\"command\":\"scripts\"}";
    int length = AsciiToUtf16(scripts_command, buffer);
    // Send scripts command.

6620 6621 6622
    for (int i = 0; i < 20; i++) {
      v8::base::ElapsedTimer timer;
      timer.Start();
6623 6624
      CHECK_EQ(i, counting_message_handler_counter);
      // Queue debug message.
6625
      v8::Debug::SendCommand(isolate_, buffer, length);
6626
      // Wait for the message handler to pick up the response.
6627
      semaphore_.Wait();
6628 6629
      i::PrintF("iteration %d took %f ms\n", i,
                timer.Elapsed().InMillisecondsF());
6630 6631 6632 6633 6634
    }

    v8::V8::TerminateExecution(isolate_);
  }

6635
  void StartSending() { semaphore_.Signal(); }
6636 6637

 private:
6638
  v8::base::Semaphore semaphore_;
6639 6640 6641 6642 6643 6644 6645 6646 6647 6648 6649 6650 6651 6652 6653 6654 6655
  v8::Isolate* isolate_;
};


static void StartSendingCommands(
    const v8::FunctionCallbackInfo<v8::Value>& info) {
  send_command_thread_->StartSending();
}


TEST(ProcessDebugMessagesThreaded) {
  DebugLocalContext env;
  v8::Isolate* isolate = env->GetIsolate();
  v8::HandleScope scope(isolate);

  counting_message_handler_counter = 0;

6656 6657
  v8::Debug::SetMessageHandler(
      SendCommandThread::CountingAndSignallingMessageHandler);
6658 6659 6660 6661 6662 6663 6664 6665 6666
  send_command_thread_ = new SendCommandThread(isolate);
  send_command_thread_->Start();

  v8::Handle<v8::FunctionTemplate> start =
      v8::FunctionTemplate::New(isolate, StartSendingCommands);
  env->Global()->Set(v8_str("start"), start->GetFunction());

  CompileRun("start(); while (true) { }");

6667
  CHECK_EQ(20, counting_message_handler_counter);
6668

6669
  v8::Debug::SetMessageHandler(NULL);
6670 6671 6672 6673
  CheckDebuggerUnloaded();
}


serya@chromium.org's avatar
serya@chromium.org committed
6674
struct BacktraceData {
6675 6676 6677 6678 6679 6680 6681 6682 6683 6684 6685 6686 6687
  static int frame_counter;
  static void MessageHandler(const v8::Debug::Message& message) {
    char print_buffer[1000];
    v8::String::Value json(message.GetJSON());
    Utf16ToAscii(*json, json.length(), print_buffer, 1000);

    if (strstr(print_buffer, "backtrace") == NULL) {
      return;
    }
    frame_counter = GetTotalFramesInt(print_buffer);
  }
};

serya@chromium.org's avatar
serya@chromium.org committed
6688
int BacktraceData::frame_counter;
6689 6690 6691 6692 6693


// Test that debug messages get processed when ProcessDebugMessages is called.
TEST(Backtrace) {
  DebugLocalContext env;
6694 6695
  v8::Isolate* isolate = env->GetIsolate();
  v8::HandleScope scope(isolate);
6696

6697
  v8::Debug::SetMessageHandler(BacktraceData::MessageHandler);
6698

6699 6700
  // TODO(mstarzinger): This doesn't work with --always-opt because we don't
  // have correct source positions in optimized code. Enable once we have.
6701 6702
  i::FLAG_always_opt = false;

6703 6704 6705 6706 6707 6708 6709 6710
  const int kBufferSize = 1000;
  uint16_t buffer[kBufferSize];
  const char* scripts_command =
    "{\"seq\":0,"
     "\"type\":\"request\","
     "\"command\":\"backtrace\"}";

  // Check backtrace from ProcessDebugMessages.
serya@chromium.org's avatar
serya@chromium.org committed
6711
  BacktraceData::frame_counter = -10;
6712 6713 6714 6715 6716
  v8::Debug::SendCommand(
      isolate,
      buffer,
      AsciiToUtf16(scripts_command, buffer),
      NULL);
6717
  v8::Debug::ProcessDebugMessages();
serya@chromium.org's avatar
serya@chromium.org committed
6718
  CHECK_EQ(BacktraceData::frame_counter, 0);
6719

6720 6721
  v8::Handle<v8::String> void0 =
      v8::String::NewFromUtf8(env->GetIsolate(), "void(0)");
6722
  v8::Handle<v8::Script> script = CompileWithOrigin(void0, void0);
6723 6724

  // Check backtrace from "void(0)" script.
serya@chromium.org's avatar
serya@chromium.org committed
6725
  BacktraceData::frame_counter = -10;
6726 6727 6728 6729 6730
  v8::Debug::SendCommand(
      isolate,
      buffer,
      AsciiToUtf16(scripts_command, buffer),
      NULL);
6731
  script->Run();
serya@chromium.org's avatar
serya@chromium.org committed
6732
  CHECK_EQ(BacktraceData::frame_counter, 1);
6733 6734

  // Get rid of the debug message handler.
6735
  v8::Debug::SetMessageHandler(NULL);
6736 6737 6738 6739
  CheckDebuggerUnloaded();
}


6740 6741
TEST(GetMirror) {
  DebugLocalContext env;
6742 6743
  v8::Isolate* isolate = env->GetIsolate();
  v8::HandleScope scope(isolate);
6744
  v8::Handle<v8::Value> obj =
6745
      v8::Debug::GetMirror(v8::String::NewFromUtf8(isolate, "hodja"));
6746 6747 6748 6749 6750 6751 6752 6753 6754 6755
  v8::ScriptCompiler::Source source(v8_str(
      "function runTest(mirror) {"
      "  return mirror.isString() && (mirror.length() == 5);"
      "}"
      ""
      "runTest;"));
  v8::Handle<v8::Function> run_test = v8::Handle<v8::Function>::Cast(
      v8::ScriptCompiler::CompileUnbound(isolate, &source)
          ->BindToCurrentContext()
          ->Run());
6756 6757 6758
  v8::Handle<v8::Value> result = run_test->Call(env->Global(), 1, &obj);
  CHECK(result->IsTrue());
}
6759 6760 6761 6762 6763


// Test that the debug break flag works with function.apply.
TEST(DebugBreakFunctionApply) {
  DebugLocalContext env;
6764
  v8::HandleScope scope(env->GetIsolate());
6765 6766 6767 6768 6769 6770 6771 6772 6773 6774

  // Create a function for testing breaking in apply.
  v8::Local<v8::Function> foo = CompileFunction(
      &env,
      "function baz(x) { }"
      "function bar(x) { baz(); }"
      "function foo(){ bar.apply(this, [1]); }",
      "foo");

  // Register a debug event listener which steps and counts.
6775
  v8::Debug::SetDebugEventListener(DebugEventBreakMax);
6776 6777

  // Set the debug break flag before calling the code using function.apply.
6778
  v8::Debug::DebugBreak(env->GetIsolate());
6779 6780 6781 6782 6783 6784 6785 6786

  // Limit the number of debug breaks. This is a regression test for issue 493
  // where this test would enter an infinite loop.
  break_point_hit_count = 0;
  max_break_point_hit_count = 10000;  // 10000 => infinite loop.
  foo->Call(env->Global(), 0, NULL);

  // When keeping the debug break several break will happen.
6787
  CHECK_GT(break_point_hit_count, 1);
6788

6789
  v8::Debug::SetDebugEventListener(NULL);
6790 6791
  CheckDebuggerUnloaded();
}
6792 6793 6794 6795 6796 6797 6798 6799


v8::Handle<v8::Context> debugee_context;
v8::Handle<v8::Context> debugger_context;


// Property getter that checks that current and calling contexts
// are both the debugee contexts.
6800
static void NamedGetterWithCallingContextCheck(
6801
    v8::Local<v8::String> name,
6802
    const v8::PropertyCallbackInfo<v8::Value>& info) {
6803
  CHECK_EQ(0, strcmp(*v8::String::Utf8Value(name), "a"));
6804
  v8::Handle<v8::Context> current = info.GetIsolate()->GetCurrentContext();
6805 6806
  CHECK(current == debugee_context);
  CHECK(current != debugger_context);
6807
  v8::Handle<v8::Context> calling = info.GetIsolate()->GetCallingContext();
6808 6809
  CHECK(calling == debugee_context);
  CHECK(calling != debugger_context);
6810
  info.GetReturnValue().Set(1);
6811 6812 6813 6814 6815 6816 6817
}


// Debug event listener that checks if the first argument of a function is
// an object with property 'a' == 1. If the property has custom accessor
// this handler will eventually invoke it.
static void DebugEventGetAtgumentPropertyValue(
6818 6819 6820
    const v8::Debug::EventDetails& event_details) {
  v8::DebugEvent event = event_details.GetEvent();
  v8::Handle<v8::Object> exec_state = event_details.GetExecutionState();
6821 6822
  if (event == v8::Break) {
    break_point_hit_count++;
6823
    CHECK(debugger_context == CcTest::isolate()->GetCurrentContext());
6824
    v8::Handle<v8::Function> func = v8::Handle<v8::Function>::Cast(CompileRun(
6825 6826 6827
        "(function(exec_state) {\n"
        "    return (exec_state.frame(0).argumentValue(0).property('a').\n"
        "            value().value() == 1);\n"
6828
        "})"));
6829 6830 6831 6832 6833 6834 6835 6836 6837
    const int argc = 1;
    v8::Handle<v8::Value> argv[argc] = { exec_state };
    v8::Handle<v8::Value> result = func->Call(exec_state, argc, argv);
    CHECK(result->IsTrue());
  }
}


TEST(CallingContextIsNotDebugContext) {
6838
  v8::internal::Debug* debug = CcTest::i_isolate()->debug();
6839 6840
  // Create and enter a debugee context.
  DebugLocalContext env;
6841 6842
  v8::Isolate* isolate = env->GetIsolate();
  v8::HandleScope scope(isolate);
6843 6844 6845 6846
  env.ExposeDebug();

  // Save handles to the debugger and debugee contexts to be used in
  // NamedGetterWithCallingContextCheck.
6847
  debugee_context = env.context();
6848
  debugger_context = v8::Utils::ToLocal(debug->debug_context());
6849 6850

  // Create object with 'a' property accessor.
6851 6852
  v8::Handle<v8::ObjectTemplate> named = v8::ObjectTemplate::New(isolate);
  named->SetAccessor(v8::String::NewFromUtf8(isolate, "a"),
6853
                     NamedGetterWithCallingContextCheck);
6854
  env->Global()->Set(v8::String::NewFromUtf8(isolate, "obj"),
6855 6856 6857
                     named->NewInstance());

  // Register the debug event listener
6858
  v8::Debug::SetDebugEventListener(DebugEventGetAtgumentPropertyValue);
6859 6860 6861 6862 6863 6864 6865 6866 6867 6868 6869 6870

  // Create a function that invokes debugger.
  v8::Local<v8::Function> foo = CompileFunction(
      &env,
      "function bar(x) { debugger; }"
      "function foo(){ bar(obj); }",
      "foo");

  break_point_hit_count = 0;
  foo->Call(env->Global(), 0, NULL);
  CHECK_EQ(1, break_point_hit_count);

6871
  v8::Debug::SetDebugEventListener(NULL);
6872 6873 6874 6875
  debugee_context = v8::Handle<v8::Context>();
  debugger_context = v8::Handle<v8::Context>();
  CheckDebuggerUnloaded();
}
6876 6877


6878
TEST(DebugContextIsPreservedBetweenAccesses) {
6879
  v8::HandleScope scope(CcTest::isolate());
6880
  v8::Debug::SetDebugEventListener(DebugEventBreakPointHitCount);
6881 6882
  v8::Local<v8::Context> context1 = v8::Debug::GetDebugContext();
  v8::Local<v8::Context> context2 = v8::Debug::GetDebugContext();
6883 6884 6885
  CHECK(v8::Utils::OpenHandle(*context1).is_identical_to(
            v8::Utils::OpenHandle(*context2)));
  v8::Debug::SetDebugEventListener(NULL);
6886 6887 6888
}


6889 6890 6891 6892 6893 6894 6895
TEST(NoDebugContextWhenDebuggerDisabled) {
  v8::HandleScope scope(CcTest::isolate());
  v8::Local<v8::Context> context = v8::Debug::GetDebugContext();
  CHECK(context.IsEmpty());
}


6896 6897 6898
static v8::Handle<v8::Value> expected_callback_data;
static void DebugEventContextChecker(const v8::Debug::EventDetails& details) {
  CHECK(details.GetEventContext() == expected_context);
6899
  CHECK(expected_callback_data->Equals(details.GetCallbackData()));
6900 6901
}

6902

6903 6904
// Check that event details contain context where debug event occured.
TEST(DebugEventContext) {
6905
  v8::Isolate* isolate = CcTest::isolate();
6906
  v8::HandleScope scope(isolate);
6907
  expected_context = v8::Context::New(isolate);
6908
  expected_callback_data = v8::Int32::New(isolate, 2010);
6909
  v8::Debug::SetDebugEventListener(DebugEventContextChecker,
6910
                                    expected_callback_data);
6911
  v8::Context::Scope context_scope(expected_context);
6912 6913
  v8::Script::Compile(
      v8::String::NewFromUtf8(isolate, "(function(){debugger;})();"))->Run();
6914
  expected_context.Clear();
6915
  v8::Debug::SetDebugEventListener(NULL);
6916
  expected_context_data = v8::Handle<v8::Value>();
6917 6918
  CheckDebuggerUnloaded();
}
6919

6920

6921 6922
static bool debug_event_break_deoptimize_done = false;

6923 6924 6925 6926
static void DebugEventBreakDeoptimize(
    const v8::Debug::EventDetails& event_details) {
  v8::DebugEvent event = event_details.GetEvent();
  v8::Handle<v8::Object> exec_state = event_details.GetExecutionState();
6927 6928 6929 6930
  if (event == v8::Break) {
    if (!frame_function_name.IsEmpty()) {
      // Get the name of the function.
      const int argc = 2;
6931 6932 6933
      v8::Handle<v8::Value> argv[argc] = {
        exec_state, v8::Integer::New(CcTest::isolate(), 0)
      };
6934 6935 6936 6937 6938
      v8::Handle<v8::Value> result =
          frame_function_name->Call(exec_state, argc, argv);
      if (!result->IsUndefined()) {
        char fn[80];
        CHECK(result->IsString());
6939 6940
        v8::Handle<v8::String> function_name(
            result->ToString(CcTest::isolate()));
6941
        function_name->WriteUtf8(fn);
6942
        if (strcmp(fn, "bar") == 0) {
6943
          i::Deoptimizer::DeoptimizeAll(CcTest::i_isolate());
6944 6945 6946 6947 6948
          debug_event_break_deoptimize_done = true;
        }
      }
    }

6949
    v8::Debug::DebugBreak(CcTest::isolate());
6950 6951 6952 6953 6954 6955 6956 6957
  }
}


// Test deoptimization when execution is broken using the debug break stack
// check interrupt.
TEST(DeoptimizeDuringDebugBreak) {
  DebugLocalContext env;
6958
  v8::HandleScope scope(env->GetIsolate());
6959 6960 6961 6962 6963 6964 6965 6966 6967 6968 6969 6970
  env.ExposeDebug();

  // Create a function for checking the function when hitting a break point.
  frame_function_name = CompileFunction(&env,
                                        frame_function_name_source,
                                        "frame_function_name");

  // Set a debug event listener which will keep interrupting execution until
  // debug break. When inside function bar it will deoptimize all functions.
  // This tests lazy deoptimization bailout for the stack check, as the first
  // time in function bar when using debug break and no break points will be at
  // the initial stack check.
6971
  v8::Debug::SetDebugEventListener(DebugEventBreakDeoptimize);
6972 6973

  // Compile and run function bar which will optimize it for some flag settings.
6974 6975
  v8::Local<v8::Function> f = CompileFunction(&env, "function bar(){}", "bar");
  f->Call(v8::Undefined(env->GetIsolate()), 0, NULL);
6976 6977

  // Set debug break and call bar again.
6978
  v8::Debug::DebugBreak(env->GetIsolate());
6979
  f->Call(v8::Undefined(env->GetIsolate()), 0, NULL);
6980 6981 6982

  CHECK(debug_event_break_deoptimize_done);

6983
  v8::Debug::SetDebugEventListener(NULL);
6984 6985 6986
}


6987 6988
static void DebugEventBreakWithOptimizedStack(
    const v8::Debug::EventDetails& event_details) {
6989
  v8::Isolate* isolate = event_details.GetEventContext()->GetIsolate();
6990 6991
  v8::DebugEvent event = event_details.GetEvent();
  v8::Handle<v8::Object> exec_state = event_details.GetExecutionState();
6992 6993 6994 6995
  if (event == v8::Break) {
    if (!frame_function_name.IsEmpty()) {
      for (int i = 0; i < 2; i++) {
        const int argc = 2;
6996 6997 6998
        v8::Handle<v8::Value> argv[argc] = {
          exec_state, v8::Integer::New(isolate, i)
        };
6999 7000 7001 7002
        // Get the name of the function in frame i.
        v8::Handle<v8::Value> result =
            frame_function_name->Call(exec_state, argc, argv);
        CHECK(result->IsString());
7003
        v8::Handle<v8::String> function_name(result->ToString(isolate));
7004
        CHECK(function_name->Equals(v8::String::NewFromUtf8(isolate, "loop")));
7005 7006 7007
        // Get the name of the first argument in frame i.
        result = frame_argument_name->Call(exec_state, argc, argv);
        CHECK(result->IsString());
7008
        v8::Handle<v8::String> argument_name(result->ToString(isolate));
7009
        CHECK(argument_name->Equals(v8::String::NewFromUtf8(isolate, "count")));
7010 7011 7012 7013 7014 7015 7016 7017 7018 7019 7020
        // Get the value of the first argument in frame i. If the
        // funtion is optimized the value will be undefined, otherwise
        // the value will be '1 - i'.
        //
        // TODO(3141533): We should be able to get the real value for
        // optimized frames.
        result = frame_argument_value->Call(exec_state, argc, argv);
        CHECK(result->IsUndefined() || (result->Int32Value() == 1 - i));
        // Get the name of the first local variable.
        result = frame_local_name->Call(exec_state, argc, argv);
        CHECK(result->IsString());
7021
        v8::Handle<v8::String> local_name(result->ToString(isolate));
7022
        CHECK(local_name->Equals(v8::String::NewFromUtf8(isolate, "local")));
7023 7024 7025 7026 7027 7028 7029 7030 7031 7032 7033 7034 7035 7036
        // Get the value of the first local variable. If the function
        // is optimized the value will be undefined, otherwise it will
        // be 42.
        //
        // TODO(3141533): We should be able to get the real value for
        // optimized frames.
        result = frame_local_value->Call(exec_state, argc, argv);
        CHECK(result->IsUndefined() || (result->Int32Value() == 42));
      }
    }
  }
}


7037
static void ScheduleBreak(const v8::FunctionCallbackInfo<v8::Value>& args) {
7038
  v8::Debug::SetDebugEventListener(DebugEventBreakWithOptimizedStack);
7039
  v8::Debug::DebugBreak(args.GetIsolate());
7040 7041 7042 7043 7044
}


TEST(DebugBreakStackInspection) {
  DebugLocalContext env;
7045
  v8::HandleScope scope(env->GetIsolate());
7046 7047 7048 7049 7050 7051 7052 7053 7054 7055 7056 7057 7058 7059

  frame_function_name =
      CompileFunction(&env, frame_function_name_source, "frame_function_name");
  frame_argument_name =
      CompileFunction(&env, frame_argument_name_source, "frame_argument_name");
  frame_argument_value = CompileFunction(&env,
                                         frame_argument_value_source,
                                         "frame_argument_value");
  frame_local_name =
      CompileFunction(&env, frame_local_name_source, "frame_local_name");
  frame_local_value =
      CompileFunction(&env, frame_local_value_source, "frame_local_value");

  v8::Handle<v8::FunctionTemplate> schedule_break_template =
7060
      v8::FunctionTemplate::New(env->GetIsolate(), ScheduleBreak);
7061 7062 7063 7064 7065 7066 7067 7068 7069 7070
  v8::Handle<v8::Function> schedule_break =
      schedule_break_template->GetFunction();
  env->Global()->Set(v8_str("scheduleBreak"), schedule_break);

  const char* src =
      "function loop(count) {"
      "  var local = 42;"
      "  if (count < 1) { scheduleBreak(); loop(count + 1); }"
      "}"
      "loop(0);";
7071
  v8::Script::Compile(v8::String::NewFromUtf8(env->GetIsolate(), src))->Run();
7072 7073
}

7074 7075

// Test that setting the terminate execution flag during debug break processing.
7076 7077 7078
static void TestDebugBreakInLoop(const char* loop_head,
                                 const char** loop_bodies,
                                 const char* loop_tail) {
7079 7080
  // Receive 10 breaks for each test and then terminate JavaScript execution.
  static const int kBreaksPerTest = 10;
7081

7082
  for (int i = 0; loop_bodies[i] != NULL; i++) {
7083 7084
    // Perform a lazy deoptimization after various numbers of breaks
    // have been hit.
7085 7086 7087 7088 7089 7090 7091 7092

    EmbeddedVector<char, 1024> buffer;
    SNPrintF(buffer, "function f() {%s%s%s}", loop_head, loop_bodies[i],
             loop_tail);

    i::PrintF("%s\n", buffer.start());

    for (int j = 0; j < 3; j++) {
7093
      break_point_hit_count_deoptimize = j;
7094
      if (j == 2) {
7095 7096
        break_point_hit_count_deoptimize = kBreaksPerTest;
      }
7097

7098 7099 7100
      break_point_hit_count = 0;
      max_break_point_hit_count = kBreaksPerTest;
      terminate_after_max_break_point_hit = true;
7101

7102 7103
      // Function with infinite loop.
      CompileRun(buffer.start());
7104

7105
      // Set the debug break to enter the debugger as soon as possible.
7106
      v8::Debug::DebugBreak(CcTest::isolate());
7107

7108 7109 7110
      // Call function with infinite loop.
      CompileRun("f();");
      CHECK_EQ(kBreaksPerTest, break_point_hit_count);
7111

7112 7113
      CHECK(!v8::V8::IsExecutionTerminating());
    }
7114 7115 7116 7117
  }
}


7118 7119 7120 7121 7122 7123 7124 7125 7126 7127 7128 7129 7130 7131 7132 7133 7134 7135 7136 7137
static const char* loop_bodies_1[] = {"",
                                      "g()",
                                      "if (a == 0) { g() }",
                                      "if (a == 1) { g() }",
                                      "if (a == 0) { g() } else { h() }",
                                      "if (a == 0) { continue }",
                                      NULL};


static const char* loop_bodies_2[] = {
    "if (a == 1) { continue }",
    "switch (a) { case 1: g(); }",
    "switch (a) { case 1: continue; }",
    "switch (a) { case 1: g(); break; default: h() }",
    "switch (a) { case 1: continue; break; default: h() }",
    NULL};


void DebugBreakLoop(const char* loop_header, const char** loop_bodies,
                    const char* loop_footer) {
7138
  DebugLocalContext env;
7139
  v8::HandleScope scope(env->GetIsolate());
7140 7141

  // Register a debug event listener which sets the break flag and counts.
7142
  v8::Debug::SetDebugEventListener(DebugEventBreakMax);
7143

7144 7145 7146 7147
  CompileRun(
      "var a = 1;\n"
      "function g() { }\n"
      "function h() { }");
7148

7149
  TestDebugBreakInLoop(loop_header, loop_bodies, loop_footer);
7150 7151

  // Get rid of the debug event listener.
7152
  v8::Debug::SetDebugEventListener(NULL);
7153 7154 7155 7156
  CheckDebuggerUnloaded();
}


7157 7158 7159 7160 7161 7162 7163 7164 7165 7166 7167 7168 7169 7170 7171 7172 7173 7174 7175 7176 7177 7178 7179 7180 7181 7182 7183 7184 7185 7186 7187 7188 7189 7190 7191 7192 7193 7194 7195 7196 7197 7198 7199 7200 7201 7202 7203 7204 7205 7206 7207 7208 7209 7210 7211 7212
TEST(DebugBreakInWhileTrue1) {
  DebugBreakLoop("while (true) {", loop_bodies_1, "}");
}


TEST(DebugBreakInWhileTrue2) {
  DebugBreakLoop("while (true) {", loop_bodies_2, "}");
}


TEST(DebugBreakInWhileCondition1) {
  DebugBreakLoop("while (a == 1) {", loop_bodies_1, "}");
}


TEST(DebugBreakInWhileCondition2) {
  DebugBreakLoop("while (a == 1) {", loop_bodies_2, "}");
}


TEST(DebugBreakInDoWhileTrue1) {
  DebugBreakLoop("do {", loop_bodies_1, "} while (true)");
}


TEST(DebugBreakInDoWhileTrue2) {
  DebugBreakLoop("do {", loop_bodies_2, "} while (true)");
}


TEST(DebugBreakInDoWhileCondition1) {
  DebugBreakLoop("do {", loop_bodies_1, "} while (a == 1)");
}


TEST(DebugBreakInDoWhileCondition2) {
  DebugBreakLoop("do {", loop_bodies_2, "} while (a == 1)");
}


TEST(DebugBreakInFor1) { DebugBreakLoop("for (;;) {", loop_bodies_1, "}"); }


TEST(DebugBreakInFor2) { DebugBreakLoop("for (;;) {", loop_bodies_2, "}"); }


TEST(DebugBreakInForCondition1) {
  DebugBreakLoop("for (;a == 1;) {", loop_bodies_1, "}");
}


TEST(DebugBreakInForCondition2) {
  DebugBreakLoop("for (;a == 1;) {", loop_bodies_2, "}");
}


7213 7214
v8::Local<v8::Script> inline_script;

7215 7216 7217
static void DebugBreakInlineListener(
    const v8::Debug::EventDetails& event_details) {
  v8::DebugEvent event = event_details.GetEvent();
7218 7219 7220 7221 7222 7223 7224 7225 7226
  if (event != v8::Break) return;

  int expected_frame_count = 4;
  int expected_line_number[] = {1, 4, 7, 12};

  i::Handle<i::Object> compiled_script = v8::Utils::OpenHandle(*inline_script);
  i::Handle<i::Script> source_script = i::Handle<i::Script>(i::Script::cast(
      i::JSFunction::cast(*compiled_script)->shared()->script()));

7227
  int break_id = CcTest::i_isolate()->debug()->break_id();
7228 7229
  char script[128];
  i::Vector<char> script_vector(script, sizeof(script));
7230
  SNPrintF(script_vector, "%%GetFrameCount(%d)", break_id);
7231 7232 7233 7234 7235 7236 7237 7238
  v8::Local<v8::Value> result = CompileRun(script);

  int frame_count = result->Int32Value();
  CHECK_EQ(expected_frame_count, frame_count);

  for (int i = 0; i < frame_count; i++) {
    // The 5. element in the returned array of GetFrameDetails contains the
    // source position of that frame.
7239
    SNPrintF(script_vector, "%%GetFrameDetails(%d, %d)[5]", break_id, i);
7240 7241
    v8::Local<v8::Value> result = CompileRun(script);
    CHECK_EQ(expected_line_number[i],
7242
             i::Script::GetLineNumber(source_script, result->Int32Value()));
7243
  }
7244
  v8::Debug::SetDebugEventListener(NULL);
7245
  v8::V8::TerminateExecution(CcTest::isolate());
7246 7247 7248 7249 7250 7251
}


TEST(DebugBreakInline) {
  i::FLAG_allow_natives_syntax = true;
  DebugLocalContext env;
7252
  v8::HandleScope scope(env->GetIsolate());
7253 7254 7255 7256 7257 7258 7259 7260 7261 7262 7263 7264 7265 7266
  const char* source =
      "function debug(b) {             \n"
      "  if (b) debugger;              \n"
      "}                               \n"
      "function f(b) {                 \n"
      "  debug(b)                      \n"
      "};                              \n"
      "function g(b) {                 \n"
      "  f(b);                         \n"
      "};                              \n"
      "g(false);                       \n"
      "g(false);                       \n"
      "%OptimizeFunctionOnNextCall(g); \n"
      "g(true);";
7267
  v8::Debug::SetDebugEventListener(DebugBreakInlineListener);
7268 7269
  inline_script =
      v8::Script::Compile(v8::String::NewFromUtf8(env->GetIsolate(), source));
7270 7271 7272 7273
  inline_script->Run();
}


7274 7275 7276
static void DebugEventStepNext(
    const v8::Debug::EventDetails& event_details) {
  v8::DebugEvent event = event_details.GetEvent();
7277 7278 7279 7280 7281 7282 7283
  if (event == v8::Break) {
    PrepareStep(StepNext);
  }
}


static void RunScriptInANewCFrame(const char* source) {
7284
  v8::TryCatch try_catch(CcTest::isolate());
7285 7286 7287 7288 7289 7290 7291 7292 7293 7294 7295 7296 7297 7298 7299
  CompileRun(source);
  CHECK(try_catch.HasCaught());
}


TEST(Regress131642) {
  // Bug description:
  // When doing StepNext through the first script, the debugger is not reset
  // after exiting through exception.  A flawed implementation enabling the
  // debugger to step into Array.prototype.forEach breaks inside the callback
  // for forEach in the second script under the assumption that we are in a
  // recursive call.  In an attempt to step out, we crawl the stack using the
  // recorded frame pointer from the first script and fail when not finding it
  // on the stack.
  DebugLocalContext env;
7300
  v8::HandleScope scope(env->GetIsolate());
7301
  v8::Debug::SetDebugEventListener(DebugEventStepNext);
7302 7303 7304 7305 7306 7307 7308 7309 7310 7311 7312

  // We step through the first script.  It exits through an exception.  We run
  // this inside a new frame to record a different FP than the second script
  // would expect.
  const char* script_1 = "debugger; throw new Error();";
  RunScriptInANewCFrame(script_1);

  // The second script uses forEach.
  const char* script_2 = "[0].forEach(function() { });";
  CompileRun(script_2);

7313
  v8::Debug::SetDebugEventListener(NULL);
7314 7315
}

7316 7317

// Import from test-heap.cc
7318 7319 7320
namespace v8 {
namespace internal {

7321
int CountNativeContexts();
7322 7323
}
}
7324 7325


7326
static void NopListener(const v8::Debug::EventDetails& event_details) {
7327 7328 7329 7330 7331
}


TEST(DebuggerCreatesContextIffActive) {
  DebugLocalContext env;
7332
  v8::HandleScope scope(env->GetIsolate());
7333
  CHECK_EQ(1, v8::internal::CountNativeContexts());
7334

7335
  v8::Debug::SetDebugEventListener(NULL);
7336
  CompileRun("debugger;");
7337
  CHECK_EQ(1, v8::internal::CountNativeContexts());
7338

7339
  v8::Debug::SetDebugEventListener(NopListener);
7340
  CompileRun("debugger;");
7341
  CHECK_EQ(2, v8::internal::CountNativeContexts());
7342

7343
  v8::Debug::SetDebugEventListener(NULL);
7344 7345
}

7346 7347 7348

TEST(LiveEditEnabled) {
  v8::internal::FLAG_allow_natives_syntax = true;
7349 7350
  LocalContext env;
  v8::HandleScope scope(env->GetIsolate());
svenpanne@chromium.org's avatar
svenpanne@chromium.org committed
7351
  v8::Debug::SetLiveEditEnabled(env->GetIsolate(), true);
7352 7353 7354 7355 7356 7357
  CompileRun("%LiveEditCompareStrings('', '')");
}


TEST(LiveEditDisabled) {
  v8::internal::FLAG_allow_natives_syntax = true;
7358 7359
  LocalContext env;
  v8::HandleScope scope(env->GetIsolate());
svenpanne@chromium.org's avatar
svenpanne@chromium.org committed
7360
  v8::Debug::SetLiveEditEnabled(env->GetIsolate(), false);
7361 7362 7363 7364
  CompileRun("%LiveEditCompareStrings('', '')");
}


7365 7366 7367 7368 7369 7370 7371 7372
TEST(PrecompiledFunction) {
  // Regression test for crbug.com/346207. If we have preparse data, parsing the
  // function in the presence of the debugger (and breakpoints) should still
  // succeed. The bug was that preparsing was done lazily and parsing was done
  // eagerly, so, the symbol streams didn't match.
  DebugLocalContext env;
  v8::HandleScope scope(env->GetIsolate());
  env.ExposeDebug();
7373
  v8::Debug::SetDebugEventListener(DebugBreakInlineListener);
7374 7375 7376 7377 7378 7379 7380 7381 7382 7383 7384 7385 7386 7387 7388 7389

  v8::Local<v8::Function> break_here =
      CompileFunction(&env, "function break_here(){}", "break_here");
  SetBreakPoint(break_here, 0);

  const char* source =
      "var a = b = c = 1;              \n"
      "function this_is_lazy() {       \n"
      // This symbol won't appear in the preparse data.
      "  var a;                        \n"
      "}                               \n"
      "function bar() {                \n"
      "  return \"bar\";               \n"
      "};                              \n"
      "a = b = c = 2;                  \n"
      "bar();                          \n";
7390
  v8::Local<v8::Value> result = ParserCacheCompileRun(source);
7391 7392
  CHECK(result->IsString());
  v8::String::Utf8Value utf8(result);
7393
  CHECK_EQ(0, strcmp("bar", *utf8));
7394

7395
  v8::Debug::SetDebugEventListener(NULL);
7396 7397
  CheckDebuggerUnloaded();
}
7398 7399 7400 7401 7402 7403 7404 7405 7406 7407 7408 7409 7410 7411 7412 7413


static void DebugBreakStackTraceListener(
    const v8::Debug::EventDetails& event_details) {
  v8::StackTrace::CurrentStackTrace(CcTest::isolate(), 10);
}


static void AddDebugBreak(const v8::FunctionCallbackInfo<v8::Value>& args) {
  v8::Debug::DebugBreak(args.GetIsolate());
}


TEST(DebugBreakStackTrace) {
  DebugLocalContext env;
  v8::HandleScope scope(env->GetIsolate());
7414
  v8::Debug::SetDebugEventListener(DebugBreakStackTraceListener);
7415 7416 7417 7418 7419 7420 7421 7422 7423 7424 7425 7426 7427 7428
  v8::Handle<v8::FunctionTemplate> add_debug_break_template =
      v8::FunctionTemplate::New(env->GetIsolate(), AddDebugBreak);
  v8::Handle<v8::Function> add_debug_break =
      add_debug_break_template->GetFunction();
  env->Global()->Set(v8_str("add_debug_break"), add_debug_break);

  CompileRun("(function loop() {"
             "  for (var j = 0; j < 1000; j++) {"
             "    for (var i = 0; i < 1000; i++) {"
             "      if (i == 999) add_debug_break();"
             "    }"
             "  }"
             "})()");
}
7429 7430


7431 7432
v8::base::Semaphore terminate_requested_semaphore(0);
v8::base::Semaphore terminate_fired_semaphore(0);
7433 7434 7435 7436 7437 7438 7439 7440
bool terminate_already_fired = false;


static void DebugBreakTriggerTerminate(
    const v8::Debug::EventDetails& event_details) {
  if (event_details.GetEvent() != v8::Break || terminate_already_fired) return;
  terminate_requested_semaphore.Signal();
  // Wait for at most 2 seconds for the terminate request.
7441
  CHECK(terminate_fired_semaphore.WaitFor(v8::base::TimeDelta::FromSeconds(2)));
7442 7443 7444 7445
  terminate_already_fired = true;
}


7446
class TerminationThread : public v8::base::Thread {
7447
 public:
7448 7449
  explicit TerminationThread(v8::Isolate* isolate)
      : Thread(Options("terminator")), isolate_(isolate) {}
7450 7451 7452 7453 7454 7455 7456 7457 7458 7459 7460 7461 7462 7463 7464 7465 7466 7467 7468

  virtual void Run() {
    terminate_requested_semaphore.Wait();
    v8::V8::TerminateExecution(isolate_);
    terminate_fired_semaphore.Signal();
  }

 private:
  v8::Isolate* isolate_;
};


TEST(DebugBreakOffThreadTerminate) {
  DebugLocalContext env;
  v8::Isolate* isolate = env->GetIsolate();
  v8::HandleScope scope(isolate);
  v8::Debug::SetDebugEventListener(DebugBreakTriggerTerminate);
  TerminationThread terminator(isolate);
  terminator.Start();
7469
  v8::TryCatch try_catch(env->GetIsolate());
7470 7471
  v8::Debug::DebugBreak(isolate);
  CompileRun("while (true);");
7472
  CHECK(try_catch.HasTerminated());
7473
}
7474 7475 7476 7477 7478 7479 7480 7481 7482 7483 7484


static void DebugEventExpectNoException(
    const v8::Debug::EventDetails& event_details) {
  v8::DebugEvent event = event_details.GetEvent();
  CHECK_NE(v8::Exception, event);
}


static void TryCatchWrappedThrowCallback(
    const v8::FunctionCallbackInfo<v8::Value>& args) {
7485
  v8::TryCatch try_catch(args.GetIsolate());
7486 7487 7488 7489 7490 7491 7492 7493 7494 7495 7496 7497 7498 7499 7500 7501 7502 7503 7504 7505 7506 7507 7508 7509 7510 7511 7512 7513 7514 7515 7516 7517 7518 7519 7520 7521 7522 7523 7524 7525 7526 7527 7528 7529 7530 7531 7532 7533 7534 7535 7536 7537 7538 7539 7540 7541 7542 7543 7544 7545
  CompileRun("throw 'rejection';");
  CHECK(try_catch.HasCaught());
}


TEST(DebugPromiseInterceptedByTryCatch) {
  DebugLocalContext env;
  v8::Isolate* isolate = env->GetIsolate();
  v8::HandleScope scope(isolate);
  v8::Debug::SetDebugEventListener(&DebugEventExpectNoException);
  ChangeBreakOnException(false, true);

  v8::Handle<v8::FunctionTemplate> fun =
      v8::FunctionTemplate::New(isolate, TryCatchWrappedThrowCallback);
  env->Global()->Set(v8_str("fun"), fun->GetFunction());

  CompileRun("var p = new Promise(function(res, rej) { fun(); res(); });");
  CompileRun(
      "var r;"
      "p.chain(function() { r = 'resolved'; },"
      "        function() { r = 'rejected'; });");
  CHECK(CompileRun("r")->Equals(v8_str("resolved")));
}


static int exception_event_counter = 0;


static void DebugEventCountException(
    const v8::Debug::EventDetails& event_details) {
  v8::DebugEvent event = event_details.GetEvent();
  if (event == v8::Exception) exception_event_counter++;
}


static void ThrowCallback(const v8::FunctionCallbackInfo<v8::Value>& args) {
  CompileRun("throw 'rejection';");
}


TEST(DebugPromiseRejectedByCallback) {
  DebugLocalContext env;
  v8::Isolate* isolate = env->GetIsolate();
  v8::HandleScope scope(isolate);
  v8::Debug::SetDebugEventListener(&DebugEventCountException);
  ChangeBreakOnException(false, true);
  exception_event_counter = 0;

  v8::Handle<v8::FunctionTemplate> fun =
      v8::FunctionTemplate::New(isolate, ThrowCallback);
  env->Global()->Set(v8_str("fun"), fun->GetFunction());

  CompileRun("var p = new Promise(function(res, rej) { fun(); res(); });");
  CompileRun(
      "var r;"
      "p.chain(function() { r = 'resolved'; },"
      "        function(e) { r = 'rejected' + e; });");
  CHECK(CompileRun("r")->Equals(v8_str("rejectedrejection")));
  CHECK_EQ(1, exception_event_counter);
}
7546 7547 7548 7549 7550 7551 7552 7553 7554 7555 7556 7557 7558 7559 7560 7561 7562 7563 7564 7565 7566 7567 7568 7569 7570 7571


TEST(DebugBreakOnExceptionInObserveCallback) {
  DebugLocalContext env;
  v8::Isolate* isolate = env->GetIsolate();
  v8::HandleScope scope(isolate);
  v8::Debug::SetDebugEventListener(&DebugEventCountException);
  // Break on uncaught exception
  ChangeBreakOnException(false, true);
  exception_event_counter = 0;

  v8::Handle<v8::FunctionTemplate> fun =
      v8::FunctionTemplate::New(isolate, ThrowCallback);
  env->Global()->Set(v8_str("fun"), fun->GetFunction());

  CompileRun(
      "var obj = {};"
      "var callbackRan = false;"
      "Object.observe(obj, function() {"
      "   callbackRan = true;"
      "   throw Error('foo');"
      "});"
      "obj.prop = 1");
  CHECK(CompileRun("callbackRan")->BooleanValue());
  CHECK_EQ(1, exception_event_counter);
}
7572 7573 7574 7575 7576 7577 7578 7579 7580 7581 7582 7583


static void DebugHarmonyScopingListener(
    const v8::Debug::EventDetails& event_details) {
  v8::DebugEvent event = event_details.GetEvent();
  if (event != v8::Break) return;

  int break_id = CcTest::i_isolate()->debug()->break_id();

  char script[128];
  i::Vector<char> script_vector(script, sizeof(script));
  SNPrintF(script_vector, "%%GetFrameCount(%d)", break_id);
7584 7585 7586 7587 7588 7589 7590 7591 7592
  ExpectInt32(script, 1);

  SNPrintF(script_vector, "var frame = new FrameMirror(%d, 0);", break_id);
  CompileRun(script);
  ExpectInt32("frame.evaluate('x').value_", 1);
  ExpectInt32("frame.evaluate('y').value_", 2);

  CompileRun("var allScopes = frame.allScopes()");
  ExpectInt32("allScopes.length", 2);
7593

7594 7595 7596 7597 7598 7599 7600 7601 7602
  ExpectBoolean("allScopes[0].scopeType() === ScopeType.Script", true);

  ExpectInt32("allScopes[0].scopeObject().value_.x", 1);

  ExpectInt32("allScopes[0].scopeObject().value_.y", 2);

  CompileRun("allScopes[0].setVariableValue('x', 5);");
  CompileRun("allScopes[0].setVariableValue('y', 6);");
  ExpectInt32("frame.evaluate('x + y').value_", 11);
7603 7604 7605 7606 7607 7608 7609 7610 7611 7612 7613 7614 7615 7616
}


TEST(DebugBreakInLexicalScopes) {
  i::FLAG_allow_natives_syntax = true;

  DebugLocalContext env;
  v8::Isolate* isolate = env->GetIsolate();
  v8::HandleScope scope(isolate);
  v8::Debug::SetDebugEventListener(DebugHarmonyScopingListener);

  CompileRun(
      "'use strict';            \n"
      "let x = 1;               \n");
7617
  ExpectInt32(
7618
      "'use strict';            \n"
7619 7620 7621 7622 7623 7624 7625 7626 7627
      "let y = 2;               \n"
      "debugger;                \n"
      "x * y",
      30);
  ExpectInt32(
      "x = 1; y = 2; \n"
      "debugger;"
      "x * y",
      30);
7628
}
7629 7630 7631 7632 7633 7634 7635 7636 7637 7638 7639 7640 7641 7642 7643 7644 7645 7646 7647 7648 7649 7650 7651 7652

static int after_compile_handler_depth = 0;
static void HandleInterrupt(v8::Isolate* isolate, void* data) {
  CHECK_EQ(0, after_compile_handler_depth);
}

static void NoInterruptsOnDebugEvent(
    const v8::Debug::EventDetails& event_details) {
  if (event_details.GetEvent() != v8::AfterCompile) return;
  ++after_compile_handler_depth;
  // Do not allow nested AfterCompile events.
  CHECK(after_compile_handler_depth <= 1);
  v8::Isolate* isolate = event_details.GetEventContext()->GetIsolate();
  isolate->RequestInterrupt(&HandleInterrupt, nullptr);
  CompileRun("function foo() {}; foo();");
  --after_compile_handler_depth;
}


TEST(NoInterruptsInDebugListener) {
  DebugLocalContext env;
  v8::Debug::SetDebugEventListener(NoInterruptsOnDebugEvent);
  CompileRun("void(0);");
}