blob: 0b82ff1d8ea64cd1fde3e7610b21ec3f8bad8a10 [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 "JITServerPch.h"
__declspec(dllexport)
HRESULT JsInitializeJITServer(
__in UUID* connectionUuid,
__in_opt void* securityDescriptor,
__in_opt void* alpcSecurityDescriptor)
{
RPC_STATUS status;
RPC_BINDING_VECTOR* bindingVector = NULL;
UUID_VECTOR uuidVector;
uuidVector.Count = 1;
uuidVector.Uuid[0] = connectionUuid;
status = RpcServerUseProtseqW(
(RPC_WSTR)L"ncalrpc",
RPC_C_PROTSEQ_MAX_REQS_DEFAULT,
alpcSecurityDescriptor);
if (status != RPC_S_OK)
{
return status;
}
#ifndef NTBUILD
status = RpcServerRegisterIf2(
ServerIChakraJIT_v0_0_s_ifspec,
NULL,
NULL,
RPC_IF_AUTOLISTEN,
RPC_C_LISTEN_MAX_CALLS_DEFAULT,
(ULONG)-1,
NULL);
#else
status = RpcServerRegisterIf3(
ServerIChakraJIT_v0_0_s_ifspec,
NULL,
NULL,
RPC_IF_AUTOLISTEN,
RPC_C_LISTEN_MAX_CALLS_DEFAULT,
(ULONG)-1,
NULL,
securityDescriptor);
#endif
if (status != RPC_S_OK)
{
return status;
}
status = RpcServerInqBindings(&bindingVector);
if (status != RPC_S_OK)
{
return status;
}
JITManager::GetJITManager()->SetIsJITServer();
PageAllocatorPool::Initialize();
status = RpcEpRegister(
ServerIChakraJIT_v0_0_s_ifspec,
bindingVector,
&uuidVector,
NULL);
if (status != RPC_S_OK)
{
return status;
}
status = RpcBindingVectorFree(&bindingVector);
if (status != RPC_S_OK)
{
return status;
}
status = RpcServerListen(1, RPC_C_LISTEN_MAX_CALLS_DEFAULT, FALSE);
return status;
}
HRESULT
ShutdownCommon()
{
HRESULT status = RpcMgmtStopServerListening(NULL);
if (status != RPC_S_OK)
{
return status;
}
status = RpcServerUnregisterIf(ServerIChakraJIT_v0_0_s_ifspec, NULL, FALSE);
ServerContextManager::Shutdown();
PageAllocatorPool::Shutdown();
return status;
}
HRESULT
ServerShutdown(
/* [in] */ handle_t binding)
{
return ShutdownCommon();
}
void
__RPC_USER PTHREADCONTEXT_HANDLE_rundown(__RPC__in PTHREADCONTEXT_HANDLE phContext)
{
ServerCleanupThreadContext(nullptr, &phContext);
}
void
__RPC_USER PSCRIPTCONTEXT_HANDLE_rundown(__RPC__in PSCRIPTCONTEXT_HANDLE phContext)
{
ServerCloseScriptContext(nullptr, phContext);
ServerCleanupScriptContext(nullptr, &phContext);
}
HRESULT CheckModuleAddress(HANDLE process, LPCVOID remoteImageBase, LPCVOID localImageBase)
{
byte remoteImageHeader[0x1000];
MEMORY_BASIC_INFORMATION remoteImageInfo;
SIZE_T resultBytes = VirtualQueryEx(process, (LPCVOID)remoteImageBase, &remoteImageInfo, sizeof(remoteImageInfo));
if (resultBytes != sizeof(remoteImageInfo))
{
return E_ACCESSDENIED;
}
if (remoteImageInfo.BaseAddress != (PVOID)remoteImageBase)
{
return E_ACCESSDENIED;
}
if (remoteImageInfo.Type != MEM_IMAGE)
{
return E_ACCESSDENIED;
}
if (remoteImageInfo.State != MEM_COMMIT)
{
return E_ACCESSDENIED;
}
if (remoteImageInfo.RegionSize < sizeof(remoteImageHeader))
{
return E_ACCESSDENIED;
}
if (!ReadProcessMemory(process, remoteImageBase, remoteImageHeader, sizeof(remoteImageHeader), &resultBytes))
{
return HRESULT_FROM_WIN32(GetLastError());
}
if (resultBytes < sizeof(remoteImageHeader))
{
return E_ACCESSDENIED;
}
PIMAGE_DOS_HEADER localDosHeader = (PIMAGE_DOS_HEADER)localImageBase;
PIMAGE_NT_HEADERS localNtHeader = (PIMAGE_NT_HEADERS)((BYTE*)localDosHeader + localDosHeader->e_lfanew);
PIMAGE_DOS_HEADER remoteDosHeader = (PIMAGE_DOS_HEADER)remoteImageHeader;
PIMAGE_NT_HEADERS remoteNtHeader = (PIMAGE_NT_HEADERS)((BYTE*)remoteDosHeader + remoteDosHeader->e_lfanew);
uintptr_t remoteHeaderMax = (uintptr_t)remoteImageHeader + sizeof(remoteImageHeader);
uintptr_t remoteMaxRead = (uintptr_t)remoteNtHeader + sizeof(IMAGE_NT_HEADERS);
if (remoteMaxRead >= remoteHeaderMax || remoteMaxRead < (uintptr_t)remoteImageHeader)
{
return E_ACCESSDENIED;
}
if (localNtHeader->FileHeader.NumberOfSections != remoteNtHeader->FileHeader.NumberOfSections)
{
return E_ACCESSDENIED;
}
if (localNtHeader->FileHeader.NumberOfSymbols != remoteNtHeader->FileHeader.NumberOfSymbols)
{
return E_ACCESSDENIED;
}
if (localNtHeader->OptionalHeader.CheckSum != remoteNtHeader->OptionalHeader.CheckSum)
{
return E_ACCESSDENIED;
}
if (localNtHeader->OptionalHeader.SizeOfImage != remoteNtHeader->OptionalHeader.SizeOfImage)
{
return E_ACCESSDENIED;
}
return S_OK;
}
#pragma warning(push)
#pragma warning(disable:6387 28196) // PREFast does not understand the out context can be null here
HRESULT
ServerInitializeThreadContext(
/* [in] */ handle_t binding,
/* [in] */ __RPC__in ThreadContextDataIDL * threadContextData,
/* [out] */ __RPC__deref_out_opt PPTHREADCONTEXT_HANDLE threadContextInfoAddress,
/* [out] */ __RPC__out intptr_t *prereservedRegionAddr,
/* [out] */ __RPC__out intptr_t *jitThunkAddr)
{
if (threadContextInfoAddress == nullptr || prereservedRegionAddr == nullptr)
{
Assert(false);
return RPC_S_INVALID_ARG;
}
*threadContextInfoAddress = nullptr;
*prereservedRegionAddr = 0;
*jitThunkAddr = 0;
ServerThreadContext * contextInfo = nullptr;
try
{
AUTO_NESTED_HANDLED_EXCEPTION_TYPE(static_cast<ExceptionType>(ExceptionType_OutOfMemory));
contextInfo = HeapNew(ServerThreadContext, threadContextData);
ServerContextManager::RegisterThreadContext(contextInfo);
}
catch (Js::OutOfMemoryException)
{
CloseHandle((HANDLE)threadContextData->processHandle);
return E_OUTOFMEMORY;
}
return ServerCallWrapper(contextInfo, [&]()->HRESULT
{
RPC_CALL_ATTRIBUTES CallAttributes = { 0 };
CallAttributes.Version = RPC_CALL_ATTRIBUTES_VERSION;
CallAttributes.Flags = RPC_QUERY_CLIENT_PID;
HRESULT hr = HRESULT_FROM_WIN32(RpcServerInqCallAttributes(binding, &CallAttributes));
if (FAILED(hr))
{
return hr;
}
if (CallAttributes.ClientPID != (HANDLE)contextInfo->GetRuntimePid())
{
return E_ACCESSDENIED;
}
hr = CheckModuleAddress(contextInfo->GetProcessHandle(), (LPCVOID)contextInfo->GetRuntimeChakraBaseAddress(), (LPCVOID)AutoSystemInfo::Data.dllLoadAddress);
if (FAILED(hr))
{
return hr;
}
if (contextInfo->GetUCrtC99MathApis()->IsAvailable())
{
hr = CheckModuleAddress(contextInfo->GetProcessHandle(), (LPCVOID)contextInfo->GetRuntimeCRTBaseAddress(), (LPCVOID)contextInfo->GetJITCRTBaseAddress());
if (FAILED(hr))
{
return hr;
}
}
*threadContextInfoAddress = (PTHREADCONTEXT_HANDLE)EncodePointer(contextInfo);
#if defined(_CONTROL_FLOW_GUARD)
if (contextInfo->IsCFGEnabled())
{
if (!PHASE_OFF1(Js::PreReservedHeapAllocPhase))
{
*prereservedRegionAddr = (intptr_t)contextInfo->GetPreReservedSectionAllocator()->EnsurePreReservedRegion();
}
#if _M_IX86 || _M_X64
*jitThunkAddr = (intptr_t)contextInfo->GetJITThunkEmitter()->EnsureInitialized();
#endif
}
#endif
return hr;
});
}
HRESULT
ServerInitializeScriptContext(
/* [in] */ handle_t binding,
/* [in] */ __RPC__in ScriptContextDataIDL * scriptContextData,
/* [in] */ __RPC__in PTHREADCONTEXT_HANDLE threadContextInfoAddress,
/* [out] */ __RPC__deref_out_opt PPSCRIPTCONTEXT_HANDLE scriptContextInfoAddress)
{
if (scriptContextInfoAddress == nullptr || threadContextInfoAddress == nullptr)
{
Assert(false);
return RPC_S_INVALID_ARG;
}
*scriptContextInfoAddress = nullptr;
ServerThreadContext * threadContextInfo = (ServerThreadContext*)DecodePointer(threadContextInfoAddress);
return ServerCallWrapper(threadContextInfo, [&]()->HRESULT
{
ServerScriptContext * contextInfo = HeapNew(ServerScriptContext, scriptContextData, threadContextInfo);
ServerContextManager::RegisterScriptContext(contextInfo);
*scriptContextInfoAddress = (PSCRIPTCONTEXT_HANDLE)EncodePointer(contextInfo);
#if !FLOATVAR
// TODO: should move this to ServerInitializeThreadContext, also for the fields in IDL
XProcNumberPageSegmentImpl::Initialize(contextInfo->IsRecyclerVerifyEnabled(), contextInfo->GetRecyclerVerifyPad());
#endif
return S_OK;
});
}
#pragma warning(pop)
HRESULT
ServerCleanupThreadContext(
/* [in] */ handle_t binding,
/* [in] */ __RPC__deref_inout_opt PPTHREADCONTEXT_HANDLE threadContextInfoAddress)
{
if (threadContextInfoAddress == nullptr)
{
Assert(false);
return RPC_S_INVALID_ARG;
}
ServerThreadContext * threadContextInfo = (ServerThreadContext*)DecodePointer(*threadContextInfoAddress);
if (threadContextInfo == nullptr)
{
Assert(false);
return RPC_S_INVALID_ARG;
}
// This tells the run-time, when it is marshalling the out
// parameters, that the context handle has been closed normally.
*threadContextInfoAddress = nullptr;
return ServerCallWrapper(threadContextInfo, [&]()->HRESULT
{
threadContextInfo->Close();
ServerContextManager::UnRegisterThreadContext(threadContextInfo);
return S_OK;
});
}
HRESULT
ServerUpdatePropertyRecordMap(
/* [in] */ handle_t binding,
/* [in] */ __RPC__in PTHREADCONTEXT_HANDLE threadContextInfoAddress,
/* [in] */ __RPC__in_opt BVSparseNodeIDL * updatedPropsBVHead)
{
ServerThreadContext * threadContextInfo = (ServerThreadContext*)DecodePointer(threadContextInfoAddress);
if (threadContextInfo == nullptr)
{
Assert(false);
return RPC_S_INVALID_ARG;
}
return ServerCallWrapper(threadContextInfo, [&]()->HRESULT
{
typedef ServerThreadContext::BVSparseNode BVSparseNode;
CompileAssert(sizeof(BVSparseNode) == sizeof(BVSparseNodeIDL));
threadContextInfo->UpdateNumericPropertyBV((BVSparseNode*)updatedPropsBVHead);
return S_OK;
});
}
HRESULT
ServerAddDOMFastPathHelper(
/* [in] */ handle_t binding,
/* [in] */ __RPC__in PSCRIPTCONTEXT_HANDLE scriptContextInfoAddress,
/* [in] */ intptr_t funcInfoAddr,
/* [in] */ int helper)
{
ServerScriptContext * scriptContextInfo = (ServerScriptContext*)DecodePointer(scriptContextInfoAddress);
if (scriptContextInfo == nullptr)
{
Assert(false);
return RPC_S_INVALID_ARG;
}
return ServerCallWrapper(scriptContextInfo, [&]()->HRESULT
{
scriptContextInfo->AddToDOMFastPathHelperMap(funcInfoAddr, (IR::JnHelperMethod)helper);
return S_OK;
});
}
HRESULT
ServerAddModuleRecordInfo(
/* [in] */ handle_t binding,
/* [in] */ __RPC__in PSCRIPTCONTEXT_HANDLE scriptContextInfoAddress,
/* [in] */ unsigned int moduleId,
/* [in] */ intptr_t localExportSlotsAddr)
{
ServerScriptContext * serverScriptContext = (ServerScriptContext*)DecodePointer(scriptContextInfoAddress);
if (serverScriptContext == nullptr)
{
Assert(false);
return RPC_S_INVALID_ARG;
}
return ServerCallWrapper(serverScriptContext, [&]()->HRESULT
{
serverScriptContext->AddModuleRecordInfo(moduleId, localExportSlotsAddr);
return S_OK;
});
}
HRESULT
ServerSetWellKnownHostTypeId(
/* [in] */ handle_t binding,
/* [in] */ __RPC__in PTHREADCONTEXT_HANDLE threadContextInfoAddress,
/* [in] */ int typeId)
{
ServerThreadContext * threadContextInfo = (ServerThreadContext*)DecodePointer(threadContextInfoAddress);
if (threadContextInfo == nullptr)
{
Assert(false);
return RPC_S_INVALID_ARG;
}
return ServerCallWrapper(threadContextInfo, [&]()->HRESULT
{
threadContextInfo->SetWellKnownHostTypeId((Js::TypeId)typeId);
return S_OK;
});
}
HRESULT
ServerCleanupScriptContext(
/* [in] */ handle_t binding,
/* [in] */ __RPC__deref_inout_opt PPSCRIPTCONTEXT_HANDLE scriptContextInfoAddress)
{
if (scriptContextInfoAddress == nullptr)
{
Assert(false);
return RPC_S_INVALID_ARG;
}
ServerScriptContext * scriptContextInfo = (ServerScriptContext*)DecodePointer(*scriptContextInfoAddress);
if (scriptContextInfo == nullptr)
{
Assert(false);
return RPC_S_INVALID_ARG;
}
if (!scriptContextInfo->IsClosed())
{
scriptContextInfo->Close();
ServerContextManager::UnRegisterScriptContext(scriptContextInfo);
}
// This tells the run-time, when it is marshalling the out
// parameters, that the context handle has been closed normally.
*scriptContextInfoAddress = nullptr;
HeapDelete(scriptContextInfo);
return S_OK;
}
HRESULT
ServerCloseScriptContext(
/* [in] */ handle_t binding,
/* [in] */ __RPC__in PSCRIPTCONTEXT_HANDLE scriptContextInfoAddress)
{
ServerScriptContext * scriptContextInfo = (ServerScriptContext*)DecodePointer(scriptContextInfoAddress);
if (scriptContextInfo == nullptr)
{
Assert(false);
return RPC_S_INVALID_ARG;
}
return ServerCallWrapper(scriptContextInfo, [&]()->HRESULT
{
#ifdef PROFILE_EXEC
auto profiler = scriptContextInfo->GetCodeGenProfiler();
if (profiler && profiler->IsInitialized())
{
profiler->ProfilePrint(Js::Configuration::Global.flags.Profile.GetFirstPhase());
}
#endif
scriptContextInfo->Close();
ServerContextManager::UnRegisterScriptContext(scriptContextInfo);
return S_OK;
});
}
HRESULT
ServerDecommitInterpreterBufferManager(
/* [in] */ handle_t binding,
/* [in] */ __RPC__in PSCRIPTCONTEXT_HANDLE scriptContextInfoAddress,
/* [in] */ boolean asmJsManager)
{
ServerScriptContext * scriptContext = (ServerScriptContext *)DecodePointer((void*)scriptContextInfoAddress);
if (scriptContext == nullptr)
{
Assert(false);
return RPC_S_INVALID_ARG;
}
return ServerCallWrapper(scriptContext, [&]()->HRESULT
{
scriptContext->DecommitEmitBufferManager(asmJsManager != FALSE);
return S_OK;
});
}
HRESULT
ServerNewInterpreterThunkBlock(
/* [in] */ handle_t binding,
/* [in] */ __RPC__in PSCRIPTCONTEXT_HANDLE scriptContextInfo,
/* [in] */ __RPC__in InterpreterThunkInputIDL * thunkInput,
/* [out] */ __RPC__out InterpreterThunkOutputIDL * thunkOutput)
{
memset(thunkOutput, 0, sizeof(InterpreterThunkOutputIDL));
ServerScriptContext * scriptContext = (ServerScriptContext *)DecodePointer(scriptContextInfo);
if (scriptContext == nullptr)
{
Assert(false);
return RPC_S_INVALID_ARG;
}
return ServerCallWrapper(scriptContext, [&]()->HRESULT
{
ServerThreadContext * threadContext = scriptContext->GetThreadContext();
class AutoLocalAlloc
{
public:
AutoLocalAlloc(ServerThreadContext * threadContext) : localAddress(nullptr), threadContext(threadContext) { }
~AutoLocalAlloc()
{
if (localAddress)
{
threadContext->GetCodePageAllocators()->FreeLocal(this->localAddress, this->segment);
}
}
char * localAddress;
void * segment;
ServerThreadContext * threadContext;
} localAlloc(threadContext);
OOPEmitBufferManager * emitBufferManager = scriptContext->GetEmitBufferManager(thunkInput->asmJsThunk != FALSE);
BYTE* runtimeAddress;
EmitBufferAllocation<SectionAllocWrapper, PreReservedSectionAllocWrapper> * alloc = emitBufferManager->AllocateBuffer(InterpreterThunkEmitter::BlockSize, &runtimeAddress);
CompileAssert(InterpreterThunkEmitter::BlockSize <= CustomHeap::Page::MaxAllocationSize);
localAlloc.segment = alloc->allocation->page->segment;
localAlloc.localAddress = threadContext->GetCodePageAllocators()->AllocLocal((char*)runtimeAddress, InterpreterThunkEmitter::BlockSize, localAlloc.segment);
if (!localAlloc.localAddress)
{
Js::Throw::OutOfMemory();
}
#if PDATA_ENABLED
PRUNTIME_FUNCTION pdataStart = {0};
intptr_t epilogEnd = 0;
#endif
DWORD thunkCount = 0;
InterpreterThunkEmitter::FillBuffer(
threadContext,
thunkInput->asmJsThunk != FALSE,
(intptr_t)runtimeAddress,
InterpreterThunkEmitter::BlockSize,
(BYTE*)localAlloc.localAddress,
#if PDATA_ENABLED
&pdataStart,
&epilogEnd,
#endif
&thunkCount
);
emitBufferManager->CommitBufferForInterpreter(alloc, runtimeAddress, InterpreterThunkEmitter::BlockSize);
// Call to set VALID flag for CFG check
if (CONFIG_FLAG(OOPCFGRegistration))
{
threadContext->SetValidCallTargetForCFG(runtimeAddress);
}
thunkOutput->thunkCount = thunkCount;
thunkOutput->mappedBaseAddr = (intptr_t)runtimeAddress;
#if PDATA_ENABLED
thunkOutput->pdataTableStart = (intptr_t)pdataStart;
thunkOutput->epilogEndAddr = epilogEnd;
#endif
return S_OK;
});
}
#if DBG
HRESULT
ServerIsInterpreterThunkAddr(
/* [in] */ handle_t binding,
/* [in] */ PSCRIPTCONTEXT_HANDLE scriptContextInfoAddress,
/* [in] */ intptr_t address,
/* [in] */ boolean asmjsThunk,
/* [out] */ __RPC__out boolean * result)
{
ServerScriptContext * context = (ServerScriptContext*)DecodePointer((void*)scriptContextInfoAddress);
if (context == nullptr)
{
*result = false;
return RPC_S_INVALID_ARG;
}
OOPEmitBufferManager * manager = context->GetEmitBufferManager(asmjsThunk != FALSE);
if (manager == nullptr)
{
*result = false;
return S_OK;
}
*result = manager->IsInHeap((void*)address);
return S_OK;
}
#endif
HRESULT
ServerFreeAllocation(
/* [in] */ handle_t binding,
/* [in] */ __RPC__in PTHREADCONTEXT_HANDLE threadContextInfo,
/* [in] */ intptr_t codeAddress,
/* [in] */ intptr_t thunkAddress)
{
ServerThreadContext * context = (ServerThreadContext*)DecodePointer(threadContextInfo);
if (context == nullptr)
{
Assert(false);
return RPC_S_INVALID_ARG;
}
return ServerCallWrapper(context, [&]()->HRESULT
{
if (CONFIG_FLAG(OOPCFGRegistration) && !thunkAddress)
{
context->SetValidCallTargetForCFG((PVOID)codeAddress, false);
}
context->GetCodeGenAllocators()->emitBufferManager.FreeAllocation((void*)codeAddress);
#if defined(_CONTROL_FLOW_GUARD) && (_M_IX86 || _M_X64)
if (thunkAddress)
{
context->GetJITThunkEmitter()->FreeThunk(thunkAddress);
}
#endif
return S_OK;
});
}
HRESULT
ServerIsNativeAddr(
/* [in] */ handle_t binding,
/* [in] */ __RPC__in PTHREADCONTEXT_HANDLE threadContextInfo,
/* [in] */ intptr_t address,
/* [out] */ __RPC__out boolean * result)
{
if (result == nullptr)
{
Assert(false);
return RPC_S_INVALID_ARG;
}
*result = false;
ServerThreadContext * context = (ServerThreadContext*)DecodePointer(threadContextInfo);
if (context == nullptr)
{
Assert(false);
return RPC_S_INVALID_ARG;
}
return ServerCallWrapper(context, [&]()->HRESULT
{
PreReservedSectionAllocWrapper *preReservedAllocWrapper = context->GetPreReservedSectionAllocator();
if (preReservedAllocWrapper->IsInRange((void*)address))
{
*result = true;
}
else if (!context->IsAllJITCodeInPreReservedRegion())
{
AutoCriticalSection autoLock(&context->GetCodePageAllocators()->cs);
*result = context->GetCodePageAllocators()->IsInNonPreReservedPageAllocator((void*)address);
}
else
{
*result = false;
}
return S_OK;
});
}
HRESULT
ServerSetIsPRNGSeeded(
/* [in] */ handle_t binding,
/* [in] */ __RPC__in PSCRIPTCONTEXT_HANDLE scriptContextInfoAddress,
/* [in] */ boolean value)
{
ServerScriptContext * scriptContextInfo = (ServerScriptContext*)DecodePointer(scriptContextInfoAddress);
if (scriptContextInfo == nullptr)
{
Assert(false);
return RPC_S_INVALID_ARG;
}
return ServerCallWrapper(scriptContextInfo, [&]()->HRESULT
{
scriptContextInfo->SetIsPRNGSeeded(value != FALSE);
return S_OK;
});
}
HRESULT
ServerRemoteCodeGen(
/* [in] */ handle_t binding,
/* [in] */ __RPC__in PSCRIPTCONTEXT_HANDLE scriptContextInfoAddress,
/* [in] */ __RPC__in CodeGenWorkItemIDL *workItemData,
/* [out] */ __RPC__out JITOutputIDL *jitData)
{
memset(jitData, 0, sizeof(JITOutputIDL));
ServerScriptContext * scriptContextInfo = (ServerScriptContext*)DecodePointer(scriptContextInfoAddress);
if (scriptContextInfo == nullptr)
{
Assert(false);
return RPC_S_INVALID_ARG;
}
return ServerCallWrapper(scriptContextInfo, [&]() ->HRESULT
{
LARGE_INTEGER start_time = { 0 };
if (PHASE_TRACE1(Js::BackEndPhase))
{
QueryPerformanceCounter(&start_time);
}
scriptContextInfo->UpdateGlobalObjectThisAddr(workItemData->globalThisAddr);
ServerThreadContext * threadContextInfo = scriptContextInfo->GetThreadContext();
AutoReturnPageAllocator autoReturnPageAllocator;
PageAllocator* pageAllocator = autoReturnPageAllocator.GetPageAllocator();
NoRecoverMemoryJitArenaAllocator jitArena(L"JITArena", pageAllocator, Js::Throw::OutOfMemory);
#if DBG
jitArena.SetNeedsDelayFreeList();
#endif
JITTimeWorkItem * jitWorkItem = Anew(&jitArena, JITTimeWorkItem, workItemData);
if (PHASE_VERBOSE_TRACE_RAW(Js::BackEndPhase, jitWorkItem->GetJITTimeInfo()->GetSourceContextId(), jitWorkItem->GetJITTimeInfo()->GetLocalFunctionId()))
{
LARGE_INTEGER freq;
LARGE_INTEGER end_time;
QueryPerformanceCounter(&end_time);
QueryPerformanceFrequency(&freq);
Output::Print(
L"BackendMarshalIn - function: %s time:%8.6f mSec\r\n",
jitWorkItem->GetJITFunctionBody()->GetDisplayName(),
(((double)((end_time.QuadPart - workItemData->startTime)* (double)1000.0 / (double)freq.QuadPart))) / (1));
Output::Flush();
}
auto profiler = scriptContextInfo->GetCodeGenProfiler();
#ifdef PROFILE_EXEC
if (profiler && !profiler->IsInitialized())
{
profiler->Initialize(pageAllocator, nullptr);
}
#endif
if (jitWorkItem->GetWorkItemData()->xProcNumberPageSegment)
{
jitData->numberPageSegments = (XProcNumberPageSegment*)midl_user_allocate(sizeof(XProcNumberPageSegment));
if (!jitData->numberPageSegments)
{
return E_OUTOFMEMORY;
}
__analysis_assume(jitData->numberPageSegments);
memcpy_s(jitData->numberPageSegments, sizeof(XProcNumberPageSegment), jitWorkItem->GetWorkItemData()->xProcNumberPageSegment, sizeof(XProcNumberPageSegment));
}
Func::Codegen(
&jitArena,
jitWorkItem,
threadContextInfo,
scriptContextInfo,
jitData,
nullptr,
nullptr,
jitWorkItem->GetPolymorphicInlineCacheInfo(),
threadContextInfo->GetCodeGenAllocators(),
#if !FLOATVAR
nullptr, // number allocator
#endif
profiler,
true);
#ifdef PROFILE_EXEC
if (profiler && profiler->IsInitialized())
{
profiler->ProfilePrint(Js::Configuration::Global.flags.Profile.GetFirstPhase());
}
#endif
if (PHASE_VERBOSE_TRACE_RAW(Js::BackEndPhase, jitWorkItem->GetJITTimeInfo()->GetSourceContextId(), jitWorkItem->GetJITTimeInfo()->GetLocalFunctionId()))
{
LARGE_INTEGER freq;
LARGE_INTEGER end_time;
QueryPerformanceCounter(&end_time);
QueryPerformanceFrequency(&freq);
Output::Print(
L"EndBackEndInner - function: %s time:%8.6f mSec\r\n",
jitWorkItem->GetJITFunctionBody()->GetDisplayName(),
(((double)((end_time.QuadPart - start_time.QuadPart)* (double)1000.0 / (double)freq.QuadPart))) / (1));
Output::Flush();
}
LARGE_INTEGER out_time = { 0 };
if (PHASE_TRACE1(Js::BackEndPhase))
{
QueryPerformanceCounter(&out_time);
jitData->startTime = out_time.QuadPart;
}
Assert(jitData->codeAddress);
Assert(jitData->codeSize);
return S_OK;
});
}
JsUtil::BaseHashSet<ServerThreadContext*, HeapAllocator> ServerContextManager::threadContexts(&HeapAllocator::Instance);
JsUtil::BaseHashSet<ServerScriptContext*, HeapAllocator> ServerContextManager::scriptContexts(&HeapAllocator::Instance);
CriticalSection ServerContextManager::cs;
#ifdef STACK_BACK_TRACE
SList<ServerContextManager::ClosedContextEntry<ServerThreadContext>*, NoThrowHeapAllocator> ServerContextManager::ClosedThreadContextList(&NoThrowHeapAllocator::Instance);
SList<ServerContextManager::ClosedContextEntry<ServerScriptContext>*, NoThrowHeapAllocator> ServerContextManager::ClosedScriptContextList(&NoThrowHeapAllocator::Instance);
#endif
void ServerContextManager::RegisterThreadContext(ServerThreadContext* threadContext)
{
AutoCriticalSection autoCS(&cs);
threadContexts.Add(threadContext);
}
void ServerContextManager::UnRegisterThreadContext(ServerThreadContext* threadContext)
{
AutoCriticalSection autoCS(&cs);
threadContexts.Remove(threadContext);
auto iter = scriptContexts.GetIteratorWithRemovalSupport();
while (iter.IsValid())
{
ServerScriptContext* scriptContext = iter.Current().Key();
if (scriptContext->GetThreadContext() == threadContext)
{
if (!scriptContext->IsClosed())
{
scriptContext->Close();
}
iter.RemoveCurrent();
}
iter.MoveNext();
}
}
void ServerContextManager::RegisterScriptContext(ServerScriptContext* scriptContext)
{
AutoCriticalSection autoCS(&cs);
scriptContexts.Add(scriptContext);
}
void ServerContextManager::UnRegisterScriptContext(ServerScriptContext* scriptContext)
{
AutoCriticalSection autoCS(&cs);
scriptContexts.Remove(scriptContext);
}
bool ServerContextManager::CheckLivenessAndAddref(ServerScriptContext* context)
{
AutoCriticalSection autoCS(&cs);
if (scriptContexts.LookupWithKey(context))
{
if (!context->IsClosed() && !context->GetThreadContext()->IsClosed())
{
context->AddRef();
context->GetThreadContext()->AddRef();
return true;
}
}
return false;
}
bool ServerContextManager::CheckLivenessAndAddref(ServerThreadContext* context)
{
AutoCriticalSection autoCS(&cs);
if (threadContexts.LookupWithKey(context))
{
if (!context->IsClosed())
{
context->AddRef();
return true;
}
}
return false;
}
template<typename Fn>
HRESULT ServerCallWrapper(ServerThreadContext* threadContextInfo, Fn fn)
{
MemoryOperationLastError::ClearLastError();
HRESULT hr = S_OK;
try
{
AUTO_NESTED_HANDLED_EXCEPTION_TYPE(static_cast<ExceptionType>(ExceptionType_OutOfMemory | ExceptionType_StackOverflow));
AutoReleaseThreadContext autoThreadContext(threadContextInfo);
hr = fn();
}
catch (ContextClosedException&)
{
hr = E_ACCESSDENIED;
}
catch (Js::OutOfMemoryException)
{
hr = E_OUTOFMEMORY;
}
catch (Js::StackOverflowException)
{
hr = VBSERR_OutOfStack;
}
catch (Js::OperationAbortedException)
{
hr = E_ABORT;
}
catch (...)
{
AssertOrFailFastMsg(false, "Unknown exception caught in JIT server call.");
}
if (hr == S_OK)
{
return MemoryOperationLastError::GetLastError();
}
return hr;
}
template<typename Fn>
HRESULT ServerCallWrapper(ServerScriptContext* scriptContextInfo, Fn fn)
{
try
{
AutoReleaseScriptContext autoScriptContext(scriptContextInfo);
ServerThreadContext* threadContextInfo = scriptContextInfo->GetThreadContext();
return ServerCallWrapper(threadContextInfo, fn);
}
catch (ContextClosedException&)
{
return E_ACCESSDENIED;
}
}