-
Notifications
You must be signed in to change notification settings - Fork 1.2k
/
Copy pathTTEventLog.h
653 lines (485 loc) · 29.3 KB
/
TTEventLog.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
//-------------------------------------------------------------------------------------------------------
// Copyright (C) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
//-------------------------------------------------------------------------------------------------------
#pragma once
#if ENABLE_TTD
#define TTD_EVENTLOG_LIST_BLOCK_SIZE 65536
namespace TTD
{
//A class to ensure that even when exceptions are thrown we increment/decrement the root nesting depth
class TTDNestingDepthAutoAdjuster
{
private:
ThreadContext* m_threadContext;
public:
TTDNestingDepthAutoAdjuster(ThreadContext* threadContext)
: m_threadContext(threadContext)
{
this->m_threadContext->TTDRootNestingCount++;
}
~TTDNestingDepthAutoAdjuster()
{
this->m_threadContext->TTDRootNestingCount--;
}
};
//A class to manage the recording of JsRT action call state
class TTDJsRTActionResultAutoRecorder
{
private:
NSLogEvents::EventLogEntry* m_actionEvent;
TTDVar* m_resultPtr;
public:
TTDJsRTActionResultAutoRecorder()
: m_actionEvent(nullptr), m_resultPtr(nullptr)
{
;
}
void InitializeWithEventAndEnter(NSLogEvents::EventLogEntry* actionEvent)
{
TTDAssert(this->m_actionEvent == nullptr, "Don't double initialize");
this->m_actionEvent = actionEvent;
}
void InitializeWithEventAndEnterWResult(NSLogEvents::EventLogEntry* actionEvent, TTDVar* resultPtr)
{
TTDAssert(this->m_actionEvent == nullptr, "Don't double initialize");
this->m_actionEvent = actionEvent;
this->m_resultPtr = resultPtr;
*(this->m_resultPtr) = (TTDVar)nullptr; //set the result field to a default value in case we fail during execution
}
void SetResult(Js::Var* result)
{
TTDAssert(this->m_resultPtr != nullptr, "Why are we calling this then???");
if(result != nullptr)
{
*(this->m_resultPtr) = TTD_CONVERT_JSVAR_TO_TTDVAR(*(result));
}
}
void CompleteWithStatusCode(int32 exitStatus)
{
if(this->m_actionEvent != nullptr)
{
TTDAssert(this->m_actionEvent->ResultStatus == -1, "Hmm this got changed somewhere???");
this->m_actionEvent->ResultStatus = exitStatus;
}
}
};
//A class to ensure that even when exceptions are thrown we record the time difference info
class TTDJsRTFunctionCallActionPopperRecorder
{
private:
Js::ScriptContext* m_ctx;
double m_beginTime;
NSLogEvents::EventLogEntry* m_callAction;
public:
TTDJsRTFunctionCallActionPopperRecorder();
~TTDJsRTFunctionCallActionPopperRecorder();
void InitializeForRecording(Js::ScriptContext* ctx, double beginWallTime, NSLogEvents::EventLogEntry* callAction);
};
//A list class for the events that we accumulate in the event log
class TTEventList
{
public:
struct TTEventListLink
{
//The current end of the allocated data in the block
size_t CurrPos;
//The First index that holds data
size_t StartPos;
//The actual block for the data
byte* BlockData;
//The next block in the list
TTEventListLink* Next;
TTEventListLink* Previous;
};
private:
//The the data in this
TTEventListLink* m_headBlock;
//the allocators we use for this work
UnlinkableSlabAllocator* m_alloc;
//The vtable with callbacks for the event log entries in the list
const NSLogEvents::EventLogEntryVTableEntry* m_vtable;
//Map from event entries to previous event entries -- only valid in replay mode otherwise empty
JsUtil::BaseDictionary<const NSLogEvents::EventLogEntry*, size_t, HeapAllocator> m_previousEventMap;
void AddArrayLink();
void RemoveArrayLink(TTEventListLink* block);
public:
TTEventList(UnlinkableSlabAllocator* alloc);
void SetVTable(const NSLogEvents::EventLogEntryVTableEntry* vtable);
void InitializePreviousEventMap();
void UnloadEventList();
//Add the entry to the list
template <typename T>
NSLogEvents::EventLogEntry* GetNextAvailableEntry()
{
const size_t esize = TTD_EVENT_PLUS_DATA_SIZE(T);
if((this->m_headBlock == nullptr) || (this->m_headBlock->CurrPos + esize >= TTD_EVENTLOG_LIST_BLOCK_SIZE))
{
this->AddArrayLink();
}
NSLogEvents::EventLogEntry* entry = reinterpret_cast<NSLogEvents::EventLogEntry*>(this->m_headBlock->BlockData + this->m_headBlock->CurrPos);
this->m_headBlock->CurrPos += esize;
return entry;
}
//Add the entry to the list
NSLogEvents::EventLogEntry* GetNextAvailableEntry(size_t requiredSize);
//Delete the entry from the list (must always be the first link/entry in the list)
//This also calls unload on the entry
void DeleteFirstEntry(TTEventListLink* block, NSLogEvents::EventLogEntry* data);
//Return true if this is empty
bool IsEmpty() const;
//NOT constant time
uint32 Count() const;
class Iterator
{
private:
TTEventListLink* m_currLink;
size_t m_currIdx;
const NSLogEvents::EventLogEntryVTableEntry* m_vtable;
const JsUtil::BaseDictionary<const NSLogEvents::EventLogEntry*, size_t, HeapAllocator>* m_previousEventMap;
public:
Iterator();
Iterator(TTEventListLink* head, size_t pos, const NSLogEvents::EventLogEntryVTableEntry* vtable, const JsUtil::BaseDictionary<const NSLogEvents::EventLogEntry*, size_t, HeapAllocator>* previousEventMap);
const NSLogEvents::EventLogEntry* Current() const;
NSLogEvents::EventLogEntry* Current();
//Get the underlying block for deletion support
TTEventListLink* GetBlock();
bool IsValid() const;
void MoveNext();
void MovePrevious_ReplayOnly();
};
Iterator GetIteratorAtFirst() const;
Iterator GetIteratorAtLast_ReplayOnly() const;
};
//A class that represents the event log for the program execution
class EventLog
{
private:
ThreadContext* m_threadContext;
//Allocator we use for all the events we see
UnlinkableSlabAllocator m_eventSlabAllocator;
//Allocator we use for all the property records
SlabAllocator m_miscSlabAllocator;
//The global event time variable and a high res timer we can use to extract some diagnostic timing info as we go
int64 m_eventTimeCtr;
//A high res timer we can use to extract some diagnostic timing info as we go
TTDTimer m_timer;
//Top-Level callback event time (or -1 if we are not in a callback)
int64 m_topLevelCallbackEventTime;
//The list of all the events and the iterator we use during replay
NSLogEvents::EventLogEntryVTableEntry* m_eventListVTable;
TTEventList m_eventList;
TTEventList::Iterator m_currentReplayEventIterator;
//The current mode the system is running in (and a stack of mode push/pops that we use to generate it)
TTModeStack m_modeStack;
TTDMode m_currentMode;
bool m_autoTracesEnabled;
//The snapshot extractor that this log uses
SnapshotExtractor m_snapExtractor;
//The execution time that has elapsed since the last snapshot
double m_elapsedExecutionTimeSinceSnapshot;
//If we are inflating a snapshot multiple times we want to re-use the inflated objects when possible so keep this recent info
int64 m_lastInflateSnapshotTime;
InflateMap* m_lastInflateMap;
//Pin set of all property records created during this logging session
RecyclerRootPtr<PropertyRecordPinSet> m_propertyRecordPinSet;
UnorderedArrayList<NSSnapType::SnapPropertyRecord, TTD_ARRAY_LIST_SIZE_DEFAULT> m_propertyRecordList;
//The value of the threadContext sourceInfoCounter in record -- in replay initialize to this value to avoid collisions
uint32 m_sourceInfoCount;
//A list of all *root* scripts that have been loaded during this session
UnorderedArrayList<NSSnapValues::TopLevelScriptLoadFunctionBodyResolveInfo, TTD_ARRAY_LIST_SIZE_MID> m_loadedTopLevelScripts;
UnorderedArrayList<NSSnapValues::TopLevelNewFunctionBodyResolveInfo, TTD_ARRAY_LIST_SIZE_SMALL> m_newFunctionTopLevelScripts;
UnorderedArrayList<NSSnapValues::TopLevelEvalFunctionBodyResolveInfo, TTD_ARRAY_LIST_SIZE_SMALL> m_evalTopLevelScripts;
////
//Helper methods
//Get the current XTTDEventTime and advance the event time counter
int64 GetCurrentEventTimeAndAdvance()
{
return this->m_eventTimeCtr++;
}
//Advance the time and event position for replay
void AdvanceTimeAndPositionForReplay();
//Look at the stack to get the new computed mode
void UpdateComputedMode();
//A helper for extracting snapshots
SnapShot* DoSnapshotExtract_Helper(double gcTime, JsUtil::BaseHashSet<Js::FunctionBody*, HeapAllocator>& liveTopLevelBodies);
//Replay a snapshot event -- either just advance the event position or, if running diagnostics, take new snapshot and compare
void ReplaySnapshotEvent();
//Replay an event loop yield point event
void ReplayEventLoopYieldPointEvent();
template <typename T, NSLogEvents::EventKind tag>
NSLogEvents::EventLogEntry* RecordGetInitializedEvent(T** extraData)
{
AssertMsg(TTD_EVENT_PLUS_DATA_SIZE_DIRECT(sizeof(T)) == this->m_eventListVTable[(uint32)tag].DataSize, "Computed and extracted data sizes don't match!!!");
NSLogEvents::EventLogEntry* res = this->m_eventList.GetNextAvailableEntry<T>();
NSLogEvents::EventLogEntry_Initialize<tag>(res, this->GetCurrentEventTimeAndAdvance());
*extraData = NSLogEvents::GetInlineEventDataAs<T, tag>(res);
return res;
}
template <typename T, NSLogEvents::EventKind tag>
T* RecordGetInitializedEvent_DataOnly()
{
AssertMsg(TTD_EVENT_PLUS_DATA_SIZE_DIRECT(sizeof(T)) == this->m_eventListVTable[(uint32)tag].DataSize, "Computed and extracted data sizes don't match!!!");
NSLogEvents::EventLogEntry* res = this->m_eventList.GetNextAvailableEntry<T>();
NSLogEvents::EventLogEntry_Initialize<tag>(res, this->GetCurrentEventTimeAndAdvance());
//For these operations are not allowed to fail so success is always 0
res->ResultStatus = 0;
return NSLogEvents::GetInlineEventDataAs<T, tag>(res);
}
//Sometimes we need to abort replay and immediately return to the top-level host (debugger) so it can decide what to do next
// (1) If we are trying to replay something and we are at the end of the log then we need to terminate
// (2) If we are at a breakpoint and we want to step back (in some form) then we need to terminate
void AbortReplayReturnToHost();
//A helper for getting and doing some iterator manipulation during replay
template <typename T, NSLogEvents::EventKind tag>
const T* ReplayGetReplayEvent_Helper()
{
if(!this->m_currentReplayEventIterator.IsValid())
{
this->AbortReplayReturnToHost();
}
#if ENABLE_TTD_INTERNAL_DIAGNOSTICS
TTDAssert(this->m_currentReplayEventIterator.Current()->EventTimeStamp == this->m_eventTimeCtr, "Out of Sync!!!");
#endif
const NSLogEvents::EventLogEntry* evt = this->m_currentReplayEventIterator.Current();
this->AdvanceTimeAndPositionForReplay();
return NSLogEvents::GetInlineEventDataAs<T, tag>(evt);
}
//Initialize the vtable for the event list data
void InitializeEventListVTable();
public:
EventLog(ThreadContext* threadContext);
~EventLog();
//When we stop recording we want to unload all of the data in the log (otherwise we get strange transitions if we start again later)
void UnloadAllLogData();
//Initialize the log so that it is ready to perform TTD (record or replay) and set into the correct global mode
void InitForTTDRecord(bool debug);
void InitForTTDReplay(TTDataIOInfo& iofp, const char* parseUri, size_t parseUriLength, bool debug);
//If the last statement of this log is an inner loop emit event put the data in lsi otherwise leave it as the default value
void LoadLastSourceLineInfo(TTInnerLoopLastStatementInfo& lsi, TTD::TTDebuggerSourceLocation& dsl) const;
//reset the bottom (global) mode with the specific value
void SetGlobalMode(TTDMode m);
//Mark that a snapshot is in (or or is now complete)
void SetSnapshotOrInflateInProgress(bool flag);
//push a new debugger mode
void PushMode(TTDMode m);
//pop the top debugger mode
void PopMode(TTDMode m);
//Get the current mode for TTD execution
TTDMode GetCurrentTTDMode() const;
//Set the mode flags on the script context based on the TTDMode in the Log
void SetModeFlagsOnContext(Js::ScriptContext* ctx);
//Get the global mode flags for creating a script context
void GetModesForExplicitContextCreate(bool& inRecord, bool& activelyRecording, bool& inReplay);
//Just check if the debug mode flag has been set (don't check any active or suppressed properties)
bool IsDebugModeFlagSet() const;
//Add a property record to our pin set
void AddPropertyRecord(const Js::PropertyRecord* record);
//Add top level function load info to our sets
const NSSnapValues::TopLevelScriptLoadFunctionBodyResolveInfo* AddScriptLoad(Js::FunctionBody* fb, Js::ModuleID moduleId, uint64 sourceContextId, const byte* source, uint32 sourceLen, LoadScriptFlag loadFlag);
const NSSnapValues::TopLevelNewFunctionBodyResolveInfo* AddNewFunction(Js::FunctionBody* fb, Js::ModuleID moduleId, const char16* source, uint32 sourceLen);
const NSSnapValues::TopLevelEvalFunctionBodyResolveInfo* AddEvalFunction(Js::FunctionBody* fb, Js::ModuleID moduleId, const char16* source, uint32 sourceLen, uint32 grfscr, bool registerDocument, BOOL isIndirect, BOOL strictMode);
uint32 GetSourceInfoCount() const;
void RecordTopLevelCodeAction(uint32 bodyCtrId);
uint32 ReplayTopLevelCodeAction();
////////////////////////////////
//Logging support
//Log an event generated by user telemetry
void RecordTelemetryLogEvent(Js::JavascriptString* infoStringJs, bool doPrint);
//Replay a user telemetry event
void ReplayTelemetryLogEvent(Js::JavascriptString* infoStringJs);
//Log an event generated to write the log to a given uri
void RecordEmitLogEvent(Js::JavascriptString* uriString);
//Replay a event that writes the log to a given uri
void ReplayEmitLogEvent();
//Record that we are accessing the TTDFetchAutoTraceStatus and what the value is
void RecordTTDFetchAutoTraceStatusEvent(bool status);
//Replay that we are accessing the TTDFetchAutoTraceStatus
bool ReplayTTDFetchAutoTraceStatusLogEvent();
//Log a time that is fetched during date operations
void RecordDateTimeEvent(double time);
//Log a time (as a string) that is fetched during date operations
void RecordDateStringEvent(Js::JavascriptString* stringValue);
//replay date event (which should be the current event)
void ReplayDateTimeEvent(double* result);
//replay date event with a string result (which should be the current event)
void ReplayDateStringEvent(Js::ScriptContext* ctx, Js::JavascriptString** result);
//Log a random seed value that is being generated using external entropy
void RecordExternalEntropyRandomEvent(uint64 seed0, uint64 seed1);
//Replay a random seed value that is being generated using external entropy
void ReplayExternalEntropyRandomEvent(uint64* seed0, uint64* seed1);
//Log property enumeration step
void RecordPropertyEnumEvent(BOOL returnCode, Js::PropertyId pid, Js::PropertyAttributes attributes, Js::JavascriptString* propertyName);
//Replay a property enumeration step
void ReplayPropertyEnumEvent(Js::ScriptContext* requestContext, BOOL* returnCode, Js::BigPropertyIndex* newIndex, const Js::DynamicObject* obj, Js::PropertyId* pid, Js::PropertyAttributes* attributes, Js::JavascriptString** propertyName);
//Log symbol creation
void RecordSymbolCreationEvent(Js::PropertyId pid);
//Replay symbol creation
void ReplaySymbolCreationEvent(Js::PropertyId* pid);
//Log if a weak collection contained a value when an operation occours
void RecordWeakCollectionContainsEvent(bool contains);
//Replay a weak collection contained a value when an operation occours (return the truth value)
bool ReplayWeakCollectionContainsEvent();
//Log a value event for return from an external call
NSLogEvents::EventLogEntry* RecordExternalCallEvent(Js::JavascriptFunction* func, int32 rootDepth, const Js::Arguments& args, bool checkExceptions);
void RecordExternalCallEvent_Complete(Js::JavascriptFunction* efunction, NSLogEvents::EventLogEntry* evt, Js::Var result);
//replay an external return event (which should be the current event)
void ReplayExternalCallEvent(Js::JavascriptFunction* function, const Js::Arguments& args, Js::Var* result);
NSLogEvents::EventLogEntry* RecordEnqueueTaskEvent(Js::Var taskVar);
void RecordEnqueueTaskEvent_Complete(NSLogEvents::EventLogEntry* evt);
void ReplayEnqueueTaskEvent(Js::ScriptContext* ctx, Js::Var taskVar);
//Get the current top-level event time
int64 GetCurrentTopLevelEventTime() const;
//Get the event time corresponding to the first/last/k-th top-level event in the log
int64 GetFirstEventTimeInLog() const;
int64 GetLastEventTimeInLog() const;
int64 GetKthEventTimeInLog(uint32 k) const;
//Ensure the call stack is clear and counters are zeroed appropriately
void ResetCallStackForTopLevelCall(int64 topLevelCallbackEventTime);
//Check if we want to take a snapshot
bool IsTimeForSnapshot() const;
//After a snapshot we may want to discard old events so do that in here as needed
void PruneLogLength();
//Get/Increment the elapsed time since the last snapshot
void IncrementElapsedSnapshotTime(double addtlTime);
////////////////////////////////
//Snapshot and replay support
//Do the snapshot extraction
void DoSnapshotExtract();
//Take a ready-to-run snapshot for the event if needed
void DoRtrSnapIfNeeded();
//Find the event time that has the snapshot we want to inflate from in order to replay to the requested target time
//Return -1 if no such snapshot is available
int64 FindSnapTimeForEventTime(int64 targetTime, int64* optEndSnapTime);
//Find the enclosing snapshot interval for the specified event time
void GetSnapShotBoundInterval(int64 targetTime, int64* snapIntervalStart, int64* snapIntervalEnd) const;
//Find the snapshot start time for the previous interval return -1 if no such time exists
int64 GetPreviousSnapshotInterval(int64 currentSnapTime) const;
//Do the inflation of the snapshot that is at the given event time
void DoSnapshotInflate(int64 etime);
//Run execute top level event calls until the given time is reached
void ReplayRootEventsToTime(int64 eventTime);
//For a single root level event -- snapshot, yield point, or ActionEvent
void ReplaySingleRootEntry();
//When we have an externalFunction (or promise register) we exit script context and need to play until the event time counts up to (and including) the given eventTime
void ReplayActionEventSequenceThroughTime(int64 eventTime);
//Replay the enter/exit and any iteration need to discharge all the effects of a single ActionEvent
void ReplaySingleActionEventEntry();
////////////////////////////////
//Host API record & replay support
//Return true if this is a propertyRecord reference
bool IsPropertyRecordRef(void* ref) const;
//Get the current time from the hi res timer
double GetCurrentWallTime();
//Get the most recently assigned event time value
int64 GetLastEventTime() const;
NSLogEvents::EventLogEntry* RecordJsRTCreateScriptContext(TTDJsRTActionResultAutoRecorder& actionPopper);
void RecordJsRTCreateScriptContextResult(NSLogEvents::EventLogEntry* evt, Js::ScriptContext* newCtx);
void RecordJsRTSetCurrentContext(TTDJsRTActionResultAutoRecorder& actionPopper, Js::Var globalObject);
#if !INT32VAR
void RecordJsRTCreateInteger(TTDJsRTActionResultAutoRecorder& actionPopper, int value);
#endif
//Record creation operations
void RecordJsRTCreateNumber(TTDJsRTActionResultAutoRecorder& actionPopper, double value);
void RecordJsRTCreateBoolean(TTDJsRTActionResultAutoRecorder& actionPopper, bool value);
void RecordJsRTCreateString(TTDJsRTActionResultAutoRecorder& actionPopper, const char16* stringValue, size_t stringLength);
void RecordJsRTCreateSymbol(TTDJsRTActionResultAutoRecorder& actionPopper, Js::Var var);
//Record error creation
void RecordJsRTCreateError(TTDJsRTActionResultAutoRecorder& actionPopper, Js::Var msg);
void RecordJsRTCreateRangeError(TTDJsRTActionResultAutoRecorder& actionPopper, Js::Var vmsg);
void RecordJsRTCreateReferenceError(TTDJsRTActionResultAutoRecorder& actionPopper, Js::Var msg);
void RecordJsRTCreateSyntaxError(TTDJsRTActionResultAutoRecorder& actionPopper, Js::Var msg);
void RecordJsRTCreateTypeError(TTDJsRTActionResultAutoRecorder& actionPopper, Js::Var msg);
void RecordJsRTCreateURIError(TTDJsRTActionResultAutoRecorder& actionPopper, Js::Var msg);
//Record conversions
void RecordJsRTVarToNumberConversion(TTDJsRTActionResultAutoRecorder& actionPopper, Js::Var var);
void RecordJsRTVarToBooleanConversion(TTDJsRTActionResultAutoRecorder& actionPopper, Js::Var var);
void RecordJsRTVarToStringConversion(TTDJsRTActionResultAutoRecorder& actionPopper, Js::Var var);
void RecordJsRTVarToObjectConversion(TTDJsRTActionResultAutoRecorder& actionPopper, Js::Var var);
//Record lifetime management events
void RecordJsRTAddRootRef(TTDJsRTActionResultAutoRecorder& actionPopper, Js::Var var);
void RecordJsRTAddWeakRootRef(TTDJsRTActionResultAutoRecorder& actionPopper, Js::Var var);
void RecordJsRTEventLoopYieldPoint();
//Record object allocate operations
void RecordJsRTAllocateBasicObject(TTDJsRTActionResultAutoRecorder& actionPopper);
void RecordJsRTAllocateExternalObject(TTDJsRTActionResultAutoRecorder& actionPopper, Js::Var prototype);
void RecordJsRTAllocateBasicArray(TTDJsRTActionResultAutoRecorder& actionPopper, uint32 length);
void RecordJsRTAllocateArrayBuffer(TTDJsRTActionResultAutoRecorder& actionPopper, uint32 size);
void RecordJsRTAllocateExternalArrayBuffer(TTDJsRTActionResultAutoRecorder& actionPopper, byte* buff, uint32 size);
void RecordJsRTAllocateFunction(TTDJsRTActionResultAutoRecorder& actionPopper, Js::Var optMetadata);
//Record GetAndClearException
void RecordJsRTHostExitProcess(TTDJsRTActionResultAutoRecorder& actionPopper, int32 exitCode);
void RecordJsRTGetAndClearExceptionWithMetadata(TTDJsRTActionResultAutoRecorder& actionPopper);
void RecordJsRTGetAndClearException(TTDJsRTActionResultAutoRecorder& actionPopper);
void RecordJsRTSetException(TTDJsRTActionResultAutoRecorder& actionPopper, Js::Var var, bool propagateToDebugger);
//Record query operations
void RecordJsRTHasProperty(TTDJsRTActionResultAutoRecorder& actionPopper, const Js::PropertyRecord* pRecord, Js::Var var);
void RecordJsRTHasOwnProperty(TTDJsRTActionResultAutoRecorder& actionPopper, const Js::PropertyRecord* pRecord, Js::Var var);
void RecordJsRTInstanceOf(TTDJsRTActionResultAutoRecorder& actionPopper, Js::Var object, Js::Var constructor);
void RecordJsRTEquals(TTDJsRTActionResultAutoRecorder& actionPopper, Js::Var var1, Js::Var var2, bool doStrict);
void RecordJsRTLessThan(TTDJsRTActionResultAutoRecorder& actionPopper, Js::Var var1, Js::Var var2, bool allowsEqual);
//Record getters with native results
void RecordJsRTGetPropertyIdFromSymbol(TTDJsRTActionResultAutoRecorder& actionPopper, Js::Var sym);
//Record Object Getters
void RecordJsRTGetPrototype(TTDJsRTActionResultAutoRecorder& actionPopper, Js::Var var);
void RecordJsRTGetProperty(TTDJsRTActionResultAutoRecorder& actionPopper, const Js::PropertyRecord* pRecord, Js::Var var);
void RecordJsRTGetIndex(TTDJsRTActionResultAutoRecorder& actionPopper, Js::Var index, Js::Var var);
void RecordJsRTGetOwnPropertyInfo(TTDJsRTActionResultAutoRecorder& actionPopper, const Js::PropertyRecord* pRecord, Js::Var var);
void RecordJsRTGetOwnPropertyNamesInfo(TTDJsRTActionResultAutoRecorder& actionPopper, Js::Var var);
void RecordJsRTGetOwnPropertySymbolsInfo(TTDJsRTActionResultAutoRecorder& actionPopper, Js::Var var);
//Record Object Setters
void RecordJsRTDefineProperty(TTDJsRTActionResultAutoRecorder& actionPopper, Js::Var var, const Js::PropertyRecord* pRecord, Js::Var propertyDescriptor);
void RecordJsRTDeleteProperty(TTDJsRTActionResultAutoRecorder& actionPopper, Js::Var var, const Js::PropertyRecord* pRecord, bool useStrictRules);
void RecordJsRTSetPrototype(TTDJsRTActionResultAutoRecorder& actionPopper, Js::Var var, Js::Var proto);
void RecordJsRTSetProperty(TTDJsRTActionResultAutoRecorder& actionPopper, Js::Var var, const Js::PropertyRecord* pRecord, Js::Var val, bool useStrictRules);
void RecordJsRTSetIndex(TTDJsRTActionResultAutoRecorder& actionPopper, Js::Var var, Js::Var index, Js::Var val);
//Record a get info from a typed array
void RecordJsRTGetTypedArrayInfo(Js::Var var, Js::Var result);
void RecordJsRTGetDataViewInfo(Js::Var var, Js::Var result);
//Record various raw byte* from ArrayBuffer manipulations
void RecordJsRTRawBufferCopySync(TTDJsRTActionResultAutoRecorder& actionPopper, Js::Var dst, uint32 dstIndex, Js::Var src, uint32 srcIndex, uint32 length);
void RecordJsRTRawBufferModifySync(TTDJsRTActionResultAutoRecorder& actionPopper, Js::Var dst, uint32 index, uint32 count);
void RecordJsRTRawBufferAsyncModificationRegister(TTDJsRTActionResultAutoRecorder& actionPopper, Js::Var dst, uint32 index);
void RecordJsRTRawBufferAsyncModifyComplete(TTDJsRTActionResultAutoRecorder& actionPopper, TTDPendingAsyncBufferModification& pendingAsyncInfo, byte* finalModPos);
//Record a constructor call from JsRT
void RecordJsRTConstructCall(TTDJsRTActionResultAutoRecorder& actionPopper, Js::Var funcVar, uint32 argCount, Js::Var* args);
//Record code parse
NSLogEvents::EventLogEntry* RecordJsRTCodeParse(TTDJsRTActionResultAutoRecorder& actionPopper, LoadScriptFlag loadFlag, bool isUft8, const byte* script, uint32 scriptByteLength, uint64 sourceContextId, const char16* sourceUri);
//Record callback of an existing function
NSLogEvents::EventLogEntry* RecordJsRTCallFunction(TTDJsRTActionResultAutoRecorder& actionPopper, int32 rootDepth, Js::Var funcVar, uint32 argCount, Js::Var* args);
////////////////////////////////
//Emit code and support
void InnerLoopEmitLog(const TTDebuggerSourceLocation& writeLocation, const char* emitUri, size_t emitUriLength);
bool CanWriteInnerLoopTrace() const;
void SetAutoTraceEnabled(bool enabled);
bool GetAutoTraceEnabled() const;
void EmitLog(const char* emitUri, size_t emitUriLength, NSLogEvents::EventLogEntry* optInnerLoopEvent = nullptr);
void ParseLogInto(TTDataIOInfo& iofp, const char* parseUri, size_t parseUriLength);
};
//In cases where we may have many exits where we need to pop something we pushed earlier (i.e. exceptions)
class TTModeStackAutoPopper
{
private:
EventLog* m_log;
TTDMode m_popMode; //the mode to pop or invalid if we don't need to pop anything
public:
TTModeStackAutoPopper(EventLog* log)
: m_log(log), m_popMode(TTDMode::Invalid)
{
;
}
void PushModeAndSetToAutoPop(TTDMode mode)
{
this->m_log->PushMode(mode);
this->m_popMode = mode;
}
~TTModeStackAutoPopper()
{
if(this->m_popMode != TTDMode::Invalid)
{
this->m_log->PopMode(this->m_popMode);
}
}
};
}
#endif