v8  3.11.10(node0.8.26)
V8 is Google's open source JavaScript engine
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
debug.cc
Go to the documentation of this file.
1 // Copyright 2012 the V8 project authors. All rights reserved.
2 // Redistribution and use in source and binary forms, with or without
3 // modification, are permitted provided that the following conditions are
4 // met:
5 //
6 // * Redistributions of source code must retain the above copyright
7 // notice, this list of conditions and the following disclaimer.
8 // * Redistributions in binary form must reproduce the above
9 // copyright notice, this list of conditions and the following
10 // disclaimer in the documentation and/or other materials provided
11 // with the distribution.
12 // * Neither the name of Google Inc. nor the names of its
13 // contributors may be used to endorse or promote products derived
14 // from this software without specific prior written permission.
15 //
16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 
28 #include "v8.h"
29 
30 #include "api.h"
31 #include "arguments.h"
32 #include "bootstrapper.h"
33 #include "code-stubs.h"
34 #include "codegen.h"
35 #include "compilation-cache.h"
36 #include "compiler.h"
37 #include "debug.h"
38 #include "deoptimizer.h"
39 #include "execution.h"
40 #include "full-codegen.h"
41 #include "global-handles.h"
42 #include "ic.h"
43 #include "ic-inl.h"
44 #include "isolate-inl.h"
45 #include "list.h"
46 #include "messages.h"
47 #include "natives.h"
48 #include "stub-cache.h"
49 #include "log.h"
50 
51 #include "../include/v8-debug.h"
52 
53 namespace v8 {
54 namespace internal {
55 
56 #ifdef ENABLE_DEBUGGER_SUPPORT
57 
58 
59 Debug::Debug(Isolate* isolate)
60  : has_break_points_(false),
61  script_cache_(NULL),
62  debug_info_list_(NULL),
63  disable_break_(false),
64  break_on_exception_(false),
65  break_on_uncaught_exception_(false),
66  debug_break_return_(NULL),
67  debug_break_slot_(NULL),
68  isolate_(isolate) {
69  memset(registers_, 0, sizeof(JSCallerSavedBuffer));
70 }
71 
72 
73 Debug::~Debug() {
74 }
75 
76 
77 static void PrintLn(v8::Local<v8::Value> value) {
78  v8::Local<v8::String> s = value->ToString();
79  ScopedVector<char> data(s->Length() + 1);
80  if (data.start() == NULL) {
81  V8::FatalProcessOutOfMemory("PrintLn");
82  return;
83  }
84  s->WriteAscii(data.start());
85  PrintF("%s\n", data.start());
86 }
87 
88 
89 static Handle<Code> ComputeCallDebugPrepareStepIn(int argc, Code::Kind kind) {
90  Isolate* isolate = Isolate::Current();
91  return isolate->stub_cache()->ComputeCallDebugPrepareStepIn(argc, kind);
92 }
93 
94 
95 static v8::Handle<v8::Context> GetDebugEventContext(Isolate* isolate) {
96  Handle<Context> context = isolate->debug()->debugger_entry()->GetContext();
97  // Isolate::context() may have been NULL when "script collected" event
98  // occured.
99  if (context.is_null()) return v8::Local<v8::Context>();
100  Handle<Context> global_context(context->global_context());
101  return v8::Utils::ToLocal(global_context);
102 }
103 
104 
105 BreakLocationIterator::BreakLocationIterator(Handle<DebugInfo> debug_info,
106  BreakLocatorType type) {
107  debug_info_ = debug_info;
108  type_ = type;
109  reloc_iterator_ = NULL;
110  reloc_iterator_original_ = NULL;
111  Reset(); // Initialize the rest of the member variables.
112 }
113 
114 
115 BreakLocationIterator::~BreakLocationIterator() {
116  ASSERT(reloc_iterator_ != NULL);
117  ASSERT(reloc_iterator_original_ != NULL);
118  delete reloc_iterator_;
119  delete reloc_iterator_original_;
120 }
121 
122 
123 void BreakLocationIterator::Next() {
124  AssertNoAllocation nogc;
125  ASSERT(!RinfoDone());
126 
127  // Iterate through reloc info for code and original code stopping at each
128  // breakable code target.
129  bool first = break_point_ == -1;
130  while (!RinfoDone()) {
131  if (!first) RinfoNext();
132  first = false;
133  if (RinfoDone()) return;
134 
135  // Whenever a statement position or (plain) position is passed update the
136  // current value of these.
137  if (RelocInfo::IsPosition(rmode())) {
138  if (RelocInfo::IsStatementPosition(rmode())) {
139  statement_position_ = static_cast<int>(
140  rinfo()->data() - debug_info_->shared()->start_position());
141  }
142  // Always update the position as we don't want that to be before the
143  // statement position.
144  position_ = static_cast<int>(
145  rinfo()->data() - debug_info_->shared()->start_position());
146  ASSERT(position_ >= 0);
147  ASSERT(statement_position_ >= 0);
148  }
149 
150  if (IsDebugBreakSlot()) {
151  // There is always a possible break point at a debug break slot.
152  break_point_++;
153  return;
154  } else if (RelocInfo::IsCodeTarget(rmode())) {
155  // Check for breakable code target. Look in the original code as setting
156  // break points can cause the code targets in the running (debugged) code
157  // to be of a different kind than in the original code.
158  Address target = original_rinfo()->target_address();
159  Code* code = Code::GetCodeFromTargetAddress(target);
160  if ((code->is_inline_cache_stub() &&
161  !code->is_binary_op_stub() &&
162  !code->is_unary_op_stub() &&
163  !code->is_compare_ic_stub() &&
164  !code->is_to_boolean_ic_stub()) ||
165  RelocInfo::IsConstructCall(rmode())) {
166  break_point_++;
167  return;
168  }
169  if (code->kind() == Code::STUB) {
170  if (IsDebuggerStatement()) {
171  break_point_++;
172  return;
173  }
174  if (type_ == ALL_BREAK_LOCATIONS) {
175  if (Debug::IsBreakStub(code)) {
176  break_point_++;
177  return;
178  }
179  } else {
180  ASSERT(type_ == SOURCE_BREAK_LOCATIONS);
181  if (Debug::IsSourceBreakStub(code)) {
182  break_point_++;
183  return;
184  }
185  }
186  }
187  }
188 
189  // Check for break at return.
190  if (RelocInfo::IsJSReturn(rmode())) {
191  // Set the positions to the end of the function.
192  if (debug_info_->shared()->HasSourceCode()) {
193  position_ = debug_info_->shared()->end_position() -
194  debug_info_->shared()->start_position() - 1;
195  } else {
196  position_ = 0;
197  }
198  statement_position_ = position_;
199  break_point_++;
200  return;
201  }
202  }
203 }
204 
205 
206 void BreakLocationIterator::Next(int count) {
207  while (count > 0) {
208  Next();
209  count--;
210  }
211 }
212 
213 
214 // Find the break point closest to the supplied address.
215 void BreakLocationIterator::FindBreakLocationFromAddress(Address pc) {
216  // Run through all break points to locate the one closest to the address.
217  int closest_break_point = 0;
218  int distance = kMaxInt;
219  while (!Done()) {
220  // Check if this break point is closer that what was previously found.
221  if (this->pc() < pc && pc - this->pc() < distance) {
222  closest_break_point = break_point();
223  distance = static_cast<int>(pc - this->pc());
224  // Check whether we can't get any closer.
225  if (distance == 0) break;
226  }
227  Next();
228  }
229 
230  // Move to the break point found.
231  Reset();
232  Next(closest_break_point);
233 }
234 
235 
236 // Find the break point closest to the supplied source position.
237 void BreakLocationIterator::FindBreakLocationFromPosition(int position) {
238  // Run through all break points to locate the one closest to the source
239  // position.
240  int closest_break_point = 0;
241  int distance = kMaxInt;
242  while (!Done()) {
243  // Check if this break point is closer that what was previously found.
244  if (position <= statement_position() &&
245  statement_position() - position < distance) {
246  closest_break_point = break_point();
247  distance = statement_position() - position;
248  // Check whether we can't get any closer.
249  if (distance == 0) break;
250  }
251  Next();
252  }
253 
254  // Move to the break point found.
255  Reset();
256  Next(closest_break_point);
257 }
258 
259 
261  // Create relocation iterators for the two code objects.
262  if (reloc_iterator_ != NULL) delete reloc_iterator_;
263  if (reloc_iterator_original_ != NULL) delete reloc_iterator_original_;
264  reloc_iterator_ = new RelocIterator(debug_info_->code());
265  reloc_iterator_original_ = new RelocIterator(debug_info_->original_code());
266 
267  // Position at the first break point.
268  break_point_ = -1;
269  position_ = 1;
270  statement_position_ = 1;
271  Next();
272 }
273 
274 
275 bool BreakLocationIterator::Done() const {
276  return RinfoDone();
277 }
278 
279 
280 void BreakLocationIterator::SetBreakPoint(Handle<Object> break_point_object) {
281  // If there is not already a real break point here patch code with debug
282  // break.
283  if (!HasBreakPoint()) {
284  SetDebugBreak();
285  }
286  ASSERT(IsDebugBreak() || IsDebuggerStatement());
287  // Set the break point information.
288  DebugInfo::SetBreakPoint(debug_info_, code_position(),
289  position(), statement_position(),
290  break_point_object);
291 }
292 
293 
294 void BreakLocationIterator::ClearBreakPoint(Handle<Object> break_point_object) {
295  // Clear the break point information.
296  DebugInfo::ClearBreakPoint(debug_info_, code_position(), break_point_object);
297  // If there are no more break points here remove the debug break.
298  if (!HasBreakPoint()) {
299  ClearDebugBreak();
300  ASSERT(!IsDebugBreak());
301  }
302 }
303 
304 
305 void BreakLocationIterator::SetOneShot() {
306  // Debugger statement always calls debugger. No need to modify it.
307  if (IsDebuggerStatement()) {
308  return;
309  }
310 
311  // If there is a real break point here no more to do.
312  if (HasBreakPoint()) {
313  ASSERT(IsDebugBreak());
314  return;
315  }
316 
317  // Patch code with debug break.
318  SetDebugBreak();
319 }
320 
321 
322 void BreakLocationIterator::ClearOneShot() {
323  // Debugger statement always calls debugger. No need to modify it.
324  if (IsDebuggerStatement()) {
325  return;
326  }
327 
328  // If there is a real break point here no more to do.
329  if (HasBreakPoint()) {
330  ASSERT(IsDebugBreak());
331  return;
332  }
333 
334  // Patch code removing debug break.
335  ClearDebugBreak();
336  ASSERT(!IsDebugBreak());
337 }
338 
339 
340 void BreakLocationIterator::SetDebugBreak() {
341  // Debugger statement always calls debugger. No need to modify it.
342  if (IsDebuggerStatement()) {
343  return;
344  }
345 
346  // If there is already a break point here just return. This might happen if
347  // the same code is flooded with break points twice. Flooding the same
348  // function twice might happen when stepping in a function with an exception
349  // handler as the handler and the function is the same.
350  if (IsDebugBreak()) {
351  return;
352  }
353 
354  if (RelocInfo::IsJSReturn(rmode())) {
355  // Patch the frame exit code with a break point.
356  SetDebugBreakAtReturn();
357  } else if (IsDebugBreakSlot()) {
358  // Patch the code in the break slot.
359  SetDebugBreakAtSlot();
360  } else {
361  // Patch the IC call.
362  SetDebugBreakAtIC();
363  }
364  ASSERT(IsDebugBreak());
365 }
366 
367 
368 void BreakLocationIterator::ClearDebugBreak() {
369  // Debugger statement always calls debugger. No need to modify it.
370  if (IsDebuggerStatement()) {
371  return;
372  }
373 
374  if (RelocInfo::IsJSReturn(rmode())) {
375  // Restore the frame exit code.
376  ClearDebugBreakAtReturn();
377  } else if (IsDebugBreakSlot()) {
378  // Restore the code in the break slot.
379  ClearDebugBreakAtSlot();
380  } else {
381  // Patch the IC call.
382  ClearDebugBreakAtIC();
383  }
384  ASSERT(!IsDebugBreak());
385 }
386 
387 
388 void BreakLocationIterator::PrepareStepIn() {
389  HandleScope scope;
390 
391  // Step in can only be prepared if currently positioned on an IC call,
392  // construct call or CallFunction stub call.
393  Address target = rinfo()->target_address();
394  Handle<Code> target_code(Code::GetCodeFromTargetAddress(target));
395  if (target_code->is_call_stub() || target_code->is_keyed_call_stub()) {
396  // Step in through IC call is handled by the runtime system. Therefore make
397  // sure that the any current IC is cleared and the runtime system is
398  // called. If the executing code has a debug break at the location change
399  // the call in the original code as it is the code there that will be
400  // executed in place of the debug break call.
401  Handle<Code> stub = ComputeCallDebugPrepareStepIn(
402  target_code->arguments_count(), target_code->kind());
403  if (IsDebugBreak()) {
404  original_rinfo()->set_target_address(stub->entry());
405  } else {
406  rinfo()->set_target_address(stub->entry());
407  }
408  } else {
409 #ifdef DEBUG
410  // All the following stuff is needed only for assertion checks so the code
411  // is wrapped in ifdef.
412  Handle<Code> maybe_call_function_stub = target_code;
413  if (IsDebugBreak()) {
414  Address original_target = original_rinfo()->target_address();
415  maybe_call_function_stub =
416  Handle<Code>(Code::GetCodeFromTargetAddress(original_target));
417  }
418  bool is_call_function_stub =
419  (maybe_call_function_stub->kind() == Code::STUB &&
420  maybe_call_function_stub->major_key() == CodeStub::CallFunction);
421 
422  // Step in through construct call requires no changes to the running code.
423  // Step in through getters/setters should already be prepared as well
424  // because caller of this function (Debug::PrepareStep) is expected to
425  // flood the top frame's function with one shot breakpoints.
426  // Step in through CallFunction stub should also be prepared by caller of
427  // this function (Debug::PrepareStep) which should flood target function
428  // with breakpoints.
429  ASSERT(RelocInfo::IsConstructCall(rmode()) ||
430  target_code->is_inline_cache_stub() ||
431  is_call_function_stub);
432 #endif
433  }
434 }
435 
436 
437 // Check whether the break point is at a position which will exit the function.
438 bool BreakLocationIterator::IsExit() const {
439  return (RelocInfo::IsJSReturn(rmode()));
440 }
441 
442 
443 bool BreakLocationIterator::HasBreakPoint() {
444  return debug_info_->HasBreakPoint(code_position());
445 }
446 
447 
448 // Check whether there is a debug break at the current position.
449 bool BreakLocationIterator::IsDebugBreak() {
450  if (RelocInfo::IsJSReturn(rmode())) {
451  return IsDebugBreakAtReturn();
452  } else if (IsDebugBreakSlot()) {
453  return IsDebugBreakAtSlot();
454  } else {
455  return Debug::IsDebugBreak(rinfo()->target_address());
456  }
457 }
458 
459 
460 void BreakLocationIterator::SetDebugBreakAtIC() {
461  // Patch the original code with the current address as the current address
462  // might have changed by the inline caching since the code was copied.
463  original_rinfo()->set_target_address(rinfo()->target_address());
464 
465  RelocInfo::Mode mode = rmode();
466  if (RelocInfo::IsCodeTarget(mode)) {
467  Address target = rinfo()->target_address();
468  Handle<Code> target_code(Code::GetCodeFromTargetAddress(target));
469 
470  // Patch the code to invoke the builtin debug break function matching the
471  // calling convention used by the call site.
472  Handle<Code> dbgbrk_code(Debug::FindDebugBreak(target_code, mode));
473  rinfo()->set_target_address(dbgbrk_code->entry());
474  }
475 }
476 
477 
478 void BreakLocationIterator::ClearDebugBreakAtIC() {
479  // Patch the code to the original invoke.
480  rinfo()->set_target_address(original_rinfo()->target_address());
481 }
482 
483 
484 bool BreakLocationIterator::IsDebuggerStatement() {
485  return RelocInfo::DEBUG_BREAK == rmode();
486 }
487 
488 
489 bool BreakLocationIterator::IsDebugBreakSlot() {
490  return RelocInfo::DEBUG_BREAK_SLOT == rmode();
491 }
492 
493 
494 Object* BreakLocationIterator::BreakPointObjects() {
495  return debug_info_->GetBreakPointObjects(code_position());
496 }
497 
498 
499 // Clear out all the debug break code. This is ONLY supposed to be used when
500 // shutting down the debugger as it will leave the break point information in
501 // DebugInfo even though the code is patched back to the non break point state.
502 void BreakLocationIterator::ClearAllDebugBreak() {
503  while (!Done()) {
504  ClearDebugBreak();
505  Next();
506  }
507 }
508 
509 
510 bool BreakLocationIterator::RinfoDone() const {
511  ASSERT(reloc_iterator_->done() == reloc_iterator_original_->done());
512  return reloc_iterator_->done();
513 }
514 
515 
516 void BreakLocationIterator::RinfoNext() {
517  reloc_iterator_->next();
518  reloc_iterator_original_->next();
519 #ifdef DEBUG
520  ASSERT(reloc_iterator_->done() == reloc_iterator_original_->done());
521  if (!reloc_iterator_->done()) {
522  ASSERT(rmode() == original_rmode());
523  }
524 #endif
525 }
526 
527 
528 // Threading support.
529 void Debug::ThreadInit() {
530  thread_local_.break_count_ = 0;
531  thread_local_.break_id_ = 0;
532  thread_local_.break_frame_id_ = StackFrame::NO_ID;
533  thread_local_.last_step_action_ = StepNone;
534  thread_local_.last_statement_position_ = RelocInfo::kNoPosition;
535  thread_local_.step_count_ = 0;
536  thread_local_.last_fp_ = 0;
537  thread_local_.queued_step_count_ = 0;
538  thread_local_.step_into_fp_ = 0;
539  thread_local_.step_out_fp_ = 0;
540  thread_local_.after_break_target_ = 0;
541  // TODO(isolates): frames_are_dropped_?
542  thread_local_.debugger_entry_ = NULL;
543  thread_local_.pending_interrupts_ = 0;
544  thread_local_.restarter_frame_function_pointer_ = NULL;
545 }
546 
547 
548 char* Debug::ArchiveDebug(char* storage) {
549  char* to = storage;
550  memcpy(to, reinterpret_cast<char*>(&thread_local_), sizeof(ThreadLocal));
551  to += sizeof(ThreadLocal);
552  memcpy(to, reinterpret_cast<char*>(&registers_), sizeof(registers_));
553  ThreadInit();
554  ASSERT(to <= storage + ArchiveSpacePerThread());
555  return storage + ArchiveSpacePerThread();
556 }
557 
558 
559 char* Debug::RestoreDebug(char* storage) {
560  char* from = storage;
561  memcpy(reinterpret_cast<char*>(&thread_local_), from, sizeof(ThreadLocal));
562  from += sizeof(ThreadLocal);
563  memcpy(reinterpret_cast<char*>(&registers_), from, sizeof(registers_));
564  ASSERT(from <= storage + ArchiveSpacePerThread());
565  return storage + ArchiveSpacePerThread();
566 }
567 
568 
569 int Debug::ArchiveSpacePerThread() {
570  return sizeof(ThreadLocal) + sizeof(JSCallerSavedBuffer);
571 }
572 
573 
574 // Frame structure (conforms InternalFrame structure):
575 // -- code
576 // -- SMI maker
577 // -- function (slot is called "context")
578 // -- frame base
579 Object** Debug::SetUpFrameDropperFrame(StackFrame* bottom_js_frame,
580  Handle<Code> code) {
581  ASSERT(bottom_js_frame->is_java_script());
582 
583  Address fp = bottom_js_frame->fp();
584 
585  // Move function pointer into "context" slot.
588 
592 
593  return reinterpret_cast<Object**>(&Memory::Object_at(
595 }
596 
597 const int Debug::kFrameDropperFrameSize = 4;
598 
599 
600 void ScriptCache::Add(Handle<Script> script) {
601  GlobalHandles* global_handles = Isolate::Current()->global_handles();
602  // Create an entry in the hash map for the script.
603  int id = Smi::cast(script->id())->value();
604  HashMap::Entry* entry =
605  HashMap::Lookup(reinterpret_cast<void*>(id), Hash(id), true);
606  if (entry->value != NULL) {
607  ASSERT(*script == *reinterpret_cast<Script**>(entry->value));
608  return;
609  }
610 
611  // Globalize the script object, make it weak and use the location of the
612  // global handle as the value in the hash map.
613  Handle<Script> script_ =
615  (global_handles->Create(*script)));
616  global_handles->MakeWeak(
617  reinterpret_cast<Object**>(script_.location()),
618  this,
619  ScriptCache::HandleWeakScript);
620  entry->value = script_.location();
621 }
622 
623 
624 Handle<FixedArray> ScriptCache::GetScripts() {
625  Handle<FixedArray> instances = FACTORY->NewFixedArray(occupancy());
626  int count = 0;
627  for (HashMap::Entry* entry = Start(); entry != NULL; entry = Next(entry)) {
628  ASSERT(entry->value != NULL);
629  if (entry->value != NULL) {
630  instances->set(count, *reinterpret_cast<Script**>(entry->value));
631  count++;
632  }
633  }
634  return instances;
635 }
636 
637 
638 void ScriptCache::ProcessCollectedScripts() {
639  Debugger* debugger = Isolate::Current()->debugger();
640  for (int i = 0; i < collected_scripts_.length(); i++) {
641  debugger->OnScriptCollected(collected_scripts_[i]);
642  }
643  collected_scripts_.Clear();
644 }
645 
646 
647 void ScriptCache::Clear() {
648  GlobalHandles* global_handles = Isolate::Current()->global_handles();
649  // Iterate the script cache to get rid of all the weak handles.
650  for (HashMap::Entry* entry = Start(); entry != NULL; entry = Next(entry)) {
651  ASSERT(entry != NULL);
652  Object** location = reinterpret_cast<Object**>(entry->value);
653  ASSERT((*location)->IsScript());
654  global_handles->ClearWeakness(location);
655  global_handles->Destroy(location);
656  }
657  // Clear the content of the hash map.
658  HashMap::Clear();
659 }
660 
661 
662 void ScriptCache::HandleWeakScript(v8::Persistent<v8::Value> obj, void* data) {
663  ScriptCache* script_cache = reinterpret_cast<ScriptCache*>(data);
664  // Find the location of the global handle.
665  Script** location =
666  reinterpret_cast<Script**>(Utils::OpenHandle(*obj).location());
667  ASSERT((*location)->IsScript());
668 
669  // Remove the entry from the cache.
670  int id = Smi::cast((*location)->id())->value();
671  script_cache->Remove(reinterpret_cast<void*>(id), Hash(id));
672  script_cache->collected_scripts_.Add(id);
673 
674  // Clear the weak handle.
675  obj.Dispose();
676  obj.Clear();
677 }
678 
679 
680 void Debug::SetUp(bool create_heap_objects) {
681  ThreadInit();
682  if (create_heap_objects) {
683  // Get code to handle debug break on return.
684  debug_break_return_ =
685  isolate_->builtins()->builtin(Builtins::kReturn_DebugBreak);
686  ASSERT(debug_break_return_->IsCode());
687  // Get code to handle debug break in debug break slots.
688  debug_break_slot_ =
689  isolate_->builtins()->builtin(Builtins::kSlot_DebugBreak);
690  ASSERT(debug_break_slot_->IsCode());
691  }
692 }
693 
694 
695 void Debug::HandleWeakDebugInfo(v8::Persistent<v8::Value> obj, void* data) {
696  Debug* debug = Isolate::Current()->debug();
697  DebugInfoListNode* node = reinterpret_cast<DebugInfoListNode*>(data);
698  // We need to clear all breakpoints associated with the function to restore
699  // original code and avoid patching the code twice later because
700  // the function will live in the heap until next gc, and can be found by
701  // Runtime::FindSharedFunctionInfoInScript.
702  BreakLocationIterator it(node->debug_info(), ALL_BREAK_LOCATIONS);
703  it.ClearAllDebugBreak();
704  debug->RemoveDebugInfo(node->debug_info());
705 #ifdef DEBUG
706  node = debug->debug_info_list_;
707  while (node != NULL) {
708  ASSERT(node != reinterpret_cast<DebugInfoListNode*>(data));
709  node = node->next();
710  }
711 #endif
712 }
713 
714 
715 DebugInfoListNode::DebugInfoListNode(DebugInfo* debug_info): next_(NULL) {
716  GlobalHandles* global_handles = Isolate::Current()->global_handles();
717  // Globalize the request debug info object and make it weak.
718  debug_info_ = Handle<DebugInfo>::cast(
719  (global_handles->Create(debug_info)));
720  global_handles->MakeWeak(
721  reinterpret_cast<Object**>(debug_info_.location()),
722  this,
723  Debug::HandleWeakDebugInfo);
724 }
725 
726 
727 DebugInfoListNode::~DebugInfoListNode() {
728  Isolate::Current()->global_handles()->Destroy(
729  reinterpret_cast<Object**>(debug_info_.location()));
730 }
731 
732 
733 bool Debug::CompileDebuggerScript(int index) {
734  Isolate* isolate = Isolate::Current();
735  Factory* factory = isolate->factory();
736  HandleScope scope(isolate);
737 
738  // Bail out if the index is invalid.
739  if (index == -1) {
740  return false;
741  }
742 
743  // Find source and name for the requested script.
744  Handle<String> source_code =
745  isolate->bootstrapper()->NativesSourceLookup(index);
746  Vector<const char> name = Natives::GetScriptName(index);
747  Handle<String> script_name = factory->NewStringFromAscii(name);
748 
749  // Compile the script.
750  Handle<SharedFunctionInfo> function_info;
751  function_info = Compiler::Compile(source_code,
752  script_name,
753  0, 0, NULL, NULL,
755  NATIVES_CODE);
756 
757  // Silently ignore stack overflows during compilation.
758  if (function_info.is_null()) {
759  ASSERT(isolate->has_pending_exception());
760  isolate->clear_pending_exception();
761  return false;
762  }
763 
764  // Execute the shared function in the debugger context.
765  Handle<Context> context = isolate->global_context();
766  bool caught_exception;
767  Handle<JSFunction> function =
768  factory->NewFunctionFromSharedFunctionInfo(function_info, context);
769 
770  Handle<Object> exception =
771  Execution::TryCall(function, Handle<Object>(context->global()),
772  0, NULL, &caught_exception);
773 
774  // Check for caught exceptions.
775  if (caught_exception) {
776  ASSERT(!isolate->has_pending_exception());
777  MessageLocation computed_location;
778  isolate->ComputeLocation(&computed_location);
779  Handle<Object> message = MessageHandler::MakeMessageObject(
780  "error_loading_debugger", &computed_location,
781  Vector<Handle<Object> >::empty(), Handle<String>(), Handle<JSArray>());
782  ASSERT(!isolate->has_pending_exception());
783  isolate->set_pending_exception(*exception);
784  MessageHandler::ReportMessage(Isolate::Current(), NULL, message);
785  isolate->clear_pending_exception();
786  return false;
787  }
788 
789  // Mark this script as native and return successfully.
790  Handle<Script> script(Script::cast(function->shared()->script()));
791  script->set_type(Smi::FromInt(Script::TYPE_NATIVE));
792  return true;
793 }
794 
795 
796 bool Debug::Load() {
797  // Return if debugger is already loaded.
798  if (IsLoaded()) return true;
799 
800  Debugger* debugger = isolate_->debugger();
801 
802  // Bail out if we're already in the process of compiling the native
803  // JavaScript source code for the debugger.
804  if (debugger->compiling_natives() ||
805  debugger->is_loading_debugger())
806  return false;
807  debugger->set_loading_debugger(true);
808 
809  // Disable breakpoints and interrupts while compiling and running the
810  // debugger scripts including the context creation code.
811  DisableBreak disable(true);
812  PostponeInterruptsScope postpone(isolate_);
813 
814  // Create the debugger context.
815  HandleScope scope(isolate_);
816  Handle<Context> context =
817  isolate_->bootstrapper()->CreateEnvironment(
818  isolate_,
821  NULL);
822 
823  // Fail if no context could be created.
824  if (context.is_null()) return false;
825 
826  // Use the debugger context.
827  SaveContext save(isolate_);
828  isolate_->set_context(*context);
829 
830  // Expose the builtins object in the debugger context.
831  Handle<String> key = isolate_->factory()->LookupAsciiSymbol("builtins");
832  Handle<GlobalObject> global = Handle<GlobalObject>(context->global());
834  isolate_,
835  JSReceiver::SetProperty(global, key, Handle<Object>(global->builtins()),
837  false);
838 
839  // Compile the JavaScript for the debugger in the debugger context.
840  debugger->set_compiling_natives(true);
841  bool caught_exception =
842  !CompileDebuggerScript(Natives::GetIndex("mirror")) ||
843  !CompileDebuggerScript(Natives::GetIndex("debug"));
844 
845  if (FLAG_enable_liveedit) {
846  caught_exception = caught_exception ||
847  !CompileDebuggerScript(Natives::GetIndex("liveedit"));
848  }
849 
850  debugger->set_compiling_natives(false);
851 
852  // Make sure we mark the debugger as not loading before we might
853  // return.
854  debugger->set_loading_debugger(false);
855 
856  // Check for caught exceptions.
857  if (caught_exception) return false;
858 
859  // Debugger loaded.
860  debug_context_ = context;
861 
862  return true;
863 }
864 
865 
866 void Debug::Unload() {
867  // Return debugger is not loaded.
868  if (!IsLoaded()) {
869  return;
870  }
871 
872  // Clear the script cache.
873  DestroyScriptCache();
874 
875  // Clear debugger context global handle.
876  Isolate::Current()->global_handles()->Destroy(
877  reinterpret_cast<Object**>(debug_context_.location()));
878  debug_context_ = Handle<Context>();
879 }
880 
881 
882 // Set the flag indicating that preemption happened during debugging.
883 void Debug::PreemptionWhileInDebugger() {
884  ASSERT(InDebugger());
885  Debug::set_interrupts_pending(PREEMPT);
886 }
887 
888 
889 void Debug::Iterate(ObjectVisitor* v) {
890  v->VisitPointer(BitCast<Object**>(&(debug_break_return_)));
891  v->VisitPointer(BitCast<Object**>(&(debug_break_slot_)));
892 }
893 
894 
895 void Debug::PutValuesOnStackAndDie(int start,
896  Address c_entry_fp,
897  Address last_fp,
898  Address larger_fp,
899  int count,
900  int end) {
901  OS::Abort();
902 }
903 
904 
905 Object* Debug::Break(Arguments args) {
906  Heap* heap = isolate_->heap();
907  HandleScope scope(isolate_);
908  ASSERT(args.length() == 0);
909 
910  thread_local_.frame_drop_mode_ = FRAMES_UNTOUCHED;
911 
912  // Get the top-most JavaScript frame.
913  JavaScriptFrameIterator it(isolate_);
914  JavaScriptFrame* frame = it.frame();
915 
916  // Just continue if breaks are disabled or debugger cannot be loaded.
917  if (disable_break() || !Load()) {
918  SetAfterBreakTarget(frame);
919  return heap->undefined_value();
920  }
921 
922  // Enter the debugger.
923  EnterDebugger debugger;
924  if (debugger.FailedToEnter()) {
925  return heap->undefined_value();
926  }
927 
928  // Postpone interrupt during breakpoint processing.
929  PostponeInterruptsScope postpone(isolate_);
930 
931  // Get the debug info (create it if it does not exist).
932  Handle<SharedFunctionInfo> shared =
933  Handle<SharedFunctionInfo>(JSFunction::cast(frame->function())->shared());
934  Handle<DebugInfo> debug_info = GetDebugInfo(shared);
935 
936  // Find the break point where execution has stopped.
937  BreakLocationIterator break_location_iterator(debug_info,
938  ALL_BREAK_LOCATIONS);
939  break_location_iterator.FindBreakLocationFromAddress(frame->pc());
940 
941  // Check whether step next reached a new statement.
942  if (!StepNextContinue(&break_location_iterator, frame)) {
943  // Decrease steps left if performing multiple steps.
944  if (thread_local_.step_count_ > 0) {
945  thread_local_.step_count_--;
946  }
947  }
948 
949  // If there is one or more real break points check whether any of these are
950  // triggered.
951  Handle<Object> break_points_hit(heap->undefined_value());
952  if (break_location_iterator.HasBreakPoint()) {
953  Handle<Object> break_point_objects =
954  Handle<Object>(break_location_iterator.BreakPointObjects());
955  break_points_hit = CheckBreakPoints(break_point_objects);
956  }
957 
958  // If step out is active skip everything until the frame where we need to step
959  // out to is reached, unless real breakpoint is hit.
960  if (StepOutActive() && frame->fp() != step_out_fp() &&
961  break_points_hit->IsUndefined() ) {
962  // Step count should always be 0 for StepOut.
963  ASSERT(thread_local_.step_count_ == 0);
964  } else if (!break_points_hit->IsUndefined() ||
965  (thread_local_.last_step_action_ != StepNone &&
966  thread_local_.step_count_ == 0)) {
967  // Notify debugger if a real break point is triggered or if performing
968  // single stepping with no more steps to perform. Otherwise do another step.
969 
970  // Clear all current stepping setup.
971  ClearStepping();
972 
973  if (thread_local_.queued_step_count_ > 0) {
974  // Perform queued steps
975  int step_count = thread_local_.queued_step_count_;
976 
977  // Clear queue
978  thread_local_.queued_step_count_ = 0;
979 
980  PrepareStep(StepNext, step_count);
981  } else {
982  // Notify the debug event listeners.
983  isolate_->debugger()->OnDebugBreak(break_points_hit, false);
984  }
985  } else if (thread_local_.last_step_action_ != StepNone) {
986  // Hold on to last step action as it is cleared by the call to
987  // ClearStepping.
988  StepAction step_action = thread_local_.last_step_action_;
989  int step_count = thread_local_.step_count_;
990 
991  // If StepNext goes deeper in code, StepOut until original frame
992  // and keep step count queued up in the meantime.
993  if (step_action == StepNext && frame->fp() < thread_local_.last_fp_) {
994  // Count frames until target frame
995  int count = 0;
996  JavaScriptFrameIterator it(isolate_);
997  while (!it.done() && it.frame()->fp() < thread_local_.last_fp_) {
998  count++;
999  it.Advance();
1000  }
1001 
1002  // Catch the cases that would lead to crashes and capture
1003  // - C entry FP at which to start stack crawl.
1004  // - FP of the frame at which we plan to stop stepping out (last FP).
1005  // - current FP that's larger than last FP.
1006  // - Counter for the number of steps to step out.
1007  if (it.done()) {
1008  // We crawled the entire stack, never reaching last_fp_.
1009  PutValuesOnStackAndDie(0xBEEEEEEE,
1010  frame->fp(),
1011  thread_local_.last_fp_,
1012  NULL,
1013  count,
1014  0xFEEEEEEE);
1015  } else if (it.frame()->fp() != thread_local_.last_fp_) {
1016  // We crawled over last_fp_, without getting a match.
1017  PutValuesOnStackAndDie(0xBEEEEEEE,
1018  frame->fp(),
1019  thread_local_.last_fp_,
1020  it.frame()->fp(),
1021  count,
1022  0xFEEEEEEE);
1023  }
1024 
1025  // If we found original frame
1026  if (it.frame()->fp() == thread_local_.last_fp_) {
1027  if (step_count > 1) {
1028  // Save old count and action to continue stepping after
1029  // StepOut
1030  thread_local_.queued_step_count_ = step_count - 1;
1031  }
1032 
1033  // Set up for StepOut to reach target frame
1034  step_action = StepOut;
1035  step_count = count;
1036  }
1037  }
1038 
1039  // Clear all current stepping setup.
1040  ClearStepping();
1041 
1042  // Set up for the remaining steps.
1043  PrepareStep(step_action, step_count);
1044  }
1045 
1046  if (thread_local_.frame_drop_mode_ == FRAMES_UNTOUCHED) {
1047  SetAfterBreakTarget(frame);
1048  } else if (thread_local_.frame_drop_mode_ ==
1049  FRAME_DROPPED_IN_IC_CALL) {
1050  // We must have been calling IC stub. Do not go there anymore.
1051  Code* plain_return = isolate_->builtins()->builtin(
1052  Builtins::kPlainReturn_LiveEdit);
1053  thread_local_.after_break_target_ = plain_return->entry();
1054  } else if (thread_local_.frame_drop_mode_ ==
1055  FRAME_DROPPED_IN_DEBUG_SLOT_CALL) {
1056  // Debug break slot stub does not return normally, instead it manually
1057  // cleans the stack and jumps. We should patch the jump address.
1058  Code* plain_return = isolate_->builtins()->builtin(
1059  Builtins::kFrameDropper_LiveEdit);
1060  thread_local_.after_break_target_ = plain_return->entry();
1061  } else if (thread_local_.frame_drop_mode_ ==
1062  FRAME_DROPPED_IN_DIRECT_CALL) {
1063  // Nothing to do, after_break_target is not used here.
1064  } else if (thread_local_.frame_drop_mode_ ==
1065  FRAME_DROPPED_IN_RETURN_CALL) {
1066  Code* plain_return = isolate_->builtins()->builtin(
1067  Builtins::kFrameDropper_LiveEdit);
1068  thread_local_.after_break_target_ = plain_return->entry();
1069  } else {
1070  UNREACHABLE();
1071  }
1072 
1073  return heap->undefined_value();
1074 }
1075 
1076 
1077 RUNTIME_FUNCTION(Object*, Debug_Break) {
1078  return isolate->debug()->Break(args);
1079 }
1080 
1081 
1082 // Check the break point objects for whether one or more are actually
1083 // triggered. This function returns a JSArray with the break point objects
1084 // which is triggered.
1085 Handle<Object> Debug::CheckBreakPoints(Handle<Object> break_point_objects) {
1086  Factory* factory = isolate_->factory();
1087 
1088  // Count the number of break points hit. If there are multiple break points
1089  // they are in a FixedArray.
1090  Handle<FixedArray> break_points_hit;
1091  int break_points_hit_count = 0;
1092  ASSERT(!break_point_objects->IsUndefined());
1093  if (break_point_objects->IsFixedArray()) {
1094  Handle<FixedArray> array(FixedArray::cast(*break_point_objects));
1095  break_points_hit = factory->NewFixedArray(array->length());
1096  for (int i = 0; i < array->length(); i++) {
1097  Handle<Object> o(array->get(i));
1098  if (CheckBreakPoint(o)) {
1099  break_points_hit->set(break_points_hit_count++, *o);
1100  }
1101  }
1102  } else {
1103  break_points_hit = factory->NewFixedArray(1);
1104  if (CheckBreakPoint(break_point_objects)) {
1105  break_points_hit->set(break_points_hit_count++, *break_point_objects);
1106  }
1107  }
1108 
1109  // Return undefined if no break points were triggered.
1110  if (break_points_hit_count == 0) {
1111  return factory->undefined_value();
1112  }
1113  // Return break points hit as a JSArray.
1114  Handle<JSArray> result = factory->NewJSArrayWithElements(break_points_hit);
1115  result->set_length(Smi::FromInt(break_points_hit_count));
1116  return result;
1117 }
1118 
1119 
1120 // Check whether a single break point object is triggered.
1121 bool Debug::CheckBreakPoint(Handle<Object> break_point_object) {
1122  Factory* factory = isolate_->factory();
1123  HandleScope scope(isolate_);
1124 
1125  // Ignore check if break point object is not a JSObject.
1126  if (!break_point_object->IsJSObject()) return true;
1127 
1128  // Get the function IsBreakPointTriggered (defined in debug-debugger.js).
1129  Handle<String> is_break_point_triggered_symbol =
1130  factory->LookupAsciiSymbol("IsBreakPointTriggered");
1131  Handle<JSFunction> check_break_point =
1132  Handle<JSFunction>(JSFunction::cast(
1133  debug_context()->global()->GetPropertyNoExceptionThrown(
1134  *is_break_point_triggered_symbol)));
1135 
1136  // Get the break id as an object.
1137  Handle<Object> break_id = factory->NewNumberFromInt(Debug::break_id());
1138 
1139  // Call HandleBreakPointx.
1140  bool caught_exception;
1141  Handle<Object> argv[] = { break_id, break_point_object };
1142  Handle<Object> result = Execution::TryCall(check_break_point,
1143  isolate_->js_builtins_object(),
1144  ARRAY_SIZE(argv),
1145  argv,
1146  &caught_exception);
1147 
1148  // If exception or non boolean result handle as not triggered
1149  if (caught_exception || !result->IsBoolean()) {
1150  return false;
1151  }
1152 
1153  // Return whether the break point is triggered.
1154  ASSERT(!result.is_null());
1155  return (*result)->IsTrue();
1156 }
1157 
1158 
1159 // Check whether the function has debug information.
1160 bool Debug::HasDebugInfo(Handle<SharedFunctionInfo> shared) {
1161  return !shared->debug_info()->IsUndefined();
1162 }
1163 
1164 
1165 // Return the debug info for this function. EnsureDebugInfo must be called
1166 // prior to ensure the debug info has been generated for shared.
1167 Handle<DebugInfo> Debug::GetDebugInfo(Handle<SharedFunctionInfo> shared) {
1168  ASSERT(HasDebugInfo(shared));
1169  return Handle<DebugInfo>(DebugInfo::cast(shared->debug_info()));
1170 }
1171 
1172 
1173 void Debug::SetBreakPoint(Handle<SharedFunctionInfo> shared,
1174  Handle<Object> break_point_object,
1175  int* source_position) {
1176  HandleScope scope(isolate_);
1177 
1178  PrepareForBreakPoints();
1179 
1180  if (!EnsureDebugInfo(shared)) {
1181  // Return if retrieving debug info failed.
1182  return;
1183  }
1184 
1185  Handle<DebugInfo> debug_info = GetDebugInfo(shared);
1186  // Source positions starts with zero.
1187  ASSERT(*source_position >= 0);
1188 
1189  // Find the break point and change it.
1190  BreakLocationIterator it(debug_info, SOURCE_BREAK_LOCATIONS);
1191  it.FindBreakLocationFromPosition(*source_position);
1192  it.SetBreakPoint(break_point_object);
1193 
1194  *source_position = it.position();
1195 
1196  // At least one active break point now.
1197  ASSERT(debug_info->GetBreakPointCount() > 0);
1198 }
1199 
1200 
1201 void Debug::ClearBreakPoint(Handle<Object> break_point_object) {
1202  HandleScope scope(isolate_);
1203 
1204  DebugInfoListNode* node = debug_info_list_;
1205  while (node != NULL) {
1206  Object* result = DebugInfo::FindBreakPointInfo(node->debug_info(),
1207  break_point_object);
1208  if (!result->IsUndefined()) {
1209  // Get information in the break point.
1210  BreakPointInfo* break_point_info = BreakPointInfo::cast(result);
1211  Handle<DebugInfo> debug_info = node->debug_info();
1212  Handle<SharedFunctionInfo> shared(debug_info->shared());
1213  int source_position = break_point_info->statement_position()->value();
1214 
1215  // Source positions starts with zero.
1216  ASSERT(source_position >= 0);
1217 
1218  // Find the break point and clear it.
1219  BreakLocationIterator it(debug_info, SOURCE_BREAK_LOCATIONS);
1220  it.FindBreakLocationFromPosition(source_position);
1221  it.ClearBreakPoint(break_point_object);
1222 
1223  // If there are no more break points left remove the debug info for this
1224  // function.
1225  if (debug_info->GetBreakPointCount() == 0) {
1226  RemoveDebugInfo(debug_info);
1227  }
1228 
1229  return;
1230  }
1231  node = node->next();
1232  }
1233 }
1234 
1235 
1236 void Debug::ClearAllBreakPoints() {
1237  DebugInfoListNode* node = debug_info_list_;
1238  while (node != NULL) {
1239  // Remove all debug break code.
1240  BreakLocationIterator it(node->debug_info(), ALL_BREAK_LOCATIONS);
1241  it.ClearAllDebugBreak();
1242  node = node->next();
1243  }
1244 
1245  // Remove all debug info.
1246  while (debug_info_list_ != NULL) {
1247  RemoveDebugInfo(debug_info_list_->debug_info());
1248  }
1249 }
1250 
1251 
1252 void Debug::FloodWithOneShot(Handle<SharedFunctionInfo> shared) {
1253  PrepareForBreakPoints();
1254  // Make sure the function has set up the debug info.
1255  if (!EnsureDebugInfo(shared)) {
1256  // Return if we failed to retrieve the debug info.
1257  return;
1258  }
1259 
1260  // Flood the function with break points.
1261  BreakLocationIterator it(GetDebugInfo(shared), ALL_BREAK_LOCATIONS);
1262  while (!it.Done()) {
1263  it.SetOneShot();
1264  it.Next();
1265  }
1266 }
1267 
1268 
1269 void Debug::FloodBoundFunctionWithOneShot(Handle<JSFunction> function) {
1270  Handle<FixedArray> new_bindings(function->function_bindings());
1271  Handle<Object> bindee(new_bindings->get(JSFunction::kBoundFunctionIndex));
1272 
1273  if (!bindee.is_null() && bindee->IsJSFunction() &&
1274  !JSFunction::cast(*bindee)->IsBuiltin()) {
1275  Handle<SharedFunctionInfo> shared_info(JSFunction::cast(*bindee)->shared());
1276  Debug::FloodWithOneShot(shared_info);
1277  }
1278 }
1279 
1280 
1281 void Debug::FloodHandlerWithOneShot() {
1282  // Iterate through the JavaScript stack looking for handlers.
1283  StackFrame::Id id = break_frame_id();
1284  if (id == StackFrame::NO_ID) {
1285  // If there is no JavaScript stack don't do anything.
1286  return;
1287  }
1288  for (JavaScriptFrameIterator it(isolate_, id); !it.done(); it.Advance()) {
1289  JavaScriptFrame* frame = it.frame();
1290  if (frame->HasHandler()) {
1291  Handle<SharedFunctionInfo> shared =
1292  Handle<SharedFunctionInfo>(
1293  JSFunction::cast(frame->function())->shared());
1294  // Flood the function with the catch block with break points
1295  FloodWithOneShot(shared);
1296  return;
1297  }
1298  }
1299 }
1300 
1301 
1302 void Debug::ChangeBreakOnException(ExceptionBreakType type, bool enable) {
1303  if (type == BreakUncaughtException) {
1304  break_on_uncaught_exception_ = enable;
1305  } else {
1306  break_on_exception_ = enable;
1307  }
1308 }
1309 
1310 
1311 bool Debug::IsBreakOnException(ExceptionBreakType type) {
1312  if (type == BreakUncaughtException) {
1313  return break_on_uncaught_exception_;
1314  } else {
1315  return break_on_exception_;
1316  }
1317 }
1318 
1319 
1320 void Debug::PrepareStep(StepAction step_action, int step_count) {
1321  HandleScope scope(isolate_);
1322 
1323  PrepareForBreakPoints();
1324 
1325  ASSERT(Debug::InDebugger());
1326 
1327  // Remember this step action and count.
1328  thread_local_.last_step_action_ = step_action;
1329  if (step_action == StepOut) {
1330  // For step out target frame will be found on the stack so there is no need
1331  // to set step counter for it. It's expected to always be 0 for StepOut.
1332  thread_local_.step_count_ = 0;
1333  } else {
1334  thread_local_.step_count_ = step_count;
1335  }
1336 
1337  // Get the frame where the execution has stopped and skip the debug frame if
1338  // any. The debug frame will only be present if execution was stopped due to
1339  // hitting a break point. In other situations (e.g. unhandled exception) the
1340  // debug frame is not present.
1341  StackFrame::Id id = break_frame_id();
1342  if (id == StackFrame::NO_ID) {
1343  // If there is no JavaScript stack don't do anything.
1344  return;
1345  }
1346  JavaScriptFrameIterator frames_it(isolate_, id);
1347  JavaScriptFrame* frame = frames_it.frame();
1348 
1349  // First of all ensure there is one-shot break points in the top handler
1350  // if any.
1351  FloodHandlerWithOneShot();
1352 
1353  // If the function on the top frame is unresolved perform step out. This will
1354  // be the case when calling unknown functions and having the debugger stopped
1355  // in an unhandled exception.
1356  if (!frame->function()->IsJSFunction()) {
1357  // Step out: Find the calling JavaScript frame and flood it with
1358  // breakpoints.
1359  frames_it.Advance();
1360  // Fill the function to return to with one-shot break points.
1361  JSFunction* function = JSFunction::cast(frames_it.frame()->function());
1362  FloodWithOneShot(Handle<SharedFunctionInfo>(function->shared()));
1363  return;
1364  }
1365 
1366  // Get the debug info (create it if it does not exist).
1367  Handle<SharedFunctionInfo> shared =
1368  Handle<SharedFunctionInfo>(JSFunction::cast(frame->function())->shared());
1369  if (!EnsureDebugInfo(shared)) {
1370  // Return if ensuring debug info failed.
1371  return;
1372  }
1373  Handle<DebugInfo> debug_info = GetDebugInfo(shared);
1374 
1375  // Find the break location where execution has stopped.
1376  BreakLocationIterator it(debug_info, ALL_BREAK_LOCATIONS);
1377  it.FindBreakLocationFromAddress(frame->pc());
1378 
1379  // Compute whether or not the target is a call target.
1380  bool is_load_or_store = false;
1381  bool is_inline_cache_stub = false;
1382  bool is_at_restarted_function = false;
1383  Handle<Code> call_function_stub;
1384 
1385  if (thread_local_.restarter_frame_function_pointer_ == NULL) {
1386  if (RelocInfo::IsCodeTarget(it.rinfo()->rmode())) {
1387  bool is_call_target = false;
1388  Address target = it.rinfo()->target_address();
1389  Code* code = Code::GetCodeFromTargetAddress(target);
1390  if (code->is_call_stub() || code->is_keyed_call_stub()) {
1391  is_call_target = true;
1392  }
1393  if (code->is_inline_cache_stub()) {
1394  is_inline_cache_stub = true;
1395  is_load_or_store = !is_call_target;
1396  }
1397 
1398  // Check if target code is CallFunction stub.
1399  Code* maybe_call_function_stub = code;
1400  // If there is a breakpoint at this line look at the original code to
1401  // check if it is a CallFunction stub.
1402  if (it.IsDebugBreak()) {
1403  Address original_target = it.original_rinfo()->target_address();
1404  maybe_call_function_stub =
1405  Code::GetCodeFromTargetAddress(original_target);
1406  }
1407  if (maybe_call_function_stub->kind() == Code::STUB &&
1408  maybe_call_function_stub->major_key() == CodeStub::CallFunction) {
1409  // Save reference to the code as we may need it to find out arguments
1410  // count for 'step in' later.
1411  call_function_stub = Handle<Code>(maybe_call_function_stub);
1412  }
1413  }
1414  } else {
1415  is_at_restarted_function = true;
1416  }
1417 
1418  // If this is the last break code target step out is the only possibility.
1419  if (it.IsExit() || step_action == StepOut) {
1420  if (step_action == StepOut) {
1421  // Skip step_count frames starting with the current one.
1422  while (step_count-- > 0 && !frames_it.done()) {
1423  frames_it.Advance();
1424  }
1425  } else {
1426  ASSERT(it.IsExit());
1427  frames_it.Advance();
1428  }
1429  // Skip builtin functions on the stack.
1430  while (!frames_it.done() &&
1431  JSFunction::cast(frames_it.frame()->function())->IsBuiltin()) {
1432  frames_it.Advance();
1433  }
1434  // Step out: If there is a JavaScript caller frame, we need to
1435  // flood it with breakpoints.
1436  if (!frames_it.done()) {
1437  // Fill the function to return to with one-shot break points.
1438  JSFunction* function = JSFunction::cast(frames_it.frame()->function());
1439  FloodWithOneShot(Handle<SharedFunctionInfo>(function->shared()));
1440  // Set target frame pointer.
1441  ActivateStepOut(frames_it.frame());
1442  }
1443  } else if (!(is_inline_cache_stub || RelocInfo::IsConstructCall(it.rmode()) ||
1444  !call_function_stub.is_null() || is_at_restarted_function)
1445  || step_action == StepNext || step_action == StepMin) {
1446  // Step next or step min.
1447 
1448  // Fill the current function with one-shot break points.
1449  FloodWithOneShot(shared);
1450 
1451  // Remember source position and frame to handle step next.
1452  thread_local_.last_statement_position_ =
1453  debug_info->code()->SourceStatementPosition(frame->pc());
1454  thread_local_.last_fp_ = frame->UnpaddedFP();
1455  } else {
1456  // If there's restarter frame on top of the stack, just get the pointer
1457  // to function which is going to be restarted.
1458  if (is_at_restarted_function) {
1459  Handle<JSFunction> restarted_function(
1460  JSFunction::cast(*thread_local_.restarter_frame_function_pointer_));
1461  Handle<SharedFunctionInfo> restarted_shared(
1462  restarted_function->shared());
1463  FloodWithOneShot(restarted_shared);
1464  } else if (!call_function_stub.is_null()) {
1465  // If it's CallFunction stub ensure target function is compiled and flood
1466  // it with one shot breakpoints.
1467 
1468  // Find out number of arguments from the stub minor key.
1469  // Reverse lookup required as the minor key cannot be retrieved
1470  // from the code object.
1471  Handle<Object> obj(
1472  isolate_->heap()->code_stubs()->SlowReverseLookup(
1473  *call_function_stub));
1474  ASSERT(!obj.is_null());
1475  ASSERT(!(*obj)->IsUndefined());
1476  ASSERT(obj->IsSmi());
1477  // Get the STUB key and extract major and minor key.
1478  uint32_t key = Smi::cast(*obj)->value();
1479  // Argc in the stub is the number of arguments passed - not the
1480  // expected arguments of the called function.
1481  int call_function_arg_count =
1483  CodeStub::MinorKeyFromKey(key));
1484  ASSERT(call_function_stub->major_key() ==
1485  CodeStub::MajorKeyFromKey(key));
1486 
1487  // Find target function on the expression stack.
1488  // Expression stack looks like this (top to bottom):
1489  // argN
1490  // ...
1491  // arg0
1492  // Receiver
1493  // Function to call
1494  int expressions_count = frame->ComputeExpressionsCount();
1495  ASSERT(expressions_count - 2 - call_function_arg_count >= 0);
1496  Object* fun = frame->GetExpression(
1497  expressions_count - 2 - call_function_arg_count);
1498  if (fun->IsJSFunction()) {
1499  Handle<JSFunction> js_function(JSFunction::cast(fun));
1500  if (js_function->shared()->bound()) {
1501  Debug::FloodBoundFunctionWithOneShot(js_function);
1502  } else if (!js_function->IsBuiltin()) {
1503  // Don't step into builtins.
1504  // It will also compile target function if it's not compiled yet.
1505  FloodWithOneShot(Handle<SharedFunctionInfo>(js_function->shared()));
1506  }
1507  }
1508  }
1509 
1510  // Fill the current function with one-shot break points even for step in on
1511  // a call target as the function called might be a native function for
1512  // which step in will not stop. It also prepares for stepping in
1513  // getters/setters.
1514  FloodWithOneShot(shared);
1515 
1516  if (is_load_or_store) {
1517  // Remember source position and frame to handle step in getter/setter. If
1518  // there is a custom getter/setter it will be handled in
1519  // Object::Get/SetPropertyWithCallback, otherwise the step action will be
1520  // propagated on the next Debug::Break.
1521  thread_local_.last_statement_position_ =
1522  debug_info->code()->SourceStatementPosition(frame->pc());
1523  thread_local_.last_fp_ = frame->UnpaddedFP();
1524  }
1525 
1526  // Step in or Step in min
1527  it.PrepareStepIn();
1528  ActivateStepIn(frame);
1529  }
1530 }
1531 
1532 
1533 // Check whether the current debug break should be reported to the debugger. It
1534 // is used to have step next and step in only report break back to the debugger
1535 // if on a different frame or in a different statement. In some situations
1536 // there will be several break points in the same statement when the code is
1537 // flooded with one-shot break points. This function helps to perform several
1538 // steps before reporting break back to the debugger.
1539 bool Debug::StepNextContinue(BreakLocationIterator* break_location_iterator,
1540  JavaScriptFrame* frame) {
1541  // StepNext and StepOut shouldn't bring us deeper in code, so last frame
1542  // shouldn't be a parent of current frame.
1543  if (thread_local_.last_step_action_ == StepNext ||
1544  thread_local_.last_step_action_ == StepOut) {
1545  if (frame->fp() < thread_local_.last_fp_) return true;
1546  }
1547 
1548  // If the step last action was step next or step in make sure that a new
1549  // statement is hit.
1550  if (thread_local_.last_step_action_ == StepNext ||
1551  thread_local_.last_step_action_ == StepIn) {
1552  // Never continue if returning from function.
1553  if (break_location_iterator->IsExit()) return false;
1554 
1555  // Continue if we are still on the same frame and in the same statement.
1556  int current_statement_position =
1557  break_location_iterator->code()->SourceStatementPosition(frame->pc());
1558  return thread_local_.last_fp_ == frame->UnpaddedFP() &&
1559  thread_local_.last_statement_position_ == current_statement_position;
1560  }
1561 
1562  // No step next action - don't continue.
1563  return false;
1564 }
1565 
1566 
1567 // Check whether the code object at the specified address is a debug break code
1568 // object.
1569 bool Debug::IsDebugBreak(Address addr) {
1570  Code* code = Code::GetCodeFromTargetAddress(addr);
1571  return code->ic_state() == DEBUG_BREAK;
1572 }
1573 
1574 
1575 // Check whether a code stub with the specified major key is a possible break
1576 // point location when looking for source break locations.
1577 bool Debug::IsSourceBreakStub(Code* code) {
1578  CodeStub::Major major_key = CodeStub::GetMajorKey(code);
1579  return major_key == CodeStub::CallFunction;
1580 }
1581 
1582 
1583 // Check whether a code stub with the specified major key is a possible break
1584 // location.
1585 bool Debug::IsBreakStub(Code* code) {
1586  CodeStub::Major major_key = CodeStub::GetMajorKey(code);
1587  return major_key == CodeStub::CallFunction;
1588 }
1589 
1590 
1591 // Find the builtin to use for invoking the debug break
1592 Handle<Code> Debug::FindDebugBreak(Handle<Code> code, RelocInfo::Mode mode) {
1593  Isolate* isolate = Isolate::Current();
1594 
1595  // Find the builtin debug break function matching the calling convention
1596  // used by the call site.
1597  if (code->is_inline_cache_stub()) {
1598  switch (code->kind()) {
1599  case Code::CALL_IC:
1600  case Code::KEYED_CALL_IC:
1601  return isolate->stub_cache()->ComputeCallDebugBreak(
1602  code->arguments_count(), code->kind());
1603 
1604  case Code::LOAD_IC:
1605  return isolate->builtins()->LoadIC_DebugBreak();
1606 
1607  case Code::STORE_IC:
1608  return isolate->builtins()->StoreIC_DebugBreak();
1609 
1610  case Code::KEYED_LOAD_IC:
1611  return isolate->builtins()->KeyedLoadIC_DebugBreak();
1612 
1613  case Code::KEYED_STORE_IC:
1614  return isolate->builtins()->KeyedStoreIC_DebugBreak();
1615 
1616  default:
1617  UNREACHABLE();
1618  }
1619  }
1620  if (RelocInfo::IsConstructCall(mode)) {
1621  if (code->has_function_cache()) {
1622  return isolate->builtins()->CallConstructStub_Recording_DebugBreak();
1623  } else {
1624  return isolate->builtins()->CallConstructStub_DebugBreak();
1625  }
1626  }
1627  if (code->kind() == Code::STUB) {
1628  ASSERT(code->major_key() == CodeStub::CallFunction);
1629  if (code->has_function_cache()) {
1630  return isolate->builtins()->CallFunctionStub_Recording_DebugBreak();
1631  } else {
1632  return isolate->builtins()->CallFunctionStub_DebugBreak();
1633  }
1634  }
1635 
1636  UNREACHABLE();
1637  return Handle<Code>::null();
1638 }
1639 
1640 
1641 // Simple function for returning the source positions for active break points.
1642 Handle<Object> Debug::GetSourceBreakLocations(
1643  Handle<SharedFunctionInfo> shared) {
1644  Isolate* isolate = Isolate::Current();
1645  Heap* heap = isolate->heap();
1646  if (!HasDebugInfo(shared)) return Handle<Object>(heap->undefined_value());
1647  Handle<DebugInfo> debug_info = GetDebugInfo(shared);
1648  if (debug_info->GetBreakPointCount() == 0) {
1649  return Handle<Object>(heap->undefined_value());
1650  }
1651  Handle<FixedArray> locations =
1652  isolate->factory()->NewFixedArray(debug_info->GetBreakPointCount());
1653  int count = 0;
1654  for (int i = 0; i < debug_info->break_points()->length(); i++) {
1655  if (!debug_info->break_points()->get(i)->IsUndefined()) {
1656  BreakPointInfo* break_point_info =
1657  BreakPointInfo::cast(debug_info->break_points()->get(i));
1658  if (break_point_info->GetBreakPointCount() > 0) {
1659  locations->set(count++, break_point_info->statement_position());
1660  }
1661  }
1662  }
1663  return locations;
1664 }
1665 
1666 
1667 void Debug::NewBreak(StackFrame::Id break_frame_id) {
1668  thread_local_.break_frame_id_ = break_frame_id;
1669  thread_local_.break_id_ = ++thread_local_.break_count_;
1670 }
1671 
1672 
1673 void Debug::SetBreak(StackFrame::Id break_frame_id, int break_id) {
1674  thread_local_.break_frame_id_ = break_frame_id;
1675  thread_local_.break_id_ = break_id;
1676 }
1677 
1678 
1679 // Handle stepping into a function.
1680 void Debug::HandleStepIn(Handle<JSFunction> function,
1681  Handle<Object> holder,
1682  Address fp,
1683  bool is_constructor) {
1684  // If the frame pointer is not supplied by the caller find it.
1685  if (fp == 0) {
1686  StackFrameIterator it;
1687  it.Advance();
1688  // For constructor functions skip another frame.
1689  if (is_constructor) {
1690  ASSERT(it.frame()->is_construct());
1691  it.Advance();
1692  }
1693  fp = it.frame()->fp();
1694  }
1695 
1696  // Flood the function with one-shot break points if it is called from where
1697  // step into was requested.
1698  if (fp == step_in_fp()) {
1699  if (function->shared()->bound()) {
1700  // Handle Function.prototype.bind
1701  Debug::FloodBoundFunctionWithOneShot(function);
1702  } else if (!function->IsBuiltin()) {
1703  // Don't allow step into functions in the native context.
1704  if (function->shared()->code() ==
1705  Isolate::Current()->builtins()->builtin(Builtins::kFunctionApply) ||
1706  function->shared()->code() ==
1707  Isolate::Current()->builtins()->builtin(Builtins::kFunctionCall)) {
1708  // Handle function.apply and function.call separately to flood the
1709  // function to be called and not the code for Builtins::FunctionApply or
1710  // Builtins::FunctionCall. The receiver of call/apply is the target
1711  // function.
1712  if (!holder.is_null() && holder->IsJSFunction() &&
1713  !JSFunction::cast(*holder)->IsBuiltin()) {
1714  Handle<SharedFunctionInfo> shared_info(
1715  JSFunction::cast(*holder)->shared());
1716  Debug::FloodWithOneShot(shared_info);
1717  }
1718  } else {
1719  Debug::FloodWithOneShot(Handle<SharedFunctionInfo>(function->shared()));
1720  }
1721  }
1722  }
1723 }
1724 
1725 
1726 void Debug::ClearStepping() {
1727  // Clear the various stepping setup.
1728  ClearOneShot();
1729  ClearStepIn();
1730  ClearStepOut();
1731  ClearStepNext();
1732 
1733  // Clear multiple step counter.
1734  thread_local_.step_count_ = 0;
1735 }
1736 
1737 // Clears all the one-shot break points that are currently set. Normally this
1738 // function is called each time a break point is hit as one shot break points
1739 // are used to support stepping.
1740 void Debug::ClearOneShot() {
1741  // The current implementation just runs through all the breakpoints. When the
1742  // last break point for a function is removed that function is automatically
1743  // removed from the list.
1744 
1745  DebugInfoListNode* node = debug_info_list_;
1746  while (node != NULL) {
1747  BreakLocationIterator it(node->debug_info(), ALL_BREAK_LOCATIONS);
1748  while (!it.Done()) {
1749  it.ClearOneShot();
1750  it.Next();
1751  }
1752  node = node->next();
1753  }
1754 }
1755 
1756 
1757 void Debug::ActivateStepIn(StackFrame* frame) {
1758  ASSERT(!StepOutActive());
1759  thread_local_.step_into_fp_ = frame->UnpaddedFP();
1760 }
1761 
1762 
1763 void Debug::ClearStepIn() {
1764  thread_local_.step_into_fp_ = 0;
1765 }
1766 
1767 
1768 void Debug::ActivateStepOut(StackFrame* frame) {
1769  ASSERT(!StepInActive());
1770  thread_local_.step_out_fp_ = frame->UnpaddedFP();
1771 }
1772 
1773 
1774 void Debug::ClearStepOut() {
1775  thread_local_.step_out_fp_ = 0;
1776 }
1777 
1778 
1779 void Debug::ClearStepNext() {
1780  thread_local_.last_step_action_ = StepNone;
1781  thread_local_.last_statement_position_ = RelocInfo::kNoPosition;
1782  thread_local_.last_fp_ = 0;
1783 }
1784 
1785 
1786 // Helper function to compile full code for debugging. This code will
1787 // have debug break slots and deoptimization information. Deoptimization
1788 // information is required in case that an optimized version of this
1789 // function is still activated on the stack. It will also make sure that
1790 // the full code is compiled with the same flags as the previous version,
1791 // that is flags which can change the code generated. The current method
1792 // of mapping from already compiled full code without debug break slots
1793 // to full code with debug break slots depends on the generated code is
1794 // otherwise exactly the same.
1795 static bool CompileFullCodeForDebugging(Handle<JSFunction> function,
1796  Handle<Code> current_code) {
1797  ASSERT(!current_code->has_debug_break_slots());
1798 
1799  CompilationInfo info(function);
1800  info.MarkCompilingForDebugging(current_code);
1801  ASSERT(!info.shared_info()->is_compiled());
1802  ASSERT(!info.isolate()->has_pending_exception());
1803 
1804  // Use compile lazy which will end up compiling the full code in the
1805  // configuration configured above.
1806  bool result = Compiler::CompileLazy(&info);
1807  ASSERT(result != Isolate::Current()->has_pending_exception());
1808  info.isolate()->clear_pending_exception();
1809 #if DEBUG
1810  if (result) {
1811  Handle<Code> new_code(function->shared()->code());
1812  ASSERT(new_code->has_debug_break_slots());
1813  ASSERT(current_code->is_compiled_optimizable() ==
1814  new_code->is_compiled_optimizable());
1815  }
1816 #endif
1817  return result;
1818 }
1819 
1820 
1821 static void CollectActiveFunctionsFromThread(
1822  Isolate* isolate,
1823  ThreadLocalTop* top,
1824  List<Handle<JSFunction> >* active_functions,
1825  Object* active_code_marker) {
1826  // Find all non-optimized code functions with activation frames
1827  // on the stack. This includes functions which have optimized
1828  // activations (including inlined functions) on the stack as the
1829  // non-optimized code is needed for the lazy deoptimization.
1830  for (JavaScriptFrameIterator it(isolate, top); !it.done(); it.Advance()) {
1831  JavaScriptFrame* frame = it.frame();
1832  if (frame->is_optimized()) {
1833  List<JSFunction*> functions(Compiler::kMaxInliningLevels + 1);
1834  frame->GetFunctions(&functions);
1835  for (int i = 0; i < functions.length(); i++) {
1836  JSFunction* function = functions[i];
1837  active_functions->Add(Handle<JSFunction>(function));
1838  function->shared()->code()->set_gc_metadata(active_code_marker);
1839  }
1840  } else if (frame->function()->IsJSFunction()) {
1841  JSFunction* function = JSFunction::cast(frame->function());
1842  ASSERT(frame->LookupCode()->kind() == Code::FUNCTION);
1843  active_functions->Add(Handle<JSFunction>(function));
1844  function->shared()->code()->set_gc_metadata(active_code_marker);
1845  }
1846  }
1847 }
1848 
1849 
1850 static void RedirectActivationsToRecompiledCodeOnThread(
1851  Isolate* isolate,
1852  ThreadLocalTop* top) {
1853  for (JavaScriptFrameIterator it(isolate, top); !it.done(); it.Advance()) {
1854  JavaScriptFrame* frame = it.frame();
1855 
1856  if (frame->is_optimized() || !frame->function()->IsJSFunction()) continue;
1857 
1858  JSFunction* function = JSFunction::cast(frame->function());
1859 
1860  ASSERT(frame->LookupCode()->kind() == Code::FUNCTION);
1861 
1862  Handle<Code> frame_code(frame->LookupCode());
1863  if (frame_code->has_debug_break_slots()) continue;
1864 
1865  Handle<Code> new_code(function->shared()->code());
1866  if (new_code->kind() != Code::FUNCTION ||
1867  !new_code->has_debug_break_slots()) {
1868  continue;
1869  }
1870 
1871  intptr_t delta = frame->pc() - frame_code->instruction_start();
1872  int debug_break_slot_count = 0;
1873  int mask = RelocInfo::ModeMask(RelocInfo::DEBUG_BREAK_SLOT);
1874  for (RelocIterator it(*new_code, mask); !it.done(); it.next()) {
1875  // Check if the pc in the new code with debug break
1876  // slots is before this slot.
1877  RelocInfo* info = it.rinfo();
1878  int debug_break_slot_bytes =
1879  debug_break_slot_count * Assembler::kDebugBreakSlotLength;
1880  intptr_t new_delta =
1881  info->pc() -
1882  new_code->instruction_start() -
1883  debug_break_slot_bytes;
1884  if (new_delta > delta) {
1885  break;
1886  }
1887 
1888  // Passed a debug break slot in the full code with debug
1889  // break slots.
1890  debug_break_slot_count++;
1891  }
1892  int debug_break_slot_bytes =
1893  debug_break_slot_count * Assembler::kDebugBreakSlotLength;
1894  if (FLAG_trace_deopt) {
1895  PrintF("Replacing code %08" V8PRIxPTR " - %08" V8PRIxPTR " (%d) "
1896  "with %08" V8PRIxPTR " - %08" V8PRIxPTR " (%d) "
1897  "for debugging, "
1898  "changing pc from %08" V8PRIxPTR " to %08" V8PRIxPTR "\n",
1899  reinterpret_cast<intptr_t>(
1900  frame_code->instruction_start()),
1901  reinterpret_cast<intptr_t>(
1902  frame_code->instruction_start()) +
1903  frame_code->instruction_size(),
1904  frame_code->instruction_size(),
1905  reinterpret_cast<intptr_t>(new_code->instruction_start()),
1906  reinterpret_cast<intptr_t>(new_code->instruction_start()) +
1907  new_code->instruction_size(),
1908  new_code->instruction_size(),
1909  reinterpret_cast<intptr_t>(frame->pc()),
1910  reinterpret_cast<intptr_t>(new_code->instruction_start()) +
1911  delta + debug_break_slot_bytes);
1912  }
1913 
1914  // Patch the return address to return into the code with
1915  // debug break slots.
1916  frame->set_pc(
1917  new_code->instruction_start() + delta + debug_break_slot_bytes);
1918  }
1919 }
1920 
1921 
1922 class ActiveFunctionsCollector : public ThreadVisitor {
1923  public:
1924  explicit ActiveFunctionsCollector(List<Handle<JSFunction> >* active_functions,
1925  Object* active_code_marker)
1926  : active_functions_(active_functions),
1927  active_code_marker_(active_code_marker) { }
1928 
1929  void VisitThread(Isolate* isolate, ThreadLocalTop* top) {
1930  CollectActiveFunctionsFromThread(isolate,
1931  top,
1932  active_functions_,
1933  active_code_marker_);
1934  }
1935 
1936  private:
1937  List<Handle<JSFunction> >* active_functions_;
1938  Object* active_code_marker_;
1939 };
1940 
1941 
1942 class ActiveFunctionsRedirector : public ThreadVisitor {
1943  public:
1944  void VisitThread(Isolate* isolate, ThreadLocalTop* top) {
1945  RedirectActivationsToRecompiledCodeOnThread(isolate, top);
1946  }
1947 };
1948 
1949 
1950 void Debug::PrepareForBreakPoints() {
1951  // If preparing for the first break point make sure to deoptimize all
1952  // functions as debugging does not work with optimized code.
1953  if (!has_break_points_) {
1955 
1956  Handle<Code> lazy_compile =
1957  Handle<Code>(isolate_->builtins()->builtin(Builtins::kLazyCompile));
1958 
1959  // Keep the list of activated functions in a handlified list as it
1960  // is used both in GC and non-GC code.
1961  List<Handle<JSFunction> > active_functions(100);
1962 
1963  {
1964  // We are going to iterate heap to find all functions without
1965  // debug break slots.
1966  isolate_->heap()->CollectAllGarbage(Heap::kMakeHeapIterableMask,
1967  "preparing for breakpoints");
1968 
1969  // Ensure no GC in this scope as we are going to use gc_metadata
1970  // field in the Code object to mark active functions.
1971  AssertNoAllocation no_allocation;
1972 
1973  Object* active_code_marker = isolate_->heap()->the_hole_value();
1974 
1975  CollectActiveFunctionsFromThread(isolate_,
1976  isolate_->thread_local_top(),
1977  &active_functions,
1978  active_code_marker);
1979  ActiveFunctionsCollector active_functions_collector(&active_functions,
1980  active_code_marker);
1981  isolate_->thread_manager()->IterateArchivedThreads(
1982  &active_functions_collector);
1983 
1984  // Scan the heap for all non-optimized functions which have no
1985  // debug break slots and are not active or inlined into an active
1986  // function and mark them for lazy compilation.
1987  HeapIterator iterator;
1988  HeapObject* obj = NULL;
1989  while (((obj = iterator.next()) != NULL)) {
1990  if (obj->IsJSFunction()) {
1991  JSFunction* function = JSFunction::cast(obj);
1992  SharedFunctionInfo* shared = function->shared();
1993  if (shared->allows_lazy_compilation() &&
1994  shared->script()->IsScript() &&
1995  function->code()->kind() == Code::FUNCTION &&
1996  !function->code()->has_debug_break_slots() &&
1997  shared->code()->gc_metadata() != active_code_marker) {
1998  function->set_code(*lazy_compile);
1999  function->shared()->set_code(*lazy_compile);
2000  }
2001  }
2002  }
2003 
2004  // Clear gc_metadata field.
2005  for (int i = 0; i < active_functions.length(); i++) {
2006  Handle<JSFunction> function = active_functions[i];
2007  function->shared()->code()->set_gc_metadata(Smi::FromInt(0));
2008  }
2009  }
2010 
2011  // Now recompile all functions with activation frames and and
2012  // patch the return address to run in the new compiled code.
2013  for (int i = 0; i < active_functions.length(); i++) {
2014  Handle<JSFunction> function = active_functions[i];
2015  Handle<SharedFunctionInfo> shared(function->shared());
2016 
2017  if (function->code()->kind() == Code::FUNCTION &&
2018  function->code()->has_debug_break_slots()) {
2019  // Nothing to do. Function code already had debug break slots.
2020  continue;
2021  }
2022 
2023  // If recompilation is not possible just skip it.
2024  if (shared->is_toplevel() ||
2025  !shared->allows_lazy_compilation() ||
2026  shared->code()->kind() == Code::BUILTIN) {
2027  continue;
2028  }
2029 
2030  // Make sure that the shared full code is compiled with debug
2031  // break slots.
2032  if (!shared->code()->has_debug_break_slots()) {
2033  // Try to compile the full code with debug break slots. If it
2034  // fails just keep the current code.
2035  Handle<Code> current_code(function->shared()->code());
2036  ZoneScope zone_scope(isolate_, DELETE_ON_EXIT);
2037  shared->set_code(*lazy_compile);
2038  bool prev_force_debugger_active =
2039  isolate_->debugger()->force_debugger_active();
2040  isolate_->debugger()->set_force_debugger_active(true);
2041  ASSERT(current_code->kind() == Code::FUNCTION);
2042  CompileFullCodeForDebugging(function, current_code);
2043  isolate_->debugger()->set_force_debugger_active(
2044  prev_force_debugger_active);
2045  if (!shared->is_compiled()) {
2046  shared->set_code(*current_code);
2047  continue;
2048  }
2049  }
2050 
2051  // Keep function code in sync with shared function info.
2052  function->set_code(shared->code());
2053  }
2054 
2055  RedirectActivationsToRecompiledCodeOnThread(isolate_,
2056  isolate_->thread_local_top());
2057 
2058  ActiveFunctionsRedirector active_functions_redirector;
2059  isolate_->thread_manager()->IterateArchivedThreads(
2060  &active_functions_redirector);
2061  }
2062 }
2063 
2064 
2065 // Ensures the debug information is present for shared.
2066 bool Debug::EnsureDebugInfo(Handle<SharedFunctionInfo> shared) {
2067  // Return if we already have the debug info for shared.
2068  if (HasDebugInfo(shared)) {
2069  ASSERT(shared->is_compiled());
2070  return true;
2071  }
2072 
2073  // Ensure shared in compiled. Return false if this failed.
2075  return false;
2076  }
2077 
2078  // Create the debug info object.
2079  Handle<DebugInfo> debug_info = FACTORY->NewDebugInfo(shared);
2080 
2081  // Add debug info to the list.
2082  DebugInfoListNode* node = new DebugInfoListNode(*debug_info);
2083  node->set_next(debug_info_list_);
2084  debug_info_list_ = node;
2085 
2086  // Now there is at least one break point.
2087  has_break_points_ = true;
2088 
2089  return true;
2090 }
2091 
2092 
2093 void Debug::RemoveDebugInfo(Handle<DebugInfo> debug_info) {
2094  ASSERT(debug_info_list_ != NULL);
2095  // Run through the debug info objects to find this one and remove it.
2096  DebugInfoListNode* prev = NULL;
2097  DebugInfoListNode* current = debug_info_list_;
2098  while (current != NULL) {
2099  if (*current->debug_info() == *debug_info) {
2100  // Unlink from list. If prev is NULL we are looking at the first element.
2101  if (prev == NULL) {
2102  debug_info_list_ = current->next();
2103  } else {
2104  prev->set_next(current->next());
2105  }
2106  current->debug_info()->shared()->set_debug_info(
2107  isolate_->heap()->undefined_value());
2108  delete current;
2109 
2110  // If there are no more debug info objects there are not more break
2111  // points.
2112  has_break_points_ = debug_info_list_ != NULL;
2113 
2114  return;
2115  }
2116  // Move to next in list.
2117  prev = current;
2118  current = current->next();
2119  }
2120  UNREACHABLE();
2121 }
2122 
2123 
2124 void Debug::SetAfterBreakTarget(JavaScriptFrame* frame) {
2125  HandleScope scope(isolate_);
2126 
2127  PrepareForBreakPoints();
2128 
2129  // Get the executing function in which the debug break occurred.
2130  Handle<SharedFunctionInfo> shared =
2131  Handle<SharedFunctionInfo>(JSFunction::cast(frame->function())->shared());
2132  if (!EnsureDebugInfo(shared)) {
2133  // Return if we failed to retrieve the debug info.
2134  return;
2135  }
2136  Handle<DebugInfo> debug_info = GetDebugInfo(shared);
2137  Handle<Code> code(debug_info->code());
2138  Handle<Code> original_code(debug_info->original_code());
2139 #ifdef DEBUG
2140  // Get the code which is actually executing.
2141  Handle<Code> frame_code(frame->LookupCode());
2142  ASSERT(frame_code.is_identical_to(code));
2143 #endif
2144 
2145  // Find the call address in the running code. This address holds the call to
2146  // either a DebugBreakXXX or to the debug break return entry code if the
2147  // break point is still active after processing the break point.
2148  Address addr = frame->pc() - Assembler::kCallTargetAddressOffset;
2149 
2150  // Check if the location is at JS exit or debug break slot.
2151  bool at_js_return = false;
2152  bool break_at_js_return_active = false;
2153  bool at_debug_break_slot = false;
2154  RelocIterator it(debug_info->code());
2155  while (!it.done() && !at_js_return && !at_debug_break_slot) {
2156  if (RelocInfo::IsJSReturn(it.rinfo()->rmode())) {
2157  at_js_return = (it.rinfo()->pc() ==
2159  break_at_js_return_active = it.rinfo()->IsPatchedReturnSequence();
2160  }
2161  if (RelocInfo::IsDebugBreakSlot(it.rinfo()->rmode())) {
2162  at_debug_break_slot = (it.rinfo()->pc() ==
2164  }
2165  it.next();
2166  }
2167 
2168  // Handle the jump to continue execution after break point depending on the
2169  // break location.
2170  if (at_js_return) {
2171  // If the break point as return is still active jump to the corresponding
2172  // place in the original code. If not the break point was removed during
2173  // break point processing.
2174  if (break_at_js_return_active) {
2175  addr += original_code->instruction_start() - code->instruction_start();
2176  }
2177 
2178  // Move back to where the call instruction sequence started.
2179  thread_local_.after_break_target_ =
2181  } else if (at_debug_break_slot) {
2182  // Address of where the debug break slot starts.
2184 
2185  // Continue just after the slot.
2186  thread_local_.after_break_target_ = addr + Assembler::kDebugBreakSlotLength;
2187  } else if (IsDebugBreak(Assembler::target_address_at(addr))) {
2188  // We now know that there is still a debug break call at the target address,
2189  // so the break point is still there and the original code will hold the
2190  // address to jump to in order to complete the call which is replaced by a
2191  // call to DebugBreakXXX.
2192 
2193  // Find the corresponding address in the original code.
2194  addr += original_code->instruction_start() - code->instruction_start();
2195 
2196  // Install jump to the call address in the original code. This will be the
2197  // call which was overwritten by the call to DebugBreakXXX.
2198  thread_local_.after_break_target_ = Assembler::target_address_at(addr);
2199  } else {
2200  // There is no longer a break point present. Don't try to look in the
2201  // original code as the running code will have the right address. This takes
2202  // care of the case where the last break point is removed from the function
2203  // and therefore no "original code" is available.
2204  thread_local_.after_break_target_ = Assembler::target_address_at(addr);
2205  }
2206 }
2207 
2208 
2209 bool Debug::IsBreakAtReturn(JavaScriptFrame* frame) {
2210  HandleScope scope(isolate_);
2211 
2212  // If there are no break points this cannot be break at return, as
2213  // the debugger statement and stack guard bebug break cannot be at
2214  // return.
2215  if (!has_break_points_) {
2216  return false;
2217  }
2218 
2219  PrepareForBreakPoints();
2220 
2221  // Get the executing function in which the debug break occurred.
2222  Handle<SharedFunctionInfo> shared =
2223  Handle<SharedFunctionInfo>(JSFunction::cast(frame->function())->shared());
2224  if (!EnsureDebugInfo(shared)) {
2225  // Return if we failed to retrieve the debug info.
2226  return false;
2227  }
2228  Handle<DebugInfo> debug_info = GetDebugInfo(shared);
2229  Handle<Code> code(debug_info->code());
2230 #ifdef DEBUG
2231  // Get the code which is actually executing.
2232  Handle<Code> frame_code(frame->LookupCode());
2233  ASSERT(frame_code.is_identical_to(code));
2234 #endif
2235 
2236  // Find the call address in the running code.
2237  Address addr = frame->pc() - Assembler::kCallTargetAddressOffset;
2238 
2239  // Check if the location is at JS return.
2240  RelocIterator it(debug_info->code());
2241  while (!it.done()) {
2242  if (RelocInfo::IsJSReturn(it.rinfo()->rmode())) {
2243  return (it.rinfo()->pc() ==
2245  }
2246  it.next();
2247  }
2248  return false;
2249 }
2250 
2251 
2252 void Debug::FramesHaveBeenDropped(StackFrame::Id new_break_frame_id,
2253  FrameDropMode mode,
2254  Object** restarter_frame_function_pointer) {
2255  thread_local_.frame_drop_mode_ = mode;
2256  thread_local_.break_frame_id_ = new_break_frame_id;
2257  thread_local_.restarter_frame_function_pointer_ =
2258  restarter_frame_function_pointer;
2259 }
2260 
2261 
2262 const int Debug::FramePaddingLayout::kInitialSize = 1;
2263 
2264 
2265 // Any even value bigger than kInitialSize as needed for stack scanning.
2266 const int Debug::FramePaddingLayout::kPaddingValue = kInitialSize + 1;
2267 
2268 
2269 bool Debug::IsDebugGlobal(GlobalObject* global) {
2270  return IsLoaded() && global == debug_context()->global();
2271 }
2272 
2273 
2274 void Debug::ClearMirrorCache() {
2275  PostponeInterruptsScope postpone(isolate_);
2276  HandleScope scope(isolate_);
2277  ASSERT(isolate_->context() == *Debug::debug_context());
2278 
2279  // Clear the mirror cache.
2280  Handle<String> function_name =
2281  isolate_->factory()->LookupSymbol(CStrVector("ClearMirrorCache"));
2282  Handle<Object> fun(Isolate::Current()->global()->GetPropertyNoExceptionThrown(
2283  *function_name));
2284  ASSERT(fun->IsJSFunction());
2285  bool caught_exception;
2286  Execution::TryCall(Handle<JSFunction>::cast(fun),
2287  Handle<JSObject>(Debug::debug_context()->global()),
2288  0, NULL, &caught_exception);
2289 }
2290 
2291 
2292 void Debug::CreateScriptCache() {
2293  Heap* heap = isolate_->heap();
2294  HandleScope scope(isolate_);
2295 
2296  // Perform two GCs to get rid of all unreferenced scripts. The first GC gets
2297  // rid of all the cached script wrappers and the second gets rid of the
2298  // scripts which are no longer referenced. The second also sweeps precisely,
2299  // which saves us doing yet another GC to make the heap iterable.
2300  heap->CollectAllGarbage(Heap::kNoGCFlags, "Debug::CreateScriptCache");
2301  heap->CollectAllGarbage(Heap::kMakeHeapIterableMask,
2302  "Debug::CreateScriptCache");
2303 
2304  ASSERT(script_cache_ == NULL);
2305  script_cache_ = new ScriptCache();
2306 
2307  // Scan heap for Script objects.
2308  int count = 0;
2309  HeapIterator iterator;
2310  AssertNoAllocation no_allocation;
2311 
2312  for (HeapObject* obj = iterator.next(); obj != NULL; obj = iterator.next()) {
2313  if (obj->IsScript() && Script::cast(obj)->HasValidSource()) {
2314  script_cache_->Add(Handle<Script>(Script::cast(obj)));
2315  count++;
2316  }
2317  }
2318 }
2319 
2320 
2321 void Debug::DestroyScriptCache() {
2322  // Get rid of the script cache if it was created.
2323  if (script_cache_ != NULL) {
2324  delete script_cache_;
2325  script_cache_ = NULL;
2326  }
2327 }
2328 
2329 
2330 void Debug::AddScriptToScriptCache(Handle<Script> script) {
2331  if (script_cache_ != NULL) {
2332  script_cache_->Add(script);
2333  }
2334 }
2335 
2336 
2337 Handle<FixedArray> Debug::GetLoadedScripts() {
2338  // Create and fill the script cache when the loaded scripts is requested for
2339  // the first time.
2340  if (script_cache_ == NULL) {
2341  CreateScriptCache();
2342  }
2343 
2344  // If the script cache is not active just return an empty array.
2345  ASSERT(script_cache_ != NULL);
2346  if (script_cache_ == NULL) {
2347  isolate_->factory()->NewFixedArray(0);
2348  }
2349 
2350  // Perform GC to get unreferenced scripts evicted from the cache before
2351  // returning the content.
2352  isolate_->heap()->CollectAllGarbage(Heap::kNoGCFlags,
2353  "Debug::GetLoadedScripts");
2354 
2355  // Get the scripts from the cache.
2356  return script_cache_->GetScripts();
2357 }
2358 
2359 
2360 void Debug::AfterGarbageCollection() {
2361  // Generate events for collected scripts.
2362  if (script_cache_ != NULL) {
2363  script_cache_->ProcessCollectedScripts();
2364  }
2365 }
2366 
2367 
2368 Debugger::Debugger(Isolate* isolate)
2369  : debugger_access_(isolate->debugger_access()),
2370  event_listener_(Handle<Object>()),
2371  event_listener_data_(Handle<Object>()),
2372  compiling_natives_(false),
2373  is_loading_debugger_(false),
2374  never_unload_debugger_(false),
2375  force_debugger_active_(false),
2376  message_handler_(NULL),
2377  debugger_unload_pending_(false),
2378  host_dispatch_handler_(NULL),
2379  dispatch_handler_access_(OS::CreateMutex()),
2380  debug_message_dispatch_handler_(NULL),
2381  message_dispatch_helper_thread_(NULL),
2382  host_dispatch_micros_(100 * 1000),
2383  agent_(NULL),
2384  command_queue_(isolate->logger(), kQueueInitialSize),
2385  command_received_(OS::CreateSemaphore(0)),
2386  event_command_queue_(isolate->logger(), kQueueInitialSize),
2387  isolate_(isolate) {
2388 }
2389 
2390 
2391 Debugger::~Debugger() {
2392  delete dispatch_handler_access_;
2393  dispatch_handler_access_ = 0;
2394  delete command_received_;
2395  command_received_ = 0;
2396 }
2397 
2398 
2399 Handle<Object> Debugger::MakeJSObject(Vector<const char> constructor_name,
2400  int argc,
2401  Handle<Object> argv[],
2402  bool* caught_exception) {
2403  ASSERT(isolate_->context() == *isolate_->debug()->debug_context());
2404 
2405  // Create the execution state object.
2406  Handle<String> constructor_str =
2407  isolate_->factory()->LookupSymbol(constructor_name);
2408  Handle<Object> constructor(
2409  isolate_->global()->GetPropertyNoExceptionThrown(*constructor_str));
2410  ASSERT(constructor->IsJSFunction());
2411  if (!constructor->IsJSFunction()) {
2412  *caught_exception = true;
2413  return isolate_->factory()->undefined_value();
2414  }
2415  Handle<Object> js_object = Execution::TryCall(
2416  Handle<JSFunction>::cast(constructor),
2417  Handle<JSObject>(isolate_->debug()->debug_context()->global()),
2418  argc,
2419  argv,
2420  caught_exception);
2421  return js_object;
2422 }
2423 
2424 
2425 Handle<Object> Debugger::MakeExecutionState(bool* caught_exception) {
2426  // Create the execution state object.
2427  Handle<Object> break_id = isolate_->factory()->NewNumberFromInt(
2428  isolate_->debug()->break_id());
2429  Handle<Object> argv[] = { break_id };
2430  return MakeJSObject(CStrVector("MakeExecutionState"),
2431  ARRAY_SIZE(argv),
2432  argv,
2433  caught_exception);
2434 }
2435 
2436 
2437 Handle<Object> Debugger::MakeBreakEvent(Handle<Object> exec_state,
2438  Handle<Object> break_points_hit,
2439  bool* caught_exception) {
2440  // Create the new break event object.
2441  Handle<Object> argv[] = { exec_state, break_points_hit };
2442  return MakeJSObject(CStrVector("MakeBreakEvent"),
2443  ARRAY_SIZE(argv),
2444  argv,
2445  caught_exception);
2446 }
2447 
2448 
2449 Handle<Object> Debugger::MakeExceptionEvent(Handle<Object> exec_state,
2450  Handle<Object> exception,
2451  bool uncaught,
2452  bool* caught_exception) {
2453  Factory* factory = isolate_->factory();
2454  // Create the new exception event object.
2455  Handle<Object> argv[] = { exec_state,
2456  exception,
2457  factory->ToBoolean(uncaught) };
2458  return MakeJSObject(CStrVector("MakeExceptionEvent"),
2459  ARRAY_SIZE(argv),
2460  argv,
2461  caught_exception);
2462 }
2463 
2464 
2465 Handle<Object> Debugger::MakeNewFunctionEvent(Handle<Object> function,
2466  bool* caught_exception) {
2467  // Create the new function event object.
2468  Handle<Object> argv[] = { function };
2469  return MakeJSObject(CStrVector("MakeNewFunctionEvent"),
2470  ARRAY_SIZE(argv),
2471  argv,
2472  caught_exception);
2473 }
2474 
2475 
2476 Handle<Object> Debugger::MakeCompileEvent(Handle<Script> script,
2477  bool before,
2478  bool* caught_exception) {
2479  Factory* factory = isolate_->factory();
2480  // Create the compile event object.
2481  Handle<Object> exec_state = MakeExecutionState(caught_exception);
2482  Handle<Object> script_wrapper = GetScriptWrapper(script);
2483  Handle<Object> argv[] = { exec_state,
2484  script_wrapper,
2485  factory->ToBoolean(before) };
2486  return MakeJSObject(CStrVector("MakeCompileEvent"),
2487  ARRAY_SIZE(argv),
2488  argv,
2489  caught_exception);
2490 }
2491 
2492 
2493 Handle<Object> Debugger::MakeScriptCollectedEvent(int id,
2494  bool* caught_exception) {
2495  // Create the script collected event object.
2496  Handle<Object> exec_state = MakeExecutionState(caught_exception);
2497  Handle<Object> id_object = Handle<Smi>(Smi::FromInt(id));
2498  Handle<Object> argv[] = { exec_state, id_object };
2499 
2500  return MakeJSObject(CStrVector("MakeScriptCollectedEvent"),
2501  ARRAY_SIZE(argv),
2502  argv,
2503  caught_exception);
2504 }
2505 
2506 
2507 void Debugger::OnException(Handle<Object> exception, bool uncaught) {
2508  HandleScope scope(isolate_);
2509  Debug* debug = isolate_->debug();
2510 
2511  // Bail out based on state or if there is no listener for this event
2512  if (debug->InDebugger()) return;
2513  if (!Debugger::EventActive(v8::Exception)) return;
2514 
2515  // Bail out if exception breaks are not active
2516  if (uncaught) {
2517  // Uncaught exceptions are reported by either flags.
2518  if (!(debug->break_on_uncaught_exception() ||
2519  debug->break_on_exception())) return;
2520  } else {
2521  // Caught exceptions are reported is activated.
2522  if (!debug->break_on_exception()) return;
2523  }
2524 
2525  // Enter the debugger.
2526  EnterDebugger debugger;
2527  if (debugger.FailedToEnter()) return;
2528 
2529  // Clear all current stepping setup.
2530  debug->ClearStepping();
2531  // Create the event data object.
2532  bool caught_exception = false;
2533  Handle<Object> exec_state = MakeExecutionState(&caught_exception);
2534  Handle<Object> event_data;
2535  if (!caught_exception) {
2536  event_data = MakeExceptionEvent(exec_state, exception, uncaught,
2537  &caught_exception);
2538  }
2539  // Bail out and don't call debugger if exception.
2540  if (caught_exception) {
2541  return;
2542  }
2543 
2544  // Process debug event.
2545  ProcessDebugEvent(v8::Exception, Handle<JSObject>::cast(event_data), false);
2546  // Return to continue execution from where the exception was thrown.
2547 }
2548 
2549 
2550 void Debugger::OnDebugBreak(Handle<Object> break_points_hit,
2551  bool auto_continue) {
2552  HandleScope scope(isolate_);
2553 
2554  // Debugger has already been entered by caller.
2555  ASSERT(isolate_->context() == *isolate_->debug()->debug_context());
2556 
2557  // Bail out if there is no listener for this event
2558  if (!Debugger::EventActive(v8::Break)) return;
2559 
2560  // Debugger must be entered in advance.
2561  ASSERT(isolate_->context() == *isolate_->debug()->debug_context());
2562 
2563  // Create the event data object.
2564  bool caught_exception = false;
2565  Handle<Object> exec_state = MakeExecutionState(&caught_exception);
2566  Handle<Object> event_data;
2567  if (!caught_exception) {
2568  event_data = MakeBreakEvent(exec_state, break_points_hit,
2569  &caught_exception);
2570  }
2571  // Bail out and don't call debugger if exception.
2572  if (caught_exception) {
2573  return;
2574  }
2575 
2576  // Process debug event.
2577  ProcessDebugEvent(v8::Break,
2578  Handle<JSObject>::cast(event_data),
2579  auto_continue);
2580 }
2581 
2582 
2583 void Debugger::OnBeforeCompile(Handle<Script> script) {
2584  HandleScope scope(isolate_);
2585 
2586  // Bail out based on state or if there is no listener for this event
2587  if (isolate_->debug()->InDebugger()) return;
2588  if (compiling_natives()) return;
2589  if (!EventActive(v8::BeforeCompile)) return;
2590 
2591  // Enter the debugger.
2592  EnterDebugger debugger;
2593  if (debugger.FailedToEnter()) return;
2594 
2595  // Create the event data object.
2596  bool caught_exception = false;
2597  Handle<Object> event_data = MakeCompileEvent(script, true, &caught_exception);
2598  // Bail out and don't call debugger if exception.
2599  if (caught_exception) {
2600  return;
2601  }
2602 
2603  // Process debug event.
2604  ProcessDebugEvent(v8::BeforeCompile,
2605  Handle<JSObject>::cast(event_data),
2606  true);
2607 }
2608 
2609 
2610 // Handle debugger actions when a new script is compiled.
2611 void Debugger::OnAfterCompile(Handle<Script> script,
2612  AfterCompileFlags after_compile_flags) {
2613  HandleScope scope(isolate_);
2614  Debug* debug = isolate_->debug();
2615 
2616  // Add the newly compiled script to the script cache.
2617  debug->AddScriptToScriptCache(script);
2618 
2619  // No more to do if not debugging.
2620  if (!IsDebuggerActive()) return;
2621 
2622  // No compile events while compiling natives.
2623  if (compiling_natives()) return;
2624 
2625  // Store whether in debugger before entering debugger.
2626  bool in_debugger = debug->InDebugger();
2627 
2628  // Enter the debugger.
2629  EnterDebugger debugger;
2630  if (debugger.FailedToEnter()) return;
2631 
2632  // If debugging there might be script break points registered for this
2633  // script. Make sure that these break points are set.
2634 
2635  // Get the function UpdateScriptBreakPoints (defined in debug-debugger.js).
2636  Handle<String> update_script_break_points_symbol =
2637  isolate_->factory()->LookupAsciiSymbol("UpdateScriptBreakPoints");
2638  Handle<Object> update_script_break_points =
2639  Handle<Object>(debug->debug_context()->global()->
2640  GetPropertyNoExceptionThrown(*update_script_break_points_symbol));
2641  if (!update_script_break_points->IsJSFunction()) {
2642  return;
2643  }
2644  ASSERT(update_script_break_points->IsJSFunction());
2645 
2646  // Wrap the script object in a proper JS object before passing it
2647  // to JavaScript.
2648  Handle<JSValue> wrapper = GetScriptWrapper(script);
2649 
2650  // Call UpdateScriptBreakPoints expect no exceptions.
2651  bool caught_exception;
2652  Handle<Object> argv[] = { wrapper };
2653  Execution::TryCall(Handle<JSFunction>::cast(update_script_break_points),
2654  Isolate::Current()->js_builtins_object(),
2655  ARRAY_SIZE(argv),
2656  argv,
2657  &caught_exception);
2658  if (caught_exception) {
2659  return;
2660  }
2661  // Bail out based on state or if there is no listener for this event
2662  if (in_debugger && (after_compile_flags & SEND_WHEN_DEBUGGING) == 0) return;
2663  if (!Debugger::EventActive(v8::AfterCompile)) return;
2664 
2665  // Create the compile state object.
2666  Handle<Object> event_data = MakeCompileEvent(script,
2667  false,
2668  &caught_exception);
2669  // Bail out and don't call debugger if exception.
2670  if (caught_exception) {
2671  return;
2672  }
2673  // Process debug event.
2674  ProcessDebugEvent(v8::AfterCompile,
2675  Handle<JSObject>::cast(event_data),
2676  true);
2677 }
2678 
2679 
2680 void Debugger::OnScriptCollected(int id) {
2681  HandleScope scope(isolate_);
2682 
2683  // No more to do if not debugging.
2684  if (!IsDebuggerActive()) return;
2685  if (!Debugger::EventActive(v8::ScriptCollected)) return;
2686 
2687  // Enter the debugger.
2688  EnterDebugger debugger;
2689  if (debugger.FailedToEnter()) return;
2690 
2691  // Create the script collected state object.
2692  bool caught_exception = false;
2693  Handle<Object> event_data = MakeScriptCollectedEvent(id,
2694  &caught_exception);
2695  // Bail out and don't call debugger if exception.
2696  if (caught_exception) {
2697  return;
2698  }
2699 
2700  // Process debug event.
2701  ProcessDebugEvent(v8::ScriptCollected,
2702  Handle<JSObject>::cast(event_data),
2703  true);
2704 }
2705 
2706 
2707 void Debugger::ProcessDebugEvent(v8::DebugEvent event,
2708  Handle<JSObject> event_data,
2709  bool auto_continue) {
2710  HandleScope scope(isolate_);
2711 
2712  // Clear any pending debug break if this is a real break.
2713  if (!auto_continue) {
2714  isolate_->debug()->clear_interrupt_pending(DEBUGBREAK);
2715  }
2716 
2717  // Create the execution state.
2718  bool caught_exception = false;
2719  Handle<Object> exec_state = MakeExecutionState(&caught_exception);
2720  if (caught_exception) {
2721  return;
2722  }
2723  // First notify the message handler if any.
2724  if (message_handler_ != NULL) {
2725  NotifyMessageHandler(event,
2726  Handle<JSObject>::cast(exec_state),
2727  event_data,
2728  auto_continue);
2729  }
2730  // Notify registered debug event listener. This can be either a C or
2731  // a JavaScript function. Don't call event listener for v8::Break
2732  // here, if it's only a debug command -- they will be processed later.
2733  if ((event != v8::Break || !auto_continue) && !event_listener_.is_null()) {
2734  CallEventCallback(event, exec_state, event_data, NULL);
2735  }
2736  // Process pending debug commands.
2737  if (event == v8::Break) {
2738  while (!event_command_queue_.IsEmpty()) {
2739  CommandMessage command = event_command_queue_.Get();
2740  if (!event_listener_.is_null()) {
2741  CallEventCallback(v8::BreakForCommand,
2742  exec_state,
2743  event_data,
2744  command.client_data());
2745  }
2746  command.Dispose();
2747  }
2748  }
2749 }
2750 
2751 
2752 void Debugger::CallEventCallback(v8::DebugEvent event,
2753  Handle<Object> exec_state,
2754  Handle<Object> event_data,
2755  v8::Debug::ClientData* client_data) {
2756  if (event_listener_->IsForeign()) {
2757  CallCEventCallback(event, exec_state, event_data, client_data);
2758  } else {
2759  CallJSEventCallback(event, exec_state, event_data);
2760  }
2761 }
2762 
2763 
2764 void Debugger::CallCEventCallback(v8::DebugEvent event,
2765  Handle<Object> exec_state,
2766  Handle<Object> event_data,
2767  v8::Debug::ClientData* client_data) {
2768  Handle<Foreign> callback_obj(Handle<Foreign>::cast(event_listener_));
2769  v8::Debug::EventCallback2 callback =
2770  FUNCTION_CAST<v8::Debug::EventCallback2>(
2771  callback_obj->foreign_address());
2772  EventDetailsImpl event_details(
2773  event,
2774  Handle<JSObject>::cast(exec_state),
2775  Handle<JSObject>::cast(event_data),
2776  event_listener_data_,
2777  client_data);
2778  callback(event_details);
2779 }
2780 
2781 
2782 void Debugger::CallJSEventCallback(v8::DebugEvent event,
2783  Handle<Object> exec_state,
2784  Handle<Object> event_data) {
2785  ASSERT(event_listener_->IsJSFunction());
2786  Handle<JSFunction> fun(Handle<JSFunction>::cast(event_listener_));
2787 
2788  // Invoke the JavaScript debug event listener.
2789  Handle<Object> argv[] = { Handle<Object>(Smi::FromInt(event)),
2790  exec_state,
2791  event_data,
2792  event_listener_data_ };
2793  bool caught_exception;
2794  Execution::TryCall(fun,
2795  isolate_->global(),
2796  ARRAY_SIZE(argv),
2797  argv,
2798  &caught_exception);
2799  // Silently ignore exceptions from debug event listeners.
2800 }
2801 
2802 
2803 Handle<Context> Debugger::GetDebugContext() {
2804  never_unload_debugger_ = true;
2805  EnterDebugger debugger;
2806  return isolate_->debug()->debug_context();
2807 }
2808 
2809 
2810 void Debugger::UnloadDebugger() {
2811  Debug* debug = isolate_->debug();
2812 
2813  // Make sure that there are no breakpoints left.
2814  debug->ClearAllBreakPoints();
2815 
2816  // Unload the debugger if feasible.
2817  if (!never_unload_debugger_) {
2818  debug->Unload();
2819  }
2820 
2821  // Clear the flag indicating that the debugger should be unloaded.
2822  debugger_unload_pending_ = false;
2823 }
2824 
2825 
2826 void Debugger::NotifyMessageHandler(v8::DebugEvent event,
2827  Handle<JSObject> exec_state,
2828  Handle<JSObject> event_data,
2829  bool auto_continue) {
2830  HandleScope scope(isolate_);
2831 
2832  if (!isolate_->debug()->Load()) return;
2833 
2834  // Process the individual events.
2835  bool sendEventMessage = false;
2836  switch (event) {
2837  case v8::Break:
2838  case v8::BreakForCommand:
2839  sendEventMessage = !auto_continue;
2840  break;
2841  case v8::Exception:
2842  sendEventMessage = true;
2843  break;
2844  case v8::BeforeCompile:
2845  break;
2846  case v8::AfterCompile:
2847  sendEventMessage = true;
2848  break;
2849  case v8::ScriptCollected:
2850  sendEventMessage = true;
2851  break;
2852  case v8::NewFunction:
2853  break;
2854  default:
2855  UNREACHABLE();
2856  }
2857 
2858  // The debug command interrupt flag might have been set when the command was
2859  // added. It should be enough to clear the flag only once while we are in the
2860  // debugger.
2861  ASSERT(isolate_->debug()->InDebugger());
2862  isolate_->stack_guard()->Continue(DEBUGCOMMAND);
2863 
2864  // Notify the debugger that a debug event has occurred unless auto continue is
2865  // active in which case no event is send.
2866  if (sendEventMessage) {
2867  MessageImpl message = MessageImpl::NewEvent(
2868  event,
2869  auto_continue,
2870  Handle<JSObject>::cast(exec_state),
2871  Handle<JSObject>::cast(event_data));
2872  InvokeMessageHandler(message);
2873  }
2874 
2875  // If auto continue don't make the event cause a break, but process messages
2876  // in the queue if any. For script collected events don't even process
2877  // messages in the queue as the execution state might not be what is expected
2878  // by the client.
2879  if ((auto_continue && !HasCommands()) || event == v8::ScriptCollected) {
2880  return;
2881  }
2882 
2883  v8::TryCatch try_catch;
2884 
2885  // DebugCommandProcessor goes here.
2886  v8::Local<v8::Object> cmd_processor;
2887  {
2888  v8::Local<v8::Object> api_exec_state =
2889  v8::Utils::ToLocal(Handle<JSObject>::cast(exec_state));
2890  v8::Local<v8::String> fun_name =
2891  v8::String::New("debugCommandProcessor");
2893  v8::Function::Cast(*api_exec_state->Get(fun_name));
2894 
2895  v8::Handle<v8::Boolean> running =
2896  auto_continue ? v8::True() : v8::False();
2897  static const int kArgc = 1;
2898  v8::Handle<Value> argv[kArgc] = { running };
2899  cmd_processor = v8::Object::Cast(*fun->Call(api_exec_state, kArgc, argv));
2900  if (try_catch.HasCaught()) {
2901  PrintLn(try_catch.Exception());
2902  return;
2903  }
2904  }
2905 
2906  bool running = auto_continue;
2907 
2908  // Process requests from the debugger.
2909  while (true) {
2910  // Wait for new command in the queue.
2911  if (Debugger::host_dispatch_handler_) {
2912  // In case there is a host dispatch - do periodic dispatches.
2913  if (!command_received_->Wait(host_dispatch_micros_)) {
2914  // Timout expired, do the dispatch.
2915  Debugger::host_dispatch_handler_();
2916  continue;
2917  }
2918  } else {
2919  // In case there is no host dispatch - just wait.
2920  command_received_->Wait();
2921  }
2922 
2923  // Get the command from the queue.
2924  CommandMessage command = command_queue_.Get();
2925  isolate_->logger()->DebugTag(
2926  "Got request from command queue, in interactive loop.");
2927  if (!Debugger::IsDebuggerActive()) {
2928  // Delete command text and user data.
2929  command.Dispose();
2930  return;
2931  }
2932 
2933  // Invoke JavaScript to process the debug request.
2934  v8::Local<v8::String> fun_name;
2936  v8::Local<v8::Value> request;
2937  v8::TryCatch try_catch;
2938  fun_name = v8::String::New("processDebugRequest");
2939  fun = v8::Function::Cast(*cmd_processor->Get(fun_name));
2940 
2941  request = v8::String::New(command.text().start(),
2942  command.text().length());
2943  static const int kArgc = 1;
2944  v8::Handle<Value> argv[kArgc] = { request };
2945  v8::Local<v8::Value> response_val = fun->Call(cmd_processor, kArgc, argv);
2946 
2947  // Get the response.
2948  v8::Local<v8::String> response;
2949  if (!try_catch.HasCaught()) {
2950  // Get response string.
2951  if (!response_val->IsUndefined()) {
2952  response = v8::String::Cast(*response_val);
2953  } else {
2954  response = v8::String::New("");
2955  }
2956 
2957  // Log the JSON request/response.
2958  if (FLAG_trace_debug_json) {
2959  PrintLn(request);
2960  PrintLn(response);
2961  }
2962 
2963  // Get the running state.
2964  fun_name = v8::String::New("isRunning");
2965  fun = v8::Function::Cast(*cmd_processor->Get(fun_name));
2966  static const int kArgc = 1;
2967  v8::Handle<Value> argv[kArgc] = { response };
2968  v8::Local<v8::Value> running_val = fun->Call(cmd_processor, kArgc, argv);
2969  if (!try_catch.HasCaught()) {
2970  running = running_val->ToBoolean()->Value();
2971  }
2972  } else {
2973  // In case of failure the result text is the exception text.
2974  response = try_catch.Exception()->ToString();
2975  }
2976 
2977  // Return the result.
2978  MessageImpl message = MessageImpl::NewResponse(
2979  event,
2980  running,
2981  Handle<JSObject>::cast(exec_state),
2982  Handle<JSObject>::cast(event_data),
2983  Handle<String>(Utils::OpenHandle(*response)),
2984  command.client_data());
2985  InvokeMessageHandler(message);
2986  command.Dispose();
2987 
2988  // Return from debug event processing if either the VM is put into the
2989  // running state (through a continue command) or auto continue is active
2990  // and there are no more commands queued.
2991  if (running && !HasCommands()) {
2992  return;
2993  }
2994  }
2995 }
2996 
2997 
2998 void Debugger::SetEventListener(Handle<Object> callback,
2999  Handle<Object> data) {
3000  HandleScope scope(isolate_);
3001  GlobalHandles* global_handles = isolate_->global_handles();
3002 
3003  // Clear the global handles for the event listener and the event listener data
3004  // object.
3005  if (!event_listener_.is_null()) {
3006  global_handles->Destroy(
3007  reinterpret_cast<Object**>(event_listener_.location()));
3008  event_listener_ = Handle<Object>();
3009  }
3010  if (!event_listener_data_.is_null()) {
3011  global_handles->Destroy(
3012  reinterpret_cast<Object**>(event_listener_data_.location()));
3013  event_listener_data_ = Handle<Object>();
3014  }
3015 
3016  // If there is a new debug event listener register it together with its data
3017  // object.
3018  if (!callback->IsUndefined() && !callback->IsNull()) {
3019  event_listener_ = Handle<Object>::cast(
3020  global_handles->Create(*callback));
3021  if (data.is_null()) {
3022  data = isolate_->factory()->undefined_value();
3023  }
3024  event_listener_data_ = Handle<Object>::cast(
3025  global_handles->Create(*data));
3026  }
3027 
3028  ListenersChanged();
3029 }
3030 
3031 
3032 void Debugger::SetMessageHandler(v8::Debug::MessageHandler2 handler) {
3033  ScopedLock with(debugger_access_);
3034 
3035  message_handler_ = handler;
3036  ListenersChanged();
3037  if (handler == NULL) {
3038  // Send an empty command to the debugger if in a break to make JavaScript
3039  // run again if the debugger is closed.
3040  if (isolate_->debug()->InDebugger()) {
3041  ProcessCommand(Vector<const uint16_t>::empty());
3042  }
3043  }
3044 }
3045 
3046 
3047 void Debugger::ListenersChanged() {
3048  if (IsDebuggerActive()) {
3049  // Disable the compilation cache when the debugger is active.
3050  isolate_->compilation_cache()->Disable();
3051  debugger_unload_pending_ = false;
3052  } else {
3053  isolate_->compilation_cache()->Enable();
3054  // Unload the debugger if event listener and message handler cleared.
3055  // Schedule this for later, because we may be in non-V8 thread.
3056  debugger_unload_pending_ = true;
3057  }
3058 }
3059 
3060 
3061 void Debugger::SetHostDispatchHandler(v8::Debug::HostDispatchHandler handler,
3062  int period) {
3063  host_dispatch_handler_ = handler;
3064  host_dispatch_micros_ = period * 1000;
3065 }
3066 
3067 
3068 void Debugger::SetDebugMessageDispatchHandler(
3069  v8::Debug::DebugMessageDispatchHandler handler, bool provide_locker) {
3070  ScopedLock with(dispatch_handler_access_);
3071  debug_message_dispatch_handler_ = handler;
3072 
3073  if (provide_locker && message_dispatch_helper_thread_ == NULL) {
3074  message_dispatch_helper_thread_ = new MessageDispatchHelperThread(isolate_);
3075  message_dispatch_helper_thread_->Start();
3076  }
3077 }
3078 
3079 
3080 // Calls the registered debug message handler. This callback is part of the
3081 // public API.
3082 void Debugger::InvokeMessageHandler(MessageImpl message) {
3083  ScopedLock with(debugger_access_);
3084 
3085  if (message_handler_ != NULL) {
3086  message_handler_(message);
3087  }
3088 }
3089 
3090 
3091 // Puts a command coming from the public API on the queue. Creates
3092 // a copy of the command string managed by the debugger. Up to this
3093 // point, the command data was managed by the API client. Called
3094 // by the API client thread.
3095 void Debugger::ProcessCommand(Vector<const uint16_t> command,
3096  v8::Debug::ClientData* client_data) {
3097  // Need to cast away const.
3098  CommandMessage message = CommandMessage::New(
3099  Vector<uint16_t>(const_cast<uint16_t*>(command.start()),
3100  command.length()),
3101  client_data);
3102  isolate_->logger()->DebugTag("Put command on command_queue.");
3103  command_queue_.Put(message);
3104  command_received_->Signal();
3105 
3106  // Set the debug command break flag to have the command processed.
3107  if (!isolate_->debug()->InDebugger()) {
3108  isolate_->stack_guard()->DebugCommand();
3109  }
3110 
3111  MessageDispatchHelperThread* dispatch_thread;
3112  {
3113  ScopedLock with(dispatch_handler_access_);
3114  dispatch_thread = message_dispatch_helper_thread_;
3115  }
3116 
3117  if (dispatch_thread == NULL) {
3118  CallMessageDispatchHandler();
3119  } else {
3120  dispatch_thread->Schedule();
3121  }
3122 }
3123 
3124 
3125 bool Debugger::HasCommands() {
3126  return !command_queue_.IsEmpty();
3127 }
3128 
3129 
3130 void Debugger::EnqueueDebugCommand(v8::Debug::ClientData* client_data) {
3131  CommandMessage message = CommandMessage::New(Vector<uint16_t>(), client_data);
3132  event_command_queue_.Put(message);
3133 
3134  // Set the debug command break flag to have the command processed.
3135  if (!isolate_->debug()->InDebugger()) {
3136  isolate_->stack_guard()->DebugCommand();
3137  }
3138 }
3139 
3140 
3141 bool Debugger::IsDebuggerActive() {
3142  ScopedLock with(debugger_access_);
3143 
3144  return message_handler_ != NULL ||
3145  !event_listener_.is_null() ||
3146  force_debugger_active_;
3147 }
3148 
3149 
3150 Handle<Object> Debugger::Call(Handle<JSFunction> fun,
3151  Handle<Object> data,
3152  bool* pending_exception) {
3153  // When calling functions in the debugger prevent it from beeing unloaded.
3154  Debugger::never_unload_debugger_ = true;
3155 
3156  // Enter the debugger.
3157  EnterDebugger debugger;
3158  if (debugger.FailedToEnter()) {
3159  return isolate_->factory()->undefined_value();
3160  }
3161 
3162  // Create the execution state.
3163  bool caught_exception = false;
3164  Handle<Object> exec_state = MakeExecutionState(&caught_exception);
3165  if (caught_exception) {
3166  return isolate_->factory()->undefined_value();
3167  }
3168 
3169  Handle<Object> argv[] = { exec_state, data };
3170  Handle<Object> result = Execution::Call(
3171  fun,
3172  Handle<Object>(isolate_->debug()->debug_context_->global_proxy()),
3173  ARRAY_SIZE(argv),
3174  argv,
3175  pending_exception);
3176  return result;
3177 }
3178 
3179 
3180 static void StubMessageHandler2(const v8::Debug::Message& message) {
3181  // Simply ignore message.
3182 }
3183 
3184 
3185 bool Debugger::StartAgent(const char* name, int port,
3186  bool wait_for_connection) {
3187  ASSERT(Isolate::Current() == isolate_);
3188  if (wait_for_connection) {
3189  // Suspend V8 if it is already running or set V8 to suspend whenever
3190  // it starts.
3191  // Provide stub message handler; V8 auto-continues each suspend
3192  // when there is no message handler; we doesn't need it.
3193  // Once become suspended, V8 will stay so indefinitely long, until remote
3194  // debugger connects and issues "continue" command.
3195  Debugger::message_handler_ = StubMessageHandler2;
3197  }
3198 
3199  if (Socket::SetUp()) {
3200  if (agent_ == NULL) {
3201  agent_ = new DebuggerAgent(name, port);
3202  agent_->Start();
3203  }
3204  return true;
3205  }
3206 
3207  return false;
3208 }
3209 
3210 
3211 void Debugger::StopAgent() {
3212  ASSERT(Isolate::Current() == isolate_);
3213  if (agent_ != NULL) {
3214  agent_->Shutdown();
3215  agent_->Join();
3216  delete agent_;
3217  agent_ = NULL;
3218  }
3219 }
3220 
3221 
3222 void Debugger::WaitForAgent() {
3223  ASSERT(Isolate::Current() == isolate_);
3224  if (agent_ != NULL)
3225  agent_->WaitUntilListening();
3226 }
3227 
3228 
3229 void Debugger::CallMessageDispatchHandler() {
3231  {
3232  ScopedLock with(dispatch_handler_access_);
3233  handler = Debugger::debug_message_dispatch_handler_;
3234  }
3235  if (handler != NULL) {
3236  handler();
3237  }
3238 }
3239 
3240 
3241 EnterDebugger::EnterDebugger()
3242  : isolate_(Isolate::Current()),
3243  prev_(isolate_->debug()->debugger_entry()),
3244  it_(isolate_),
3245  has_js_frames_(!it_.done()),
3246  save_(isolate_) {
3247  Debug* debug = isolate_->debug();
3248  ASSERT(prev_ != NULL || !debug->is_interrupt_pending(PREEMPT));
3249  ASSERT(prev_ != NULL || !debug->is_interrupt_pending(DEBUGBREAK));
3250 
3251  // Link recursive debugger entry.
3252  debug->set_debugger_entry(this);
3253 
3254  // Store the previous break id and frame id.
3255  break_id_ = debug->break_id();
3256  break_frame_id_ = debug->break_frame_id();
3257 
3258  // Create the new break info. If there is no JavaScript frames there is no
3259  // break frame id.
3260  if (has_js_frames_) {
3261  debug->NewBreak(it_.frame()->id());
3262  } else {
3263  debug->NewBreak(StackFrame::NO_ID);
3264  }
3265 
3266  // Make sure that debugger is loaded and enter the debugger context.
3267  load_failed_ = !debug->Load();
3268  if (!load_failed_) {
3269  // NOTE the member variable save which saves the previous context before
3270  // this change.
3271  isolate_->set_context(*debug->debug_context());
3272  }
3273 }
3274 
3275 
3276 EnterDebugger::~EnterDebugger() {
3277  ASSERT(Isolate::Current() == isolate_);
3278  Debug* debug = isolate_->debug();
3279 
3280  // Restore to the previous break state.
3281  debug->SetBreak(break_frame_id_, break_id_);
3282 
3283  // Check for leaving the debugger.
3284  if (!load_failed_ && prev_ == NULL) {
3285  // Clear mirror cache when leaving the debugger. Skip this if there is a
3286  // pending exception as clearing the mirror cache calls back into
3287  // JavaScript. This can happen if the v8::Debug::Call is used in which
3288  // case the exception should end up in the calling code.
3289  if (!isolate_->has_pending_exception()) {
3290  // Try to avoid any pending debug break breaking in the clear mirror
3291  // cache JavaScript code.
3292  if (isolate_->stack_guard()->IsDebugBreak()) {
3293  debug->set_interrupts_pending(DEBUGBREAK);
3294  isolate_->stack_guard()->Continue(DEBUGBREAK);
3295  }
3296  debug->ClearMirrorCache();
3297  }
3298 
3299  // Request preemption and debug break when leaving the last debugger entry
3300  // if any of these where recorded while debugging.
3301  if (debug->is_interrupt_pending(PREEMPT)) {
3302  // This re-scheduling of preemption is to avoid starvation in some
3303  // debugging scenarios.
3304  debug->clear_interrupt_pending(PREEMPT);
3305  isolate_->stack_guard()->Preempt();
3306  }
3307  if (debug->is_interrupt_pending(DEBUGBREAK)) {
3308  debug->clear_interrupt_pending(DEBUGBREAK);
3309  isolate_->stack_guard()->DebugBreak();
3310  }
3311 
3312  // If there are commands in the queue when leaving the debugger request
3313  // that these commands are processed.
3314  if (isolate_->debugger()->HasCommands()) {
3315  isolate_->stack_guard()->DebugCommand();
3316  }
3317 
3318  // If leaving the debugger with the debugger no longer active unload it.
3319  if (!isolate_->debugger()->IsDebuggerActive()) {
3320  isolate_->debugger()->UnloadDebugger();
3321  }
3322  }
3323 
3324  // Leaving this debugger entry.
3325  debug->set_debugger_entry(prev_);
3326 }
3327 
3328 
3329 MessageImpl MessageImpl::NewEvent(DebugEvent event,
3330  bool running,
3331  Handle<JSObject> exec_state,
3332  Handle<JSObject> event_data) {
3333  MessageImpl message(true, event, running,
3334  exec_state, event_data, Handle<String>(), NULL);
3335  return message;
3336 }
3337 
3338 
3339 MessageImpl MessageImpl::NewResponse(DebugEvent event,
3340  bool running,
3341  Handle<JSObject> exec_state,
3342  Handle<JSObject> event_data,
3343  Handle<String> response_json,
3344  v8::Debug::ClientData* client_data) {
3345  MessageImpl message(false, event, running,
3346  exec_state, event_data, response_json, client_data);
3347  return message;
3348 }
3349 
3350 
3351 MessageImpl::MessageImpl(bool is_event,
3352  DebugEvent event,
3353  bool running,
3354  Handle<JSObject> exec_state,
3355  Handle<JSObject> event_data,
3356  Handle<String> response_json,
3357  v8::Debug::ClientData* client_data)
3358  : is_event_(is_event),
3359  event_(event),
3360  running_(running),
3361  exec_state_(exec_state),
3362  event_data_(event_data),
3363  response_json_(response_json),
3364  client_data_(client_data) {}
3365 
3366 
3367 bool MessageImpl::IsEvent() const {
3368  return is_event_;
3369 }
3370 
3371 
3372 bool MessageImpl::IsResponse() const {
3373  return !is_event_;
3374 }
3375 
3376 
3377 DebugEvent MessageImpl::GetEvent() const {
3378  return event_;
3379 }
3380 
3381 
3382 bool MessageImpl::WillStartRunning() const {
3383  return running_;
3384 }
3385 
3386 
3387 v8::Handle<v8::Object> MessageImpl::GetExecutionState() const {
3388  return v8::Utils::ToLocal(exec_state_);
3389 }
3390 
3391 
3392 v8::Handle<v8::Object> MessageImpl::GetEventData() const {
3393  return v8::Utils::ToLocal(event_data_);
3394 }
3395 
3396 
3397 v8::Handle<v8::String> MessageImpl::GetJSON() const {
3398  v8::HandleScope scope;
3399 
3400  if (IsEvent()) {
3401  // Call toJSONProtocol on the debug event object.
3402  Handle<Object> fun = GetProperty(event_data_, "toJSONProtocol");
3403  if (!fun->IsJSFunction()) {
3404  return v8::Handle<v8::String>();
3405  }
3406  bool caught_exception;
3407  Handle<Object> json = Execution::TryCall(Handle<JSFunction>::cast(fun),
3408  event_data_,
3409  0, NULL, &caught_exception);
3410  if (caught_exception || !json->IsString()) {
3411  return v8::Handle<v8::String>();
3412  }
3413  return scope.Close(v8::Utils::ToLocal(Handle<String>::cast(json)));
3414  } else {
3415  return v8::Utils::ToLocal(response_json_);
3416  }
3417 }
3418 
3419 
3420 v8::Handle<v8::Context> MessageImpl::GetEventContext() const {
3421  Isolate* isolate = Isolate::Current();
3422  v8::Handle<v8::Context> context = GetDebugEventContext(isolate);
3423  // Isolate::context() may be NULL when "script collected" event occures.
3424  ASSERT(!context.IsEmpty() || event_ == v8::ScriptCollected);
3425  return context;
3426 }
3427 
3428 
3429 v8::Debug::ClientData* MessageImpl::GetClientData() const {
3430  return client_data_;
3431 }
3432 
3433 
3434 EventDetailsImpl::EventDetailsImpl(DebugEvent event,
3435  Handle<JSObject> exec_state,
3436  Handle<JSObject> event_data,
3437  Handle<Object> callback_data,
3438  v8::Debug::ClientData* client_data)
3439  : event_(event),
3440  exec_state_(exec_state),
3441  event_data_(event_data),
3442  callback_data_(callback_data),
3443  client_data_(client_data) {}
3444 
3445 
3446 DebugEvent EventDetailsImpl::GetEvent() const {
3447  return event_;
3448 }
3449 
3450 
3451 v8::Handle<v8::Object> EventDetailsImpl::GetExecutionState() const {
3452  return v8::Utils::ToLocal(exec_state_);
3453 }
3454 
3455 
3456 v8::Handle<v8::Object> EventDetailsImpl::GetEventData() const {
3457  return v8::Utils::ToLocal(event_data_);
3458 }
3459 
3460 
3461 v8::Handle<v8::Context> EventDetailsImpl::GetEventContext() const {
3462  return GetDebugEventContext(Isolate::Current());
3463 }
3464 
3465 
3466 v8::Handle<v8::Value> EventDetailsImpl::GetCallbackData() const {
3467  return v8::Utils::ToLocal(callback_data_);
3468 }
3469 
3470 
3471 v8::Debug::ClientData* EventDetailsImpl::GetClientData() const {
3472  return client_data_;
3473 }
3474 
3475 
3476 CommandMessage::CommandMessage() : text_(Vector<uint16_t>::empty()),
3477  client_data_(NULL) {
3478 }
3479 
3480 
3481 CommandMessage::CommandMessage(const Vector<uint16_t>& text,
3482  v8::Debug::ClientData* data)
3483  : text_(text),
3484  client_data_(data) {
3485 }
3486 
3487 
3488 CommandMessage::~CommandMessage() {
3489 }
3490 
3491 
3492 void CommandMessage::Dispose() {
3493  text_.Dispose();
3494  delete client_data_;
3495  client_data_ = NULL;
3496 }
3497 
3498 
3499 CommandMessage CommandMessage::New(const Vector<uint16_t>& command,
3500  v8::Debug::ClientData* data) {
3501  return CommandMessage(command.Clone(), data);
3502 }
3503 
3504 
3505 CommandMessageQueue::CommandMessageQueue(int size) : start_(0), end_(0),
3506  size_(size) {
3507  messages_ = NewArray<CommandMessage>(size);
3508 }
3509 
3510 
3511 CommandMessageQueue::~CommandMessageQueue() {
3512  while (!IsEmpty()) {
3513  CommandMessage m = Get();
3514  m.Dispose();
3515  }
3516  DeleteArray(messages_);
3517 }
3518 
3519 
3520 CommandMessage CommandMessageQueue::Get() {
3521  ASSERT(!IsEmpty());
3522  int result = start_;
3523  start_ = (start_ + 1) % size_;
3524  return messages_[result];
3525 }
3526 
3527 
3528 void CommandMessageQueue::Put(const CommandMessage& message) {
3529  if ((end_ + 1) % size_ == start_) {
3530  Expand();
3531  }
3532  messages_[end_] = message;
3533  end_ = (end_ + 1) % size_;
3534 }
3535 
3536 
3537 void CommandMessageQueue::Expand() {
3538  CommandMessageQueue new_queue(size_ * 2);
3539  while (!IsEmpty()) {
3540  new_queue.Put(Get());
3541  }
3542  CommandMessage* array_to_free = messages_;
3543  *this = new_queue;
3544  new_queue.messages_ = array_to_free;
3545  // Make the new_queue empty so that it doesn't call Dispose on any messages.
3546  new_queue.start_ = new_queue.end_;
3547  // Automatic destructor called on new_queue, freeing array_to_free.
3548 }
3549 
3550 
3551 LockingCommandMessageQueue::LockingCommandMessageQueue(Logger* logger, int size)
3552  : logger_(logger), queue_(size) {
3553  lock_ = OS::CreateMutex();
3554 }
3555 
3556 
3557 LockingCommandMessageQueue::~LockingCommandMessageQueue() {
3558  delete lock_;
3559 }
3560 
3561 
3562 bool LockingCommandMessageQueue::IsEmpty() const {
3563  ScopedLock sl(lock_);
3564  return queue_.IsEmpty();
3565 }
3566 
3567 
3568 CommandMessage LockingCommandMessageQueue::Get() {
3569  ScopedLock sl(lock_);
3570  CommandMessage result = queue_.Get();
3571  logger_->DebugEvent("Get", result.text());
3572  return result;
3573 }
3574 
3575 
3576 void LockingCommandMessageQueue::Put(const CommandMessage& message) {
3577  ScopedLock sl(lock_);
3578  queue_.Put(message);
3579  logger_->DebugEvent("Put", message.text());
3580 }
3581 
3582 
3583 void LockingCommandMessageQueue::Clear() {
3584  ScopedLock sl(lock_);
3585  queue_.Clear();
3586 }
3587 
3588 
3589 MessageDispatchHelperThread::MessageDispatchHelperThread(Isolate* isolate)
3590  : Thread("v8:MsgDispHelpr"),
3591  sem_(OS::CreateSemaphore(0)), mutex_(OS::CreateMutex()),
3592  already_signalled_(false) {
3593 }
3594 
3595 
3596 MessageDispatchHelperThread::~MessageDispatchHelperThread() {
3597  delete mutex_;
3598  delete sem_;
3599 }
3600 
3601 
3602 void MessageDispatchHelperThread::Schedule() {
3603  {
3604  ScopedLock lock(mutex_);
3605  if (already_signalled_) {
3606  return;
3607  }
3608  already_signalled_ = true;
3609  }
3610  sem_->Signal();
3611 }
3612 
3613 
3614 void MessageDispatchHelperThread::Run() {
3615  while (true) {
3616  sem_->Wait();
3617  {
3618  ScopedLock lock(mutex_);
3619  already_signalled_ = false;
3620  }
3621  {
3622  Locker locker;
3623  Isolate::Current()->debugger()->CallMessageDispatchHandler();
3624  }
3625  }
3626 }
3627 
3628 #endif // ENABLE_DEBUGGER_SUPPORT
3629 
3630 } } // namespace v8::internal
byte * Address
Definition: globals.h:172
V8EXPORT int Length() const
Definition: api.cc:3718
static Handle< Object > SetProperty(Handle< JSReceiver > object, Handle< String > key, Handle< Object > value, PropertyAttributes attributes, StrictModeFlag strict_mode)
Definition: objects.cc:1944
static Object * Cast(Value *obj)
Definition: v8.h:4386
void Reset()
Definition: flags.cc:1446
static Object *& Object_at(Address addr)
Definition: v8memory.h:75
#define V8PRIxPTR
Definition: globals.h:204
static Handle< Object > TryCall(Handle< JSFunction > func, Handle< Object > receiver, int argc, Handle< Object > argv[], bool *caught_exception)
Definition: execution.cc:186
Handle< Boolean > V8EXPORT True()
Definition: api.cc:566
void Dispose()
Definition: v8.h:4065
void PrintF(const char *format,...)
Definition: v8utils.cc:40
Local< Value > Exception() const
Definition: api.cc:1712
static Handle< JSMessageObject > MakeMessageObject(const char *type, MessageLocation *loc, Vector< Handle< Object > > args, Handle< String > stack_trace, Handle< JSArray > stack_frames)
Definition: messages.cc:58
V8EXPORT Local< Value > Get(Handle< Value > key)
Definition: api.cc:2845
static Smi * FromInt(int value)
Definition: objects-inl.h:973
static int GetIndex(const char *name)
bool HasCaught() const
Definition: api.cc:1695
static int ExtractArgcFromMinorKey(int minor_key)
Definition: code-stubs.h:757
value format" "after each garbage collection") DEFINE_bool(print_cumulative_gc_stat, false, "print cumulative GC statistics in name=value format on exit") DEFINE_bool(trace_gc_verbose, false, "print more details following each garbage collection") DEFINE_bool(trace_fragmentation, false, "report fragmentation for old pointer and data pages") DEFINE_bool(collect_maps, true, "garbage collect maps from which no objects can be reached") DEFINE_bool(flush_code, true, "flush code that we expect not to use again before full gc") DEFINE_bool(incremental_marking, true, "use incremental marking") DEFINE_bool(incremental_marking_steps, true, "do incremental marking steps") DEFINE_bool(trace_incremental_marking, false, "trace progress of the incremental marking") DEFINE_bool(use_idle_notification, true, "Use idle notification to reduce memory footprint.") DEFINE_bool(send_idle_notification, false, "Send idle notifcation between stress runs.") DEFINE_bool(use_ic, true, "use inline caching") DEFINE_bool(native_code_counters, false, "generate extra code for manipulating stats counters") DEFINE_bool(always_compact, false, "Perform compaction on every full GC") DEFINE_bool(lazy_sweeping, true, "Use lazy sweeping for old pointer and data spaces") DEFINE_bool(never_compact, false, "Never perform compaction on full GC-testing only") DEFINE_bool(compact_code_space, true, "Compact code space on full non-incremental collections") DEFINE_bool(cleanup_code_caches_at_gc, true, "Flush inline caches prior to mark compact collection and" "flush code caches in maps during mark compact cycle.") DEFINE_int(random_seed, 0, "Default seed for initializing random generator" "(0, the default, means to use system random).") DEFINE_bool(use_verbose_printer, true, "allows verbose printing") DEFINE_bool(allow_natives_syntax, false, "allow natives syntax") DEFINE_bool(trace_sim, false, "Trace simulator execution") DEFINE_bool(check_icache, false, "Check icache flushes in ARM and MIPS simulator") DEFINE_int(stop_sim_at, 0, "Simulator stop after x number of instructions") DEFINE_int(sim_stack_alignment, 8, "Stack alingment in bytes in simulator(4 or 8, 8 is default)") DEFINE_bool(trace_exception, false, "print stack trace when throwing exceptions") DEFINE_bool(preallocate_message_memory, false, "preallocate some memory to build stack traces.") DEFINE_bool(randomize_hashes, true, "randomize hashes to avoid predictable hash collisions" "(with snapshots this option cannot override the baked-in seed)") DEFINE_int(hash_seed, 0, "Fixed seed to use to hash property keys(0 means random)" "(with snapshots this option cannot override the baked-in seed)") DEFINE_bool(preemption, false, "activate a 100ms timer that switches between V8 threads") DEFINE_bool(regexp_optimization, true, "generate optimized regexp code") DEFINE_bool(testing_bool_flag, true, "testing_bool_flag") DEFINE_int(testing_int_flag, 13, "testing_int_flag") DEFINE_float(testing_float_flag, 2.5, "float-flag") DEFINE_string(testing_string_flag, "Hello, world!", "string-flag") DEFINE_int(testing_prng_seed, 42, "Seed used for threading test randomness") DEFINE_string(testing_serialization_file, "/tmp/serdes", "file in which to serialize heap") DEFINE_bool(help, false, "Print usage message, including flags, on console") DEFINE_bool(dump_counters, false, "Dump counters on exit") DEFINE_string(map_counters, "", "Map counters to a file") DEFINE_args(js_arguments, JSARGUMENTS_INIT, "Pass all remaining arguments to the script.Alias for\"--\".") DEFINE_bool(debug_compile_events, true,"Enable debugger compile events") DEFINE_bool(debug_script_collected_events, true,"Enable debugger script collected events") DEFINE_bool(gdbjit, false,"enable GDBJIT interface (disables compacting GC)") DEFINE_bool(gdbjit_full, false,"enable GDBJIT interface for all code objects") DEFINE_bool(gdbjit_dump, false,"dump elf objects with debug info to disk") DEFINE_string(gdbjit_dump_filter,"","dump only objects containing this substring") DEFINE_bool(force_marking_deque_overflows, false,"force overflows of marking deque by reducing it's size ""to 64 words") DEFINE_bool(stress_compaction, false,"stress the GC compactor to flush out bugs (implies ""--force_marking_deque_overflows)")#define FLAG DEFINE_bool(enable_slow_asserts, false,"enable asserts that are slow to execute") DEFINE_bool(trace_codegen, false,"print name of functions for which code is generated") DEFINE_bool(print_source, false,"pretty print source code") DEFINE_bool(print_builtin_source, false,"pretty print source code for builtins") DEFINE_bool(print_ast, false,"print source AST") DEFINE_bool(print_builtin_ast, false,"print source AST for builtins") DEFINE_string(stop_at,"","function name where to insert a breakpoint") DEFINE_bool(print_builtin_scopes, false,"print scopes for builtins") DEFINE_bool(print_scopes, false,"print scopes") DEFINE_bool(trace_contexts, false,"trace contexts operations") DEFINE_bool(gc_greedy, false,"perform GC prior to some allocations") DEFINE_bool(gc_verbose, false,"print stuff during garbage collection") DEFINE_bool(heap_stats, false,"report heap statistics before and after GC") DEFINE_bool(code_stats, false,"report code statistics after GC") DEFINE_bool(verify_heap, false,"verify heap pointers before and after GC") DEFINE_bool(print_handles, false,"report handles after GC") DEFINE_bool(print_global_handles, false,"report global handles after GC") DEFINE_bool(trace_ic, false,"trace inline cache state transitions") DEFINE_bool(print_interfaces, false,"print interfaces") DEFINE_bool(print_interface_details, false,"print interface inference details") DEFINE_int(print_interface_depth, 5,"depth for printing interfaces") DEFINE_bool(trace_normalization, false,"prints when objects are turned into dictionaries.") DEFINE_bool(trace_lazy, false,"trace lazy compilation") DEFINE_bool(collect_heap_spill_statistics, false,"report heap spill statistics along with heap_stats ""(requires heap_stats)") DEFINE_bool(trace_isolates, false,"trace isolate state changes") DEFINE_bool(log_state_changes, false,"Log state changes.") DEFINE_bool(regexp_possessive_quantifier, false,"enable possessive quantifier syntax for testing") DEFINE_bool(trace_regexp_bytecodes, false,"trace regexp bytecode execution") DEFINE_bool(trace_regexp_assembler, false,"trace regexp macro assembler calls.")#define FLAG DEFINE_bool(log, false,"Minimal logging (no API, code, GC, suspect, or handles samples).") DEFINE_bool(log_all, false,"Log all events to the log file.") DEFINE_bool(log_runtime, false,"Activate runtime system %Log call.") DEFINE_bool(log_api, false,"Log API events to the log file.") DEFINE_bool(log_code, false,"Log code events to the log file without profiling.") DEFINE_bool(log_gc, false,"Log heap samples on garbage collection for the hp2ps tool.") DEFINE_bool(log_handles, false,"Log global handle events.") DEFINE_bool(log_snapshot_positions, false,"log positions of (de)serialized objects in the snapshot.") DEFINE_bool(log_suspect, false,"Log suspect operations.") DEFINE_bool(prof, false,"Log statistical profiling information (implies --log-code).") DEFINE_bool(prof_auto, true,"Used with --prof, starts profiling automatically") DEFINE_bool(prof_lazy, false,"Used with --prof, only does sampling and logging"" when profiler is active (implies --noprof_auto).") DEFINE_bool(prof_browser_mode, true,"Used with --prof, turns on browser-compatible mode for profiling.") DEFINE_bool(log_regexp, false,"Log regular expression execution.") DEFINE_bool(sliding_state_window, false,"Update sliding state window counters.") DEFINE_string(logfile,"v8.log","Specify the name of the log file.") DEFINE_bool(ll_prof, false,"Enable low-level linux profiler.")#define FLAG DEFINE_bool(trace_elements_transitions, false,"trace elements transitions") DEFINE_bool(print_code_stubs, false,"print code stubs") DEFINE_bool(test_secondary_stub_cache, false,"test secondary stub cache by disabling the primary one") DEFINE_bool(test_primary_stub_cache, false,"test primary stub cache by disabling the secondary one") DEFINE_bool(print_code, false,"print generated code") DEFINE_bool(print_opt_code, false,"print optimized code") DEFINE_bool(print_unopt_code, false,"print unoptimized code before ""printing optimized code based on it") DEFINE_bool(print_code_verbose, false,"print more information for code") DEFINE_bool(print_builtin_code, false,"print generated code for builtins")#43"/Users/thlorenz/dev/dx/v8-perf/build/v8/src/flags.cc"2#define FLAG_MODE_DEFINE_DEFAULTS#1"/Users/thlorenz/dev/dx/v8-perf/build/v8/src/flag-definitions.h"1#define FLAG_FULL(ftype, ctype, nam, def, cmt)#define FLAG_READONLY(ftype, ctype, nam, def, cmt)#define DEFINE_implication(whenflag, thenflag)#define DEFINE_bool(nam, def, cmt)#define DEFINE_int(nam, def, cmt)#define DEFINE_float(nam, def, cmt)#define DEFINE_string(nam, def, cmt)#define DEFINE_args(nam, def, cmt)#define FLAG DEFINE_bool(use_strict, false,"enforce strict mode") DEFINE_bool(es5_readonly, false,"activate correct semantics for inheriting readonliness") DEFINE_bool(es52_globals, false,"activate new semantics for global var declarations") DEFINE_bool(harmony_typeof, false,"enable harmony semantics for typeof") DEFINE_bool(harmony_scoping, false,"enable harmony block scoping") DEFINE_bool(harmony_modules, false,"enable harmony modules (implies block scoping)") DEFINE_bool(harmony_proxies, false,"enable harmony proxies") DEFINE_bool(harmony_collections, false,"enable harmony collections (sets, maps, and weak maps)") DEFINE_bool(harmony, false,"enable all harmony features (except typeof)") DEFINE_implication(harmony, harmony_scoping) DEFINE_implication(harmony, harmony_modules) DEFINE_implication(harmony, harmony_proxies) DEFINE_implication(harmony, harmony_collections) DEFINE_implication(harmony_modules, harmony_scoping) DEFINE_bool(packed_arrays, false,"optimizes arrays that have no holes") DEFINE_bool(smi_only_arrays, true,"tracks arrays with only smi values") DEFINE_bool(clever_optimizations, true,"Optimize object size, Array shift, DOM strings and string +") DEFINE_bool(unbox_double_arrays, true,"automatically unbox arrays of doubles") DEFINE_bool(string_slices, true,"use string slices") DEFINE_bool(crankshaft, true,"use crankshaft") DEFINE_string(hydrogen_filter,"","optimization filter") DEFINE_bool(use_range, true,"use hydrogen range analysis") DEFINE_bool(eliminate_dead_phis, true,"eliminate dead phis") DEFINE_bool(use_gvn, true,"use hydrogen global value numbering") DEFINE_bool(use_canonicalizing, true,"use hydrogen instruction canonicalizing") DEFINE_bool(use_inlining, true,"use function inlining") DEFINE_int(max_inlined_source_size, 600,"maximum source size in bytes considered for a single inlining") DEFINE_int(max_inlined_nodes, 196,"maximum number of AST nodes considered for a single inlining") DEFINE_int(max_inlined_nodes_cumulative, 196,"maximum cumulative number of AST nodes considered for inlining") DEFINE_bool(loop_invariant_code_motion, true,"loop invariant code motion") DEFINE_bool(collect_megamorphic_maps_from_stub_cache, true,"crankshaft harvests type feedback from stub cache") DEFINE_bool(hydrogen_stats, false,"print statistics for hydrogen") DEFINE_bool(trace_hydrogen, false,"trace generated hydrogen to file") DEFINE_string(trace_phase,"Z","trace generated IR for specified phases") DEFINE_bool(trace_inlining, false,"trace inlining decisions") DEFINE_bool(trace_alloc, false,"trace register allocator") DEFINE_bool(trace_all_uses, false,"trace all use positions") DEFINE_bool(trace_range, false,"trace range analysis") DEFINE_bool(trace_gvn, false,"trace global value numbering") DEFINE_bool(trace_representation, false,"trace representation types") DEFINE_bool(stress_pointer_maps, false,"pointer map for every instruction") DEFINE_bool(stress_environments, false,"environment for every instruction") DEFINE_int(deopt_every_n_times, 0,"deoptimize every n times a deopt point is passed") DEFINE_bool(trap_on_deopt, false,"put a break point before deoptimizing") DEFINE_bool(deoptimize_uncommon_cases, true,"deoptimize uncommon cases") DEFINE_bool(polymorphic_inlining, true,"polymorphic inlining") DEFINE_bool(use_osr, true,"use on-stack replacement") DEFINE_bool(array_bounds_checks_elimination, false,"perform array bounds checks elimination") DEFINE_bool(array_index_dehoisting, false,"perform array index dehoisting") DEFINE_bool(trace_osr, false,"trace on-stack replacement") DEFINE_int(stress_runs, 0,"number of stress runs") DEFINE_bool(optimize_closures, true,"optimize closures") DEFINE_bool(inline_construct, true,"inline constructor calls") DEFINE_bool(inline_arguments, true,"inline functions with arguments object") DEFINE_int(loop_weight, 1,"loop weight for representation inference") DEFINE_bool(optimize_for_in, true,"optimize functions containing for-in loops") DEFINE_bool(experimental_profiler, true,"enable all profiler experiments") DEFINE_bool(watch_ic_patching, false,"profiler considers IC stability") DEFINE_int(frame_count, 1,"number of stack frames inspected by the profiler") DEFINE_bool(self_optimization, false,"primitive functions trigger their own optimization") DEFINE_bool(direct_self_opt, false,"call recompile stub directly when self-optimizing") DEFINE_bool(retry_self_opt, false,"re-try self-optimization if it failed") DEFINE_bool(count_based_interrupts, false,"trigger profiler ticks based on counting instead of timing") DEFINE_bool(interrupt_at_exit, false,"insert an interrupt check at function exit") DEFINE_bool(weighted_back_edges, false,"weight back edges by jump distance for interrupt triggering") DEFINE_int(interrupt_budget, 5900,"execution budget before interrupt is triggered") DEFINE_int(type_info_threshold, 15,"percentage of ICs that must have type info to allow optimization") DEFINE_int(self_opt_count, 130,"call count before self-optimization") DEFINE_implication(experimental_profiler, watch_ic_patching) DEFINE_implication(experimental_profiler, self_optimization) DEFINE_implication(experimental_profiler, retry_self_opt) DEFINE_implication(experimental_profiler, count_based_interrupts) DEFINE_implication(experimental_profiler, interrupt_at_exit) DEFINE_implication(experimental_profiler, weighted_back_edges) DEFINE_bool(trace_opt_verbose, false,"extra verbose compilation tracing") DEFINE_implication(trace_opt_verbose, trace_opt) DEFINE_bool(debug_code, false,"generate extra code (assertions) for debugging") DEFINE_bool(code_comments, false,"emit comments in code disassembly") DEFINE_bool(enable_sse2, true,"enable use of SSE2 instructions if available") DEFINE_bool(enable_sse3, true,"enable use of SSE3 instructions if available") DEFINE_bool(enable_sse4_1, true,"enable use of SSE4.1 instructions if available") DEFINE_bool(enable_cmov, true,"enable use of CMOV instruction if available") DEFINE_bool(enable_rdtsc, true,"enable use of RDTSC instruction if available") DEFINE_bool(enable_sahf, true,"enable use of SAHF instruction if available (X64 only)") DEFINE_bool(enable_vfp3, true,"enable use of VFP3 instructions if available - this implies ""enabling ARMv7 instructions (ARM only)") DEFINE_bool(enable_armv7, true,"enable use of ARMv7 instructions if available (ARM only)") DEFINE_bool(enable_fpu, true,"enable use of MIPS FPU instructions if available (MIPS only)") DEFINE_string(expose_natives_as, NULL,"expose natives in global object") DEFINE_string(expose_debug_as, NULL,"expose debug in global object") DEFINE_bool(expose_gc, false,"expose gc extension") DEFINE_bool(expose_externalize_string, false,"expose externalize string extension") DEFINE_int(stack_trace_limit, 10,"number of stack frames to capture") DEFINE_bool(builtins_in_stack_traces, false,"show built-in functions in stack traces") DEFINE_bool(disable_native_files, false,"disable builtin natives files") DEFINE_bool(inline_new, true,"use fast inline allocation") DEFINE_bool(stack_trace_on_abort, true,"print a stack trace if an assertion failure occurs") DEFINE_bool(trace, false,"trace function calls") DEFINE_bool(mask_constants_with_cookie, true,"use random jit cookie to mask large constants") DEFINE_bool(lazy, true,"use lazy compilation") DEFINE_bool(trace_opt, false,"trace lazy optimization") DEFINE_bool(trace_opt_stats, false,"trace lazy optimization statistics") DEFINE_bool(opt, true,"use adaptive optimizations") DEFINE_bool(always_opt, false,"always try to optimize functions") DEFINE_bool(prepare_always_opt, false,"prepare for turning on always opt") DEFINE_bool(trace_deopt, false,"trace deoptimization") DEFINE_int(min_preparse_length, 1024,"minimum length for automatic enable preparsing") DEFINE_bool(always_full_compiler, false,"try to use the dedicated run-once backend for all code") DEFINE_bool(trace_bailout, false,"print reasons for falling back to using the classic V8 backend") DEFINE_bool(compilation_cache, true,"enable compilation cache") DEFINE_bool(cache_prototype_transitions, true,"cache prototype transitions") DEFINE_bool(trace_debug_json, false,"trace debugging JSON request/response") DEFINE_bool(debugger_auto_break, true,"automatically set the debug break flag when debugger commands are ""in the queue") DEFINE_bool(enable_liveedit, true,"enable liveedit experimental feature") DEFINE_bool(break_on_abort, true,"always cause a debug break before aborting") DEFINE_int(stack_size, kPointerSize *123,"default size of stack region v8 is allowed to use (in kBytes)") DEFINE_int(max_stack_trace_source_length, 300,"maximum length of function source code printed in a stack trace.") DEFINE_bool(always_inline_smi_code, false,"always inline smi code in non-opt code") DEFINE_int(max_new_space_size, 0,"max size of the new generation (in kBytes)") DEFINE_int(max_old_space_size, 0,"max size of the old generation (in Mbytes)") DEFINE_int(max_executable_size, 0,"max size of executable memory (in Mbytes)") DEFINE_bool(gc_global, false,"always perform global GCs") DEFINE_int(gc_interval,-1,"garbage collect after <n> allocations") DEFINE_bool(trace_gc, false,"print one trace line following each garbage collection") DEFINE_bool(trace_gc_nvp, false,"print one detailed trace line in name=value format ""after each garbage collection") DEFINE_bool(print_cumulative_gc_stat, false,"print cumulative GC statistics in name=value format on exit") DEFINE_bool(trace_gc_verbose, false,"print more details following each garbage collection") DEFINE_bool(trace_fragmentation, false,"report fragmentation for old pointer and data pages") DEFINE_bool(collect_maps, true,"garbage collect maps from which no objects can be reached") DEFINE_bool(flush_code, true,"flush code that we expect not to use again before full gc") DEFINE_bool(incremental_marking, true,"use incremental marking") DEFINE_bool(incremental_marking_steps, true,"do incremental marking steps") DEFINE_bool(trace_incremental_marking, false,"trace progress of the incremental marking") DEFINE_bool(use_idle_notification, true,"Use idle notification to reduce memory footprint.") DEFINE_bool(send_idle_notification, false,"Send idle notifcation between stress runs.") DEFINE_bool(use_ic, true,"use inline caching") DEFINE_bool(native_code_counters, false,"generate extra code for manipulating stats counters") DEFINE_bool(always_compact, false,"Perform compaction on every full GC") DEFINE_bool(lazy_sweeping, true,"Use lazy sweeping for old pointer and data spaces") DEFINE_bool(never_compact, false,"Never perform compaction on full GC - testing only") DEFINE_bool(compact_code_space, true,"Compact code space on full non-incremental collections") DEFINE_bool(cleanup_code_caches_at_gc, true,"Flush inline caches prior to mark compact collection and ""flush code caches in maps during mark compact cycle.") DEFINE_int(random_seed, 0,"Default seed for initializing random generator ""(0, the default, means to use system random).") DEFINE_bool(use_verbose_printer, true,"allows verbose printing") DEFINE_bool(allow_natives_syntax, false,"allow natives syntax") DEFINE_bool(trace_sim, false,"Trace simulator execution") DEFINE_bool(check_icache, false,"Check icache flushes in ARM and MIPS simulator") DEFINE_int(stop_sim_at, 0,"Simulator stop after x number of instructions") DEFINE_int(sim_stack_alignment, 8,"Stack alingment in bytes in simulator (4 or 8, 8 is default)") DEFINE_bool(trace_exception, false,"print stack trace when throwing exceptions") DEFINE_bool(preallocate_message_memory, false,"preallocate some memory to build stack traces.") DEFINE_bool(randomize_hashes, true,"randomize hashes to avoid predictable hash collisions ""(with snapshots this option cannot override the baked-in seed)") DEFINE_int(hash_seed, 0,"Fixed seed to use to hash property keys (0 means random)""(with snapshots this option cannot override the baked-in seed)") DEFINE_bool(preemption, false,"activate a 100ms timer that switches between V8 threads") DEFINE_bool(regexp_optimization, true,"generate optimized regexp code") DEFINE_bool(testing_bool_flag, true,"testing_bool_flag") DEFINE_int(testing_int_flag, 13,"testing_int_flag") DEFINE_float(testing_float_flag, 2.5,"float-flag") DEFINE_string(testing_string_flag,"Hello, world!","string-flag") DEFINE_int(testing_prng_seed, 42,"Seed used for threading test randomness") DEFINE_string(testing_serialization_file,"/tmp/serdes","file in which to serialize heap") DEFINE_bool(help, false,"Print usage message, including flags, on console") DEFINE_bool(dump_counters, false,"Dump counters on exit") DEFINE_string(map_counters,"","Map counters to a file") DEFINE_args(js_arguments, JSARGUMENTS_INIT,"Pass all remaining arguments to the script. Alias for \"--\".") DEFINE_bool(debug_compile_events, true,"Enable debugger compile events") DEFINE_bool(debug_script_collected_events, true,"Enable debugger script collected events") DEFINE_bool(gdbjit, false,"enable GDBJIT interface (disables compacting GC)") DEFINE_bool(gdbjit_full, false,"enable GDBJIT interface for all code objects") DEFINE_bool(gdbjit_dump, false,"dump elf objects with debug info to disk") DEFINE_string(gdbjit_dump_filter,"","dump only objects containing this substring") DEFINE_bool(force_marking_deque_overflows, false,"force overflows of marking deque by reducing it's size ""to 64 words") DEFINE_bool(stress_compaction, false,"stress the GC compactor to flush out bugs (implies ""--force_marking_deque_overflows)")#define FLAG DEFINE_bool(enable_slow_asserts, false,"enable asserts that are slow to execute") DEFINE_bool(trace_codegen, false,"print name of functions for which code is generated") DEFINE_bool(print_source, false,"pretty print source code") DEFINE_bool(print_builtin_source, false,"pretty print source code for builtins") DEFINE_bool(print_ast, false,"print source AST") DEFINE_bool(print_builtin_ast, false,"print source AST for builtins") DEFINE_string(stop_at,"","function name where to insert a breakpoint") DEFINE_bool(print_builtin_scopes, false,"print scopes for builtins") DEFINE_bool(print_scopes, false,"print scopes") DEFINE_bool(trace_contexts, false,"trace contexts operations") DEFINE_bool(gc_greedy, false,"perform GC prior to some allocations") DEFINE_bool(gc_verbose, false,"print stuff during garbage collection") DEFINE_bool(heap_stats, false,"report heap statistics before and after GC") DEFINE_bool(code_stats, false,"report code statistics after GC") DEFINE_bool(verify_heap, false,"verify heap pointers before and after GC") DEFINE_bool(print_handles, false,"report handles after GC") DEFINE_bool(print_global_handles, false,"report global handles after GC") DEFINE_bool(trace_ic, false,"trace inline cache state transitions") DEFINE_bool(print_interfaces, false,"print interfaces") DEFINE_bool(print_interface_details, false,"print interface inference details") DEFINE_int(print_interface_depth, 5,"depth for printing interfaces") DEFINE_bool(trace_normalization, false,"prints when objects are turned into dictionaries.") DEFINE_bool(trace_lazy, false,"trace lazy compilation") DEFINE_bool(collect_heap_spill_statistics, false,"report heap spill statistics along with heap_stats ""(requires heap_stats)") DEFINE_bool(trace_isolates, false,"trace isolate state changes") DEFINE_bool(log_state_changes, false,"Log state changes.") DEFINE_bool(regexp_possessive_quantifier, false,"enable possessive quantifier syntax for testing") DEFINE_bool(trace_regexp_bytecodes, false,"trace regexp bytecode execution") DEFINE_bool(trace_regexp_assembler, false,"trace regexp macro assembler calls.")#define FLAG DEFINE_bool(log, false,"Minimal logging (no API, code, GC, suspect, or handles samples).") DEFINE_bool(log_all, false,"Log all events to the log file.") DEFINE_bool(log_runtime, false,"Activate runtime system %Log call.") DEFINE_bool(log_api, false,"Log API events to the log file.") DEFINE_bool(log_code, false,"Log code events to the log file without profiling.") DEFINE_bool(log_gc, false,"Log heap samples on garbage collection for the hp2ps tool.") DEFINE_bool(log_handles, false,"Log global handle events.") DEFINE_bool(log_snapshot_positions, false,"log positions of (de)serialized objects in the snapshot.") DEFINE_bool(log_suspect, false,"Log suspect operations.") DEFINE_bool(prof, false,"Log statistical profiling information (implies --log-code).") DEFINE_bool(prof_auto, true,"Used with --prof, starts profiling automatically") DEFINE_bool(prof_lazy, false,"Used with --prof, only does sampling and logging"" when profiler is active (implies --noprof_auto).") DEFINE_bool(prof_browser_mode, true,"Used with --prof, turns on browser-compatible mode for profiling.") DEFINE_bool(log_regexp, false,"Log regular expression execution.") DEFINE_bool(sliding_state_window, false,"Update sliding state window counters.") DEFINE_string(logfile,"v8.log","Specify the name of the log file.") DEFINE_bool(ll_prof, false,"Enable low-level linux profiler.")#define FLAG DEFINE_bool(trace_elements_transitions, false,"trace elements transitions") DEFINE_bool(print_code_stubs, false,"print code stubs") DEFINE_bool(test_secondary_stub_cache, false,"test secondary stub cache by disabling the primary one") DEFINE_bool(test_primary_stub_cache, false,"test primary stub cache by disabling the secondary one") DEFINE_bool(print_code, false,"print generated code") DEFINE_bool(print_opt_code, false,"print optimized code") DEFINE_bool(print_unopt_code, false,"print unoptimized code before ""printing optimized code based on it") DEFINE_bool(print_code_verbose, false,"print more information for code") DEFINE_bool(print_builtin_code, false,"print generated code for builtins")#47"/Users/thlorenz/dev/dx/v8-perf/build/v8/src/flags.cc"2 namespace{struct Flag{enum FlagType{TYPE_BOOL, TYPE_INT, TYPE_FLOAT, TYPE_STRING, TYPE_ARGS} name
Definition: flags.cc:1349
static Handle< T > cast(Handle< S > that)
Definition: handles.h:81
static Vector< const char > GetScriptName(int index)
static V8EXPORT Local< String > New(const char *data, int length=-1)
Definition: api.cc:4655
DebugEvent
Definition: v8-debug.h:73
const int kMaxInt
Definition: globals.h:224
void(* DebugMessageDispatchHandler)()
Definition: v8-debug.h:245
V8EXPORT Local< Value > Call(Handle< Object > recv, int argc, Handle< Value > argv[])
Definition: api.cc:3629
FlagType type_
Definition: flags.cc:1351
#define ASSERT(condition)
Definition: checks.h:270
static const int kPatchReturnSequenceAddressOffset
void Clear()
Definition: v8.h:213
static Script * cast(Object *obj)
void(* MessageHandler2)(const Message &message)
Definition: v8-debug.h:235
unsigned short uint16_t
Definition: unicode.cc:46
static void DeoptimizeAll()
Definition: deoptimizer.cc:249
V8EXPORT Local< String > ToString() const
Definition: api.cc:2305
Handle< Object > GetProperty(Handle< JSReceiver > obj, const char *name)
Definition: handles.cc:282
static Function * Cast(Value *obj)
Definition: v8.h:4402
#define RETURN_IF_EMPTY_HANDLE_VALUE(isolate, call, value)
Definition: isolate.h:119
static Smi * cast(Object *object)
HANDLE HANDLE LPSTACKFRAME64 StackFrame
static void Abort()
#define UNREACHABLE()
Definition: checks.h:50
static const int kNoGCFlags
Definition: heap.h:1049
Handle< JSValue > GetScriptWrapper(Handle< Script > script)
Definition: handles.cc:366
Entry * Lookup(void *key, uint32_t hash, bool insert, FreeStoreAllocationPolicyallocator=FreeStoreAllocationPolicy())
const Register pc
static Mutex * CreateMutex()
static Code * GetCodeFromTargetAddress(Address address)
Definition: objects-inl.h:3380
static const int kMakeHeapIterableMask
Definition: heap.h:1056
static String * Cast(v8::Value *obj)
Definition: v8.h:4242
static const int kCallTargetAddressOffset
bool IsUndefined() const
Definition: v8.h:4277
Handle< Boolean > V8EXPORT False()
Definition: api.cc:576
static Handle< Object > Call(Handle< Object > callable, Handle< Object > receiver, int argc, Handle< Object > argv[], bool *pending_exception, bool convert_receiver=false)
Definition: execution.cc:144
Vector< const char > CStrVector(const char *data)
Definition: utils.h:525
static const int kDebugBreakSlotLength
static Local< Context > ToLocal(v8::internal::Handle< v8::internal::Context > obj)
void(* EventCallback2)(const EventDetails &event_details)
Definition: v8-debug.h:210
static Address target_address_at(Address pc)
void(* HostDispatchHandler)()
Definition: v8-debug.h:240
JavaScriptFrameIteratorTemp< StackFrameIterator > JavaScriptFrameIterator
Definition: frames.h:773
Object * JSCallerSavedBuffer[kNumJSCallerSaved]
Definition: frames-arm.h:55
static Handle< SharedFunctionInfo > Compile(Handle< String > source, Handle< Object > script_name, int line_offset, int column_offset, v8::Extension *extension, ScriptDataImpl *pre_data, Handle< Object > script_data, NativesFlag is_natives_code)
Definition: compiler.cc:473
v8::Handle< v8::Value > Load(const v8::Arguments &args)
Definition: shell.cc:159
static Handle< String > null()
Definition: handles.h:86
activate correct semantics for inheriting readonliness enable harmony semantics for typeof enable harmony enable harmony proxies enable all harmony harmony_scoping harmony_proxies harmony_scoping tracks arrays with only smi values automatically unbox arrays of doubles use crankshaft use hydrogen range analysis use hydrogen global value numbering use function inlining maximum number of AST nodes considered for a single inlining loop invariant code motion print statistics for hydrogen trace generated IR for specified phases trace register allocator trace range analysis trace representation types environment for every instruction put a break point before deoptimizing polymorphic inlining perform array bounds checks elimination trace on stack replacement optimize closures functions with arguments object optimize functions containing for in loops profiler considers IC stability primitive functions trigger their own optimization re try self optimization if it failed insert an interrupt check at function exit execution budget before interrupt is triggered call count before self optimization self_optimization count_based_interrupts weighted_back_edges trace_opt emit comments in code disassembly enable use of SSE3 instructions if available enable use of CMOV instruction if available enable use of SAHF instruction if enable use of VFP3 instructions if available this implies enabling ARMv7 enable use of ARMv7 instructions if enable use of MIPS FPU instructions if NULL
Definition: flags.cc:274
static bool EnsureCompiled(Handle< SharedFunctionInfo > shared, ClearExceptionFlag flag)
Definition: objects.cc:7438
Local< T > Close(Handle< T > value)
Definition: v8.h:4149
static FixedArray * cast(Object *obj)
bool end_
V8EXPORT int WriteAscii(char *buffer, int start=0, int length=-1, int options=NO_OPTIONS) const
Definition: api.cc:3960
static bool CompileLazy(CompilationInfo *info)
Definition: compiler.cc:605
static const int kBoundFunctionIndex
Definition: objects.h:5997
bool IsEmpty() const
Definition: v8.h:208
#define FACTORY
Definition: isolate.h:1409
static const int kMaxInliningLevels
Definition: compiler.h:278
V8EXPORT Local< Boolean > ToBoolean() const
Definition: api.cc:2365
static void DebugBreak(Isolate *isolate=NULL)
const Register fp
static void ReportMessage(Isolate *isolate, MessageLocation *loc, Handle< Object > message)
Definition: messages.cc:103
void DeleteArray(T *array)
Definition: allocation.h:91
static const int kPatchDebugBreakSlotAddressOffset
static void FatalProcessOutOfMemory(const char *location, bool take_snapshot=false)
#define ARRAY_SIZE(a)
Definition: globals.h:295
Definition: v8.h:105
FlagType type() const
Definition: flags.cc:1358
static v8::internal::Handle< v8::internal::TemplateInfo > OpenHandle(const Template *that)
static JSFunction * cast(Object *obj)