blob: 8b7f70a092662df56fbf601c43d77bef8c950d30 [file]
//-------------------------------------------------------------------------------------------------------
// Copyright (C) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
//-------------------------------------------------------------------------------------------------------
#include "RuntimeDebugPch.h"
#if ENABLE_TTD
#define TTD_CREATE_EVENTLIST_VTABLE_ENTRY(TAG, WRAPPER, TYPE, EXEC_FP, UNLOAD_FP, EMIT_FP, PARSE_FP) this->m_eventListVTable[(uint32)NSLogEvents::EventKind:: ## TAG] = { NSLogEvents::ContextExecuteKind:: ## WRAPPER, EXEC_FP, UNLOAD_FP, EMIT_FP, PARSE_FP, TTD_EVENT_PLUS_DATA_SIZE_DIRECT(sizeof(NSLogEvents:: TYPE)) }
#define TTD_CREATE_EVENTLIST_VTABLE_ENTRY_COMMON(TAG, WRAPPER, TYPE, EXEC_FP) this->m_eventListVTable[(uint32)NSLogEvents::EventKind:: ## TAG] = { NSLogEvents::ContextExecuteKind:: ## WRAPPER, NSLogEvents:: ## EXEC_FP, nullptr, NSLogEvents:: ## TYPE ## _Emit ## <NSLogEvents::EventKind:: ## TAG ## >, NSLogEvents:: ## TYPE ## _Parse ## <NSLogEvents::EventKind:: ## TAG ## >, TTD_EVENT_PLUS_DATA_SIZE_DIRECT(sizeof(NSLogEvents:: ## TYPE)) }
namespace TTD
{
TTDJsRTFunctionCallActionPopperRecorder::TTDJsRTFunctionCallActionPopperRecorder()
: m_ctx(nullptr), m_beginTime(0.0), m_callAction(nullptr)
{
;
}
TTDJsRTFunctionCallActionPopperRecorder::~TTDJsRTFunctionCallActionPopperRecorder()
{
if(this->m_ctx != nullptr)
{
TTDAssert(this->m_callAction != nullptr, "Should be set in sync with ctx!!!");
TTD::EventLog* elog = this->m_ctx->GetThreadContext()->TTDLog;
NSLogEvents::JsRTCallFunctionAction* cfAction = NSLogEvents::GetInlineEventDataAs<NSLogEvents::JsRTCallFunctionAction, NSLogEvents::EventKind::CallExistingFunctionActionTag>(this->m_callAction);
#if ENABLE_TTD_INTERNAL_DIAGNOSTICS
NSLogEvents::JsRTCallFunctionAction_ProcessDiagInfoPost(this->m_callAction, this->m_ctx->GetThreadContext()->TTDLog->GetLastEventTime());
#endif
//Update the time elapsed since a snapshot if needed
if(cfAction->CallbackDepth == 0)
{
double elapsedTime = (elog->GetCurrentWallTime() - this->m_beginTime);
elog->IncrementElapsedSnapshotTime(elapsedTime);
}
}
}
void TTDJsRTFunctionCallActionPopperRecorder::InitializeForRecording(Js::ScriptContext* ctx, double beginWallTime, NSLogEvents::EventLogEntry* callAction)
{
TTDAssert(this->m_ctx == nullptr && this->m_callAction == nullptr, "Don't double initialize!!!");
this->m_ctx = ctx;
this->m_beginTime = beginWallTime;
this->m_callAction = callAction;
}
/////////////
void TTEventList::AddArrayLink()
{
TTEventListLink* newHeadBlock = this->m_alloc->SlabAllocateStruct<TTEventListLink>();
newHeadBlock->BlockData = this->m_alloc->SlabAllocateFixedSizeArray<byte, TTD_EVENTLOG_LIST_BLOCK_SIZE>();
memset(newHeadBlock->BlockData, 0, TTD_EVENTLOG_LIST_BLOCK_SIZE);
newHeadBlock->CurrPos = 0;
newHeadBlock->StartPos = 0;
newHeadBlock->Next = nullptr;
newHeadBlock->Previous = this->m_headBlock;
if(this->m_headBlock != nullptr)
{
this->m_headBlock->Next = newHeadBlock;
}
this->m_headBlock = newHeadBlock;
}
void TTEventList::RemoveArrayLink(TTEventListLink* block)
{
TTDAssert(block->Previous == nullptr, "Not first event block in log!!!");
TTDAssert(block->StartPos == block->CurrPos, "Haven't cleared all the events in this link");
if(block->Next == nullptr)
{
this->m_headBlock = nullptr; //was only 1 block to we are now all null
}
else
{
block->Next->Previous = nullptr;
}
this->m_alloc->UnlinkAllocation(block->BlockData);
this->m_alloc->UnlinkAllocation(block);
}
TTEventList::TTEventList(UnlinkableSlabAllocator* alloc)
: m_alloc(alloc), m_headBlock(nullptr), m_vtable(nullptr), m_previousEventMap(&HeapAllocator::Instance)
{
;
}
void TTEventList::SetVTable(const NSLogEvents::EventLogEntryVTableEntry* vtable)
{
this->m_vtable = vtable;
}
void TTEventList::InitializePreviousEventMap()
{
for(TTEventListLink* curr = this->m_headBlock; curr != nullptr; curr = curr->Previous)
{
size_t cpos = curr->StartPos;
size_t ppos = TTD_EVENTLOG_LIST_BLOCK_SIZE; //an invalid sentinal value
while(cpos != curr->CurrPos)
{
NSLogEvents::EventLogEntry* data = reinterpret_cast<NSLogEvents::EventLogEntry*>(curr->BlockData + cpos);
if(cpos != curr->StartPos)
{
this->m_previousEventMap.AddNew(data, ppos);
}
ppos = cpos;
cpos += this->m_vtable[(uint32)data->EventKind].DataSize;
}
}
}
void TTEventList::UnloadEventList()
{
if(this->m_headBlock == nullptr)
{
return;
}
TTEventListLink* firstBlock = this->m_headBlock;
while(firstBlock->Previous != nullptr)
{
firstBlock = firstBlock->Previous;
}
TTEventListLink* curr = firstBlock;
while(curr != nullptr)
{
size_t cpos = curr->StartPos;
while(cpos < curr->CurrPos)
{
NSLogEvents::EventLogEntry* entry = reinterpret_cast<NSLogEvents::EventLogEntry*>(curr->BlockData + cpos);
auto unloadFP = this->m_vtable[(uint32)entry->EventKind].UnloadFP; //use vtable magic here
if(unloadFP != nullptr)
{
unloadFP(entry, *(this->m_alloc));
}
cpos += this->m_vtable[(uint32)entry->EventKind].DataSize;
}
curr->StartPos = curr->CurrPos;
TTEventListLink* next = curr->Next;
this->RemoveArrayLink(curr);
curr = next;
}
this->m_headBlock = nullptr;
}
NSLogEvents::EventLogEntry* TTEventList::GetNextAvailableEntry(size_t requiredSize)
{
if((this->m_headBlock == nullptr) || (this->m_headBlock->CurrPos + requiredSize >= 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 += requiredSize;
return entry;
}
void TTEventList::DeleteFirstEntry(TTEventListLink* block, NSLogEvents::EventLogEntry* data)
{
TTDAssert(reinterpret_cast<NSLogEvents::EventLogEntry*>(block->BlockData + block->StartPos) == data, "Not the data at the start of the list!!!");
auto unloadFP = this->m_vtable[(uint32)data->EventKind].UnloadFP; //use vtable magic here
if(unloadFP != nullptr)
{
unloadFP(data, *(this->m_alloc));
}
block->StartPos += this->m_vtable[(uint32)data->EventKind].DataSize;
if(block->StartPos == block->CurrPos)
{
this->RemoveArrayLink(block);
}
}
bool TTEventList::IsEmpty() const
{
return this->m_headBlock == nullptr;
}
uint32 TTEventList::Count() const
{
uint32 count = 0;
for(TTEventListLink* curr = this->m_headBlock; curr != nullptr; curr = curr->Previous)
{
size_t cpos = curr->StartPos;
while(cpos != curr->CurrPos)
{
count++;
NSLogEvents::EventLogEntry* data = reinterpret_cast<NSLogEvents::EventLogEntry*>(curr->BlockData + cpos);
cpos += this->m_vtable[(uint32)data->EventKind].DataSize;
}
}
return count;
}
TTEventList::Iterator::Iterator()
: m_currLink(nullptr), m_currIdx(0), m_previousEventMap(nullptr)
{
;
}
TTEventList::Iterator::Iterator(TTEventListLink* head, size_t pos, const NSLogEvents::EventLogEntryVTableEntry* vtable, const JsUtil::BaseDictionary<const NSLogEvents::EventLogEntry*, size_t, HeapAllocator>* previousEventMap)
: m_currLink(head), m_currIdx(pos), m_vtable(vtable), m_previousEventMap(previousEventMap)
{
;
}
const NSLogEvents::EventLogEntry* TTEventList::Iterator::Current() const
{
TTDAssert(this->IsValid(), "Iterator is invalid!!!");
return reinterpret_cast<const NSLogEvents::EventLogEntry*>(this->m_currLink->BlockData + this->m_currIdx);
}
NSLogEvents::EventLogEntry* TTEventList::Iterator::Current()
{
TTDAssert(this->IsValid(), "Iterator is invalid!!!");
return reinterpret_cast<NSLogEvents::EventLogEntry*>(this->m_currLink->BlockData + this->m_currIdx);
}
TTEventList::TTEventListLink* TTEventList::Iterator::GetBlock()
{
return this->m_currLink;
}
bool TTEventList::Iterator::IsValid() const
{
return (this->m_currLink != nullptr && this->m_currLink->StartPos <= this->m_currIdx && this->m_currIdx < this->m_currLink->CurrPos);
}
void TTEventList::Iterator::MoveNext()
{
NSLogEvents::EventLogEntry* data = this->Current();
size_t dataSize = this->m_vtable[(uint32)data->EventKind].DataSize;
if(this->m_currIdx + dataSize < this->m_currLink->CurrPos)
{
this->m_currIdx += dataSize;
}
else
{
this->m_currLink = this->m_currLink->Next;
this->m_currIdx = (this->m_currLink != nullptr) ? this->m_currLink->StartPos : 0;
}
}
void TTEventList::Iterator::MovePrevious_ReplayOnly()
{
if(this->m_currIdx > this->m_currLink->StartPos)
{
this->m_currIdx = this->m_previousEventMap->Item(this->Current());
}
else
{
this->m_currLink = this->m_currLink->Previous;
this->m_currIdx = 0;
//move index to the last element
if(this->m_currLink != nullptr && this->m_currIdx < this->m_currLink->CurrPos)
{
NSLogEvents::EventLogEntry* data = this->Current();
size_t npos = this->m_vtable[(uint32)data->EventKind].DataSize;
while(npos < this->m_currLink->CurrPos)
{
this->m_currIdx = npos;
data = this->Current();
npos += this->m_vtable[(uint32)data->EventKind].DataSize;
}
}
}
}
TTEventList::Iterator TTEventList::GetIteratorAtFirst() const
{
if(this->m_headBlock == nullptr)
{
return Iterator(nullptr, 0, this->m_vtable, &this->m_previousEventMap);
}
else
{
TTEventListLink* firstBlock = this->m_headBlock;
while(firstBlock->Previous != nullptr)
{
firstBlock = firstBlock->Previous;
}
return Iterator(firstBlock, firstBlock->StartPos, this->m_vtable, &this->m_previousEventMap);
}
}
TTEventList::Iterator TTEventList::GetIteratorAtLast_ReplayOnly() const
{
if(this->m_headBlock == nullptr)
{
return Iterator(nullptr, 0, this->m_vtable, &this->m_previousEventMap);
}
else
{
size_t cpos = this->m_headBlock->StartPos;
size_t ipos = 0;
do
{
ipos = cpos;
NSLogEvents::EventLogEntry* data = reinterpret_cast<NSLogEvents::EventLogEntry*>(this->m_headBlock->BlockData + cpos);
cpos += this->m_vtable[(uint32)data->EventKind].DataSize;
} while(cpos != this->m_headBlock->CurrPos);
return Iterator(this->m_headBlock, ipos, this->m_vtable, &this->m_previousEventMap);
}
}
//////
void EventLog::AdvanceTimeAndPositionForReplay()
{
this->m_eventTimeCtr++;
this->m_currentReplayEventIterator.MoveNext();
#if ENABLE_TTD_INTERNAL_DIAGNOSTICS
TTDAssert(!this->m_currentReplayEventIterator.IsValid() || this->m_eventTimeCtr == this->m_currentReplayEventIterator.Current()->EventTimeStamp, "Something is out of sync.");
#endif
}
void EventLog::UpdateComputedMode()
{
TTDAssert(this->m_modeStack.Count() > 0, "Should never be empty!!!");
TTDMode cm = TTDMode::Invalid;
for(uint32 i = 0; i < this->m_modeStack.Count(); ++i)
{
TTDMode m = this->m_modeStack.GetAt(i);
switch(m)
{
case TTDMode::RecordMode:
case TTDMode::ReplayMode:
case TTDMode::DebuggerMode:
TTDAssert(i == 0, "One of these should always be first on the stack.");
cm = m;
break;
case TTDMode::CurrentlyEnabled:
case TTDMode::ExcludedExecutionTTAction:
case TTDMode::ExcludedExecutionDebuggerAction:
case TTDMode::DebuggerSuppressGetter:
case TTDMode::DebuggerSuppressBreakpoints:
case TTDMode::DebuggerLogBreakpoints:
TTDAssert(i != 0, "A base mode should always be first on the stack.");
cm |= m;
break;
default:
TTDAssert(false, "This mode is unknown or should never appear.");
break;
}
}
this->m_currentMode = cm;
//Set fast path values on ThreadContext
const JsUtil::List<Js::ScriptContext*, HeapAllocator>& contexts = this->m_threadContext->TTDContext->GetTTDContexts();
for(int32 i = 0; i < contexts.Count(); ++i)
{
this->SetModeFlagsOnContext(contexts.Item(i));
}
}
SnapShot* EventLog::DoSnapshotExtract_Helper(double gcTime)
{
SnapShot* snap = nullptr;
//Begin the actual snapshot operation
this->m_snapExtractor.BeginSnapshot(this->m_threadContext, gcTime);
this->m_snapExtractor.DoMarkWalk(this->m_threadContext);
///////////////////////////
//Phase 2: Evacuate marked objects
//Allows for parallel execute and evacuate (in conjunction with later refactoring)
this->m_snapExtractor.EvacuateMarkedIntoSnapshot(this->m_threadContext);
///////////////////////////
//Phase 3: Complete and return snapshot
snap = this->m_snapExtractor.CompleteSnapshot();
return snap;
}
void EventLog::ReplaySnapshotEvent()
{
SnapShot* snap = nullptr;
try
{
AUTO_NESTED_HANDLED_EXCEPTION_TYPE((ExceptionType)(ExceptionType_OutOfMemory | ExceptionType_StackOverflow));
//clear the weak collection pin set and force a GC (to get weak containers in a consistent state)
NSLogEvents::EventLogEntry* revt = this->m_currentReplayEventIterator.Current();
NSLogEvents::SnapshotEventLogEntry* snapUpdateEvt = NSLogEvents::GetInlineEventDataAs<NSLogEvents::SnapshotEventLogEntry, NSLogEvents::EventKind::SnapshotTag>(revt);
this->m_threadContext->TTDContext->SyncCtxtsAndRootsWithSnapshot_Replay(snapUpdateEvt->LiveContextCount, snapUpdateEvt->LiveContextIdArray, snapUpdateEvt->LongLivedRefRootsCount, snapUpdateEvt->LongLivedRefRootsIdArray);
this->m_threadContext->GetRecycler()->CollectNow<CollectNowForceInThread>();
//need to do a visit of some sort to reset the weak collection pin set
this->m_snapExtractor.DoResetWeakCollectionPinSet(this->m_threadContext);
//We always need to cleanup references (above but only do compare in extra diagnostics mode)
#if ENABLE_SNAPSHOT_COMPARE
this->SetSnapshotOrInflateInProgress(true);
this->PushMode(TTDMode::ExcludedExecutionTTAction);
snap = this->DoSnapshotExtract_Helper(0.0);
NSLogEvents::EventLogEntry* evt = this->m_currentReplayEventIterator.Current();
NSLogEvents::SnapshotEventLogEntry_EnsureSnapshotDeserialized(evt, this->m_threadContext);
const NSLogEvents::SnapshotEventLogEntry* recordedSnapEntry = NSLogEvents::GetInlineEventDataAs<NSLogEvents::SnapshotEventLogEntry, NSLogEvents::EventKind::SnapshotTag>(evt);
const SnapShot* recordedSnap = recordedSnapEntry->Snap;
TTDCompareMap compareMap(this->m_threadContext);
SnapShot::InitializeForSnapshotCompare(recordedSnap, snap, compareMap);
SnapShot::DoSnapshotCompare(recordedSnap, snap, compareMap);
TT_HEAP_DELETE(SnapShot, snap);
this->PopMode(TTDMode::ExcludedExecutionTTAction);
this->SetSnapshotOrInflateInProgress(false);
#endif
}
catch(...)
{
if(snap != nullptr)
{
TT_HEAP_DELETE(SnapShot, snap);
}
TTDAssert(false, "OOM in snapshot replay...");
}
#if ENABLE_BASIC_TRACE || ENABLE_FULL_BC_TRACE
this->m_threadContext->TTDExecutionInfo->GetTraceLogger()->WriteLiteralMsg("---SNAPSHOT EVENT---\n");
#endif
this->AdvanceTimeAndPositionForReplay(); //move along
}
void EventLog::ReplayEventLoopYieldPointEvent()
{
try
{
AUTO_NESTED_HANDLED_EXCEPTION_TYPE((ExceptionType)(ExceptionType_OutOfMemory | ExceptionType_StackOverflow));
this->m_threadContext->TTDContext->ClearLocalRootsAndRefreshMap_Replay();
}
catch(...)
{
TTDAssert(false, "OOM in yield point replay...");
}
this->AdvanceTimeAndPositionForReplay(); //move along
}
void EventLog::AbortReplayReturnToHost()
{
throw TTDebuggerAbortException::CreateAbortEndOfLog(_u("End of log reached -- returning to top-level."));
}
void EventLog::InitializeEventListVTable()
{
this->m_eventListVTable = this->m_miscSlabAllocator.SlabAllocateArray<NSLogEvents::EventLogEntryVTableEntry>((uint32)NSLogEvents::EventKind::Count);
TTD_CREATE_EVENTLIST_VTABLE_ENTRY(SnapshotTag, GlobalAPIWrapper, SnapshotEventLogEntry, nullptr, NSLogEvents::SnapshotEventLogEntry_UnloadEventMemory, NSLogEvents::SnapshotEventLogEntry_Emit, NSLogEvents::SnapshotEventLogEntry_Parse);
TTD_CREATE_EVENTLIST_VTABLE_ENTRY(EventLoopYieldPointTag, GlobalAPIWrapper, EventLoopYieldPointEntry, nullptr, nullptr, NSLogEvents::EventLoopYieldPointEntry_Emit, NSLogEvents::EventLoopYieldPointEntry_Parse);
TTD_CREATE_EVENTLIST_VTABLE_ENTRY(TopLevelCodeTag, None, CodeLoadEventLogEntry, nullptr, nullptr, NSLogEvents::CodeLoadEventLogEntry_Emit, NSLogEvents::CodeLoadEventLogEntry_Parse);
TTD_CREATE_EVENTLIST_VTABLE_ENTRY(TelemetryLogTag, None, TelemetryEventLogEntry, nullptr, NSLogEvents::TelemetryEventLogEntry_UnloadEventMemory, NSLogEvents::TelemetryEventLogEntry_Emit, NSLogEvents::TelemetryEventLogEntry_Parse);
TTD_CREATE_EVENTLIST_VTABLE_ENTRY(DoubleTag, None, DoubleEventLogEntry, nullptr, nullptr, NSLogEvents::DoubleEventLogEntry_Emit, NSLogEvents::DoubleEventLogEntry_Parse);
TTD_CREATE_EVENTLIST_VTABLE_ENTRY(StringTag, None, StringValueEventLogEntry, nullptr, NSLogEvents::StringValueEventLogEntry_UnloadEventMemory, NSLogEvents::StringValueEventLogEntry_Emit, NSLogEvents::StringValueEventLogEntry_Parse);
TTD_CREATE_EVENTLIST_VTABLE_ENTRY(RandomSeedTag, None, RandomSeedEventLogEntry, nullptr, nullptr, NSLogEvents::RandomSeedEventLogEntry_Emit, NSLogEvents::RandomSeedEventLogEntry_Parse);
TTD_CREATE_EVENTLIST_VTABLE_ENTRY(PropertyEnumTag, None, PropertyEnumStepEventLogEntry, nullptr, NSLogEvents::PropertyEnumStepEventLogEntry_UnloadEventMemory, NSLogEvents::PropertyEnumStepEventLogEntry_Emit, NSLogEvents::PropertyEnumStepEventLogEntry_Parse);
TTD_CREATE_EVENTLIST_VTABLE_ENTRY(SymbolCreationTag, None, SymbolCreationEventLogEntry, nullptr, nullptr, NSLogEvents::SymbolCreationEventLogEntry_Emit, NSLogEvents::SymbolCreationEventLogEntry_Parse);
TTD_CREATE_EVENTLIST_VTABLE_ENTRY(WeakCollectionContainsTag, None, WeakCollectionContainsEventLogEntry, nullptr, nullptr, NSLogEvents::WeakCollectionContainsEventLogEntry_Emit, NSLogEvents::WeakCollectionContainsEventLogEntry_Parse);
TTD_CREATE_EVENTLIST_VTABLE_ENTRY(ExternalCbRegisterCall, None, ExternalCbRegisterCallEventLogEntry, nullptr, nullptr, NSLogEvents::ExternalCbRegisterCallEventLogEntry_Emit, NSLogEvents::ExternalCbRegisterCallEventLogEntry_Parse);
TTD_CREATE_EVENTLIST_VTABLE_ENTRY(ExternalCallTag, None, ExternalCallEventLogEntry, nullptr, NSLogEvents::ExternalCallEventLogEntry_UnloadEventMemory, NSLogEvents::ExternalCallEventLogEntry_Emit, NSLogEvents::ExternalCallEventLogEntry_Parse);
TTD_CREATE_EVENTLIST_VTABLE_ENTRY(ExplicitLogWriteTag, None, ExplicitLogWriteEventLogEntry, nullptr, nullptr, NSLogEvents::ExplicitLogWriteEntry_Emit, NSLogEvents::ExplicitLogWriteEntry_Parse);
TTD_CREATE_EVENTLIST_VTABLE_ENTRY(CreateScriptContextActionTag, GlobalAPIWrapper, JsRTCreateScriptContextAction, NSLogEvents::CreateScriptContext_Execute, NSLogEvents::CreateScriptContext_UnloadEventMemory, NSLogEvents::CreateScriptContext_Emit, NSLogEvents::CreateScriptContext_Parse);
TTD_CREATE_EVENTLIST_VTABLE_ENTRY_COMMON(SetActiveScriptContextActionTag, GlobalAPIWrapper, JsRTSingleVarArgumentAction, SetActiveScriptContext_Execute);
#if !INT32VAR
TTD_CREATE_EVENTLIST_VTABLE_ENTRY_COMMON(CreateIntegerActionTag, ContextAPINoScriptWrapper, JsRTIntegralArgumentAction, CreateInt_Execute);
#endif
TTD_CREATE_EVENTLIST_VTABLE_ENTRY(CreateNumberActionTag, ContextAPINoScriptWrapper, JsRTDoubleArgumentAction, NSLogEvents::CreateNumber_Execute, nullptr, NSLogEvents::JsRTDoubleArgumentAction_Emit<NSLogEvents::EventKind::CreateNumberActionTag>, NSLogEvents::JsRTDoubleArgumentAction_Parse<NSLogEvents::EventKind::CreateNumberActionTag>);
TTD_CREATE_EVENTLIST_VTABLE_ENTRY_COMMON(CreateBooleanActionTag, ContextAPINoScriptWrapper, JsRTIntegralArgumentAction, CreateBoolean_Execute);
TTD_CREATE_EVENTLIST_VTABLE_ENTRY(CreateStringActionTag, ContextAPINoScriptWrapper, JsRTStringArgumentAction, NSLogEvents::CreateString_Execute, NSLogEvents::JsRTStringArgumentAction_UnloadEventMemory<NSLogEvents::EventKind::CreateStringActionTag>, NSLogEvents::JsRTStringArgumentAction_Emit<NSLogEvents::EventKind::CreateStringActionTag>, NSLogEvents::JsRTStringArgumentAction_Parse<NSLogEvents::EventKind::CreateStringActionTag>);
TTD_CREATE_EVENTLIST_VTABLE_ENTRY_COMMON(CreateSymbolActionTag, ContextAPIWrapper, JsRTSingleVarArgumentAction, CreateSymbol_Execute);
TTD_CREATE_EVENTLIST_VTABLE_ENTRY_COMMON(CreateErrorActionTag, ContextAPIWrapper, JsRTSingleVarArgumentAction, CreateError_Execute<NSLogEvents::EventKind::CreateErrorActionTag>);
TTD_CREATE_EVENTLIST_VTABLE_ENTRY_COMMON(CreateRangeErrorActionTag, ContextAPIWrapper, JsRTSingleVarArgumentAction, CreateError_Execute<NSLogEvents::EventKind::CreateRangeErrorActionTag>);
TTD_CREATE_EVENTLIST_VTABLE_ENTRY_COMMON(CreateReferenceErrorActionTag, ContextAPIWrapper, JsRTSingleVarArgumentAction, CreateError_Execute<NSLogEvents::EventKind::CreateReferenceErrorActionTag>);
TTD_CREATE_EVENTLIST_VTABLE_ENTRY_COMMON(CreateSyntaxErrorActionTag, ContextAPIWrapper, JsRTSingleVarArgumentAction, CreateError_Execute<NSLogEvents::EventKind::CreateSyntaxErrorActionTag>);
TTD_CREATE_EVENTLIST_VTABLE_ENTRY_COMMON(CreateTypeErrorActionTag, ContextAPIWrapper, JsRTSingleVarArgumentAction, CreateError_Execute<NSLogEvents::EventKind::CreateTypeErrorActionTag>);
TTD_CREATE_EVENTLIST_VTABLE_ENTRY_COMMON(CreateURIErrorActionTag, ContextAPIWrapper, JsRTSingleVarArgumentAction, CreateError_Execute<NSLogEvents::EventKind::CreateURIErrorActionTag>);
TTD_CREATE_EVENTLIST_VTABLE_ENTRY_COMMON(VarConvertToNumberActionTag, ContextAPIWrapper, JsRTSingleVarArgumentAction, VarConvertToNumber_Execute);
TTD_CREATE_EVENTLIST_VTABLE_ENTRY_COMMON(VarConvertToBooleanActionTag, ContextAPIWrapper, JsRTSingleVarArgumentAction, VarConvertToBoolean_Execute);
TTD_CREATE_EVENTLIST_VTABLE_ENTRY_COMMON(VarConvertToStringActionTag, ContextAPIWrapper, JsRTSingleVarArgumentAction, VarConvertToString_Execute);
TTD_CREATE_EVENTLIST_VTABLE_ENTRY_COMMON(VarConvertToObjectActionTag, ContextAPIWrapper, JsRTSingleVarArgumentAction, VarConvertToObject_Execute);
TTD_CREATE_EVENTLIST_VTABLE_ENTRY_COMMON(AddRootRefActionTag, GlobalAPIWrapper, JsRTSingleVarArgumentAction, AddRootRef_Execute);
TTD_CREATE_EVENTLIST_VTABLE_ENTRY_COMMON(AddWeakRootRefActionTag, GlobalAPIWrapper, JsRTSingleVarArgumentAction, AddWeakRootRef_Execute);
TTD_CREATE_EVENTLIST_VTABLE_ENTRY_COMMON(AllocateObjectActionTag, ContextAPINoScriptWrapper, JsRTResultOnlyAction, AllocateObject_Execute);
TTD_CREATE_EVENTLIST_VTABLE_ENTRY_COMMON(AllocateExternalObjectActionTag, ContextAPINoScriptWrapper, JsRTResultOnlyAction, AllocateExternalObject_Execute);
TTD_CREATE_EVENTLIST_VTABLE_ENTRY_COMMON(AllocateArrayActionTag, ContextAPINoScriptWrapper, JsRTIntegralArgumentAction, AllocateArrayAction_Execute);
TTD_CREATE_EVENTLIST_VTABLE_ENTRY_COMMON(AllocateArrayBufferActionTag, ContextAPIWrapper, JsRTIntegralArgumentAction, AllocateArrayBufferAction_Execute);
TTD_CREATE_EVENTLIST_VTABLE_ENTRY(AllocateExternalArrayBufferActionTag, ContextAPINoScriptWrapper, JsRTByteBufferAction, NSLogEvents::AllocateExternalArrayBufferAction_Execute, NSLogEvents::JsRTByteBufferAction_UnloadEventMemory<NSLogEvents::EventKind::AllocateExternalArrayBufferActionTag>, NSLogEvents::JsRTByteBufferAction_Emit<NSLogEvents::EventKind::AllocateExternalArrayBufferActionTag>, NSLogEvents::JsRTByteBufferAction_Parse<NSLogEvents::EventKind::AllocateExternalArrayBufferActionTag>);
TTD_CREATE_EVENTLIST_VTABLE_ENTRY_COMMON(AllocateFunctionActionTag, ContextAPIWrapper, JsRTSingleVarScalarArgumentAction, AllocateFunctionAction_Execute);
TTD_CREATE_EVENTLIST_VTABLE_ENTRY_COMMON(HostExitProcessTag, ContextAPIWrapper, JsRTIntegralArgumentAction, HostProcessExitAction_Execute);
TTD_CREATE_EVENTLIST_VTABLE_ENTRY_COMMON(GetAndClearExceptionWithMetadataActionTag, None, JsRTResultOnlyAction, GetAndClearExceptionWithMetadataAction_Execute);
TTD_CREATE_EVENTLIST_VTABLE_ENTRY_COMMON(GetAndClearExceptionActionTag, None, JsRTResultOnlyAction, GetAndClearExceptionAction_Execute);
TTD_CREATE_EVENTLIST_VTABLE_ENTRY_COMMON(SetExceptionActionTag, ContextAPINoScriptWrapper, JsRTSingleVarScalarArgumentAction, SetExceptionAction_Execute);
TTD_CREATE_EVENTLIST_VTABLE_ENTRY_COMMON(HasPropertyActionTag, ContextAPIWrapper, JsRTSingleVarScalarArgumentAction, HasPropertyAction_Execute);
TTD_CREATE_EVENTLIST_VTABLE_ENTRY_COMMON(InstanceOfActionTag, ContextAPIWrapper, JsRTDoubleVarArgumentAction, InstanceOfAction_Execute);
TTD_CREATE_EVENTLIST_VTABLE_ENTRY_COMMON(EqualsActionTag, ContextAPIWrapper, JsRTDoubleVarSingleScalarArgumentAction, EqualsAction_Execute);
TTD_CREATE_EVENTLIST_VTABLE_ENTRY_COMMON(GetPropertyIdFromSymbolTag, ContextAPINoScriptWrapper, JsRTSingleVarArgumentAction, GetPropertyIdFromSymbolAction_Execute);
TTD_CREATE_EVENTLIST_VTABLE_ENTRY_COMMON(GetPrototypeActionTag, ContextAPIWrapper, JsRTSingleVarArgumentAction, GetPrototypeAction_Execute);
TTD_CREATE_EVENTLIST_VTABLE_ENTRY_COMMON(GetPropertyActionTag, ContextAPIWrapper, JsRTSingleVarScalarArgumentAction, GetPropertyAction_Execute);
TTD_CREATE_EVENTLIST_VTABLE_ENTRY_COMMON(GetIndexActionTag, ContextAPIWrapper, JsRTDoubleVarArgumentAction, GetIndexAction_Execute);
TTD_CREATE_EVENTLIST_VTABLE_ENTRY_COMMON(GetOwnPropertyInfoActionTag, ContextAPIWrapper, JsRTSingleVarScalarArgumentAction, GetOwnPropertyInfoAction_Execute);
TTD_CREATE_EVENTLIST_VTABLE_ENTRY_COMMON(GetOwnPropertyNamesInfoActionTag, ContextAPIWrapper, JsRTSingleVarArgumentAction, GetOwnPropertyNamesInfoAction_Execute);
TTD_CREATE_EVENTLIST_VTABLE_ENTRY_COMMON(GetOwnPropertySymbolsInfoActionTag, ContextAPIWrapper, JsRTSingleVarArgumentAction, GetOwnPropertySymbolsInfoAction_Execute);
TTD_CREATE_EVENTLIST_VTABLE_ENTRY_COMMON(DefinePropertyActionTag, ContextAPIWrapper, JsRTDoubleVarSingleScalarArgumentAction, DefinePropertyAction_Execute);
TTD_CREATE_EVENTLIST_VTABLE_ENTRY_COMMON(DeletePropertyActionTag, ContextAPIWrapper, JsRTSingleVarDoubleScalarArgumentAction, DeletePropertyAction_Execute);
TTD_CREATE_EVENTLIST_VTABLE_ENTRY_COMMON(SetPrototypeActionTag, ContextAPIWrapper, JsRTDoubleVarArgumentAction, SetPrototypeAction_Execute);
TTD_CREATE_EVENTLIST_VTABLE_ENTRY_COMMON(SetPropertyActionTag, ContextAPIWrapper, JsRTDoubleVarDoubleScalarArgumentAction, SetPropertyAction_Execute);
TTD_CREATE_EVENTLIST_VTABLE_ENTRY_COMMON(SetIndexActionTag, ContextAPIWrapper, JsRTTrippleVarArgumentAction, SetIndexAction_Execute);
TTD_CREATE_EVENTLIST_VTABLE_ENTRY_COMMON(GetTypedArrayInfoActionTag, None, JsRTSingleVarArgumentAction, GetTypedArrayInfoAction_Execute);
TTD_CREATE_EVENTLIST_VTABLE_ENTRY(RawBufferCopySync, ContextAPIWrapper, JsRTRawBufferCopyAction, NSLogEvents::RawBufferCopySync_Execute, nullptr, NSLogEvents::JsRTRawBufferCopyAction_Emit, NSLogEvents::JsRTRawBufferCopyAction_Parse);
TTD_CREATE_EVENTLIST_VTABLE_ENTRY(RawBufferModifySync, ContextAPIWrapper, JsRTRawBufferModifyAction, NSLogEvents::RawBufferModifySync_Execute, NSLogEvents::JsRTRawBufferModifyAction_UnloadEventMemory<NSLogEvents::EventKind::RawBufferModifySync>, NSLogEvents::JsRTRawBufferModifyAction_Emit<NSLogEvents::EventKind::RawBufferModifySync>, NSLogEvents::JsRTRawBufferModifyAction_Parse<NSLogEvents::EventKind::RawBufferModifySync>);
TTD_CREATE_EVENTLIST_VTABLE_ENTRY(RawBufferAsyncModificationRegister, ContextAPIWrapper, JsRTRawBufferModifyAction, NSLogEvents::RawBufferAsyncModificationRegister_Execute, NSLogEvents::JsRTRawBufferModifyAction_UnloadEventMemory<NSLogEvents::EventKind::RawBufferAsyncModificationRegister>, NSLogEvents::JsRTRawBufferModifyAction_Emit<NSLogEvents::EventKind::RawBufferAsyncModificationRegister>, NSLogEvents::JsRTRawBufferModifyAction_Parse<NSLogEvents::EventKind::RawBufferAsyncModificationRegister>);
TTD_CREATE_EVENTLIST_VTABLE_ENTRY(RawBufferAsyncModifyComplete, ContextAPIWrapper, JsRTRawBufferModifyAction, NSLogEvents::RawBufferAsyncModifyComplete_Execute, NSLogEvents::JsRTRawBufferModifyAction_UnloadEventMemory<NSLogEvents::EventKind::RawBufferAsyncModifyComplete>, NSLogEvents::JsRTRawBufferModifyAction_Emit<NSLogEvents::EventKind::RawBufferAsyncModifyComplete>, NSLogEvents::JsRTRawBufferModifyAction_Parse<NSLogEvents::EventKind::RawBufferAsyncModifyComplete>);
TTD_CREATE_EVENTLIST_VTABLE_ENTRY(ConstructCallActionTag, ContextAPIWrapper, JsRTConstructCallAction, NSLogEvents::JsRTConstructCallAction_Execute, NSLogEvents::JsRTConstructCallAction_UnloadEventMemory, NSLogEvents::JsRTConstructCallAction_Emit, NSLogEvents::JsRTConstructCallAction_Parse);
TTD_CREATE_EVENTLIST_VTABLE_ENTRY(CodeParseActionTag, ContextAPINoScriptWrapper, JsRTCodeParseAction, NSLogEvents::JsRTCodeParseAction_Execute, NSLogEvents::JsRTCodeParseAction_UnloadEventMemory, NSLogEvents::JsRTCodeParseAction_Emit, NSLogEvents::JsRTCodeParseAction_Parse);
TTD_CREATE_EVENTLIST_VTABLE_ENTRY(CallExistingFunctionActionTag, ContextAPIWrapper, JsRTCallFunctionAction, NSLogEvents::JsRTCallFunctionAction_Execute, NSLogEvents::JsRTCallFunctionAction_UnloadEventMemory, NSLogEvents::JsRTCallFunctionAction_Emit, NSLogEvents::JsRTCallFunctionAction_Parse);
}
EventLog::EventLog(ThreadContext* threadContext)
: m_threadContext(threadContext), m_eventSlabAllocator(TTD_SLAB_BLOCK_ALLOCATION_SIZE_MID), m_miscSlabAllocator(TTD_SLAB_BLOCK_ALLOCATION_SIZE_SMALL),
m_eventTimeCtr(0), m_timer(), m_topLevelCallbackEventTime(-1),
m_eventListVTable(nullptr), m_eventList(&this->m_eventSlabAllocator), m_currentReplayEventIterator(),
m_modeStack(), m_currentMode(TTDMode::Invalid),
m_snapExtractor(), m_elapsedExecutionTimeSinceSnapshot(0.0),
m_lastInflateSnapshotTime(-1), m_lastInflateMap(nullptr), m_propertyRecordList(&this->m_miscSlabAllocator),
m_sourceInfoCount(0), m_loadedTopLevelScripts(&this->m_miscSlabAllocator), m_newFunctionTopLevelScripts(&this->m_miscSlabAllocator), m_evalTopLevelScripts(&this->m_miscSlabAllocator)
{
this->InitializeEventListVTable();
this->m_eventList.SetVTable(this->m_eventListVTable);
this->m_modeStack.Push(TTDMode::Invalid);
Recycler * recycler = threadContext->GetRecycler();
this->m_propertyRecordPinSet.Root(RecyclerNew(recycler, PropertyRecordPinSet, recycler), recycler);
}
EventLog::~EventLog()
{
this->m_eventList.UnloadEventList();
if(this->m_lastInflateMap != nullptr)
{
TT_HEAP_DELETE(InflateMap, this->m_lastInflateMap);
this->m_lastInflateMap = nullptr;
}
if(this->m_propertyRecordPinSet != nullptr)
{
this->m_propertyRecordPinSet.Unroot(this->m_propertyRecordPinSet->GetAllocator());
}
}
void EventLog::UnloadAllLogData()
{
this->m_eventList.UnloadEventList();
}
void EventLog::InitForTTDRecord()
{
//pin all the current properties so they don't move/disappear on us
for(Js::PropertyId pid = TotalNumberOfBuiltInProperties; pid < this->m_threadContext->GetMaxPropertyId(); ++pid)
{
const Js::PropertyRecord* pRecord = this->m_threadContext->GetPropertyName(pid);
this->AddPropertyRecord(pRecord);
}
this->SetGlobalMode(TTDMode::RecordMode);
}
void EventLog::InitForTTDReplay(TTDataIOInfo& iofp, const char* parseUri, size_t parseUriLength, bool debug)
{
if (debug)
{
this->SetGlobalMode(TTDMode::DebuggerMode);
}
else
{
this->SetGlobalMode(TTDMode::ReplayMode);
}
this->ParseLogInto(iofp, parseUri, parseUriLength);
Js::PropertyId maxPid = TotalNumberOfBuiltInProperties + 1;
JsUtil::BaseDictionary<Js::PropertyId, NSSnapType::SnapPropertyRecord*, HeapAllocator> pidMap(&HeapAllocator::Instance);
for(auto iter = this->m_propertyRecordList.GetIterator(); iter.IsValid(); iter.MoveNext())
{
maxPid = max(maxPid, iter.Current()->PropertyId);
pidMap.AddNew(iter.Current()->PropertyId, iter.Current());
}
for(Js::PropertyId cpid = TotalNumberOfBuiltInProperties; cpid <= maxPid; ++cpid)
{
NSSnapType::SnapPropertyRecord* spRecord = pidMap.Item(cpid);
const Js::PropertyRecord* newPropertyRecord = NSSnapType::InflatePropertyRecord(spRecord, this->m_threadContext);
if(!this->m_propertyRecordPinSet->ContainsKey(const_cast<Js::PropertyRecord*>(newPropertyRecord)))
{
this->m_propertyRecordPinSet->AddNew(const_cast<Js::PropertyRecord*>(newPropertyRecord));
}
}
}
void EventLog::SetGlobalMode(TTDMode m)
{
TTDAssert(m == TTDMode::RecordMode || m == TTDMode::ReplayMode || m == TTDMode::DebuggerMode, "These are the only valid global modes");
this->m_modeStack.SetAt(0, m);
this->UpdateComputedMode();
}
void EventLog::SetSnapshotOrInflateInProgress(bool flag)
{
const JsUtil::List<Js::ScriptContext*, HeapAllocator>& contexts = this->m_threadContext->TTDContext->GetTTDContexts();
for(int32 i = 0; i < contexts.Count(); ++i)
{
TTDAssert(contexts.Item(i)->TTDSnapshotOrInflateInProgress != flag, "This is not re-entrant!!!");
contexts.Item(i)->TTDSnapshotOrInflateInProgress = flag;
}
}
void EventLog::PushMode(TTDMode m)
{
TTDAssert(m == TTDMode::CurrentlyEnabled || m == TTDMode::ExcludedExecutionTTAction || m == TTDMode::ExcludedExecutionDebuggerAction ||
m == TTDMode::DebuggerSuppressGetter || m == TTDMode::DebuggerSuppressBreakpoints || m == TTDMode::DebuggerLogBreakpoints, "These are the only valid mode modifiers to push");
this->m_modeStack.Push(m);
this->UpdateComputedMode();
}
void EventLog::PopMode(TTDMode m)
{
TTDAssert(m == TTDMode::CurrentlyEnabled || m == TTDMode::ExcludedExecutionTTAction || m == TTDMode::ExcludedExecutionDebuggerAction ||
m == TTDMode::DebuggerSuppressGetter || m == TTDMode::DebuggerSuppressBreakpoints || m == TTDMode::DebuggerLogBreakpoints, "These are the only valid mode modifiers to pop");
TTDAssert(this->m_modeStack.Peek() == m, "Push/Pop is not matched so something went wrong.");
this->m_modeStack.Pop();
this->UpdateComputedMode();
}
TTDMode EventLog::GetCurrentTTDMode() const
{
return this->m_currentMode;
}
void EventLog::SetModeFlagsOnContext(Js::ScriptContext* ctx)
{
TTDMode cm = this->m_currentMode;
ctx->TTDRecordModeEnabled = (cm & (TTDMode::RecordMode | TTDMode::AnyExcludedMode)) == TTDMode::RecordMode;
ctx->TTDReplayModeEnabled = (cm & (TTDMode::ReplayMode | TTDMode::AnyExcludedMode)) == TTDMode::ReplayMode;
ctx->TTDRecordOrReplayModeEnabled = (ctx->TTDRecordModeEnabled | ctx->TTDReplayModeEnabled);
ctx->TTDShouldPerformRecordAction = (cm & (TTDMode::RecordMode | TTDMode::CurrentlyEnabled | TTDMode::AnyExcludedMode)) == (TTDMode::RecordMode | TTDMode::CurrentlyEnabled);
ctx->TTDShouldPerformReplayAction = (cm & (TTDMode::ReplayMode | TTDMode::CurrentlyEnabled | TTDMode::AnyExcludedMode)) == (TTDMode::ReplayMode | TTDMode::CurrentlyEnabled);
ctx->TTDShouldPerformRecordOrReplayAction = (ctx->TTDShouldPerformRecordAction | ctx->TTDShouldPerformReplayAction);
ctx->TTDShouldPerformDebuggerAction = (cm & (TTDMode::DebuggerMode | TTDMode::CurrentlyEnabled | TTDMode::AnyExcludedMode)) == (TTDMode::DebuggerMode | TTDMode::CurrentlyEnabled);
ctx->TTDShouldSuppressGetterInvocationForDebuggerEvaluation = (cm & TTDMode::DebuggerSuppressGetter) == TTDMode::DebuggerSuppressGetter;
}
void EventLog::GetModesForExplicitContextCreate(bool& inRecord, bool& activelyRecording, bool& inReplay)
{
inRecord = (this->m_currentMode & (TTDMode::RecordMode | TTDMode::AnyExcludedMode)) == TTDMode::RecordMode;
activelyRecording = (this->m_currentMode & (TTDMode::RecordMode | TTDMode::CurrentlyEnabled | TTDMode::AnyExcludedMode)) == (TTDMode::RecordMode | TTDMode::CurrentlyEnabled);
inReplay = (this->m_currentMode & (TTDMode::ReplayMode | TTDMode::AnyExcludedMode)) == TTDMode::ReplayMode;
}
bool EventLog::IsDebugModeFlagSet() const
{
return (this->m_currentMode & TTDMode::DebuggerMode) == TTDMode::DebuggerMode;
}
bool EventLog::ShouldDoGetterInvocationSupression() const
{
return (this->m_currentMode & TTD::TTDMode::DebuggerMode) == TTD::TTDMode::DebuggerMode;
}
void EventLog::AddPropertyRecord(const Js::PropertyRecord* record)
{
this->m_propertyRecordPinSet->AddNew(const_cast<Js::PropertyRecord*>(record));
}
const NSSnapValues::TopLevelScriptLoadFunctionBodyResolveInfo* EventLog::AddScriptLoad(Js::FunctionBody* fb, Js::ModuleID moduleId, uint64 sourceContextId, const byte* source, uint32 sourceLen, LoadScriptFlag loadFlag)
{
NSSnapValues::TopLevelScriptLoadFunctionBodyResolveInfo* fbInfo = this->m_loadedTopLevelScripts.NextOpenEntry();
uint32 fCount = (this->m_loadedTopLevelScripts.Count() + this->m_newFunctionTopLevelScripts.Count() + this->m_evalTopLevelScripts.Count());
bool isUtf8 = ((loadFlag & LoadScriptFlag_Utf8Source) == LoadScriptFlag_Utf8Source);
NSSnapValues::ExtractTopLevelLoadedFunctionBodyInfo(fbInfo, fb, fCount, moduleId, sourceContextId, isUtf8, source, sourceLen, loadFlag, this->m_miscSlabAllocator);
this->m_sourceInfoCount = max(this->m_sourceInfoCount, fb->GetUtf8SourceInfo()->GetSourceInfoId() + 1);
return fbInfo;
}
const NSSnapValues::TopLevelNewFunctionBodyResolveInfo* EventLog::AddNewFunction(Js::FunctionBody* fb, Js::ModuleID moduleId, const char16* source, uint32 sourceLen)
{
NSSnapValues::TopLevelNewFunctionBodyResolveInfo* fbInfo = this->m_newFunctionTopLevelScripts.NextOpenEntry();
uint32 fCount = (this->m_loadedTopLevelScripts.Count() + this->m_newFunctionTopLevelScripts.Count() + this->m_evalTopLevelScripts.Count());
NSSnapValues::ExtractTopLevelNewFunctionBodyInfo(fbInfo, fb, fCount, moduleId, source, sourceLen, this->m_miscSlabAllocator);
this->m_sourceInfoCount = max(this->m_sourceInfoCount, fb->GetUtf8SourceInfo()->GetSourceInfoId() + 1);
return fbInfo;
}
const NSSnapValues::TopLevelEvalFunctionBodyResolveInfo* EventLog::AddEvalFunction(Js::FunctionBody* fb, Js::ModuleID moduleId, const char16* source, uint32 sourceLen, uint32 grfscr, bool registerDocument, BOOL isIndirect, BOOL strictMode)
{
NSSnapValues::TopLevelEvalFunctionBodyResolveInfo* fbInfo = this->m_evalTopLevelScripts.NextOpenEntry();
uint32 fCount = (this->m_loadedTopLevelScripts.Count() + this->m_newFunctionTopLevelScripts.Count() + this->m_evalTopLevelScripts.Count());
NSSnapValues::ExtractTopLevelEvalFunctionBodyInfo(fbInfo, fb, fCount, moduleId, source, sourceLen, grfscr, registerDocument, isIndirect, strictMode, this->m_miscSlabAllocator);
this->m_sourceInfoCount = max(this->m_sourceInfoCount, fb->GetUtf8SourceInfo()->GetSourceInfoId() + 1);
return fbInfo;
}
uint32 EventLog::GetSourceInfoCount() const
{
return this->m_sourceInfoCount;
}
void EventLog::RecordTopLevelCodeAction(uint32 bodyCtrId)
{
NSLogEvents::CodeLoadEventLogEntry* clEvent = this->RecordGetInitializedEvent_DataOnly<NSLogEvents::CodeLoadEventLogEntry, NSLogEvents::EventKind::TopLevelCodeTag>();
clEvent->BodyCounterId = bodyCtrId;
}
uint32 EventLog::ReplayTopLevelCodeAction()
{
const NSLogEvents::CodeLoadEventLogEntry* clEvent = this->ReplayGetReplayEvent_Helper<NSLogEvents::CodeLoadEventLogEntry, NSLogEvents::EventKind::TopLevelCodeTag>();
return clEvent->BodyCounterId;
}
void EventLog::RecordTelemetryLogEvent(Js::JavascriptString* infoStringJs, bool doPrint)
{
NSLogEvents::TelemetryEventLogEntry* tEvent = this->RecordGetInitializedEvent_DataOnly<NSLogEvents::TelemetryEventLogEntry, NSLogEvents::EventKind::TelemetryLogTag>();
this->m_eventSlabAllocator.CopyStringIntoWLength(infoStringJs->GetSz(), infoStringJs->GetLength(), tEvent->InfoString);
tEvent->DoPrint = doPrint;
#if ENABLE_BASIC_TRACE || ENABLE_FULL_BC_TRACE
this->m_threadContext->TTDExecutionInfo->GetTraceLogger()->ForceFlush();
#endif
}
void EventLog::ReplayTelemetryLogEvent(Js::JavascriptString* infoStringJs)
{
#if !ENABLE_TTD_INTERNAL_DIAGNOSTICS
this->AdvanceTimeAndPositionForReplay(); //just eat the telemetry event
#else
const NSLogEvents::TelemetryEventLogEntry* tEvent = this->ReplayGetReplayEvent_Helper<NSLogEvents::TelemetryEventLogEntry, NSLogEvents::EventKind::TelemetryLogTag>();
uint32 infoStrLength = (uint32)infoStringJs->GetLength();
const char16* infoStr = infoStringJs->GetSz();
if(tEvent->InfoString.Length != infoStrLength)
{
wprintf(_u("New Telemetry Msg: %ls\n"), infoStr);
wprintf(_u("Original Telemetry Msg: %ls\n"), tEvent->InfoString.Contents);
TTDAssert(false, "Telemetry messages differ??");
}
else
{
for(uint32 i = 0; i < infoStrLength; ++i)
{
if(tEvent->InfoString.Contents[i] != infoStr[i])
{
wprintf(_u("New Telemetry Msg: %ls\n"), infoStr);
wprintf(_u("Original Telemetry Msg: %ls\n"), tEvent->InfoString.Contents);
TTDAssert(false, "Telemetry messages differ??");
break;
}
}
}
#endif
#if ENABLE_BASIC_TRACE || ENABLE_FULL_BC_TRACE
this->m_threadContext->TTDExecutionInfo->GetTraceLogger()->ForceFlush();
#endif
}
void EventLog::RecordEmitLogEvent(Js::JavascriptString* uriString)
{
this->RecordGetInitializedEvent_DataOnly<NSLogEvents::ExplicitLogWriteEventLogEntry, NSLogEvents::EventKind::ExplicitLogWriteTag>();
AutoArrayPtr<char> uri(HeapNewArrayZ(char, uriString->GetLength() * 3), uriString->GetLength() * 3);
size_t uriLength = utf8::EncodeInto((LPUTF8)((char*)uri), uriString->GetSz(), uriString->GetLength());
this->EmitLog(uri, uriLength);
}
void EventLog::ReplayEmitLogEvent()
{
this->ReplayGetReplayEvent_Helper<NSLogEvents::ExplicitLogWriteEventLogEntry, NSLogEvents::EventKind::ExplicitLogWriteTag>();
//check if at end of log -- if so we are done and don't want to execute any more
if(!this->m_currentReplayEventIterator.IsValid())
{
this->AbortReplayReturnToHost();
}
}
void EventLog::RecordDateTimeEvent(double time)
{
NSLogEvents::DoubleEventLogEntry* dEvent = this->RecordGetInitializedEvent_DataOnly<NSLogEvents::DoubleEventLogEntry, NSLogEvents::EventKind::DoubleTag>();
dEvent->DoubleValue = time;
}
void EventLog::RecordDateStringEvent(Js::JavascriptString* stringValue)
{
NSLogEvents::StringValueEventLogEntry* sEvent = this->RecordGetInitializedEvent_DataOnly<NSLogEvents::StringValueEventLogEntry, NSLogEvents::EventKind::StringTag>();
this->m_eventSlabAllocator.CopyStringIntoWLength(stringValue->GetSz(), stringValue->GetLength(), sEvent->StringValue);
}
void EventLog::ReplayDateTimeEvent(double* result)
{
const NSLogEvents::DoubleEventLogEntry* dEvent = this->ReplayGetReplayEvent_Helper<NSLogEvents::DoubleEventLogEntry, NSLogEvents::EventKind::DoubleTag>();
*result = dEvent->DoubleValue;
}
void EventLog::ReplayDateStringEvent(Js::ScriptContext* ctx, Js::JavascriptString** result)
{
const NSLogEvents::StringValueEventLogEntry* sEvent = this->ReplayGetReplayEvent_Helper<NSLogEvents::StringValueEventLogEntry, NSLogEvents::EventKind::StringTag>();
const TTString& str = sEvent->StringValue;
*result = Js::JavascriptString::NewCopyBuffer(str.Contents, str.Length, ctx);
}
void EventLog::RecordExternalEntropyRandomEvent(uint64 seed0, uint64 seed1)
{
NSLogEvents::RandomSeedEventLogEntry* rsEvent = this->RecordGetInitializedEvent_DataOnly<NSLogEvents::RandomSeedEventLogEntry, NSLogEvents::EventKind::RandomSeedTag>();
rsEvent->Seed0 = seed0;
rsEvent->Seed1 = seed1;
}
void EventLog::ReplayExternalEntropyRandomEvent(uint64* seed0, uint64* seed1)
{
const NSLogEvents::RandomSeedEventLogEntry* rsEvent = this->ReplayGetReplayEvent_Helper<NSLogEvents::RandomSeedEventLogEntry, NSLogEvents::EventKind::RandomSeedTag>();
*seed0 = rsEvent->Seed0;
*seed1 = rsEvent->Seed1;
}
void EventLog::RecordPropertyEnumEvent(BOOL returnCode, Js::PropertyId pid, Js::PropertyAttributes attributes, Js::JavascriptString* propertyName)
{
//When we replay we can just skip this pid cause it should never matter -- but if return code is false then we need to record the "at end" info
if(returnCode && Js::IsInternalPropertyId(pid))
{
return;
}
NSLogEvents::PropertyEnumStepEventLogEntry* peEvent = this->RecordGetInitializedEvent_DataOnly<NSLogEvents::PropertyEnumStepEventLogEntry, NSLogEvents::EventKind::PropertyEnumTag>();
peEvent->ReturnCode = returnCode;
peEvent->Pid = pid;
peEvent->Attributes = attributes;
InitializeAsNullPtrTTString(peEvent->PropertyString);
#if ENABLE_TTD_INTERNAL_DIAGNOSTICS
if(returnCode)
{
this->m_eventSlabAllocator.CopyStringIntoWLength(propertyName->GetSz(), propertyName->GetLength(), peEvent->PropertyString);
}
#else
if(returnCode && pid == Js::Constants::NoProperty)
{
this->m_eventSlabAllocator.CopyStringIntoWLength(propertyName->GetSz(), propertyName->GetLength(), peEvent->PropertyString);
}
#endif
#if ENABLE_BASIC_TRACE || ENABLE_FULL_BC_TRACE
this->m_threadContext->TTDExecutionInfo->GetTraceLogger()->WriteEnumAction(this->m_eventTimeCtr - 1, returnCode, pid, attributes, propertyName);
#endif
}
void EventLog::ReplayPropertyEnumEvent(Js::ScriptContext* requestContext, BOOL* returnCode, Js::BigPropertyIndex* newIndex, const Js::DynamicObject* obj, Js::PropertyId* pid, Js::PropertyAttributes* attributes, Js::JavascriptString** propertyName)
{
const NSLogEvents::PropertyEnumStepEventLogEntry* peEvent = this->ReplayGetReplayEvent_Helper<NSLogEvents::PropertyEnumStepEventLogEntry, NSLogEvents::EventKind::PropertyEnumTag>();
*returnCode = peEvent->ReturnCode;
*pid = peEvent->Pid;
*attributes = peEvent->Attributes;
if(*returnCode)
{
TTDAssert(*pid != Js::Constants::NoProperty, "This is so weird we need to figure out what this means.");
TTDAssert(!Js::IsInternalPropertyId(*pid), "We should skip recording this.");
Js::PropertyString* propertyString = requestContext->GetPropertyString(*pid);
*propertyName = propertyString;
const Js::PropertyRecord* pRecord = requestContext->GetPropertyName(*pid);
*newIndex = obj->GetDynamicType()->GetTypeHandler()->GetPropertyIndex_EnumerateTTD(pRecord);
TTDAssert(*newIndex != Js::Constants::NoBigSlot, "If *returnCode is true then we found it during record -- but missing in replay.");
}
else
{
*propertyName = nullptr;
*newIndex = obj->GetDynamicType()->GetTypeHandler()->GetPropertyCount();
}
#if ENABLE_BASIC_TRACE || ENABLE_FULL_BC_TRACE
this->m_threadContext->TTDExecutionInfo->GetTraceLogger()->WriteEnumAction(this->m_eventTimeCtr - 1, *returnCode, *pid, *attributes, *propertyName);
#endif
}
void EventLog::RecordSymbolCreationEvent(Js::PropertyId pid)
{
NSLogEvents::SymbolCreationEventLogEntry* scEvent = this->RecordGetInitializedEvent_DataOnly<NSLogEvents::SymbolCreationEventLogEntry, NSLogEvents::EventKind::SymbolCreationTag>();
scEvent->Pid = pid;
}
void EventLog::ReplaySymbolCreationEvent(Js::PropertyId* pid)
{
const NSLogEvents::SymbolCreationEventLogEntry* scEvent = this->ReplayGetReplayEvent_Helper<NSLogEvents::SymbolCreationEventLogEntry, NSLogEvents::EventKind::SymbolCreationTag>();
*pid = scEvent->Pid;
}
void EventLog::RecordWeakCollectionContainsEvent(bool contains)
{
NSLogEvents::WeakCollectionContainsEventLogEntry* wcEvent = this->RecordGetInitializedEvent_DataOnly<NSLogEvents::WeakCollectionContainsEventLogEntry, NSLogEvents::EventKind::WeakCollectionContainsTag>();
wcEvent->ContainsValue = contains;
}
bool EventLog::ReplayWeakCollectionContainsEvent()
{
const NSLogEvents::WeakCollectionContainsEventLogEntry* wcEvent = this->ReplayGetReplayEvent_Helper<NSLogEvents::WeakCollectionContainsEventLogEntry, NSLogEvents::EventKind::WeakCollectionContainsTag>();
return wcEvent->ContainsValue;
}
NSLogEvents::EventLogEntry* EventLog::RecordExternalCallEvent(Js::JavascriptFunction* func, int32 rootDepth, uint32 argc, Js::Var* argv, bool checkExceptions)
{
NSLogEvents::ExternalCallEventLogEntry* ecEvent = nullptr;
NSLogEvents::EventLogEntry* evt = this->RecordGetInitializedEvent<NSLogEvents::ExternalCallEventLogEntry, NSLogEvents::EventKind::ExternalCallTag>(&ecEvent);
//We never fail with an exception (instead we set the HasRecordedException in script context)
evt->ResultStatus = 0;
NSLogEvents::ExternalCallEventLogEntry_ProcessArgs(evt, rootDepth, func, argc, argv, checkExceptions, this->m_eventSlabAllocator);
#if ENABLE_TTD_INTERNAL_DIAGNOSTICS
NSLogEvents::ExternalCallEventLogEntry_ProcessDiagInfoPre(evt, func, this->m_eventSlabAllocator);
#endif
#if ENABLE_BASIC_TRACE || ENABLE_FULL_BC_TRACE
this->m_threadContext->TTDExecutionInfo->GetTraceLogger()->WriteCall(func, true, argc, argv, this->GetLastEventTime());
#endif
return evt;
}
void EventLog::RecordExternalCallEvent_Complete(Js::JavascriptFunction* efunction, NSLogEvents::EventLogEntry* evt, Js::Var result)
{
NSLogEvents::ExternalCallEventLogEntry_ProcessReturn(evt, result, this->GetLastEventTime());
#if ENABLE_BASIC_TRACE || ENABLE_FULL_BC_TRACE
this->m_threadContext->TTDExecutionInfo->GetTraceLogger()->WriteReturn(efunction, result, this->GetLastEventTime());
#endif
}
void EventLog::ReplayExternalCallEvent(Js::JavascriptFunction* function, uint32 argc, Js::Var* argv, Js::Var* result)
{
TTDAssert(result != nullptr, "Must be non-null!!!");
TTDAssert(*result == nullptr, "And initialized to a default value.");
const NSLogEvents::ExternalCallEventLogEntry* ecEvent = this->ReplayGetReplayEvent_Helper<NSLogEvents::ExternalCallEventLogEntry, NSLogEvents::EventKind::ExternalCallTag>();
Js::ScriptContext* ctx = function->GetScriptContext();
TTDAssert(ctx != nullptr, "Not sure how this would be possible but check just in case.");
ThreadContextTTD* executeContext = ctx->GetThreadContext()->TTDContext;
#if ENABLE_BASIC_TRACE || ENABLE_FULL_BC_TRACE
this->m_threadContext->TTDExecutionInfo->GetTraceLogger()->WriteCall(function, true, argc, argv, this->GetLastEventTime());
#endif
//make sure we log all of the passed arguments in the replay host
TTDAssert(argc + 1 == ecEvent->ArgCount, "Mismatch in args!!!");
TTDVar recordedFunction = ecEvent->ArgArray[0];
NSLogEvents::PassVarToHostInReplay(executeContext, recordedFunction, function);
for(uint32 i = 0; i < argc; ++i)
{
Js::Var replayVar = argv[i];
TTDVar recordedVar = ecEvent->ArgArray[i + 1];
NSLogEvents::PassVarToHostInReplay(executeContext, recordedVar, replayVar);
}
//replay anything that happens in the external call
BEGIN_LEAVE_SCRIPT(ctx)
{
this->ReplayActionEventSequenceThroughTime(ecEvent->LastNestedEventTime);
}
END_LEAVE_SCRIPT(ctx);
#if ENABLE_TTD_INTERNAL_DIAGNOSTICS
TTDAssert(!this->m_currentReplayEventIterator.IsValid() || this->m_currentReplayEventIterator.Current()->EventTimeStamp == this->m_eventTimeCtr, "Out of Sync!!!");
#endif
*result = NSLogEvents::InflateVarInReplay(executeContext, ecEvent->ReturnValue);
#if ENABLE_BASIC_TRACE || ENABLE_FULL_BC_TRACE
this->m_threadContext->TTDExecutionInfo->GetTraceLogger()->WriteReturn(function, *result, this->GetLastEventTime());
#endif
//if we had exception info then we need to patch it up and do what the external call did
if(ecEvent->CheckExceptionStatus)
{
if(ctx->HasRecordedException())
{
bool considerPassingToDebugger = false;
Js::JavascriptExceptionObject* recordedException = ctx->GetAndClearRecordedException(&considerPassingToDebugger);
if(recordedException != nullptr)
{
// If this is script termination, then throw ScriptAbortExceptio, else throw normal Exception object.
if(recordedException == ctx->GetThreadContext()->GetPendingTerminatedErrorObject())
{
throw Js::ScriptAbortException();
}
else
{
Js::JavascriptExceptionOperators::RethrowExceptionObject(recordedException, ctx, considerPassingToDebugger);
}
}
}
}
if(*result == nullptr)
{
*result = ctx->GetLibrary()->GetUndefined();
}
else
{
*result = Js::CrossSite::MarshalVar(ctx, *result);
}
}
NSLogEvents::EventLogEntry* EventLog::RecordEnqueueTaskEvent(Js::Var taskVar)
{
NSLogEvents::ExternalCbRegisterCallEventLogEntry* ecEvent = nullptr;
NSLogEvents::EventLogEntry* evt = this->RecordGetInitializedEvent<NSLogEvents::ExternalCbRegisterCallEventLogEntry, NSLogEvents::EventKind::ExternalCbRegisterCall>(&ecEvent);
ecEvent->CallbackFunction = static_cast<TTDVar>(taskVar);
ecEvent->LastNestedEventTime = TTD_EVENT_MAXTIME;
#if ENABLE_BASIC_TRACE || ENABLE_FULL_BC_TRACE
this->m_threadContext->TTDExecutionInfo->GetTraceLogger()->WriteLiteralMsg("Enqueue Task: ");
this->m_threadContext->TTDExecutionInfo->GetTraceLogger()->WriteVar(taskVar);
#endif
return evt;
}
void EventLog::RecordEnqueueTaskEvent_Complete(NSLogEvents::EventLogEntry* evt)
{
NSLogEvents::ExternalCbRegisterCallEventLogEntry* ecEvent = NSLogEvents::GetInlineEventDataAs<NSLogEvents::ExternalCbRegisterCallEventLogEntry, NSLogEvents::EventKind::ExternalCbRegisterCall>(evt);
ecEvent->LastNestedEventTime = this->GetLastEventTime();
}
void EventLog::ReplayEnqueueTaskEvent(Js::ScriptContext* ctx, Js::Var taskVar)
{
const NSLogEvents::ExternalCbRegisterCallEventLogEntry* ecEvent = this->ReplayGetReplayEvent_Helper<NSLogEvents::ExternalCbRegisterCallEventLogEntry, NSLogEvents::EventKind::ExternalCbRegisterCall>();
ThreadContextTTD* executeContext = ctx->GetThreadContext()->TTDContext;
NSLogEvents::PassVarToHostInReplay(executeContext, ecEvent->CallbackFunction, taskVar);
//replay anything that happens when we are out of the call
BEGIN_LEAVE_SCRIPT(ctx)
{
this->ReplayActionEventSequenceThroughTime(ecEvent->LastNestedEventTime);
}
END_LEAVE_SCRIPT(ctx);
}
int64 EventLog::GetCurrentTopLevelEventTime() const
{
return this->m_topLevelCallbackEventTime;
}
int64 EventLog::GetFirstEventTimeInLog() const
{
for(auto iter = this->m_eventList.GetIteratorAtFirst(); iter.IsValid(); iter.MoveNext())
{
if(NSLogEvents::IsJsRTActionRootCall(iter.Current()))
{
return NSLogEvents::GetTimeFromRootCallOrSnapshot(iter.Current());
}
}
return -1;
}
int64 EventLog::GetLastEventTimeInLog() const
{
for(auto iter = this->m_eventList.GetIteratorAtLast_ReplayOnly(); iter.IsValid(); iter.MovePrevious_ReplayOnly())
{
if(NSLogEvents::IsJsRTActionRootCall(iter.Current()))
{
return NSLogEvents::GetTimeFromRootCallOrSnapshot(iter.Current());
}
}
return -1;
}
int64 EventLog::GetKthEventTimeInLog(uint32 k) const
{
uint32 topLevelCount = 0;
for(auto iter = this->m_eventList.GetIteratorAtFirst(); iter.IsValid(); iter.MoveNext())
{
if(NSLogEvents::IsJsRTActionRootCall(iter.Current()))
{
topLevelCount++;
if(topLevelCount == k)
{
return NSLogEvents::GetTimeFromRootCallOrSnapshot(iter.Current());
}
}
}
return -1;
}
void EventLog::ResetCallStackForTopLevelCall(int64 topLevelCallbackEventTime)
{
this->m_topLevelCallbackEventTime = topLevelCallbackEventTime;
}
bool EventLog::IsTimeForSnapshot() const
{
return (this->m_elapsedExecutionTimeSinceSnapshot > this->m_threadContext->TTDContext->SnapInterval);
}
void EventLog::PruneLogLength()
{
uint32 maxSnaps = this->m_threadContext->TTDContext->SnapHistoryLength;
uint32 snapCount = 0;
for(auto iter = this->m_eventList.GetIteratorAtFirst(); iter.IsValid(); iter.MoveNext())
{
if(iter.Current()->EventKind == NSLogEvents::EventKind::SnapshotTag)
{
snapCount++;
}
}
//If we have more than the desired number of snaps we will trim them off
if(snapCount > maxSnaps)
{
uint32 snapDelCount = snapCount - maxSnaps;
auto delIter = this->m_eventList.GetIteratorAtFirst();
while(true)
{
NSLogEvents::EventLogEntry* evt = delIter.Current();
if(delIter.Current()->EventKind == NSLogEvents::EventKind::SnapshotTag)
{
if(snapDelCount == 0)
{
break;
}
snapDelCount--;
}
TTEventList::TTEventListLink* block = delIter.GetBlock();
delIter.MoveNext();
this->m_eventList.DeleteFirstEntry(block, evt);
}
}
}
void EventLog::IncrementElapsedSnapshotTime(double addtlTime)
{
this->m_elapsedExecutionTimeSinceSnapshot += addtlTime;
}
void EventLog::DoSnapshotExtract()
{
//force a GC to get weak containers in a consistent state
TTDTimer timer;
double startTime = timer.Now();
this->m_threadContext->GetRecycler()->CollectNow<CollectNowForceInThread>();
this->m_threadContext->TTDContext->SyncRootsBeforeSnapshot_Record();
double endTime = timer.Now();
//do the rest of the snapshot
this->SetSnapshotOrInflateInProgress(true);
this->PushMode(TTDMode::ExcludedExecutionTTAction);
///////////////////////////
//Create the event object and add it to the log
NSLogEvents::SnapshotEventLogEntry* snapEvent = this->RecordGetInitializedEvent_DataOnly<NSLogEvents::SnapshotEventLogEntry, NSLogEvents::EventKind::SnapshotTag>();
snapEvent->RestoreTimestamp = this->GetLastEventTime();
snapEvent->Snap = this->DoSnapshotExtract_Helper((endTime - startTime) / 1000.0);
//get info about live weak roots etc. we want to use in the replay from the snapshot into the event as well
snapEvent->LiveContextCount = snapEvent->Snap->GetContextList().Count();
snapEvent->LiveContextIdArray = nullptr;
if(snapEvent->LiveContextCount != 0)
{
snapEvent->LiveContextIdArray = this->m_eventSlabAllocator.SlabAllocateArray<TTD_LOG_PTR_ID>(snapEvent->LiveContextCount);
uint32 clpos = 0;
for(auto iter = snapEvent->Snap->GetContextList().GetIterator(); iter.IsValid(); iter.MoveNext())
{
snapEvent->LiveContextIdArray[clpos] = iter.Current()->ScriptContextLogId;
clpos++;
}
}
//walk the roots and count all of the "interesting weak ref roots"
snapEvent->LongLivedRefRootsCount = 0;
for(auto iter = snapEvent->Snap->GetRootList().GetIterator(); iter.IsValid(); iter.MoveNext())
{
const NSSnapValues::SnapRootInfoEntry* spe = iter.Current();
if(spe->MaybeLongLivedRoot)
{
snapEvent->LongLivedRefRootsCount++;
}
}
//Now allocate the arrays for them and do the processing
snapEvent->LongLivedRefRootsIdArray = nullptr;
if(snapEvent->LongLivedRefRootsCount != 0)
{
snapEvent->LongLivedRefRootsIdArray = this->m_eventSlabAllocator.SlabAllocateArray<TTD_LOG_PTR_ID>(snapEvent->LongLivedRefRootsCount);
uint32 rpos = 0;
for(auto iter = snapEvent->Snap->GetRootList().GetIterator(); iter.IsValid(); iter.MoveNext())
{
const NSSnapValues::SnapRootInfoEntry* spe = iter.Current();
if(spe->MaybeLongLivedRoot)
{
snapEvent->LongLivedRefRootsIdArray[rpos] = spe->LogId;
rpos++;
}
}
}
this->m_elapsedExecutionTimeSinceSnapshot = 0.0;
#if ENABLE_BASIC_TRACE || ENABLE_FULL_BC_TRACE
this->m_threadContext->TTDExecutionInfo->GetTraceLogger()->WriteLiteralMsg("---SNAPSHOT EVENT---\n");
#endif
this->PopMode(TTDMode::ExcludedExecutionTTAction);
this->SetSnapshotOrInflateInProgress(false);
}
void EventLog::DoRtrSnapIfNeeded()
{
TTDAssert(this->m_currentReplayEventIterator.IsValid() && NSLogEvents::IsJsRTActionRootCall(this->m_currentReplayEventIterator.Current()), "Something in wrong with the event position.");
this->SetSnapshotOrInflateInProgress(true);
this->PushMode(TTDMode::ExcludedExecutionTTAction);
NSLogEvents::JsRTCallFunctionAction* rootCall = NSLogEvents::GetInlineEventDataAs<NSLogEvents::JsRTCallFunctionAction, NSLogEvents::EventKind::CallExistingFunctionActionTag>(this->m_currentReplayEventIterator.Current());
if(rootCall->AdditionalReplayInfo->RtRSnap == nullptr)
{
//Be careful to ensure that caller is actually doing this
AUTO_NESTED_HANDLED_EXCEPTION_TYPE((ExceptionType)(ExceptionType_OutOfMemory | ExceptionType_JavascriptException));
rootCall->AdditionalReplayInfo->RtRSnap = this->DoSnapshotExtract_Helper(0.0);
}
this->PopMode(TTDMode::ExcludedExecutionTTAction);
this->SetSnapshotOrInflateInProgress(false);
}
int64 EventLog::FindSnapTimeForEventTime(int64 targetTime, int64* optEndSnapTime)
{
int64 snapTime = -1;
if(optEndSnapTime != nullptr)
{
*optEndSnapTime = -1;
}
for(auto iter = this->m_eventList.GetIteratorAtLast_ReplayOnly(); iter.IsValid(); iter.MovePrevious_ReplayOnly())
{
bool isSnap = false;
bool isRoot = false;
bool hasRtrSnap = false;
int64 time = NSLogEvents::AccessTimeInRootCallOrSnapshot(iter.Current(), isSnap, isRoot, hasRtrSnap);
bool validSnap = isSnap | (isRoot & hasRtrSnap);
if(validSnap && time <= targetTime)
{
snapTime = time;
break;
}
}
if(optEndSnapTime != nullptr)
{
for(auto iter = this->m_eventList.GetIteratorAtFirst(); iter.IsValid(); iter.MoveNext())
{
if(iter.Current()->EventKind == NSLogEvents::EventKind::SnapshotTag)
{
NSLogEvents::SnapshotEventLogEntry* snapEvent = NSLogEvents::GetInlineEventDataAs<NSLogEvents::SnapshotEventLogEntry, NSLogEvents::EventKind::SnapshotTag>(iter.Current());
if(snapEvent->RestoreTimestamp > snapTime)
{
*optEndSnapTime = snapEvent->RestoreTimestamp;
break;
}
}
}
}
return snapTime;
}
void EventLog::GetSnapShotBoundInterval(int64 targetTime, int64* snapIntervalStart, int64* snapIntervalEnd) const
{
*snapIntervalStart = -1;
*snapIntervalEnd = -1;
//move the iterator to the current snapshot just before the event
auto iter = this->m_eventList.GetIteratorAtLast_ReplayOnly();
while(iter.IsValid())
{
NSLogEvents::EventLogEntry* evt = iter.Current();
if(evt->EventKind == NSLogEvents::EventKind::SnapshotTag)
{
NSLogEvents::SnapshotEventLogEntry* snapEvent = NSLogEvents::GetInlineEventDataAs<NSLogEvents::SnapshotEventLogEntry, NSLogEvents::EventKind::SnapshotTag>(iter.Current());
if(snapEvent->RestoreTimestamp <= targetTime)
{
*snapIntervalStart = snapEvent->RestoreTimestamp;
break;
}
}
iter.MovePrevious_ReplayOnly();
}
//now move the iter to the next snapshot
while(iter.IsValid())
{
NSLogEvents::EventLogEntry* evt = iter.Current();
if(evt->EventKind == NSLogEvents::EventKind::SnapshotTag)
{
NSLogEvents::SnapshotEventLogEntry* snapEvent = NSLogEvents::GetInlineEventDataAs<NSLogEvents::SnapshotEventLogEntry, NSLogEvents::EventKind::SnapshotTag>(iter.Current());
if(*snapIntervalStart < snapEvent->RestoreTimestamp)
{
*snapIntervalEnd = snapEvent->RestoreTimestamp;
break;
}
}
iter.MoveNext();
}
}
int64 EventLog::GetPreviousSnapshotInterval(int64 currentSnapTime) const
{
//move the iterator to the current snapshot just before the event
for(auto iter = this->m_eventList.GetIteratorAtLast_ReplayOnly(); iter.IsValid(); iter.MovePrevious_ReplayOnly())
{
NSLogEvents::EventLogEntry* evt = iter.Current();
if(evt->EventKind == NSLogEvents::EventKind::SnapshotTag)
{
NSLogEvents::SnapshotEventLogEntry* snapEvent = NSLogEvents::GetInlineEventDataAs<NSLogEvents::SnapshotEventLogEntry, NSLogEvents::EventKind::SnapshotTag>(iter.Current());
if(snapEvent->RestoreTimestamp < currentSnapTime)
{
return snapEvent->RestoreTimestamp;
}
}
}
return -1;
}
void EventLog::DoSnapshotInflate(int64 etime)
{
this->PushMode(TTDMode::ExcludedExecutionTTAction);
const SnapShot* snap = nullptr;
int64 restoreEventTime = -1;
for(auto iter = this->m_eventList.GetIteratorAtLast_ReplayOnly(); iter.IsValid(); iter.MovePrevious_ReplayOnly())
{
NSLogEvents::EventLogEntry* evt = iter.Current();
if(evt->EventKind == NSLogEvents::EventKind::SnapshotTag)
{
NSLogEvents::SnapshotEventLogEntry* snapEvent = NSLogEvents::GetInlineEventDataAs<NSLogEvents::SnapshotEventLogEntry, NSLogEvents::EventKind::SnapshotTag>(evt);
if(snapEvent->RestoreTimestamp == etime)
{
NSLogEvents::SnapshotEventLogEntry_EnsureSnapshotDeserialized(evt, this->m_threadContext);
restoreEventTime = snapEvent->RestoreTimestamp;
snap = snapEvent->Snap;
break;
}
}
if(NSLogEvents::IsJsRTActionRootCall(evt))
{
const NSLogEvents::JsRTCallFunctionAction* rootEntry = NSLogEvents::GetInlineEventDataAs<NSLogEvents::JsRTCallFunctionAction, NSLogEvents::EventKind::CallExistingFunctionActionTag>(evt);
if(rootEntry->CallEventTime == etime)
{
restoreEventTime = rootEntry->CallEventTime;
snap = rootEntry->AdditionalReplayInfo->RtRSnap;
break;
}
}
}
TTDAssert(snap != nullptr, "Log should start with a snapshot!!!");
uint32 dbgScopeCount = snap->GetDbgScopeCountNonTopLevel();
TTDIdentifierDictionary<uint64, NSSnapValues::TopLevelScriptLoadFunctionBodyResolveInfo*> topLevelLoadScriptMap;
topLevelLoadScriptMap.Initialize(this->m_loadedTopLevelScripts.Count());
for(auto iter = this->m_loadedTopLevelScripts.GetIterator(); iter.IsValid(); iter.MoveNext())
{
topLevelLoadScriptMap.AddItem(iter.Current()->TopLevelBase.TopLevelBodyCtr, iter.Current());
dbgScopeCount += iter.Current()->TopLevelBase.ScopeChainInfo.ScopeCount;
}
TTDIdentifierDictionary<uint64, NSSnapValues::TopLevelNewFunctionBodyResolveInfo*> topLevelNewScriptMap;
topLevelNewScriptMap.Initialize(this->m_newFunctionTopLevelScripts.Count());
for(auto iter = this->m_newFunctionTopLevelScripts.GetIterator(); iter.IsValid(); iter.MoveNext())
{
topLevelNewScriptMap.AddItem(iter.Current()->TopLevelBase.TopLevelBodyCtr, iter.Current());
dbgScopeCount += iter.Current()->TopLevelBase.ScopeChainInfo.ScopeCount;
}
TTDIdentifierDictionary<uint64, NSSnapValues::TopLevelEvalFunctionBodyResolveInfo*> topLevelEvalScriptMap;
topLevelEvalScriptMap.Initialize(this->m_evalTopLevelScripts.Count());
for(auto iter = this->m_evalTopLevelScripts.GetIterator(); iter.IsValid(); iter.MoveNext())
{
topLevelEvalScriptMap.AddItem(iter.Current()->TopLevelBase.TopLevelBodyCtr, iter.Current());
dbgScopeCount += iter.Current()->TopLevelBase.ScopeChainInfo.ScopeCount;
}
ThreadContextTTD* threadCtx = this->m_threadContext->TTDContext;
const UnorderedArrayList<NSSnapValues::SnapContext, TTD_ARRAY_LIST_SIZE_XSMALL>& snpCtxs = snap->GetContextList();
//check if we can reuse script contexts or we need to create new ones
bool reuseInflateMap = (this->m_lastInflateMap != nullptr && this->m_lastInflateSnapshotTime == etime && !threadCtx->ContextCreatedOrDestoyedInReplay());
//Fast checks ok but make sure we aren't blocked by a non-restorable well known object
if(reuseInflateMap)
{
reuseInflateMap = snap->AllWellKnownObjectsReusable(this->m_lastInflateMap);
}
if(reuseInflateMap)
{
this->m_lastInflateMap->PrepForReInflate(snap->ContextCount(), snap->HandlerCount(), snap->TypeCount(), snap->PrimitiveCount() + snap->ObjectCount(), snap->BodyCount(), dbgScopeCount, snap->EnvCount(), snap->SlotArrayCount());
//collect anything that is dead
threadCtx->ClearRootsForSnapRestore();
this->m_threadContext->GetRecycler()->CollectNow<CollectNowForceInThread>();
//inflate into existing contexts
const JsUtil::List<Js::ScriptContext*, HeapAllocator>& oldCtxts = threadCtx->GetTTDContexts();
for(auto iter = snpCtxs.GetIterator(); iter.IsValid(); iter.MoveNext())
{
const NSSnapValues::SnapContext* sCtx = iter.Current();
Js::ScriptContext* vCtx = nullptr;
for(int32 i = 0; i < oldCtxts.Count(); ++i)
{
if(oldCtxts.Item(i)->ScriptContextLogTag == sCtx->ScriptContextLogId)
{
vCtx = oldCtxts.Item(i);
break;
}
}
TTDAssert(vCtx != nullptr, "We lost a context somehow!!!");
NSSnapValues::InflateScriptContext(sCtx, vCtx, this->m_lastInflateMap, topLevelLoadScriptMap, topLevelNewScriptMap, topLevelEvalScriptMap);
}
}
else
{
bool shouldReleaseCtxs = false;
if(this->m_lastInflateMap != nullptr)
{
shouldReleaseCtxs = true;
TT_HEAP_DELETE(InflateMap, this->m_lastInflateMap);
this->m_lastInflateMap = nullptr;
}
this->m_lastInflateMap = TT_HEAP_NEW(InflateMap);
this->m_lastInflateMap->PrepForInitialInflate(this->m_threadContext, snap->ContextCount(), snap->HandlerCount(), snap->TypeCount(), snap->PrimitiveCount() + snap->ObjectCount(), snap->BodyCount(), dbgScopeCount, snap->EnvCount(), snap->SlotArrayCount());
this->m_lastInflateSnapshotTime = etime;
//collect anything that is dead
JsUtil::List<FinalizableObject*, HeapAllocator> deadCtxs(&HeapAllocator::Instance);
threadCtx->ClearContextsForSnapRestore(deadCtxs);
threadCtx->ClearRootsForSnapRestore();
//allocate and inflate into new contexts
for(auto iter = snpCtxs.GetIterator(); iter.IsValid(); iter.MoveNext())
{
const NSSnapValues::SnapContext* sCtx = iter.Current();
Js::ScriptContext* vCtx = nullptr;
threadCtx->TTDExternalObjectFunctions.pfCreateJsRTContextCallback(threadCtx->GetRuntimeHandle(), &vCtx);
NSSnapValues::InflateScriptContext(sCtx, vCtx, this->m_lastInflateMap, topLevelLoadScriptMap, topLevelNewScriptMap, topLevelEvalScriptMap);
}
threadCtx->ResetContextCreatedOrDestoyedInReplay();
if(shouldReleaseCtxs)
{
for(int32 i = 0; i < deadCtxs.Count(); ++i)
{
threadCtx->TTDExternalObjectFunctions.pfReleaseJsRTContextCallback(deadCtxs.Item(i));
}
this->m_threadContext->GetRecycler()->CollectNow<CollectNowForceInThread>();
}
//We don't want to have a bunch of snapshots in memory (that will get big fast) so unload all but the current one
for(auto iter = this->m_eventList.GetIteratorAtLast_ReplayOnly(); iter.IsValid(); iter.MovePrevious_ReplayOnly())
{
bool isSnap = false;
bool isRoot = false;
bool hasRtrSnap = false;
int64 time = NSLogEvents::AccessTimeInRootCallOrSnapshot(iter.Current(), isSnap, isRoot, hasRtrSnap);
bool hasSnap = isSnap | (isRoot & hasRtrSnap);
if(hasSnap && time != etime)
{
if(isSnap)
{
NSLogEvents::SnapshotEventLogEntry_UnloadSnapshot(iter.Current());
}
else
{
NSLogEvents::JsRTCallFunctionAction_UnloadSnapshot(iter.Current());
}
}
}
}
this->SetSnapshotOrInflateInProgress(true); //make sure we don't do any un-intended CrossSite conversions
snap->Inflate(this->m_lastInflateMap, this->m_threadContext->TTDContext);
this->m_lastInflateMap->CleanupAfterInflate();
this->SetSnapshotOrInflateInProgress(false); //re-enable CrossSite conversions
this->m_eventTimeCtr = restoreEventTime;
if(!this->m_eventList.IsEmpty())
{
this->m_currentReplayEventIterator = this->m_eventList.GetIteratorAtLast_ReplayOnly();
while(true)
{
bool isSnap = false;
bool isRoot = false;
bool hasRtrSnap = false;
int64 time = NSLogEvents::AccessTimeInRootCallOrSnapshot(this->m_currentReplayEventIterator.Current(), isSnap, isRoot, hasRtrSnap);
if((isSnap | isRoot) && time == this->m_eventTimeCtr)
{
break;
}
this->m_currentReplayEventIterator.MovePrevious_ReplayOnly();
}
//we want to advance to the event immediately after the snapshot as well so do that
if(this->m_currentReplayEventIterator.Current()->EventKind == NSLogEvents::EventKind::SnapshotTag)
{
this->m_eventTimeCtr++;
this->m_currentReplayEventIterator.MoveNext();
}
}
this->PopMode(TTDMode::ExcludedExecutionTTAction);
#if ENABLE_BASIC_TRACE || ENABLE_FULL_BC_TRACE
this->m_threadContext->TTDExecutionInfo->GetTraceLogger()->WriteLiteralMsg("---INFLATED SNAPSHOT---\n");
#endif
}
void EventLog::ReplayRootEventsToTime(int64 eventTime)
{
while(this->m_eventTimeCtr < eventTime)
{
this->ReplaySingleRootEntry();
}
}
void EventLog::ReplaySingleRootEntry()
{
if(!this->m_currentReplayEventIterator.IsValid())
{
this->AbortReplayReturnToHost();
}
NSLogEvents::EventKind eKind = this->m_currentReplayEventIterator.Current()->EventKind;
if(eKind == NSLogEvents::EventKind::SnapshotTag)
{
this->ReplaySnapshotEvent();
}
else if(eKind == NSLogEvents::EventKind::EventLoopYieldPointTag)
{
this->ReplayEventLoopYieldPointEvent();
}
else
{
TTDAssert(eKind > NSLogEvents::EventKind::JsRTActionTag, "Either this is an invalid tag to replay directly (should be driven internally) or it is not known!!!");
this->ReplaySingleActionEventEntry();
}
#if ENABLE_TTD_INTERNAL_DIAGNOSTICS
TTDAssert(!this->m_currentReplayEventIterator.IsValid() || this->m_currentReplayEventIterator.Current()->EventTimeStamp == this->m_eventTimeCtr, "We are out of sync here");
#endif
}
void EventLog::ReplayActionEventSequenceThroughTime(int64 eventTime)
{
while(this->m_eventTimeCtr <= eventTime)
{
this->ReplaySingleActionEventEntry();
}
}
void EventLog::ReplaySingleActionEventEntry()
{
if(!this->m_currentReplayEventIterator.IsValid())
{
this->AbortReplayReturnToHost();
}
NSLogEvents::EventLogEntry* evt = this->m_currentReplayEventIterator.Current();
this->AdvanceTimeAndPositionForReplay();
NSLogEvents::ContextExecuteKind execKind = this->m_eventListVTable[(uint32)evt->EventKind].ContextKind;
auto executeFP = this->m_eventListVTable[(uint32)evt->EventKind].ExecuteFP;
TTDAssert(!NSLogEvents::EventFailsWithRuntimeError(evt), "We have a failing Event in the Log -- we assume host is correct!");
ThreadContextTTD* executeContext = this->m_threadContext->TTDContext;
if(execKind == NSLogEvents::ContextExecuteKind::GlobalAPIWrapper)
{
//enter/exit global wrapper -- see JsrtInternal.h
try
{
AUTO_NESTED_HANDLED_EXCEPTION_TYPE((ExceptionType)(ExceptionType_OutOfMemory | ExceptionType_StackOverflow));
executeFP(evt, executeContext);
TTDAssert(NSLogEvents::EventCompletesNormally(evt), "All my action events should exit or terminate before return so no need to loop yet but may want to later");
}
catch(TTD::TTDebuggerAbortException)
{
throw;
}
catch(...)
{
TTDAssert(false, "Encountered other kind of exception in replay??");
}
}
else if(execKind == NSLogEvents::ContextExecuteKind::ContextAPIWrapper)
{
//enter/exit context wrapper -- see JsrtInternal.h
Js::ScriptContext* ctx = executeContext->GetActiveScriptContext();
TTDAssert(ctx != nullptr, "This should be set!!!");
TTDAssert(ctx->GetThreadContext()->GetRecordedException() == nullptr, "Shouldn't have outstanding exceptions (assume always CheckContext when recording).");
TTDAssert(this->m_threadContext->TTDContext->GetActiveScriptContext() == ctx, "Make sure the replay host didn't change contexts on us unexpectedly without resetting back to the correct one.");
try
{
AUTO_NESTED_HANDLED_EXCEPTION_TYPE((ExceptionType)(ExceptionType_OutOfMemory | ExceptionType_JavascriptException));
// Enter script
BEGIN_ENTER_SCRIPT(ctx, true, true, true)
{
executeFP(evt, executeContext);
}
END_ENTER_SCRIPT
TTDAssert(NSLogEvents::EventCompletesNormally(evt), "All my action events should exit / terminate before return so no need to loop yet but may want to later");
}
catch(const Js::JavascriptException& err)
{
TTDAssert(NSLogEvents::EventCompletesWithException(evt), "Should see same execption here");
ctx->GetThreadContext()->SetRecordedException(err.GetAndClear());
}
catch(Js::ScriptAbortException)
{
TTDAssert(NSLogEvents::EventCompletesWithException(evt), "Should see same execption here");
Assert(ctx->GetThreadContext()->GetRecordedException() == nullptr);
ctx->GetThreadContext()->SetRecordedException(ctx->GetThreadContext()->GetPendingTerminatedErrorObject());
}
catch(TTD::TTDebuggerAbortException)
{
throw;
}
catch(...)
{
TTDAssert(false, "Encountered other kind of exception in replay??");
}
}
else if(execKind == NSLogEvents::ContextExecuteKind::ContextAPINoScriptWrapper)
{
//enter/exit context no script wrapper -- see JsrtInternal.h
Js::ScriptContext* ctx = executeContext->GetActiveScriptContext();
TTDAssert(ctx != nullptr, "This should be set!!!");
TTDAssert(ctx->GetThreadContext()->GetRecordedException() == nullptr, "Shouldn't have outstanding exceptions (assume always CheckContext when recording).");
TTDAssert(this->m_threadContext->TTDContext->GetActiveScriptContext() == ctx, "Make sure the replay host didn't change contexts on us unexpectedly without resetting back to the correct one.");
try
{
AUTO_NESTED_HANDLED_EXCEPTION_TYPE((ExceptionType)(ExceptionType_OutOfMemory | ExceptionType_StackOverflow));
executeFP(evt, executeContext);
TTDAssert(NSLogEvents::EventCompletesNormally(evt), "All my action events should both exit / terminate before return so no need to loop yet but may want to later");
}
catch(const Js::JavascriptException& err)
{
TTDAssert(NSLogEvents::EventCompletesWithException(evt), "Should see same execption here");
TTDAssert(false, "Should never get JavascriptExceptionObject for ContextAPINoScriptWrapper.");
ctx->GetThreadContext()->SetRecordedException(err.GetAndClear());
}
catch(Js::ScriptAbortException)
{
TTDAssert(NSLogEvents::EventCompletesWithException(evt), "Should see same execption here");
Assert(ctx->GetThreadContext()->GetRecordedException() == nullptr);
ctx->GetThreadContext()->SetRecordedException(ctx->GetThreadContext()->GetPendingTerminatedErrorObject());
}
catch(TTD::TTDebuggerAbortException)
{
throw;
}
catch(...)
{
TTDAssert(false, "Encountered other kind of exception in replay??");
}
}
else
{
TTDAssert(executeContext->GetActiveScriptContext() == nullptr || !executeContext->GetActiveScriptContext()->GetThreadContext()->IsScriptActive(), "These should all be outside of script context!!!");
//No need to move into script context just execute the action
executeFP(evt, executeContext);
}
#if ENABLE_TTD_INTERNAL_DIAGNOSTICS
TTDAssert(!this->m_currentReplayEventIterator.IsValid() || this->m_currentReplayEventIterator.Current()->EventTimeStamp == this->m_eventTimeCtr, "We are out of sync here");
#endif
}
bool EventLog::IsPropertyRecordRef(void* ref) const
{
//This is an ugly cast but we just want to know if the pointer is in the set so it is ok here
return this->m_propertyRecordPinSet->ContainsKey((Js::PropertyRecord*)ref);
}
double EventLog::GetCurrentWallTime()
{
return this->m_timer.Now();
}
int64 EventLog::GetLastEventTime() const
{
return this->m_eventTimeCtr - 1;
}
NSLogEvents::EventLogEntry* EventLog::RecordJsRTCreateScriptContext(TTDJsRTActionResultAutoRecorder& actionPopper)
{
NSLogEvents::JsRTCreateScriptContextAction* cAction = nullptr;
NSLogEvents::EventLogEntry* evt = this->RecordGetInitializedEvent<NSLogEvents::JsRTCreateScriptContextAction, NSLogEvents::EventKind::CreateScriptContextActionTag>(&cAction);
cAction->KnownObjects = this->m_eventSlabAllocator.SlabAllocateStruct<NSLogEvents::JsRTCreateScriptContextAction_KnownObjects>();
cAction->KnownObjects = { 0 };
actionPopper.InitializeWithEventAndEnter(evt);
return evt;
}
void EventLog::RecordJsRTCreateScriptContextResult(NSLogEvents::EventLogEntry* evt, Js::ScriptContext* newCtx)
{
NSLogEvents::JsRTCreateScriptContextAction* cAction = NSLogEvents::GetInlineEventDataAs<NSLogEvents::JsRTCreateScriptContextAction, NSLogEvents::EventKind::CreateScriptContextActionTag>(evt);
cAction->KnownObjects = this->m_eventSlabAllocator.SlabAllocateStruct<NSLogEvents::JsRTCreateScriptContextAction_KnownObjects>();
cAction->GlobalObject = TTD_CONVERT_OBJ_TO_LOG_PTR_ID(newCtx->GetGlobalObject());
cAction->KnownObjects->UndefinedObject = TTD_CONVERT_OBJ_TO_LOG_PTR_ID(newCtx->GetLibrary()->GetUndefined());
cAction->KnownObjects->NullObject = TTD_CONVERT_OBJ_TO_LOG_PTR_ID(newCtx->GetLibrary()->GetNull());
cAction->KnownObjects->TrueObject = TTD_CONVERT_OBJ_TO_LOG_PTR_ID(newCtx->GetLibrary()->GetTrue());
cAction->KnownObjects->FalseObject = TTD_CONVERT_OBJ_TO_LOG_PTR_ID(newCtx->GetLibrary()->GetFalse());
}
void EventLog::RecordJsRTSetCurrentContext(TTDJsRTActionResultAutoRecorder& actionPopper, Js::Var globalObject)
{
NSLogEvents::JsRTSingleVarArgumentAction* sAction = nullptr;
NSLogEvents::EventLogEntry* evt = this->RecordGetInitializedEvent<NSLogEvents::JsRTSingleVarArgumentAction, NSLogEvents::EventKind::SetActiveScriptContextActionTag>(&sAction);
NSLogEvents::SetVarItem_0(sAction, TTD_CONVERT_JSVAR_TO_TTDVAR(globalObject));
actionPopper.InitializeWithEventAndEnter(evt);
}
#if !INT32VAR
void EventLog::RecordJsRTCreateInteger(TTDJsRTActionResultAutoRecorder& actionPopper, int value)
{
NSLogEvents::JsRTIntegralArgumentAction* iAction = nullptr;
NSLogEvents::EventLogEntry* evt = this->RecordGetInitializedEvent<NSLogEvents::JsRTIntegralArgumentAction, NSLogEvents::EventKind::CreateIntegerActionTag>(&iAction);
iAction->Scalar = value;
actionPopper.InitializeWithEventAndEnterWResult(evt, &(iAction->Result));
}
#endif
void EventLog::RecordJsRTCreateNumber(TTDJsRTActionResultAutoRecorder& actionPopper, double value)
{
NSLogEvents::JsRTDoubleArgumentAction* dAction = nullptr;
NSLogEvents::EventLogEntry* evt = this->RecordGetInitializedEvent<NSLogEvents::JsRTDoubleArgumentAction, NSLogEvents::EventKind::CreateNumberActionTag>(&dAction);
dAction->DoubleValue = value;
actionPopper.InitializeWithEventAndEnterWResult(evt, &(dAction->Result));
}
void EventLog::RecordJsRTCreateBoolean(TTDJsRTActionResultAutoRecorder& actionPopper, bool value)
{
NSLogEvents::JsRTIntegralArgumentAction* bAction = nullptr;
NSLogEvents::EventLogEntry* evt = this->RecordGetInitializedEvent<NSLogEvents::JsRTIntegralArgumentAction, NSLogEvents::EventKind::CreateBooleanActionTag>(&bAction);
bAction->Scalar = value;
actionPopper.InitializeWithEventAndEnterWResult(evt, &(bAction->Result));
}
void EventLog::RecordJsRTCreateString(TTDJsRTActionResultAutoRecorder& actionPopper, const char16* stringValue, size_t stringLength)
{
NSLogEvents::JsRTStringArgumentAction* sAction = nullptr;
NSLogEvents::EventLogEntry* evt = this->RecordGetInitializedEvent<NSLogEvents::JsRTStringArgumentAction, NSLogEvents::EventKind::CreateStringActionTag>(&sAction);
this->m_eventSlabAllocator.CopyStringIntoWLength(stringValue, (uint32)stringLength, sAction->StringValue);
actionPopper.InitializeWithEventAndEnterWResult(evt, &(sAction->Result));
}
void EventLog::RecordJsRTCreateSymbol(TTDJsRTActionResultAutoRecorder& actionPopper, Js::Var var)
{
NSLogEvents::JsRTSingleVarArgumentAction* sAction = nullptr;
NSLogEvents::EventLogEntry* evt = this->RecordGetInitializedEvent<NSLogEvents::JsRTSingleVarArgumentAction, NSLogEvents::EventKind::CreateSymbolActionTag>(&sAction);
NSLogEvents::SetVarItem_0(sAction, TTD_CONVERT_JSVAR_TO_TTDVAR(var));
actionPopper.InitializeWithEventAndEnterWResult(evt, &(sAction->Result));
}
void EventLog::RecordJsRTCreateError(TTDJsRTActionResultAutoRecorder& actionPopper, Js::Var msg)
{
NSLogEvents::JsRTSingleVarArgumentAction* sAction = nullptr;
NSLogEvents::EventLogEntry* evt = this->RecordGetInitializedEvent<NSLogEvents::JsRTSingleVarArgumentAction, NSLogEvents::EventKind::CreateErrorActionTag>(&sAction);
NSLogEvents::SetVarItem_0(sAction, TTD_CONVERT_JSVAR_TO_TTDVAR(msg));
actionPopper.InitializeWithEventAndEnterWResult(evt, &(sAction->Result));
}
void EventLog::RecordJsRTCreateRangeError(TTDJsRTActionResultAutoRecorder& actionPopper, Js::Var msg)
{
NSLogEvents::JsRTSingleVarArgumentAction* sAction = nullptr;
NSLogEvents::EventLogEntry* evt = this->RecordGetInitializedEvent<NSLogEvents::JsRTSingleVarArgumentAction, NSLogEvents::EventKind::CreateRangeErrorActionTag>(&sAction);
NSLogEvents::SetVarItem_0(sAction, TTD_CONVERT_JSVAR_TO_TTDVAR(msg));
actionPopper.InitializeWithEventAndEnterWResult(evt, &(sAction->Result));
}
void EventLog::RecordJsRTCreateReferenceError(TTDJsRTActionResultAutoRecorder& actionPopper, Js::Var msg)
{
NSLogEvents::JsRTSingleVarArgumentAction* sAction = nullptr;
NSLogEvents::EventLogEntry* evt = this->RecordGetInitializedEvent<NSLogEvents::JsRTSingleVarArgumentAction, NSLogEvents::EventKind::CreateReferenceErrorActionTag>(&sAction);
NSLogEvents::SetVarItem_0(sAction, TTD_CONVERT_JSVAR_TO_TTDVAR(msg));
actionPopper.InitializeWithEventAndEnterWResult(evt, &(sAction->Result));
}
void EventLog::RecordJsRTCreateSyntaxError(TTDJsRTActionResultAutoRecorder& actionPopper, Js::Var msg)
{
NSLogEvents::JsRTSingleVarArgumentAction* sAction = nullptr;
NSLogEvents::EventLogEntry* evt = this->RecordGetInitializedEvent<NSLogEvents::JsRTSingleVarArgumentAction, NSLogEvents::EventKind::CreateSyntaxErrorActionTag>(&sAction);
NSLogEvents::SetVarItem_0(sAction, TTD_CONVERT_JSVAR_TO_TTDVAR(msg));
actionPopper.InitializeWithEventAndEnterWResult(evt, &(sAction->Result));
}
void EventLog::RecordJsRTCreateTypeError(TTDJsRTActionResultAutoRecorder& actionPopper, Js::Var msg)
{
NSLogEvents::JsRTSingleVarArgumentAction* sAction = nullptr;
NSLogEvents::EventLogEntry* evt = this->RecordGetInitializedEvent<NSLogEvents::JsRTSingleVarArgumentAction, NSLogEvents::EventKind::CreateTypeErrorActionTag>(&sAction);
NSLogEvents::SetVarItem_0(sAction, TTD_CONVERT_JSVAR_TO_TTDVAR(msg));
actionPopper.InitializeWithEventAndEnterWResult(evt, &(sAction->Result));
}
void EventLog::RecordJsRTCreateURIError(TTDJsRTActionResultAutoRecorder& actionPopper, Js::Var msg)
{
NSLogEvents::JsRTSingleVarArgumentAction* sAction = nullptr;
NSLogEvents::EventLogEntry* evt = this->RecordGetInitializedEvent<NSLogEvents::JsRTSingleVarArgumentAction, NSLogEvents::EventKind::CreateURIErrorActionTag>(&sAction);
NSLogEvents::SetVarItem_0(sAction, TTD_CONVERT_JSVAR_TO_TTDVAR(msg));
actionPopper.InitializeWithEventAndEnterWResult(evt, &(sAction->Result));
}
void EventLog::RecordJsRTVarToNumberConversion(TTDJsRTActionResultAutoRecorder& actionPopper, Js::Var var)
{
NSLogEvents::JsRTSingleVarArgumentAction* cAction = nullptr;
NSLogEvents::EventLogEntry* evt = this->RecordGetInitializedEvent<NSLogEvents::JsRTSingleVarArgumentAction, NSLogEvents::EventKind::VarConvertToNumberActionTag>(&cAction);
NSLogEvents::SetVarItem_0(cAction, TTD_CONVERT_JSVAR_TO_TTDVAR(var));
actionPopper.InitializeWithEventAndEnterWResult(evt, &(cAction->Result));
}
void EventLog::RecordJsRTVarToBooleanConversion(TTDJsRTActionResultAutoRecorder& actionPopper, Js::Var var)
{
NSLogEvents::JsRTSingleVarArgumentAction* cAction = nullptr;
NSLogEvents::EventLogEntry* evt = this->RecordGetInitializedEvent<NSLogEvents::JsRTSingleVarArgumentAction, NSLogEvents::EventKind::VarConvertToBooleanActionTag>(&cAction);
NSLogEvents::SetVarItem_0(cAction, TTD_CONVERT_JSVAR_TO_TTDVAR(var));
actionPopper.InitializeWithEventAndEnter(evt);
}
void EventLog::RecordJsRTVarToStringConversion(TTDJsRTActionResultAutoRecorder& actionPopper, Js::Var var)
{
NSLogEvents::JsRTSingleVarArgumentAction* cAction = nullptr;
NSLogEvents::EventLogEntry* evt = this->RecordGetInitializedEvent<NSLogEvents::JsRTSingleVarArgumentAction, NSLogEvents::EventKind::VarConvertToStringActionTag>(&cAction);
NSLogEvents::SetVarItem_0(cAction, TTD_CONVERT_JSVAR_TO_TTDVAR(var));
actionPopper.InitializeWithEventAndEnterWResult(evt, &(cAction->Result));
}
void EventLog::RecordJsRTVarToObjectConversion(TTDJsRTActionResultAutoRecorder& actionPopper, Js::Var var)
{
NSLogEvents::JsRTSingleVarArgumentAction* cAction = nullptr;
NSLogEvents::EventLogEntry* evt = this->RecordGetInitializedEvent<NSLogEvents::JsRTSingleVarArgumentAction, NSLogEvents::EventKind::VarConvertToObjectActionTag>(&cAction);
NSLogEvents::SetVarItem_0(cAction, TTD_CONVERT_JSVAR_TO_TTDVAR(var));
actionPopper.InitializeWithEventAndEnterWResult(evt, &(cAction->Result));
}
void EventLog::RecordJsRTAddRootRef(TTDJsRTActionResultAutoRecorder& actionPopper, Js::Var var)
{
NSLogEvents::JsRTSingleVarArgumentAction* addAction = nullptr;
NSLogEvents::EventLogEntry* evt = this->RecordGetInitializedEvent<NSLogEvents::JsRTSingleVarArgumentAction, NSLogEvents::EventKind::AddRootRefActionTag>(&addAction);
NSLogEvents::SetVarItem_0(addAction, TTD_CONVERT_JSVAR_TO_TTDVAR(var));
actionPopper.InitializeWithEventAndEnter(evt);
}
void EventLog::RecordJsRTAddWeakRootRef(TTDJsRTActionResultAutoRecorder& actionPopper, Js::Var var)
{
NSLogEvents::JsRTSingleVarArgumentAction* addAction = nullptr;
NSLogEvents::EventLogEntry* evt = this->RecordGetInitializedEvent<NSLogEvents::JsRTSingleVarArgumentAction, NSLogEvents::EventKind::AddWeakRootRefActionTag>(&addAction);
NSLogEvents::SetVarItem_0(addAction, TTD_CONVERT_JSVAR_TO_TTDVAR(var));
actionPopper.InitializeWithEventAndEnter(evt);
}
void EventLog::RecordJsRTEventLoopYieldPoint()
{
NSLogEvents::EventLoopYieldPointEntry* ypEvt = this->RecordGetInitializedEvent_DataOnly<NSLogEvents::EventLoopYieldPointEntry, NSLogEvents::EventKind::EventLoopYieldPointTag >();
ypEvt->EventTimeStamp = this->GetLastEventTime();
ypEvt->EventWallTime = this->GetCurrentWallTime();
//Put this here in the hope that after handling an event there is an idle period where we can work without blocking user work
if(this->IsTimeForSnapshot())
{
this->DoSnapshotExtract();
this->PruneLogLength();
}
}
void EventLog::RecordJsRTAllocateBasicObject(TTDJsRTActionResultAutoRecorder& actionPopper)
{
NSLogEvents::JsRTResultOnlyAction* cAction = nullptr;
NSLogEvents::EventLogEntry* evt = this->RecordGetInitializedEvent<NSLogEvents::JsRTResultOnlyAction, NSLogEvents::EventKind::AllocateObjectActionTag>(&cAction);
actionPopper.InitializeWithEventAndEnterWResult(evt, &(cAction->Result));
}
void EventLog::RecordJsRTAllocateExternalObject(TTDJsRTActionResultAutoRecorder& actionPopper)
{
NSLogEvents::JsRTResultOnlyAction* cAction = nullptr;
NSLogEvents::EventLogEntry* evt = this->RecordGetInitializedEvent<NSLogEvents::JsRTResultOnlyAction, NSLogEvents::EventKind::AllocateExternalObjectActionTag>(&cAction);
actionPopper.InitializeWithEventAndEnterWResult(evt, &(cAction->Result));
}
void EventLog::RecordJsRTAllocateBasicArray(TTDJsRTActionResultAutoRecorder& actionPopper, uint32 length)
{
NSLogEvents::JsRTIntegralArgumentAction* cAction = nullptr;
NSLogEvents::EventLogEntry* evt = this->RecordGetInitializedEvent<NSLogEvents::JsRTIntegralArgumentAction, NSLogEvents::EventKind::AllocateArrayActionTag>(&cAction);
cAction->Scalar = length;
actionPopper.InitializeWithEventAndEnterWResult(evt, &(cAction->Result));
}
void EventLog::RecordJsRTAllocateArrayBuffer(TTDJsRTActionResultAutoRecorder& actionPopper, uint32 size)
{
NSLogEvents::JsRTIntegralArgumentAction* cAction = nullptr;
NSLogEvents::EventLogEntry* evt = this->RecordGetInitializedEvent<NSLogEvents::JsRTIntegralArgumentAction, NSLogEvents::EventKind::AllocateArrayBufferActionTag>(&cAction);
cAction->Scalar = size;
actionPopper.InitializeWithEventAndEnterWResult(evt, &(cAction->Result));
}
void EventLog::RecordJsRTAllocateExternalArrayBuffer(TTDJsRTActionResultAutoRecorder& actionPopper, byte* buff, uint32 size)
{
NSLogEvents::JsRTByteBufferAction* cAction = nullptr;
NSLogEvents::EventLogEntry* evt = this->RecordGetInitializedEvent<NSLogEvents::JsRTByteBufferAction, NSLogEvents::EventKind::AllocateExternalArrayBufferActionTag>(&cAction);
cAction->Length = size;
cAction->Buffer = nullptr;
if(cAction->Length != 0)
{
cAction->Buffer = this->m_eventSlabAllocator.SlabAllocateArray<byte>(cAction->Length);
js_memcpy_s(cAction->Buffer, cAction->Length, buff, size);
}
actionPopper.InitializeWithEventAndEnterWResult(evt, &(cAction->Result));
}
void EventLog::RecordJsRTAllocateFunction(TTDJsRTActionResultAutoRecorder& actionPopper, bool isNamed, Js::Var optName)
{
NSLogEvents::JsRTSingleVarScalarArgumentAction* cAction = nullptr;
NSLogEvents::EventLogEntry* evt = this->RecordGetInitializedEvent<NSLogEvents::JsRTSingleVarScalarArgumentAction, NSLogEvents::EventKind::AllocateFunctionActionTag>(&cAction);
NSLogEvents::SetVarItem_0(cAction, TTD_CONVERT_JSVAR_TO_TTDVAR(optName));
NSLogEvents::SetScalarItem_0(cAction, isNamed);
actionPopper.InitializeWithEventAndEnterWResult(evt, &(cAction->Result));
}
void EventLog::RecordJsRTHostExitProcess(TTDJsRTActionResultAutoRecorder& actionPopper, int32 exitCode)
{
NSLogEvents::JsRTIntegralArgumentAction* eAction = nullptr;
NSLogEvents::EventLogEntry* evt = this->RecordGetInitializedEvent<NSLogEvents::JsRTIntegralArgumentAction, NSLogEvents::EventKind::HostExitProcessTag>(&eAction);
eAction->Scalar = exitCode;
actionPopper.InitializeWithEventAndEnter(evt);
}
void EventLog::RecordJsRTGetAndClearExceptionWithMetadata(TTDJsRTActionResultAutoRecorder& actionPopper)
{
NSLogEvents::JsRTResultOnlyAction* gcAction = nullptr;
NSLogEvents::EventLogEntry* evt = this->RecordGetInitializedEvent<NSLogEvents::JsRTResultOnlyAction, NSLogEvents::EventKind::GetAndClearExceptionWithMetadataActionTag>(&gcAction);
actionPopper.InitializeWithEventAndEnterWResult(evt, &(gcAction->Result));
}
void EventLog::RecordJsRTGetAndClearException(TTDJsRTActionResultAutoRecorder& actionPopper)
{
NSLogEvents::JsRTResultOnlyAction* gcAction = nullptr;
NSLogEvents::EventLogEntry* evt = this->RecordGetInitializedEvent<NSLogEvents::JsRTResultOnlyAction, NSLogEvents::EventKind::GetAndClearExceptionActionTag>(&gcAction);
actionPopper.InitializeWithEventAndEnterWResult(evt, &(gcAction->Result));
}
void EventLog::RecordJsRTSetException(TTDJsRTActionResultAutoRecorder& actionPopper, Js::Var var, bool propagateToDebugger)
{
NSLogEvents::JsRTSingleVarScalarArgumentAction* spAction = nullptr;
NSLogEvents::EventLogEntry* evt = this->RecordGetInitializedEvent<NSLogEvents::JsRTSingleVarScalarArgumentAction, NSLogEvents::EventKind::SetExceptionActionTag>(&spAction);
NSLogEvents::SetVarItem_0(spAction, TTD_CONVERT_JSVAR_TO_TTDVAR(var));
NSLogEvents::SetScalarItem_0(spAction, propagateToDebugger);
actionPopper.InitializeWithEventAndEnter(evt);
}
void EventLog::RecordJsRTHasProperty(TTDJsRTActionResultAutoRecorder& actionPopper, const Js::PropertyRecord* pRecord, Js::Var var)
{
//The host may not have validated this yet (and will exit early if the check fails) so we check it here as well before getting the property id below
if(pRecord == nullptr || Js::IsInternalPropertyId(pRecord->GetPropertyId()))
{
return;
}
NSLogEvents::JsRTSingleVarScalarArgumentAction* gpAction = nullptr;
NSLogEvents::EventLogEntry* evt = this->RecordGetInitializedEvent<NSLogEvents::JsRTSingleVarScalarArgumentAction, NSLogEvents::EventKind::HasPropertyActionTag>(&gpAction);
NSLogEvents::SetVarItem_0(gpAction, TTD_CONVERT_JSVAR_TO_TTDVAR(var));
NSLogEvents::SetPropertyIdItem(gpAction, pRecord->GetPropertyId());
actionPopper.InitializeWithEventAndEnter(evt);
}
void EventLog::RecordJsRTInstanceOf(TTDJsRTActionResultAutoRecorder& actionPopper, Js::Var object, Js::Var constructor)
{
NSLogEvents::JsRTDoubleVarArgumentAction* gpAction = nullptr;
NSLogEvents::EventLogEntry* evt = this->RecordGetInitializedEvent<NSLogEvents::JsRTDoubleVarArgumentAction, NSLogEvents::EventKind::InstanceOfActionTag>(&gpAction);
NSLogEvents::SetVarItem_0(gpAction, TTD_CONVERT_JSVAR_TO_TTDVAR(object));
NSLogEvents::SetVarItem_1(gpAction, TTD_CONVERT_JSVAR_TO_TTDVAR(constructor));
actionPopper.InitializeWithEventAndEnter(evt);
}
void EventLog::RecordJsRTEquals(TTDJsRTActionResultAutoRecorder& actionPopper, Js::Var var1, Js::Var var2, bool doStrict)
{
NSLogEvents::JsRTDoubleVarSingleScalarArgumentAction* gpAction = nullptr;
NSLogEvents::EventLogEntry* evt = this->RecordGetInitializedEvent<NSLogEvents::JsRTDoubleVarSingleScalarArgumentAction, NSLogEvents::EventKind::EqualsActionTag>(&gpAction);
NSLogEvents::SetVarItem_0(gpAction, TTD_CONVERT_JSVAR_TO_TTDVAR(var1));
NSLogEvents::SetVarItem_1(gpAction, TTD_CONVERT_JSVAR_TO_TTDVAR(var2));
NSLogEvents::SetScalarItem_0(gpAction, doStrict);
actionPopper.InitializeWithEventAndEnter(evt);
}
void EventLog::RecordJsRTGetPropertyIdFromSymbol(TTDJsRTActionResultAutoRecorder& actionPopper, Js::Var sym)
{
NSLogEvents::JsRTSingleVarArgumentAction* gpAction = nullptr;
NSLogEvents::EventLogEntry* evt = this->RecordGetInitializedEvent<NSLogEvents::JsRTSingleVarArgumentAction, NSLogEvents::EventKind::GetPropertyIdFromSymbolTag>(&gpAction);
NSLogEvents::SetVarItem_0(gpAction, TTD_CONVERT_JSVAR_TO_TTDVAR(sym));
actionPopper.InitializeWithEventAndEnter(evt);
}
void EventLog::RecordJsRTGetPrototype(TTDJsRTActionResultAutoRecorder& actionPopper, Js::Var var)
{
NSLogEvents::JsRTSingleVarArgumentAction* gpAction = nullptr;
NSLogEvents::EventLogEntry* evt = this->RecordGetInitializedEvent<NSLogEvents::JsRTSingleVarArgumentAction, NSLogEvents::EventKind::GetPrototypeActionTag>(&gpAction);
NSLogEvents::SetVarItem_0(gpAction, TTD_CONVERT_JSVAR_TO_TTDVAR(var));
actionPopper.InitializeWithEventAndEnterWResult(evt, &(gpAction->Result));
}
void EventLog::RecordJsRTGetProperty(TTDJsRTActionResultAutoRecorder& actionPopper, const Js::PropertyRecord* pRecord, Js::Var var)
{
//The host may not have validated this yet (and will exit early if the check fails) so we check it here as well before getting the property id below
if(pRecord == nullptr || Js::IsInternalPropertyId(pRecord->GetPropertyId()))
{
return;
}
NSLogEvents::JsRTSingleVarScalarArgumentAction* gpAction = nullptr;
NSLogEvents::EventLogEntry* evt = this->RecordGetInitializedEvent<NSLogEvents::JsRTSingleVarScalarArgumentAction, NSLogEvents::EventKind::GetPropertyActionTag>(&gpAction);
NSLogEvents::SetVarItem_0(gpAction, TTD_CONVERT_JSVAR_TO_TTDVAR(var));
NSLogEvents::SetPropertyIdItem(gpAction, pRecord->GetPropertyId());
actionPopper.InitializeWithEventAndEnterWResult(evt, &(gpAction->Result));
}
void EventLog::RecordJsRTGetIndex(TTDJsRTActionResultAutoRecorder& actionPopper, Js::Var index, Js::Var var)
{
NSLogEvents::JsRTDoubleVarArgumentAction* giAction = nullptr;
NSLogEvents::EventLogEntry* evt = this->RecordGetInitializedEvent<NSLogEvents::JsRTDoubleVarArgumentAction, NSLogEvents::EventKind::GetIndexActionTag>(&giAction);
NSLogEvents::SetVarItem_0(giAction, TTD_CONVERT_JSVAR_TO_TTDVAR(var));
NSLogEvents::SetVarItem_1(giAction, TTD_CONVERT_JSVAR_TO_TTDVAR(index));
actionPopper.InitializeWithEventAndEnterWResult(evt, &(giAction->Result));
}
void EventLog::RecordJsRTGetOwnPropertyInfo(TTDJsRTActionResultAutoRecorder& actionPopper, const Js::PropertyRecord* pRecord, Js::Var var)
{
//The host may not have validated this yet (and will exit early if the check fails) so we check it here as well before getting the property id below
if(pRecord == nullptr || Js::IsInternalPropertyId(pRecord->GetPropertyId()))
{
return;
}
NSLogEvents::JsRTSingleVarScalarArgumentAction* gpAction = nullptr;
NSLogEvents::EventLogEntry* evt = this->RecordGetInitializedEvent<NSLogEvents::JsRTSingleVarScalarArgumentAction, NSLogEvents::EventKind::GetOwnPropertyInfoActionTag>(&gpAction);
NSLogEvents::SetVarItem_0(gpAction, TTD_CONVERT_JSVAR_TO_TTDVAR(var));
NSLogEvents::SetPropertyIdItem(gpAction, pRecord->GetPropertyId());
actionPopper.InitializeWithEventAndEnterWResult(evt, &(gpAction->Result));
}
void EventLog::RecordJsRTGetOwnPropertyNamesInfo(TTDJsRTActionResultAutoRecorder& actionPopper, Js::Var var)
{
NSLogEvents::JsRTSingleVarArgumentAction* gpAction = nullptr;
NSLogEvents::EventLogEntry* evt = this->RecordGetInitializedEvent<NSLogEvents::JsRTSingleVarArgumentAction, NSLogEvents::EventKind::GetOwnPropertyNamesInfoActionTag>(&gpAction);
NSLogEvents::SetVarItem_0(gpAction, TTD_CONVERT_JSVAR_TO_TTDVAR(var));
actionPopper.InitializeWithEventAndEnterWResult(evt, &(gpAction->Result));
}
void EventLog::RecordJsRTGetOwnPropertySymbolsInfo(TTDJsRTActionResultAutoRecorder& actionPopper, Js::Var var)
{
NSLogEvents::JsRTSingleVarArgumentAction* gpAction = nullptr;
NSLogEvents::EventLogEntry* evt = this->RecordGetInitializedEvent<NSLogEvents::JsRTSingleVarArgumentAction, NSLogEvents::EventKind::GetOwnPropertySymbolsInfoActionTag>(&gpAction);
NSLogEvents::SetVarItem_0(gpAction, TTD_CONVERT_JSVAR_TO_TTDVAR(var));
actionPopper.InitializeWithEventAndEnterWResult(evt, &(gpAction->Result));
}
void EventLog::RecordJsRTDefineProperty(TTDJsRTActionResultAutoRecorder& actionPopper, Js::Var var, const Js::PropertyRecord* pRecord, Js::Var propertyDescriptor)
{
//The host may not have validated this yet (and will exit early if the check fails) so we check it here as well before getting the property id below
if(pRecord == nullptr || Js::IsInternalPropertyId(pRecord->GetPropertyId()))
{
return;
}
NSLogEvents::JsRTDoubleVarSingleScalarArgumentAction* dpAction = nullptr;
NSLogEvents::EventLogEntry* evt = this->RecordGetInitializedEvent<NSLogEvents::JsRTDoubleVarSingleScalarArgumentAction, NSLogEvents::EventKind::DefinePropertyActionTag>(&dpAction);
NSLogEvents::SetVarItem_0(dpAction, TTD_CONVERT_JSVAR_TO_TTDVAR(var));
NSLogEvents::SetVarItem_1(dpAction, TTD_CONVERT_JSVAR_TO_TTDVAR(propertyDescriptor));
NSLogEvents::SetPropertyIdItem(dpAction, pRecord->GetPropertyId());
actionPopper.InitializeWithEventAndEnter(evt);
}
void EventLog::RecordJsRTDeleteProperty(TTDJsRTActionResultAutoRecorder& actionPopper, Js::Var var, const Js::PropertyRecord* pRecord, bool useStrictRules)
{
//The host may not have validated this yet (and will exit early if the check fails) so we check it here as well before getting the property id below
if(pRecord == nullptr || Js::IsInternalPropertyId(pRecord->GetPropertyId()))
{
return;
}
NSLogEvents::JsRTSingleVarDoubleScalarArgumentAction* dpAction = nullptr;
NSLogEvents::EventLogEntry* evt = this->RecordGetInitializedEvent<NSLogEvents::JsRTSingleVarDoubleScalarArgumentAction, NSLogEvents::EventKind::DeletePropertyActionTag>(&dpAction);
NSLogEvents::SetVarItem_0(dpAction, TTD_CONVERT_JSVAR_TO_TTDVAR(var));
NSLogEvents::SetPropertyIdItem(dpAction, pRecord->GetPropertyId());
NSLogEvents::SetScalarItem_1(dpAction, useStrictRules);
actionPopper.InitializeWithEventAndEnterWResult(evt, &(dpAction->Result));
}
void EventLog::RecordJsRTSetPrototype(TTDJsRTActionResultAutoRecorder& actionPopper, Js::Var var, Js::Var proto)
{
NSLogEvents::JsRTDoubleVarArgumentAction* spAction = nullptr;
NSLogEvents::EventLogEntry* evt = this->RecordGetInitializedEvent<NSLogEvents::JsRTDoubleVarArgumentAction, NSLogEvents::EventKind::SetPrototypeActionTag>(&spAction);
NSLogEvents::SetVarItem_0(spAction, TTD_CONVERT_JSVAR_TO_TTDVAR(var));
NSLogEvents::SetVarItem_1(spAction, TTD_CONVERT_JSVAR_TO_TTDVAR(proto));
actionPopper.InitializeWithEventAndEnter(evt);
}
void EventLog::RecordJsRTSetProperty(TTDJsRTActionResultAutoRecorder& actionPopper, Js::Var var, const Js::PropertyRecord* pRecord, Js::Var val, bool useStrictRules)
{
//The host may not have validated this yet (and will exit early if the check fails) so we check it here as well before getting the property id below
if(pRecord == nullptr || Js::IsInternalPropertyId(pRecord->GetPropertyId()))
{
return;
}
NSLogEvents::JsRTDoubleVarDoubleScalarArgumentAction* spAction = nullptr;
NSLogEvents::EventLogEntry* evt = this->RecordGetInitializedEvent<NSLogEvents::JsRTDoubleVarDoubleScalarArgumentAction, NSLogEvents::EventKind::SetPropertyActionTag>(&spAction);
NSLogEvents::SetVarItem_0(spAction, TTD_CONVERT_JSVAR_TO_TTDVAR(var));
NSLogEvents::SetVarItem_1(spAction, TTD_CONVERT_JSVAR_TO_TTDVAR(val));
NSLogEvents::SetPropertyIdItem(spAction, pRecord->GetPropertyId());
NSLogEvents::SetScalarItem_1(spAction, useStrictRules);
actionPopper.InitializeWithEventAndEnter(evt);
}
void EventLog::RecordJsRTSetIndex(TTDJsRTActionResultAutoRecorder& actionPopper, Js::Var var, Js::Var index, Js::Var val)
{
NSLogEvents::JsRTTrippleVarArgumentAction* spAction = nullptr;
NSLogEvents::EventLogEntry* evt = this->RecordGetInitializedEvent<NSLogEvents::JsRTTrippleVarArgumentAction, NSLogEvents::EventKind::SetIndexActionTag>(&spAction);
NSLogEvents::SetVarItem_0(spAction, TTD_CONVERT_JSVAR_TO_TTDVAR(var));
NSLogEvents::SetVarItem_1(spAction, TTD_CONVERT_JSVAR_TO_TTDVAR(index));
NSLogEvents::SetVarItem_2(spAction, TTD_CONVERT_JSVAR_TO_TTDVAR(val));
actionPopper.InitializeWithEventAndEnter(evt);
}
void EventLog::RecordJsRTGetTypedArrayInfo(Js::Var var, Js::Var result)
{
NSLogEvents::JsRTSingleVarArgumentAction* giAction = this->RecordGetInitializedEvent_DataOnly<NSLogEvents::JsRTSingleVarArgumentAction, NSLogEvents::EventKind::GetTypedArrayInfoActionTag>();
NSLogEvents::SetVarItem_0(giAction, TTD_CONVERT_JSVAR_TO_TTDVAR(var));
//entry/exit status should be set to clead by initialization so don't need to do anything
giAction->Result = TTD_CONVERT_JSVAR_TO_TTDVAR(result);
}
void EventLog::RecordJsRTRawBufferCopySync(TTDJsRTActionResultAutoRecorder& actionPopper, Js::Var dst, uint32 dstIndex, Js::Var src, uint32 srcIndex, uint32 length)
{
TTDAssert(Js::ArrayBuffer::Is(dst) && Js::ArrayBuffer::Is(src), "Not array buffer objects!!!");
TTDAssert(dstIndex + length <= Js::ArrayBuffer::FromVar(dst)->GetByteLength(), "Copy off end of buffer!!!");
TTDAssert(srcIndex + length <= Js::ArrayBuffer::FromVar(src)->GetByteLength(), "Copy off end of buffer!!!");
NSLogEvents::JsRTRawBufferCopyAction* rbcAction = nullptr;
NSLogEvents::EventLogEntry* evt = this->RecordGetInitializedEvent<NSLogEvents::JsRTRawBufferCopyAction, NSLogEvents::EventKind::RawBufferCopySync>(&rbcAction);
rbcAction->Dst = TTD_CONVERT_JSVAR_TO_TTDVAR(dst);
rbcAction->Src = TTD_CONVERT_JSVAR_TO_TTDVAR(src);
rbcAction->DstIndx = dstIndex;
rbcAction->SrcIndx = srcIndex;
rbcAction->Count = length;
actionPopper.InitializeWithEventAndEnter(evt);
}
void EventLog::RecordJsRTRawBufferModifySync(TTDJsRTActionResultAutoRecorder& actionPopper, Js::Var dst, uint32 index, uint32 count)
{
TTDAssert(Js::ArrayBuffer::Is(dst), "Not array buffer object!!!");
TTDAssert(index + count <= Js::ArrayBuffer::FromVar(dst)->GetByteLength(), "Copy off end of buffer!!!");
NSLogEvents::JsRTRawBufferModifyAction* rbmAction = nullptr;
NSLogEvents::EventLogEntry* evt = this->RecordGetInitializedEvent<NSLogEvents::JsRTRawBufferModifyAction, NSLogEvents::EventKind::RawBufferModifySync>(&rbmAction);
rbmAction->Trgt = TTD_CONVERT_JSVAR_TO_TTDVAR(dst);
rbmAction->Index = index;
rbmAction->Length = count;
rbmAction->Data = (rbmAction->Length != 0) ? this->m_eventSlabAllocator.SlabAllocateArray<byte>(rbmAction->Length) : nullptr;
byte* copyBuff = Js::ArrayBuffer::FromVar(dst)->GetBuffer() + index;
js_memcpy_s(rbmAction->Data, rbmAction->Length, copyBuff, count);
actionPopper.InitializeWithEventAndEnter(evt);
}
void EventLog::RecordJsRTRawBufferAsyncModificationRegister(TTDJsRTActionResultAutoRecorder& actionPopper, Js::Var dst, uint32 index)
{
NSLogEvents::JsRTRawBufferModifyAction* rbrAction = nullptr;
NSLogEvents::EventLogEntry* evt = this->RecordGetInitializedEvent<NSLogEvents::JsRTRawBufferModifyAction, NSLogEvents::EventKind::RawBufferAsyncModificationRegister>(&rbrAction);
rbrAction->Trgt = TTD_CONVERT_JSVAR_TO_TTDVAR(dst);
rbrAction->Index = index;
actionPopper.InitializeWithEventAndEnter(evt);
}
void EventLog::RecordJsRTRawBufferAsyncModifyComplete(TTDJsRTActionResultAutoRecorder& actionPopper, TTDPendingAsyncBufferModification& pendingAsyncInfo, byte* finalModPos)
{
Js::ArrayBuffer* dstBuff = Js::ArrayBuffer::FromVar(pendingAsyncInfo.ArrayBufferVar);
byte* copyBuff = dstBuff->GetBuffer() + pendingAsyncInfo.Index;
NSLogEvents::JsRTRawBufferModifyAction* rbrAction = nullptr;
NSLogEvents::EventLogEntry* evt = this->RecordGetInitializedEvent<NSLogEvents::JsRTRawBufferModifyAction, NSLogEvents::EventKind::RawBufferAsyncModifyComplete>(&rbrAction);
rbrAction->Trgt = TTD_CONVERT_JSVAR_TO_TTDVAR(dstBuff);
rbrAction->Index = (uint32)pendingAsyncInfo.Index;
rbrAction->Length = (uint32)(finalModPos - copyBuff);
rbrAction->Data = (rbrAction->Length != 0) ? this->m_eventSlabAllocator.SlabAllocateArray<byte>(rbrAction->Length) : nullptr;
js_memcpy_s(rbrAction->Data, rbrAction->Length, copyBuff, rbrAction->Length);
actionPopper.InitializeWithEventAndEnter(evt);
}
void EventLog::RecordJsRTConstructCall(TTDJsRTActionResultAutoRecorder& actionPopper, Js::Var funcVar, uint32 argCount, Js::Var* args)
{
NSLogEvents::JsRTConstructCallAction* ccAction = nullptr;
NSLogEvents::EventLogEntry* evt = this->RecordGetInitializedEvent<NSLogEvents::JsRTConstructCallAction, NSLogEvents::EventKind::ConstructCallActionTag>(&ccAction);
ccAction->ArgCount = argCount + 1;
static_assert(sizeof(TTDVar) == sizeof(Js::Var), "These need to be the same size (and have same bit layout) for this to work!");
ccAction->ArgArray = this->m_eventSlabAllocator.SlabAllocateArray<TTDVar>(ccAction->ArgCount);
ccAction->ArgArray[0] = TTD_CONVERT_JSVAR_TO_TTDVAR(funcVar);
js_memcpy_s(ccAction->ArgArray + 1, (ccAction->ArgCount - 1) * sizeof(TTDVar), args, argCount * sizeof(Js::Var));
actionPopper.InitializeWithEventAndEnterWResult(evt, &(ccAction->Result));
}
NSLogEvents::EventLogEntry* EventLog::RecordJsRTCodeParse(TTDJsRTActionResultAutoRecorder& actionPopper, LoadScriptFlag loadFlag, bool isUft8, const byte* script, uint32 scriptByteLength, uint64 sourceContextId, const char16* sourceUri)
{
NSLogEvents::JsRTCodeParseAction* cpAction = nullptr;
NSLogEvents::EventLogEntry* evt = this->RecordGetInitializedEvent<NSLogEvents::JsRTCodeParseAction, NSLogEvents::EventKind::CodeParseActionTag>(&cpAction);
cpAction->BodyCtrId = 0; //initialize to known default -- should always update later or something is wrong
cpAction->IsUtf8 = isUft8;
cpAction->SourceByteLength = scriptByteLength;
cpAction->SourceCode = this->m_eventSlabAllocator.SlabAllocateArray<byte>(cpAction->SourceByteLength);
js_memcpy_s(cpAction->SourceCode, cpAction->SourceByteLength, script, scriptByteLength);
this->m_eventSlabAllocator.CopyNullTermStringInto(sourceUri, cpAction->SourceUri);
cpAction->SourceContextId = sourceContextId;
cpAction->LoadFlag = loadFlag;
actionPopper.InitializeWithEventAndEnterWResult(evt, &(cpAction->Result));
return evt;
}
NSLogEvents::EventLogEntry* EventLog::RecordJsRTCallFunction(TTDJsRTActionResultAutoRecorder& actionPopper, int32 rootDepth, Js::Var funcVar, uint32 argCount, Js::Var* args)
{
NSLogEvents::JsRTCallFunctionAction* cAction = nullptr;
NSLogEvents::EventLogEntry* evt = this->RecordGetInitializedEvent<NSLogEvents::JsRTCallFunctionAction, NSLogEvents::EventKind::CallExistingFunctionActionTag>(&cAction);
int64 evtTime = this->GetLastEventTime();
int64 topLevelCallTime = (rootDepth == 0) ? evtTime : this->m_topLevelCallbackEventTime;
NSLogEvents::JsRTCallFunctionAction_ProcessArgs(evt, rootDepth, evtTime, funcVar, argCount, args, topLevelCallTime, this->m_eventSlabAllocator);
#if ENABLE_TTD_INTERNAL_DIAGNOSTICS
NSLogEvents::JsRTCallFunctionAction_ProcessDiagInfoPre(evt, funcVar, this->m_eventSlabAllocator);
#endif
actionPopper.InitializeWithEventAndEnterWResult(evt, &(cAction->Result));
return evt;
}
void EventLog::EmitLog(const char* emitUri, size_t emitUriLength)
{
#if ENABLE_BASIC_TRACE || ENABLE_FULL_BC_TRACE
this->m_threadContext->TTDExecutionInfo->GetTraceLogger()->ForceFlush();
#endif
TTDataIOInfo& iofp = this->m_threadContext->TTDContext->TTDataIOInfo;
iofp.ActiveTTUriLength = emitUriLength;
iofp.ActiveTTUri = emitUri;
const char* logfilename = "ttdlog.log";
JsTTDStreamHandle logHandle = iofp.pfOpenResourceStream(iofp.ActiveTTUriLength, iofp.ActiveTTUri, strlen(logfilename), logfilename, false, true);
TTDAssert(logHandle != nullptr, "Failed to initialize strem for writing TTD Log.");
TTD_LOG_WRITER writer(logHandle, iofp.pfWriteBytesToStream, iofp.pfFlushAndCloseStream);
writer.WriteRecordStart();
writer.AdjustIndent(1);
TTString archString;
#if defined(_M_IX86)
this->m_miscSlabAllocator.CopyNullTermStringInto(_u("x86"), archString);
#elif defined(_M_X64)
this->m_miscSlabAllocator.CopyNullTermStringInto(_u("x64"), archString);
#elif defined(_M_ARM)
this->m_miscSlabAllocator.CopyNullTermStringInto(_u("arm"), archString);
#elif defined(_M_ARM64)
this->m_miscSlabAllocator.CopyNullTermStringInto(_u("arm64"), archString);
#else
this->m_miscSlabAllocator.CopyNullTermStringInto(_u("unknown"), archString);
#endif
writer.WriteString(NSTokens::Key::arch, archString);
TTString platformString;
#if defined(_WIN32)
this->m_miscSlabAllocator.CopyNullTermStringInto(_u("Windows"), platformString);
#elif defined(__APPLE__)
this->m_miscSlabAllocator.CopyNullTermStringInto(_u("macOS"), platformString);
#else
this->m_miscSlabAllocator.CopyNullTermStringInto(_u("Linux"), platformString);
#endif
writer.WriteString(NSTokens::Key::platform, platformString, NSTokens::Separator::CommaSeparator);
#if ENABLE_TTD_INTERNAL_DIAGNOSTICS
bool diagEnabled = true;
#else
bool diagEnabled = false;
#endif
writer.WriteBool(NSTokens::Key::diagEnabled, diagEnabled, NSTokens::Separator::CommaSeparator);
uint64 usedSpace = 0;
uint64 reservedSpace = 0;
this->m_eventSlabAllocator.ComputeMemoryUsed(&usedSpace, &reservedSpace);
writer.WriteUInt64(NSTokens::Key::usedMemory, usedSpace, NSTokens::Separator::CommaSeparator);
writer.WriteUInt64(NSTokens::Key::reservedMemory, reservedSpace, NSTokens::Separator::CommaSeparator);
uint32 ecount = this->m_eventList.Count();
writer.WriteLengthValue(ecount, NSTokens::Separator::CommaAndBigSpaceSeparator);
#if ENABLE_TTD_INTERNAL_DIAGNOSTICS
JsUtil::Stack<int64, HeapAllocator> callNestingStack(&HeapAllocator::Instance);
#endif
bool firstElem = true;
writer.WriteSequenceStart_DefaultKey(NSTokens::Separator::CommaSeparator);
writer.AdjustIndent(1);
writer.WriteSeperator(NSTokens::Separator::BigSpaceSeparator);
for(auto iter = this->m_eventList.GetIteratorAtFirst(); iter.IsValid(); iter.MoveNext())
{
const NSLogEvents::EventLogEntry* evt = iter.Current();
NSTokens::Separator sep = firstElem ? NSTokens::Separator::NoSeparator : NSTokens::Separator::BigSpaceSeparator;
NSLogEvents::EventLogEntry_Emit(evt, this->m_eventListVTable, &writer, this->m_threadContext, sep);
firstElem = false;
#if ENABLE_TTD_INTERNAL_DIAGNOSTICS
bool isJsRTCall = (evt->EventKind == NSLogEvents::EventKind::CallExistingFunctionActionTag);
bool isExternalCall = (evt->EventKind == NSLogEvents::EventKind::ExternalCallTag);
bool isRegisterCall = (evt->EventKind == NSLogEvents::EventKind::ExternalCbRegisterCall);
if(isJsRTCall | isExternalCall | isRegisterCall)
{
writer.WriteSequenceStart(NSTokens::Separator::BigSpaceSeparator);
int64 lastNestedTime = -1;
if(isJsRTCall)
{
lastNestedTime = NSLogEvents::JsRTCallFunctionAction_GetLastNestedEventTime(evt);
}
else if(isExternalCall)
{
lastNestedTime = NSLogEvents::ExternalCallEventLogEntry_GetLastNestedEventTime(evt);
}
else
{
lastNestedTime = NSLogEvents::ExternalCbRegisterCallEventLogEntry_GetLastNestedEventTime(evt);
}
callNestingStack.Push(lastNestedTime);
if(lastNestedTime != evt->EventTimeStamp)
{
writer.AdjustIndent(1);
writer.WriteSeperator(NSTokens::Separator::BigSpaceSeparator);
firstElem = true;
}
}
if(!callNestingStack.Empty() && evt->EventTimeStamp == callNestingStack.Peek())
{
int64 eTime = callNestingStack.Pop();
if(!isJsRTCall & !isExternalCall & !isRegisterCall)
{
writer.AdjustIndent(-1);
writer.WriteSeperator(NSTokens::Separator::BigSpaceSeparator);
}
writer.WriteSequenceEnd();
while(!callNestingStack.Empty() && eTime == callNestingStack.Peek())
{
callNestingStack.Pop();
writer.AdjustIndent(-1);
writer.WriteSequenceEnd(NSTokens::Separator::BigSpaceSeparator);
}
}
#endif
}
writer.AdjustIndent(-1);
writer.WriteSequenceEnd(NSTokens::Separator::BigSpaceSeparator);
//emit the properties
writer.WriteLengthValue(this->m_propertyRecordPinSet->Count(), NSTokens::Separator::CommaSeparator);
writer.WriteSequenceStart_DefaultKey(NSTokens::Separator::CommaSeparator);
writer.AdjustIndent(1);
bool firstProperty = true;
for(auto iter = this->m_propertyRecordPinSet->GetIterator(); iter.IsValid(); iter.MoveNext())
{
NSTokens::Separator sep = (!firstProperty) ? NSTokens::Separator::CommaAndBigSpaceSeparator : NSTokens::Separator::BigSpaceSeparator;
NSSnapType::EmitPropertyRecordAsSnapPropertyRecord(iter.CurrentValue(), &writer, sep);
firstProperty = false;
}
writer.AdjustIndent(-1);
writer.WriteSequenceEnd(NSTokens::Separator::BigSpaceSeparator);
//do top level script processing here
writer.WriteUInt32(NSTokens::Key::u32Val, this->m_sourceInfoCount, NSTokens::Separator::CommaSeparator);
writer.WriteLengthValue(this->m_loadedTopLevelScripts.Count(), NSTokens::Separator::CommaSeparator);
writer.WriteSequenceStart_DefaultKey(NSTokens::Separator::CommaSeparator);
writer.AdjustIndent(1);
bool firstLoadScript = true;
for(auto iter = this->m_loadedTopLevelScripts.GetIterator(); iter.IsValid(); iter.MoveNext())
{
NSTokens::Separator sep = (!firstLoadScript) ? NSTokens::Separator::CommaAndBigSpaceSeparator : NSTokens::Separator::BigSpaceSeparator;
NSSnapValues::EmitTopLevelLoadedFunctionBodyInfo(iter.Current(), this->m_threadContext, &writer, sep);
firstLoadScript = false;
}
writer.AdjustIndent(-1);
writer.WriteSequenceEnd(NSTokens::Separator::BigSpaceSeparator);
writer.WriteLengthValue(this->m_newFunctionTopLevelScripts.Count(), NSTokens::Separator::CommaSeparator);
writer.WriteSequenceStart_DefaultKey(NSTokens::Separator::CommaSeparator);
writer.AdjustIndent(1);
bool firstNewScript = true;
for(auto iter = this->m_newFunctionTopLevelScripts.GetIterator(); iter.IsValid(); iter.MoveNext())
{
NSTokens::Separator sep = (!firstNewScript) ? NSTokens::Separator::CommaAndBigSpaceSeparator : NSTokens::Separator::BigSpaceSeparator;
NSSnapValues::EmitTopLevelNewFunctionBodyInfo(iter.Current(), this->m_threadContext, &writer, sep);
firstNewScript = false;
}
writer.AdjustIndent(-1);
writer.WriteSequenceEnd(NSTokens::Separator::BigSpaceSeparator);
writer.WriteLengthValue(this->m_evalTopLevelScripts.Count(), NSTokens::Separator::CommaSeparator);
writer.WriteSequenceStart_DefaultKey(NSTokens::Separator::CommaSeparator);
writer.AdjustIndent(1);
bool firstEvalScript = true;
for(auto iter = this->m_evalTopLevelScripts.GetIterator(); iter.IsValid(); iter.MoveNext())
{
NSTokens::Separator sep = (!firstEvalScript) ? NSTokens::Separator::CommaAndBigSpaceSeparator : NSTokens::Separator::BigSpaceSeparator;
NSSnapValues::EmitTopLevelEvalFunctionBodyInfo(iter.Current(), this->m_threadContext, &writer, sep);
firstEvalScript = false;
}
writer.AdjustIndent(-1);
writer.WriteSequenceEnd(NSTokens::Separator::BigSpaceSeparator);
//
writer.AdjustIndent(-1);
writer.WriteRecordEnd(NSTokens::Separator::BigSpaceSeparator);
writer.FlushAndClose();
iofp.ActiveTTUriLength = 0;
iofp.ActiveTTUri = nullptr;
}
void EventLog::ParseLogInto(TTDataIOInfo& iofp, const char* parseUri, size_t parseUriLength)
{
iofp.ActiveTTUriLength = parseUriLength;
iofp.ActiveTTUri = parseUri;
const char* logfilename = "ttdlog.log";
JsTTDStreamHandle logHandle = iofp.pfOpenResourceStream(iofp.ActiveTTUriLength, iofp.ActiveTTUri, strlen(logfilename), logfilename, true, false);
TTDAssert(logHandle != nullptr, "Failed to initialize strem for reading TTD Log.");
TTD_LOG_READER reader(logHandle, iofp.pfReadBytesFromStream, iofp.pfFlushAndCloseStream);
reader.ReadRecordStart();
TTString archString;
reader.ReadString(NSTokens::Key::arch, this->m_miscSlabAllocator, archString);
#if defined(_M_IX86)
TTDAssert(wcscmp(_u("x86"), archString.Contents) == 0, "Mismatch in arch between record and replay!!!");
#elif defined(_M_X64)
TTDAssert(wcscmp(_u("x64"), archString.Contents) == 0, "Mismatch in arch between record and replay!!!");
#elif defined(_M_ARM)
TTDAssert(wcscmp(_u("arm64"), archString.Contents) == 0, "Mismatch in arch between record and replay!!!");
#else
TTDAssert(false, "Unknown arch!!!");
#endif
//This is informational only so just read off the value and ignore
TTString platformString;
reader.ReadString(NSTokens::Key::platform, this->m_miscSlabAllocator, platformString, true);
bool diagEnabled = reader.ReadBool(NSTokens::Key::diagEnabled, true);
#if ENABLE_TTD_INTERNAL_DIAGNOSTICS
TTDAssert(diagEnabled, "Diag was enabled in record so it shoud be in replay as well!!!");
#else
TTDAssert(!diagEnabled, "Diag was *not* enabled in record so it shoud *not* be in replay either!!!");
#endif
reader.ReadUInt64(NSTokens::Key::usedMemory, true);
reader.ReadUInt64(NSTokens::Key::reservedMemory, true);
#if ENABLE_TTD_INTERNAL_DIAGNOSTICS
JsUtil::Stack<int64, HeapAllocator> callNestingStack(&HeapAllocator::Instance);
bool doSep = false;
#endif
uint32 ecount = reader.ReadLengthValue(true);
reader.ReadSequenceStart_WDefaultKey(true);
for(uint32 i = 0; i < ecount; ++i)
{
NSLogEvents::EventKind evtKind = NSLogEvents::EventLogEntry_ParseHeader(false, &reader);
NSLogEvents::EventLogEntry* evt = this->m_eventList.GetNextAvailableEntry(this->m_eventListVTable[(uint32)evtKind].DataSize);
evt->EventKind = evtKind;
NSLogEvents::EventLogEntry_ParseRest(evt, this->m_eventListVTable, this->m_threadContext, &reader, this->m_eventSlabAllocator);
#if ENABLE_TTD_INTERNAL_DIAGNOSTICS
bool isJsRTCall = (evt->EventKind == NSLogEvents::EventKind::CallExistingFunctionActionTag);
bool isExternalCall = (evt->EventKind == NSLogEvents::EventKind::ExternalCallTag);
bool isRegisterCall = (evt->EventKind == NSLogEvents::EventKind::ExternalCbRegisterCall);
if(isJsRTCall | isExternalCall | isRegisterCall)
{
reader.ReadSequenceStart(false);
int64 lastNestedTime = -1;
if(isJsRTCall)
{
lastNestedTime = NSLogEvents::JsRTCallFunctionAction_GetLastNestedEventTime(evt);
}
else if(isExternalCall)
{
lastNestedTime = NSLogEvents::ExternalCallEventLogEntry_GetLastNestedEventTime(evt);
}
else
{
lastNestedTime = NSLogEvents::ExternalCbRegisterCallEventLogEntry_GetLastNestedEventTime(evt);
}
callNestingStack.Push(lastNestedTime);
}
doSep = (!isJsRTCall & !isExternalCall & !isRegisterCall);
while(callNestingStack.Count() != 0 && evt->EventTimeStamp == callNestingStack.Peek())
{
callNestingStack.Pop();
reader.ReadSequenceEnd();
}
#endif
}
reader.ReadSequenceEnd();
//parse the properties
uint32 propertyCount = reader.ReadLengthValue(true);
reader.ReadSequenceStart_WDefaultKey(true);
for(uint32 i = 0; i < propertyCount; ++i)
{
NSSnapType::SnapPropertyRecord* sRecord = this->m_propertyRecordList.NextOpenEntry();
NSSnapType::ParseSnapPropertyRecord(sRecord, i != 0, &reader, this->m_miscSlabAllocator);
}
reader.ReadSequenceEnd();
//do top level script processing here
this->m_sourceInfoCount = reader.ReadUInt32(NSTokens::Key::u32Val, true);
uint32 loadedScriptCount = reader.ReadLengthValue(true);
reader.ReadSequenceStart_WDefaultKey(true);
for(uint32 i = 0; i < loadedScriptCount; ++i)
{
NSSnapValues::TopLevelScriptLoadFunctionBodyResolveInfo* fbInfo = this->m_loadedTopLevelScripts.NextOpenEntry();
NSSnapValues::ParseTopLevelLoadedFunctionBodyInfo(fbInfo, i != 0, this->m_threadContext, &reader, this->m_miscSlabAllocator);
}
reader.ReadSequenceEnd();
uint32 newScriptCount = reader.ReadLengthValue(true);
reader.ReadSequenceStart_WDefaultKey(true);
for(uint32 i = 0; i < newScriptCount; ++i)
{
NSSnapValues::TopLevelNewFunctionBodyResolveInfo* fbInfo = this->m_newFunctionTopLevelScripts.NextOpenEntry();
NSSnapValues::ParseTopLevelNewFunctionBodyInfo(fbInfo, i != 0, this->m_threadContext, &reader, this->m_miscSlabAllocator);
}
reader.ReadSequenceEnd();
uint32 evalScriptCount = reader.ReadLengthValue(true);
reader.ReadSequenceStart_WDefaultKey(true);
for(uint32 i = 0; i < evalScriptCount; ++i)
{
NSSnapValues::TopLevelEvalFunctionBodyResolveInfo* fbInfo = this->m_evalTopLevelScripts.NextOpenEntry();
NSSnapValues::ParseTopLevelEvalFunctionBodyInfo(fbInfo, i != 0, this->m_threadContext, &reader, this->m_miscSlabAllocator);
}
reader.ReadSequenceEnd();
//
reader.ReadRecordEnd();
//After reading setup the previous event map
this->m_eventList.InitializePreviousEventMap();
}
}
#endif