Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(364)

Side by Side Diff: src/debug.h

Issue 298863011: Merge the classes Debug and Debugger. (Closed) Base URL: https://v8.googlecode.com/svn/branches/bleeding_edge
Patch Set: Rename EnterDebugger Created 6 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « src/compiler.cc ('k') | src/debug.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2012 the V8 project authors. All rights reserved. 1 // Copyright 2012 the V8 project authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #ifndef V8_DEBUG_H_ 5 #ifndef V8_DEBUG_H_
6 #define V8_DEBUG_H_ 6 #define V8_DEBUG_H_
7 7
8 #include "allocation.h" 8 #include "allocation.h"
9 #include "arguments.h" 9 #include "arguments.h"
10 #include "assembler.h" 10 #include "assembler.h"
11 #include "execution.h" 11 #include "execution.h"
12 #include "factory.h" 12 #include "factory.h"
13 #include "flags.h" 13 #include "flags.h"
14 #include "frames-inl.h" 14 #include "frames-inl.h"
15 #include "hashmap.h" 15 #include "hashmap.h"
16 #include "liveedit.h"
16 #include "platform.h" 17 #include "platform.h"
17 #include "string-stream.h" 18 #include "string-stream.h"
18 #include "v8threads.h" 19 #include "v8threads.h"
19 20
20 #include "../include/v8-debug.h" 21 #include "../include/v8-debug.h"
21 22
22 namespace v8 { 23 namespace v8 {
23 namespace internal { 24 namespace internal {
24 25
25 26
26 // Forward declarations. 27 // Forward declarations.
27 class EnterDebugger; 28 class DebugScope;
28 29
29 30
30 // Step actions. NOTE: These values are in macros.py as well. 31 // Step actions. NOTE: These values are in macros.py as well.
31 enum StepAction { 32 enum StepAction {
32 StepNone = -1, // Stepping not prepared. 33 StepNone = -1, // Stepping not prepared.
33 StepOut = 0, // Step out of the current function. 34 StepOut = 0, // Step out of the current function.
34 StepNext = 1, // Step to the next statement in the current function. 35 StepNext = 1, // Step to the next statement in the current function.
35 StepIn = 2, // Step into new functions invoked or the next statement 36 StepIn = 2, // Step into new functions invoked or the next statement
36 // in the current function. 37 // in the current function.
37 StepMin = 3, // Perform a minimum step in the current function. 38 StepMin = 3, // Perform a minimum step in the current function.
(...skipping 104 matching lines...) Expand 10 before | Expand all | Expand 10 after
142 DISALLOW_COPY_AND_ASSIGN(BreakLocationIterator); 143 DISALLOW_COPY_AND_ASSIGN(BreakLocationIterator);
143 }; 144 };
144 145
145 146
146 // Cache of all script objects in the heap. When a script is added a weak handle 147 // Cache of all script objects in the heap. When a script is added a weak handle
147 // to it is created and that weak handle is stored in the cache. The weak handle 148 // to it is created and that weak handle is stored in the cache. The weak handle
148 // callback takes care of removing the script from the cache. The key used in 149 // callback takes care of removing the script from the cache. The key used in
149 // the cache is the script id. 150 // the cache is the script id.
150 class ScriptCache : private HashMap { 151 class ScriptCache : private HashMap {
151 public: 152 public:
152 explicit ScriptCache(Isolate* isolate) 153 explicit ScriptCache(Isolate* isolate);
153 : HashMap(HashMap::PointersMatch),
154 isolate_(isolate),
155 collected_scripts_(10) {}
156 virtual ~ScriptCache() { Clear(); } 154 virtual ~ScriptCache() { Clear(); }
157 155
158 // Add script to the cache. 156 // Add script to the cache.
159 void Add(Handle<Script> script); 157 void Add(Handle<Script> script);
160 158
161 // Return the scripts in the cache. 159 // Return the scripts in the cache.
162 Handle<FixedArray> GetScripts(); 160 Handle<FixedArray> GetScripts();
163 161
164 // Generate debugger events for collected scripts. 162 // Generate debugger events for collected scripts.
165 void ProcessCollectedScripts(); 163 void ProcessCollectedScripts();
(...skipping 29 matching lines...) Expand all
195 Handle<DebugInfo> debug_info() { return debug_info_; } 193 Handle<DebugInfo> debug_info() { return debug_info_; }
196 194
197 private: 195 private:
198 // Global (weak) handle to the debug info object. 196 // Global (weak) handle to the debug info object.
199 Handle<DebugInfo> debug_info_; 197 Handle<DebugInfo> debug_info_;
200 198
201 // Next pointer for linked list. 199 // Next pointer for linked list.
202 DebugInfoListNode* next_; 200 DebugInfoListNode* next_;
203 }; 201 };
204 202
205 // This class contains the debugger support. The main purpose is to handle
206 // setting break points in the code.
207 //
208 // This class controls the debug info for all functions which currently have
209 // active breakpoints in them. This debug info is held in the heap root object
210 // debug_info which is a FixedArray. Each entry in this list is of class
211 // DebugInfo.
212 class Debug {
213 public:
214 bool Load();
215 void Unload();
216 bool IsLoaded() { return !debug_context_.is_null(); }
217 bool InDebugger() { return thread_local_.debugger_entry_ != NULL; }
218
219 Object* Break(Arguments args);
220 bool SetBreakPoint(Handle<JSFunction> function,
221 Handle<Object> break_point_object,
222 int* source_position);
223 bool SetBreakPointForScript(Handle<Script> script,
224 Handle<Object> break_point_object,
225 int* source_position,
226 BreakPositionAlignment alignment);
227 void ClearBreakPoint(Handle<Object> break_point_object);
228 void ClearAllBreakPoints();
229 void FloodWithOneShot(Handle<JSFunction> function);
230 void FloodBoundFunctionWithOneShot(Handle<JSFunction> function);
231 void FloodHandlerWithOneShot();
232 void ChangeBreakOnException(ExceptionBreakType type, bool enable);
233 bool IsBreakOnException(ExceptionBreakType type);
234
235 void PromiseHandlePrologue(Handle<JSFunction> promise_getter);
236 void PromiseHandleEpilogue();
237 // Returns a promise if it does not have a reject handler.
238 Handle<Object> GetPromiseForUncaughtException();
239
240 void PrepareStep(StepAction step_action,
241 int step_count,
242 StackFrame::Id frame_id);
243 void ClearStepping();
244 void ClearStepOut();
245 bool IsStepping() { return thread_local_.step_count_ > 0; }
246 bool StepNextContinue(BreakLocationIterator* break_location_iterator,
247 JavaScriptFrame* frame);
248 static Handle<DebugInfo> GetDebugInfo(Handle<SharedFunctionInfo> shared);
249 static bool HasDebugInfo(Handle<SharedFunctionInfo> shared);
250
251 void PrepareForBreakPoints();
252
253 // This function is used in FunctionNameUsing* tests.
254 Object* FindSharedFunctionInfoInScript(Handle<Script> script, int position);
255
256 // Returns whether the operation succeeded. Compilation can only be triggered
257 // if a valid closure is passed as the second argument, otherwise the shared
258 // function needs to be compiled already.
259 bool EnsureDebugInfo(Handle<SharedFunctionInfo> shared,
260 Handle<JSFunction> function);
261
262 // Returns true if the current stub call is patched to call the debugger.
263 static bool IsDebugBreak(Address addr);
264 // Returns true if the current return statement has been patched to be
265 // a debugger breakpoint.
266 static bool IsDebugBreakAtReturn(RelocInfo* rinfo);
267
268 // Check whether a code stub with the specified major key is a possible break
269 // point location.
270 static bool IsSourceBreakStub(Code* code);
271 static bool IsBreakStub(Code* code);
272
273 // Find the builtin to use for invoking the debug break
274 static Handle<Code> FindDebugBreak(Handle<Code> code, RelocInfo::Mode mode);
275
276 static Handle<Object> GetSourceBreakLocations(
277 Handle<SharedFunctionInfo> shared,
278 BreakPositionAlignment position_aligment);
279
280 // Getter for the debug_context.
281 inline Handle<Context> debug_context() { return debug_context_; }
282
283 // Check whether a global object is the debug global object.
284 bool IsDebugGlobal(GlobalObject* global);
285
286 // Check whether this frame is just about to return.
287 bool IsBreakAtReturn(JavaScriptFrame* frame);
288
289 // Fast check to see if any break points are active.
290 inline bool has_break_points() { return has_break_points_; }
291
292 void NewBreak(StackFrame::Id break_frame_id);
293 void SetBreak(StackFrame::Id break_frame_id, int break_id);
294 StackFrame::Id break_frame_id() {
295 return thread_local_.break_frame_id_;
296 }
297 int break_id() { return thread_local_.break_id_; }
298
299 bool StepInActive() { return thread_local_.step_into_fp_ != 0; }
300 void HandleStepIn(Handle<JSFunction> function,
301 Handle<Object> holder,
302 Address fp,
303 bool is_constructor);
304 Address step_in_fp() { return thread_local_.step_into_fp_; }
305 Address* step_in_fp_addr() { return &thread_local_.step_into_fp_; }
306
307 bool StepOutActive() { return thread_local_.step_out_fp_ != 0; }
308 Address step_out_fp() { return thread_local_.step_out_fp_; }
309
310 EnterDebugger* debugger_entry() {
311 return thread_local_.debugger_entry_;
312 }
313 void set_debugger_entry(EnterDebugger* entry) {
314 thread_local_.debugger_entry_ = entry;
315 }
316
317 // Check whether any of the specified interrupts are pending.
318 bool has_pending_interrupt() {
319 return thread_local_.has_pending_interrupt_;
320 }
321
322 // Set specified interrupts as pending.
323 void set_has_pending_interrupt(bool value) {
324 thread_local_.has_pending_interrupt_ = value;
325 }
326
327 // Getter and setter for the disable break state.
328 bool disable_break() { return disable_break_; }
329 void set_disable_break(bool disable_break) {
330 disable_break_ = disable_break;
331 }
332
333 // Getters for the current exception break state.
334 bool break_on_exception() { return break_on_exception_; }
335 bool break_on_uncaught_exception() {
336 return break_on_uncaught_exception_;
337 }
338
339 enum AddressId {
340 k_after_break_target_address,
341 k_restarter_frame_function_pointer
342 };
343
344 // Support for setting the address to jump to when returning from break point.
345 Address after_break_target_address() {
346 return reinterpret_cast<Address>(&thread_local_.after_break_target_);
347 }
348
349 Address restarter_frame_function_pointer_address() {
350 Object*** address = &thread_local_.restarter_frame_function_pointer_;
351 return reinterpret_cast<Address>(address);
352 }
353
354 static const int kEstimatedNofDebugInfoEntries = 16;
355 static const int kEstimatedNofBreakPointsInFunction = 16;
356
357 // Passed to MakeWeak.
358 static void HandleWeakDebugInfo(
359 const v8::WeakCallbackData<v8::Value, void>& data);
360
361 friend class Debugger;
362 friend Handle<FixedArray> GetDebuggedFunctions(); // In test-debug.cc
363 friend void CheckDebuggerUnloaded(bool check_functions); // In test-debug.cc
364
365 // Threading support.
366 char* ArchiveDebug(char* to);
367 char* RestoreDebug(char* from);
368 static int ArchiveSpacePerThread();
369 void FreeThreadResources() { }
370
371 // Mirror cache handling.
372 void ClearMirrorCache();
373
374 // Script cache handling.
375 void CreateScriptCache();
376 void DestroyScriptCache();
377 void AddScriptToScriptCache(Handle<Script> script);
378 Handle<FixedArray> GetLoadedScripts();
379
380 // Record function from which eval was called.
381 static void RecordEvalCaller(Handle<Script> script);
382
383 // Garbage collection notifications.
384 void AfterGarbageCollection();
385
386 // Code generator routines.
387 static void GenerateSlot(MacroAssembler* masm);
388 static void GenerateCallICStubDebugBreak(MacroAssembler* masm);
389 static void GenerateLoadICDebugBreak(MacroAssembler* masm);
390 static void GenerateStoreICDebugBreak(MacroAssembler* masm);
391 static void GenerateKeyedLoadICDebugBreak(MacroAssembler* masm);
392 static void GenerateKeyedStoreICDebugBreak(MacroAssembler* masm);
393 static void GenerateCompareNilICDebugBreak(MacroAssembler* masm);
394 static void GenerateReturnDebugBreak(MacroAssembler* masm);
395 static void GenerateCallFunctionStubDebugBreak(MacroAssembler* masm);
396 static void GenerateCallConstructStubDebugBreak(MacroAssembler* masm);
397 static void GenerateCallConstructStubRecordDebugBreak(MacroAssembler* masm);
398 static void GenerateSlotDebugBreak(MacroAssembler* masm);
399 static void GeneratePlainReturnLiveEdit(MacroAssembler* masm);
400
401 // FrameDropper is a code replacement for a JavaScript frame with possibly
402 // several frames above.
403 // There is no calling conventions here, because it never actually gets
404 // called, it only gets returned to.
405 static void GenerateFrameDropperLiveEdit(MacroAssembler* masm);
406
407 // Describes how exactly a frame has been dropped from stack.
408 enum FrameDropMode {
409 // No frame has been dropped.
410 FRAMES_UNTOUCHED,
411 // The top JS frame had been calling IC stub. IC stub mustn't be called now.
412 FRAME_DROPPED_IN_IC_CALL,
413 // The top JS frame had been calling debug break slot stub. Patch the
414 // address this stub jumps to in the end.
415 FRAME_DROPPED_IN_DEBUG_SLOT_CALL,
416 // The top JS frame had been calling some C++ function. The return address
417 // gets patched automatically.
418 FRAME_DROPPED_IN_DIRECT_CALL,
419 FRAME_DROPPED_IN_RETURN_CALL,
420 CURRENTLY_SET_MODE
421 };
422
423 void FramesHaveBeenDropped(StackFrame::Id new_break_frame_id,
424 FrameDropMode mode,
425 Object** restarter_frame_function_pointer);
426
427 // Initializes an artificial stack frame. The data it contains is used for:
428 // a. successful work of frame dropper code which eventually gets control,
429 // b. being compatible with regular stack structure for various stack
430 // iterators.
431 // Returns address of stack allocated pointer to restarted function,
432 // the value that is called 'restarter_frame_function_pointer'. The value
433 // at this address (possibly updated by GC) may be used later when preparing
434 // 'step in' operation.
435 static Object** SetUpFrameDropperFrame(StackFrame* bottom_js_frame,
436 Handle<Code> code);
437
438 static const int kFrameDropperFrameSize;
439
440 // Architecture-specific constant.
441 static const bool kFrameDropperSupported;
442
443 /**
444 * Defines layout of a stack frame that supports padding. This is a regular
445 * internal frame that has a flexible stack structure. LiveEdit can shift
446 * its lower part up the stack, taking up the 'padding' space when additional
447 * stack memory is required.
448 * Such frame is expected immediately above the topmost JavaScript frame.
449 *
450 * Stack Layout:
451 * --- Top
452 * LiveEdit routine frames
453 * ---
454 * C frames of debug handler
455 * ---
456 * ...
457 * ---
458 * An internal frame that has n padding words:
459 * - any number of words as needed by code -- upper part of frame
460 * - padding size: a Smi storing n -- current size of padding
461 * - padding: n words filled with kPaddingValue in form of Smi
462 * - 3 context/type words of a regular InternalFrame
463 * - fp
464 * ---
465 * Topmost JavaScript frame
466 * ---
467 * ...
468 * --- Bottom
469 */
470 class FramePaddingLayout : public AllStatic {
471 public:
472 // Architecture-specific constant.
473 static const bool kIsSupported;
474
475 // A size of frame base including fp. Padding words starts right above
476 // the base.
477 static const int kFrameBaseSize = 4;
478
479 // A number of words that should be reserved on stack for the LiveEdit use.
480 // Normally equals 1. Stored on stack in form of Smi.
481 static const int kInitialSize;
482 // A value that padding words are filled with (in form of Smi). Going
483 // bottom-top, the first word not having this value is a counter word.
484 static const int kPaddingValue;
485 };
486
487 private:
488 explicit Debug(Isolate* isolate);
489
490 static bool CompileDebuggerScript(Isolate* isolate, int index);
491 void ClearOneShot();
492 void ActivateStepIn(StackFrame* frame);
493 void ClearStepIn();
494 void ActivateStepOut(StackFrame* frame);
495 void ClearStepNext();
496 // Returns whether the compile succeeded.
497 void RemoveDebugInfo(Handle<DebugInfo> debug_info);
498 void SetAfterBreakTarget(JavaScriptFrame* frame);
499 Handle<Object> CheckBreakPoints(Handle<Object> break_point);
500 bool CheckBreakPoint(Handle<Object> break_point_object);
501
502 void EnsureFunctionHasDebugBreakSlots(Handle<JSFunction> function);
503 void RecompileAndRelocateSuspendedGenerators(
504 const List<Handle<JSGeneratorObject> > &suspended_generators);
505
506 // Global handle to debug context where all the debugger JavaScript code is
507 // loaded.
508 Handle<Context> debug_context_;
509
510 // Boolean state indicating whether any break points are set.
511 bool has_break_points_;
512
513 // Cache of all scripts in the heap.
514 ScriptCache* script_cache_;
515
516 // List of active debug info objects.
517 DebugInfoListNode* debug_info_list_;
518
519 bool disable_break_;
520 bool break_on_exception_;
521 bool break_on_uncaught_exception_;
522
523 class PromiseOnStack {
524 public:
525 PromiseOnStack(Isolate* isolate,
526 PromiseOnStack* prev,
527 Handle<JSFunction> getter);
528 ~PromiseOnStack();
529 StackHandler* handler() { return handler_; }
530 Handle<JSFunction> getter() { return getter_; }
531 PromiseOnStack* prev() { return prev_; }
532 private:
533 Isolate* isolate_;
534 StackHandler* handler_;
535 Handle<JSFunction> getter_;
536 PromiseOnStack* prev_;
537 };
538
539 // Per-thread data.
540 class ThreadLocal {
541 public:
542 // Counter for generating next break id.
543 int break_count_;
544
545 // Current break id.
546 int break_id_;
547
548 // Frame id for the frame of the current break.
549 StackFrame::Id break_frame_id_;
550
551 // Step action for last step performed.
552 StepAction last_step_action_;
553
554 // Source statement position from last step next action.
555 int last_statement_position_;
556
557 // Number of steps left to perform before debug event.
558 int step_count_;
559
560 // Frame pointer from last step next action.
561 Address last_fp_;
562
563 // Number of queued steps left to perform before debug event.
564 int queued_step_count_;
565
566 // Frame pointer for frame from which step in was performed.
567 Address step_into_fp_;
568
569 // Frame pointer for the frame where debugger should be called when current
570 // step out action is completed.
571 Address step_out_fp_;
572
573 // Storage location for jump when exiting debug break calls.
574 Address after_break_target_;
575
576 // Stores the way how LiveEdit has patched the stack. It is used when
577 // debugger returns control back to user script.
578 FrameDropMode frame_drop_mode_;
579
580 // Top debugger entry.
581 EnterDebugger* debugger_entry_;
582
583 // Pending interrupts scheduled while debugging.
584 bool has_pending_interrupt_;
585
586 // When restarter frame is on stack, stores the address
587 // of the pointer to function being restarted. Otherwise (most of the time)
588 // stores NULL. This pointer is used with 'step in' implementation.
589 Object** restarter_frame_function_pointer_;
590
591 // When a promise is being resolved, we may want to trigger a debug event
592 // if we catch a throw. For this purpose we remember the try-catch
593 // handler address that would catch the exception. We also hold onto a
594 // closure that returns a promise if the exception is considered uncaught.
595 // Due to the possibility of reentry we use a linked list.
596 PromiseOnStack* promise_on_stack_;
597 };
598
599 // Storage location for registers when handling debug break calls
600 ThreadLocal thread_local_;
601 void ThreadInit();
602
603 Isolate* isolate_;
604
605 friend class Isolate;
606
607 DISALLOW_COPY_AND_ASSIGN(Debug);
608 };
609
610
611 DECLARE_RUNTIME_FUNCTION(Debug_Break);
612 203
613 204
614 // Message delivered to the message handler callback. This is either a debugger 205 // Message delivered to the message handler callback. This is either a debugger
615 // event or the response to a command. 206 // event or the response to a command.
616 class MessageImpl: public v8::Debug::Message { 207 class MessageImpl: public v8::Debug::Message {
617 public: 208 public:
618 // Create a message object for a debug event. 209 // Create a message object for a debug event.
619 static MessageImpl NewEvent(DebugEvent event, 210 static MessageImpl NewEvent(DebugEvent event,
620 bool running, 211 bool running,
621 Handle<JSObject> exec_state, 212 Handle<JSObject> exec_state,
(...skipping 64 matching lines...) Expand 10 before | Expand all | Expand 10 after
686 277
687 // Message send by user to v8 debugger or debugger output message. 278 // Message send by user to v8 debugger or debugger output message.
688 // In addition to command text it may contain a pointer to some user data 279 // In addition to command text it may contain a pointer to some user data
689 // which are expected to be passed along with the command reponse to message 280 // which are expected to be passed along with the command reponse to message
690 // handler. 281 // handler.
691 class CommandMessage { 282 class CommandMessage {
692 public: 283 public:
693 static CommandMessage New(const Vector<uint16_t>& command, 284 static CommandMessage New(const Vector<uint16_t>& command,
694 v8::Debug::ClientData* data); 285 v8::Debug::ClientData* data);
695 CommandMessage(); 286 CommandMessage();
696 ~CommandMessage();
697 287
698 // Deletes user data and disposes of the text. 288 // Deletes user data and disposes of the text.
699 void Dispose(); 289 void Dispose();
700 Vector<uint16_t> text() const { return text_; } 290 Vector<uint16_t> text() const { return text_; }
701 v8::Debug::ClientData* client_data() const { return client_data_; } 291 v8::Debug::ClientData* client_data() const { return client_data_; }
702 private: 292 private:
703 CommandMessage(const Vector<uint16_t>& text, 293 CommandMessage(const Vector<uint16_t>& text,
704 v8::Debug::ClientData* data); 294 v8::Debug::ClientData* data);
705 295
706 Vector<uint16_t> text_; 296 Vector<uint16_t> text_;
707 v8::Debug::ClientData* client_data_; 297 v8::Debug::ClientData* client_data_;
708 }; 298 };
709 299
300
710 // A Queue of CommandMessage objects. A thread-safe version is 301 // A Queue of CommandMessage objects. A thread-safe version is
711 // LockingCommandMessageQueue, based on this class. 302 // LockingCommandMessageQueue, based on this class.
712 class CommandMessageQueue BASE_EMBEDDED { 303 class CommandMessageQueue BASE_EMBEDDED {
713 public: 304 public:
714 explicit CommandMessageQueue(int size); 305 explicit CommandMessageQueue(int size);
715 ~CommandMessageQueue(); 306 ~CommandMessageQueue();
716 bool IsEmpty() const { return start_ == end_; } 307 bool IsEmpty() const { return start_ == end_; }
717 CommandMessage Get(); 308 CommandMessage Get();
718 void Put(const CommandMessage& message); 309 void Put(const CommandMessage& message);
719 void Clear() { start_ = end_ = 0; } // Queue is empty after Clear(). 310 void Clear() { start_ = end_ = 0; } // Queue is empty after Clear().
720 private: 311 private:
721 // Doubles the size of the message queue, and copies the messages. 312 // Doubles the size of the message queue, and copies the messages.
722 void Expand(); 313 void Expand();
723 314
724 CommandMessage* messages_; 315 CommandMessage* messages_;
725 int start_; 316 int start_;
726 int end_; 317 int end_;
727 int size_; // The size of the queue buffer. Queue can hold size-1 messages. 318 int size_; // The size of the queue buffer. Queue can hold size-1 messages.
728 }; 319 };
729 320
730 321
731 class MessageDispatchHelperThread;
732
733
734 // LockingCommandMessageQueue is a thread-safe circular buffer of CommandMessage 322 // LockingCommandMessageQueue is a thread-safe circular buffer of CommandMessage
735 // messages. The message data is not managed by LockingCommandMessageQueue. 323 // messages. The message data is not managed by LockingCommandMessageQueue.
736 // Pointers to the data are passed in and out. Implemented by adding a 324 // Pointers to the data are passed in and out. Implemented by adding a
737 // Mutex to CommandMessageQueue. Includes logging of all puts and gets. 325 // Mutex to CommandMessageQueue. Includes logging of all puts and gets.
738 class LockingCommandMessageQueue BASE_EMBEDDED { 326 class LockingCommandMessageQueue BASE_EMBEDDED {
739 public: 327 public:
740 LockingCommandMessageQueue(Logger* logger, int size); 328 LockingCommandMessageQueue(Logger* logger, int size);
741 bool IsEmpty() const; 329 bool IsEmpty() const;
742 CommandMessage Get(); 330 CommandMessage Get();
743 void Put(const CommandMessage& message); 331 void Put(const CommandMessage& message);
744 void Clear(); 332 void Clear();
745 private: 333 private:
746 Logger* logger_; 334 Logger* logger_;
747 CommandMessageQueue queue_; 335 CommandMessageQueue queue_;
748 mutable Mutex mutex_; 336 mutable Mutex mutex_;
749 DISALLOW_COPY_AND_ASSIGN(LockingCommandMessageQueue); 337 DISALLOW_COPY_AND_ASSIGN(LockingCommandMessageQueue);
750 }; 338 };
751 339
752 340
753 class Debugger { 341 class PromiseOnStack {
754 public: 342 public:
755 void OnDebugBreak(Handle<Object> break_points_hit, bool auto_continue); 343 PromiseOnStack(Isolate* isolate,
756 void OnException(Handle<Object> exception, bool uncaught); 344 PromiseOnStack* prev,
757 void OnBeforeCompile(Handle<Script> script); 345 Handle<JSFunction> getter);
758 346 ~PromiseOnStack();
347 StackHandler* handler() { return handler_; }
348 Handle<JSFunction> getter() { return getter_; }
349 PromiseOnStack* prev() { return prev_; }
350 private:
351 Isolate* isolate_;
352 StackHandler* handler_;
353 Handle<JSFunction> getter_;
354 PromiseOnStack* prev_;
355 };
356
357
358 // This class contains the debugger support. The main purpose is to handle
359 // setting break points in the code.
360 //
361 // This class controls the debug info for all functions which currently have
362 // active breakpoints in them. This debug info is held in the heap root object
363 // debug_info which is a FixedArray. Each entry in this list is of class
364 // DebugInfo.
365 class Debug {
366 public:
759 enum AfterCompileFlags { 367 enum AfterCompileFlags {
760 NO_AFTER_COMPILE_FLAGS, 368 NO_AFTER_COMPILE_FLAGS,
761 SEND_WHEN_DEBUGGING 369 SEND_WHEN_DEBUGGING
762 }; 370 };
371
372 // Debug event triggers.
373 void OnDebugBreak(Handle<Object> break_points_hit, bool auto_continue);
374 void OnException(Handle<Object> exception, bool uncaught);
375 void OnBeforeCompile(Handle<Script> script);
763 void OnAfterCompile(Handle<Script> script, 376 void OnAfterCompile(Handle<Script> script,
764 AfterCompileFlags after_compile_flags); 377 AfterCompileFlags after_compile_flags);
765 void OnScriptCollected(int id); 378 void OnScriptCollected(int id);
766 379
380 // API facing.
767 void SetEventListener(Handle<Object> callback, Handle<Object> data); 381 void SetEventListener(Handle<Object> callback, Handle<Object> data);
768 void SetMessageHandler(v8::Debug::MessageHandler handler); 382 void SetMessageHandler(v8::Debug::MessageHandler handler);
769
770 // Add a debugger command to the command queue.
771 void EnqueueCommandMessage(Vector<const uint16_t> command, 383 void EnqueueCommandMessage(Vector<const uint16_t> command,
772 v8::Debug::ClientData* client_data = NULL); 384 v8::Debug::ClientData* client_data = NULL);
773
774 // Check whether there are commands in the command queue.
775 bool HasCommands();
776
777 // Enqueue a debugger command to the command queue for event listeners. 385 // Enqueue a debugger command to the command queue for event listeners.
778 void EnqueueDebugCommand(v8::Debug::ClientData* client_data = NULL); 386 void EnqueueDebugCommand(v8::Debug::ClientData* client_data = NULL);
779
780 MUST_USE_RESULT MaybeHandle<Object> Call(Handle<JSFunction> fun, 387 MUST_USE_RESULT MaybeHandle<Object> Call(Handle<JSFunction> fun,
781 Handle<Object> data); 388 Handle<Object> data);
782
783 Handle<Context> GetDebugContext(); 389 Handle<Context> GetDebugContext();
784 390 void HandleDebugBreak();
785 bool ignore_debugger() const { return ignore_debugger_; } 391 void ProcessDebugMessages(bool debug_command_only);
392
393 // Internal logic
394 bool Load();
395 void Break(Arguments args, JavaScriptFrame*);
396 void SetAfterBreakTarget(JavaScriptFrame* frame);
397
398 // Scripts handling.
399 Handle<FixedArray> GetLoadedScripts();
400
401 // Break point handling.
402 bool SetBreakPoint(Handle<JSFunction> function,
403 Handle<Object> break_point_object,
404 int* source_position);
405 bool SetBreakPointForScript(Handle<Script> script,
406 Handle<Object> break_point_object,
407 int* source_position,
408 BreakPositionAlignment alignment);
409 void ClearBreakPoint(Handle<Object> break_point_object);
410 void ClearAllBreakPoints();
411 void FloodWithOneShot(Handle<JSFunction> function);
412 void FloodBoundFunctionWithOneShot(Handle<JSFunction> function);
413 void FloodHandlerWithOneShot();
414 void ChangeBreakOnException(ExceptionBreakType type, bool enable);
415 bool IsBreakOnException(ExceptionBreakType type);
416
417 // Stepping handling.
418 void PrepareStep(StepAction step_action,
419 int step_count,
420 StackFrame::Id frame_id);
421 void ClearStepping();
422 void ClearStepOut();
423 bool IsStepping() { return thread_local_.step_count_ > 0; }
424 bool StepNextContinue(BreakLocationIterator* break_location_iterator,
425 JavaScriptFrame* frame);
426 bool StepInActive() { return thread_local_.step_into_fp_ != 0; }
427 void HandleStepIn(Handle<JSFunction> function,
428 Handle<Object> holder,
429 Address fp,
430 bool is_constructor);
431 bool StepOutActive() { return thread_local_.step_out_fp_ != 0; }
432
433 // Purge all code objects that have no debug break slots.
434 void PrepareForBreakPoints();
435
436 // Returns whether the operation succeeded. Compilation can only be triggered
437 // if a valid closure is passed as the second argument, otherwise the shared
438 // function needs to be compiled already.
439 bool EnsureDebugInfo(Handle<SharedFunctionInfo> shared,
440 Handle<JSFunction> function);
441 static Handle<DebugInfo> GetDebugInfo(Handle<SharedFunctionInfo> shared);
442 static bool HasDebugInfo(Handle<SharedFunctionInfo> shared);
443
444 // This function is used in FunctionNameUsing* tests.
445 Object* FindSharedFunctionInfoInScript(Handle<Script> script, int position);
446
447 // Returns true if the current stub call is patched to call the debugger.
448 static bool IsDebugBreak(Address addr);
449 // Returns true if the current return statement has been patched to be
450 // a debugger breakpoint.
451 static bool IsDebugBreakAtReturn(RelocInfo* rinfo);
452
453 static Handle<Object> GetSourceBreakLocations(
454 Handle<SharedFunctionInfo> shared,
455 BreakPositionAlignment position_aligment);
456
457 // Check whether a global object is the debug global object.
458 bool IsDebugGlobal(GlobalObject* global);
459
460 // Check whether this frame is just about to return.
461 bool IsBreakAtReturn(JavaScriptFrame* frame);
462
463 // Promise handling.
464 void PromiseHandlePrologue(Handle<JSFunction> promise_getter);
465 void PromiseHandleEpilogue();
466
467 // Support for LiveEdit
468 void FramesHaveBeenDropped(StackFrame::Id new_break_frame_id,
469 LiveEdit::FrameDropMode mode,
470 Object** restarter_frame_function_pointer);
471
472 // Passed to MakeWeak.
473 static void HandleWeakDebugInfo(
474 const v8::WeakCallbackData<v8::Value, void>& data);
475
476 // Threading support.
477 char* ArchiveDebug(char* to);
478 char* RestoreDebug(char* from);
479 static int ArchiveSpacePerThread();
480 void FreeThreadResources() { }
481
482 // Record function from which eval was called.
483 static void RecordEvalCaller(Handle<Script> script);
484
485 // Garbage collection notifications.
486 void AfterGarbageCollection();
487
488 // Flags and states.
489 DebugScope* debugger_entry() { return thread_local_.current_debug_scope_; }
490 inline Handle<Context> debug_context() { return debug_context_; }
786 void set_live_edit_enabled(bool v) { live_edit_enabled_ = v; } 491 void set_live_edit_enabled(bool v) { live_edit_enabled_ = v; }
787 bool live_edit_enabled() const { 492 bool live_edit_enabled() const {
788 return FLAG_enable_liveedit && live_edit_enabled_ ; 493 return FLAG_enable_liveedit && live_edit_enabled_ ;
789 } 494 }
790 495
791 bool is_active() { return is_active_; } 496 inline bool is_active() const { return is_active_; }
792 497 inline bool is_loaded() const { return !debug_context_.is_null(); }
793 class IgnoreScope { 498 inline bool has_break_points() const { return has_break_points_; }
794 public: 499 inline bool in_debug_scope() const {
795 explicit IgnoreScope(Debugger* debugger) 500 return thread_local_.current_debug_scope_ != NULL;
796 : debugger_(debugger), 501 }
797 old_state_(debugger_->ignore_debugger_) { 502 void set_disable_break(bool v) { break_disabled_ = v; }
798 debugger_->ignore_debugger_ = true; 503
799 } 504 StackFrame::Id break_frame_id() { return thread_local_.break_frame_id_; }
800 505 int break_id() { return thread_local_.break_id_; }
801 ~IgnoreScope() { 506
802 debugger_->ignore_debugger_ = old_state_; 507 // Support for embedding into generated code.
803 } 508 Address after_break_target_address() {
804 509 return reinterpret_cast<Address>(&after_break_target_);
805 private: 510 }
806 Debugger* debugger_; 511
807 bool old_state_; 512 Address restarter_frame_function_pointer_address() {
808 DISALLOW_COPY_AND_ASSIGN(IgnoreScope); 513 Object*** address = &thread_local_.restarter_frame_function_pointer_;
809 }; 514 return reinterpret_cast<Address>(address);
515 }
516
517 Address step_in_fp_addr() {
518 return reinterpret_cast<Address>(&thread_local_.step_into_fp_);
519 }
810 520
811 private: 521 private:
812 explicit Debugger(Isolate* isolate); 522 explicit Debug(Isolate* isolate);
813 ~Debugger(); 523
814 524 void UpdateState();
525 void Unload();
526 void SetNextBreakId() {
527 thread_local_.break_id_ = ++thread_local_.break_count_;
528 }
529
530 // Check whether there are commands in the command queue.
531 inline bool has_commands() const { return !command_queue_.IsEmpty(); }
532 inline bool ignore_events() const { return is_suppressed_ || !is_active_; }
533
534 // Constructors for debug event objects.
815 MUST_USE_RESULT MaybeHandle<Object> MakeJSObject( 535 MUST_USE_RESULT MaybeHandle<Object> MakeJSObject(
816 Vector<const char> constructor_name, 536 const char* constructor_name,
817 int argc, 537 int argc,
818 Handle<Object> argv[]); 538 Handle<Object> argv[]);
819 MUST_USE_RESULT MaybeHandle<Object> MakeExecutionState(); 539 MUST_USE_RESULT MaybeHandle<Object> MakeExecutionState();
820 MUST_USE_RESULT MaybeHandle<Object> MakeBreakEvent( 540 MUST_USE_RESULT MaybeHandle<Object> MakeBreakEvent(
821 Handle<Object> break_points_hit); 541 Handle<Object> break_points_hit);
822 MUST_USE_RESULT MaybeHandle<Object> MakeExceptionEvent( 542 MUST_USE_RESULT MaybeHandle<Object> MakeExceptionEvent(
823 Handle<Object> exception, 543 Handle<Object> exception,
824 bool uncaught, 544 bool uncaught,
825 Handle<Object> promise); 545 Handle<Object> promise);
826 MUST_USE_RESULT MaybeHandle<Object> MakeCompileEvent( 546 MUST_USE_RESULT MaybeHandle<Object> MakeCompileEvent(
827 Handle<Script> script, bool before); 547 Handle<Script> script, bool before);
828 MUST_USE_RESULT MaybeHandle<Object> MakeScriptCollectedEvent(int id); 548 MUST_USE_RESULT MaybeHandle<Object> MakeScriptCollectedEvent(int id);
829 549
550 // Mirror cache handling.
551 void ClearMirrorCache();
552
553 // Returns a promise if it does not have a reject handler.
554 Handle<Object> GetPromiseForUncaughtException();
555
830 void CallEventCallback(v8::DebugEvent event, 556 void CallEventCallback(v8::DebugEvent event,
831 Handle<Object> exec_state, 557 Handle<Object> exec_state,
832 Handle<Object> event_data, 558 Handle<Object> event_data,
833 v8::Debug::ClientData* client_data); 559 v8::Debug::ClientData* client_data);
834 void CallCEventCallback(v8::DebugEvent event,
835 Handle<Object> exec_state,
836 Handle<Object> event_data,
837 v8::Debug::ClientData* client_data);
838 void CallJSEventCallback(v8::DebugEvent event,
839 Handle<Object> exec_state,
840 Handle<Object> event_data);
841 void UpdateState();
842
843 void ProcessDebugEvent(v8::DebugEvent event, 560 void ProcessDebugEvent(v8::DebugEvent event,
844 Handle<JSObject> event_data, 561 Handle<JSObject> event_data,
845 bool auto_continue); 562 bool auto_continue);
846 void NotifyMessageHandler(v8::DebugEvent event, 563 void NotifyMessageHandler(v8::DebugEvent event,
847 Handle<JSObject> exec_state, 564 Handle<JSObject> exec_state,
848 Handle<JSObject> event_data, 565 Handle<JSObject> event_data,
849 bool auto_continue); 566 bool auto_continue);
850
851 // Invoke the message handler function.
852 void InvokeMessageHandler(MessageImpl message); 567 void InvokeMessageHandler(MessageImpl message);
853 568
854 inline bool EventActive() { 569 static bool CompileDebuggerScript(Isolate* isolate, int index);
855 // Check whether the message handler was been cleared. 570 void ClearOneShot();
856 // TODO(yangguo): handle loading and unloading of the debugger differently. 571 void ActivateStepIn(StackFrame* frame);
857 // Currently argument event is not used. 572 void ClearStepIn();
858 return !ignore_debugger_ && is_active_; 573 void ActivateStepOut(StackFrame* frame);
574 void ClearStepNext();
575 // Returns whether the compile succeeded.
576 void RemoveDebugInfo(Handle<DebugInfo> debug_info);
577 Handle<Object> CheckBreakPoints(Handle<Object> break_point);
578 bool CheckBreakPoint(Handle<Object> break_point_object);
579
580 inline void AssertDebugContext() {
581 ASSERT(isolate_->context() == *debug_context());
582 ASSERT(in_debug_scope());
859 } 583 }
860 584
861 Handle<Object> event_listener_; // Global handle to listener. 585 void ThreadInit();
586
587 // Global handles.
588 Handle<Context> debug_context_;
589 Handle<Object> event_listener_;
862 Handle<Object> event_listener_data_; 590 Handle<Object> event_listener_data_;
591
592 v8::Debug::MessageHandler message_handler_;
593
594 static const int kQueueInitialSize = 4;
595 Semaphore command_received_; // Signaled for each command received.
596 LockingCommandMessageQueue command_queue_;
597 LockingCommandMessageQueue event_command_queue_;
598
863 bool is_active_; 599 bool is_active_;
864 bool ignore_debugger_; // Are we temporarily ignoring the debugger? 600 bool is_suppressed_;
865 bool live_edit_enabled_; // Enable LiveEdit. 601 bool live_edit_enabled_;
866 v8::Debug::MessageHandler message_handler_; 602 bool has_break_points_;
867 bool debugger_unload_pending_; // Was message handler cleared? 603 bool break_disabled_;
868 604 bool break_on_exception_;
869 static const int kQueueInitialSize = 4; 605 bool break_on_uncaught_exception_;
870 LockingCommandMessageQueue command_queue_; 606
871 Semaphore command_received_; // Signaled for each command received. 607 ScriptCache* script_cache_; // Cache of all scripts in the heap.
872 LockingCommandMessageQueue event_command_queue_; 608 DebugInfoListNode* debug_info_list_; // List of active debug info objects.
609
610 // Storage location for jump when exiting debug break calls.
611 // Note that this address is not GC safe. It should be computed immediately
612 // before returning to the DebugBreakCallHelper.
613 Address after_break_target_;
614
615 // Per-thread data.
616 class ThreadLocal {
617 public:
618 // Top debugger entry.
619 DebugScope* current_debug_scope_;
620
621 // Counter for generating next break id.
622 int break_count_;
623
624 // Current break id.
625 int break_id_;
626
627 // Frame id for the frame of the current break.
628 StackFrame::Id break_frame_id_;
629
630 // Step action for last step performed.
631 StepAction last_step_action_;
632
633 // Source statement position from last step next action.
634 int last_statement_position_;
635
636 // Number of steps left to perform before debug event.
637 int step_count_;
638
639 // Frame pointer from last step next action.
640 Address last_fp_;
641
642 // Number of queued steps left to perform before debug event.
643 int queued_step_count_;
644
645 // Frame pointer for frame from which step in was performed.
646 Address step_into_fp_;
647
648 // Frame pointer for the frame where debugger should be called when current
649 // step out action is completed.
650 Address step_out_fp_;
651
652 // Stores the way how LiveEdit has patched the stack. It is used when
653 // debugger returns control back to user script.
654 LiveEdit::FrameDropMode frame_drop_mode_;
655
656 // When restarter frame is on stack, stores the address
657 // of the pointer to function being restarted. Otherwise (most of the time)
658 // stores NULL. This pointer is used with 'step in' implementation.
659 Object** restarter_frame_function_pointer_;
660
661 // When a promise is being resolved, we may want to trigger a debug event
662 // if we catch a throw. For this purpose we remember the try-catch
663 // handler address that would catch the exception. We also hold onto a
664 // closure that returns a promise if the exception is considered uncaught.
665 // Due to the possibility of reentry we use a linked list.
666 PromiseOnStack* promise_on_stack_;
667 };
668
669 // Storage location for registers when handling debug break calls
670 ThreadLocal thread_local_;
873 671
874 Isolate* isolate_; 672 Isolate* isolate_;
875 673
876 friend class EnterDebugger;
877 friend class Isolate; 674 friend class Isolate;
878 675 friend class DebugScope;
879 DISALLOW_COPY_AND_ASSIGN(Debugger); 676 friend class DisableBreak;
880 }; 677 friend class SuppressDebug;
881 678
882 679 friend Handle<FixedArray> GetDebuggedFunctions(); // In test-debug.cc
883 // This class is used for entering the debugger. Create an instance in the stack 680 friend void CheckDebuggerUnloaded(bool check_functions); // In test-debug.cc
884 // to enter the debugger. This will set the current break state, make sure the 681
885 // debugger is loaded and switch to the debugger context. If the debugger for 682 DISALLOW_COPY_AND_ASSIGN(Debug);
886 // some reason could not be entered FailedToEnter will return true. 683 };
887 class EnterDebugger BASE_EMBEDDED { 684
888 public: 685
889 explicit EnterDebugger(Isolate* isolate); 686 DECLARE_RUNTIME_FUNCTION(Debug_Break);
890 ~EnterDebugger(); 687
891 688
892 // Check whether the debugger could be entered. 689 // This scope is used to load and enter the debug context and create a new
893 inline bool FailedToEnter() { return load_failed_; } 690 // break state. Leaving the scope will restore the previous state.
894 691 // On failure to load, FailedToEnter returns true.
895 // Check whether there are any JavaScript frames on the stack. 692 class DebugScope BASE_EMBEDDED {
896 inline bool HasJavaScriptFrames() { return has_js_frames_; } 693 public:
694 explicit DebugScope(Debug* debug);
695 ~DebugScope();
696
697 // Check whether loading was successful.
698 inline bool failed() { return failed_; }
897 699
898 // Get the active context from before entering the debugger. 700 // Get the active context from before entering the debugger.
899 inline Handle<Context> GetContext() { return save_.context(); } 701 inline Handle<Context> GetContext() { return save_.context(); }
900 702
901 private: 703 private:
902 Isolate* isolate_; 704 Isolate* isolate() { return debug_->isolate_; }
903 EnterDebugger* prev_; // Previous debugger entry if entered recursively. 705
904 bool has_js_frames_; // Were there any JavaScript frames? 706 Debug* debug_;
707 DebugScope* prev_; // Previous scope if entered recursively.
905 StackFrame::Id break_frame_id_; // Previous break frame id. 708 StackFrame::Id break_frame_id_; // Previous break frame id.
906 int break_id_; // Previous break id. 709 int break_id_; // Previous break id.
907 bool load_failed_; // Did the debugger fail to load? 710 bool failed_; // Did the debug context fail to load?
908 SaveContext save_; // Saves previous context. 711 SaveContext save_; // Saves previous context.
909 }; 712 };
910 713
911 714
912 // Stack allocated class for disabling break. 715 // Stack allocated class for disabling break.
913 class DisableBreak BASE_EMBEDDED { 716 class DisableBreak BASE_EMBEDDED {
914 public: 717 public:
915 explicit DisableBreak(Isolate* isolate, bool disable_break) 718 explicit DisableBreak(Debug* debug, bool disable_break)
916 : isolate_(isolate) { 719 : debug_(debug), old_state_(debug->break_disabled_) {
917 prev_disable_break_ = isolate_->debug()->disable_break(); 720 debug_->break_disabled_ = disable_break;
918 isolate_->debug()->set_disable_break(disable_break);
919 } 721 }
920 ~DisableBreak() { 722 ~DisableBreak() { debug_->break_disabled_ = old_state_; }
921 isolate_->debug()->set_disable_break(prev_disable_break_); 723
724 private:
725 Debug* debug_;
726 bool old_state_;
727 DISALLOW_COPY_AND_ASSIGN(DisableBreak);
728 };
729
730
731 class SuppressDebug BASE_EMBEDDED {
732 public:
733 explicit SuppressDebug(Debug* debug)
734 : debug_(debug), old_state_(debug->is_suppressed_) {
735 debug_->is_suppressed_ = true;
922 } 736 }
737 ~SuppressDebug() { debug_->is_suppressed_ = old_state_; }
923 738
924 private: 739 private:
925 Isolate* isolate_; 740 Debug* debug_;
926 // The previous state of the disable break used to restore the value when this 741 bool old_state_;
927 // object is destructed. 742 DISALLOW_COPY_AND_ASSIGN(SuppressDebug);
928 bool prev_disable_break_; 743 };
929 }; 744
745
746 // Code generator routines.
747 class DebugCodegen : public AllStatic {
748 public:
749 static void GenerateSlot(MacroAssembler* masm);
750 static void GenerateCallICStubDebugBreak(MacroAssembler* masm);
751 static void GenerateLoadICDebugBreak(MacroAssembler* masm);
752 static void GenerateStoreICDebugBreak(MacroAssembler* masm);
753 static void GenerateKeyedLoadICDebugBreak(MacroAssembler* masm);
754 static void GenerateKeyedStoreICDebugBreak(MacroAssembler* masm);
755 static void GenerateCompareNilICDebugBreak(MacroAssembler* masm);
756 static void GenerateReturnDebugBreak(MacroAssembler* masm);
757 static void GenerateCallFunctionStubDebugBreak(MacroAssembler* masm);
758 static void GenerateCallConstructStubDebugBreak(MacroAssembler* masm);
759 static void GenerateCallConstructStubRecordDebugBreak(MacroAssembler* masm);
760 static void GenerateSlotDebugBreak(MacroAssembler* masm);
761 static void GeneratePlainReturnLiveEdit(MacroAssembler* masm);
762
763 // FrameDropper is a code replacement for a JavaScript frame with possibly
764 // several frames above.
765 // There is no calling conventions here, because it never actually gets
766 // called, it only gets returned to.
767 static void GenerateFrameDropperLiveEdit(MacroAssembler* masm);
768 };
769
930 770
931 } } // namespace v8::internal 771 } } // namespace v8::internal
932 772
933 #endif // V8_DEBUG_H_ 773 #endif // V8_DEBUG_H_
OLDNEW
« no previous file with comments | « src/compiler.cc ('k') | src/debug.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698