| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227 |
- //-------------------------------------------------------------------------------------------------------
- // Copyright (C) Microsoft. All rights reserved.
- // Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
- //-------------------------------------------------------------------------------------------------------
- #include "Backend.h"
- #include "Language/SourceDynamicProfileManager.h"
- CodeGenWorkItem::CodeGenWorkItem(
- JsUtil::JobManager *const manager,
- Js::FunctionBody *const functionBody,
- Js::EntryPointInfo* entryPointInfo,
- bool isJitInDebugMode,
- CodeGenWorkItemType type)
- : JsUtil::Job(manager)
- , codeAddress(NULL)
- , functionBody(functionBody)
- , entryPointInfo(entryPointInfo)
- , recyclableData(nullptr)
- , isInJitQueue(false)
- , isAllocationCommitted(false)
- , queuedFullJitWorkItem(nullptr)
- , allocation(nullptr)
- #ifdef IR_VIEWER
- , isRejitIRViewerFunction(false)
- , irViewerOutput(nullptr)
- , irViewerRequestContext(nullptr)
- #endif
- {
- this->jitData = {0};
- // work item data
- this->jitData.type = type;
- this->jitData.isJitInDebugMode = isJitInDebugMode;
- ResetJitMode();
- }
- CodeGenWorkItem::~CodeGenWorkItem()
- {
- if(queuedFullJitWorkItem)
- {
- HeapDelete(queuedFullJitWorkItem);
- }
- }
- //
- // Helps determine whether a function should be speculatively jitted.
- // This function is only used once and is used in a time-critical area, so
- // be careful with it (moving it around actually caused around a 5% perf
- // regression on a test).
- //
- bool CodeGenWorkItem::ShouldSpeculativelyJit(uint byteCodeSizeGenerated) const
- {
- if(PHASE_OFF(Js::FullJitPhase, this->functionBody))
- {
- return false;
- }
- byteCodeSizeGenerated += this->GetByteCodeCount();
- if(CONFIG_FLAG(ProfileBasedSpeculativeJit))
- {
- Assert(!CONFIG_ISENABLED(Js::NoDynamicProfileInMemoryCacheFlag));
- // JIT this now if we are under the speculation cap.
- return
- byteCodeSizeGenerated < (uint)CONFIG_FLAG(SpeculationCap) ||
- (
- byteCodeSizeGenerated < (uint)CONFIG_FLAG(ProfileBasedSpeculationCap) &&
- this->ShouldSpeculativelyJitBasedOnProfile()
- );
- }
- else
- {
- return byteCodeSizeGenerated < (uint)CONFIG_FLAG(SpeculationCap);
- }
- }
- bool CodeGenWorkItem::ShouldSpeculativelyJitBasedOnProfile() const
- {
- Js::FunctionBody* functionBody = this->GetFunctionBody();
- uint loopPercentage = (functionBody->GetByteCodeInLoopCount()*100) / (functionBody->GetByteCodeCount() + 1);
- uint straightLineSize = functionBody->GetByteCodeCount() - functionBody->GetByteCodeInLoopCount();
- // This ensures only small and loopy functions are prejitted.
- if(loopPercentage >= 50 || straightLineSize < 300)
- {
- Js::SourceDynamicProfileManager* profileManager = functionBody->GetSourceContextInfo()->sourceDynamicProfileManager;
- if(profileManager != nullptr)
- {
- functionBody->SetIsSpeculativeJitCandidate();
- if(!functionBody->HasDynamicProfileInfo())
- {
- return false;
- }
- Js::ExecutionFlags executionFlags = profileManager->IsFunctionExecuted(functionBody->GetLocalFunctionId());
- if(executionFlags == Js::ExecutionFlags_Executed)
- {
- return true;
- }
- }
- }
- return false;
- }
- /*
- A comment about how to cause certain phases to only be on:
- INT = Interpreted, SJ = SimpleJit, FJ = FullJit
- To get only the following levels on, use the flags:
- INT: -noNative
- SJ : -forceNative -off:fullJit
- FJ : -forceNative -off:simpleJit
- INT, SJ: -off:fullJit
- INT, FJ: -off:simpleJit
- SJ, FG: -forceNative
- INT, SJ, FG: (default)
- */
- void CodeGenWorkItem::OnAddToJitQueue()
- {
- Assert(!this->isInJitQueue);
- this->isInJitQueue = true;
- VerifyJitMode();
- this->entryPointInfo->SetCodeGenQueued();
- if(IS_JS_ETW(EventEnabledJSCRIPT_FUNCTION_JIT_QUEUED()))
- {
- WCHAR displayNameBuffer[256];
- WCHAR* displayName = displayNameBuffer;
- size_t sizeInChars = this->GetDisplayName(displayName, 256);
- if(sizeInChars > 256)
- {
- displayName = HeapNewArray(WCHAR, sizeInChars);
- this->GetDisplayName(displayName, 256);
- }
- JS_ETW(EventWriteJSCRIPT_FUNCTION_JIT_QUEUED(
- this->GetFunctionNumber(),
- displayName,
- this->GetScriptContext(),
- this->GetInterpretedCount()));
- if(displayName != displayNameBuffer)
- {
- HeapDeleteArray(sizeInChars, displayName);
- }
- }
- }
- void CodeGenWorkItem::OnRemoveFromJitQueue(NativeCodeGenerator* generator)
- {
- // This is called from within the lock
- this->isInJitQueue = false;
- this->entryPointInfo->SetCodeGenPending();
- functionBody->GetScriptContext()->GetThreadContext()->UnregisterCodeGenRecyclableData(this->recyclableData);
- this->recyclableData = nullptr;
- if(IS_JS_ETW(EventEnabledJSCRIPT_FUNCTION_JIT_DEQUEUED()))
- {
- WCHAR displayNameBuffer[256];
- WCHAR* displayName = displayNameBuffer;
- size_t sizeInChars = this->GetDisplayName(displayName, 256);
- if(sizeInChars > 256)
- {
- displayName = HeapNewArray(WCHAR, sizeInChars);
- this->GetDisplayName(displayName, 256);
- }
- JS_ETW(EventWriteJSCRIPT_FUNCTION_JIT_DEQUEUED(
- this->GetFunctionNumber(),
- displayName,
- this->GetScriptContext(),
- this->GetInterpretedCount()));
- if(displayName != displayNameBuffer)
- {
- HeapDeleteArray(sizeInChars, displayName);
- }
- }
- if(this->Type() == JsLoopBodyWorkItemType)
- {
- // Go ahead and delete it and let it re-queue if more interpreting of the loop happens
- auto loopBodyWorkItem = static_cast<JsLoopBodyCodeGen*>(this);
- loopBodyWorkItem->loopHeader->ResetInterpreterCount();
- loopBodyWorkItem->GetEntryPoint()->Reset();
- HeapDelete(loopBodyWorkItem);
- }
- else
- {
- Assert(GetJitMode() == ExecutionMode::FullJit); // simple JIT work items are not removed from the queue
- GetFunctionBody()->OnFullJitDequeued(static_cast<Js::FunctionEntryPointInfo *>(GetEntryPoint()));
- // Add it back to the list of available functions to be jitted
- generator->AddWorkItem(this);
- }
- }
- void CodeGenWorkItem::OnWorkItemProcessFail(NativeCodeGenerator* codeGen)
- {
- if (!isAllocationCommitted && this->allocation != nullptr && this->allocation->allocation != nullptr)
- {
- #if DBG
- this->allocation->allocation->isNotExecutableBecauseOOM = true;
- #endif
- codeGen->FreeNativeCodeGenAllocation(this->allocation->allocation->address);
- }
- }
- QueuedFullJitWorkItem *CodeGenWorkItem::GetQueuedFullJitWorkItem() const
- {
- return queuedFullJitWorkItem;
- }
- QueuedFullJitWorkItem *CodeGenWorkItem::EnsureQueuedFullJitWorkItem()
- {
- if(queuedFullJitWorkItem)
- {
- return queuedFullJitWorkItem;
- }
- queuedFullJitWorkItem = HeapNewNoThrow(QueuedFullJitWorkItem, this);
- return queuedFullJitWorkItem;
- }
|