blob: ef5568a2094a073d4acd8ac1bb3e55cde1a2e058 [file] [log] [blame]
//-------------------------------------------------------------------------------------------------------
// 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
ServerConnectProcess(
handle_t binding,
#ifdef USE_RPC_HANDLE_MARSHALLING
HANDLE processHandle,
#endif
intptr_t chakraBaseAddress,
intptr_t crtBaseAddress
)
{
DWORD clientPid;
HRESULT hr = HRESULT_FROM_WIN32(I_RpcBindingInqLocalClientPID(binding, &clientPid));
if (FAILED(hr))
{
return hr;
}
#ifdef USE_RPC_HANDLE_MARSHALLING
HANDLE targetHandle;
if (!DuplicateHandle(GetCurrentProcess(), processHandle, GetCurrentProcess(), &targetHandle, 0, false, DUPLICATE_SAME_ACCESS))
{
Assert(UNREACHED);
return E_ACCESSDENIED;
}
#else
HANDLE targetHandle = OpenProcess(PROCESS_VM_OPERATION | PROCESS_VM_READ | PROCESS_VM_WRITE | PROCESS_QUERY_LIMITED_INFORMATION, false, clientPid);
if (!targetHandle)
{
Assert(UNREACHED);
return E_ACCESSDENIED;
}
#endif
return ProcessContextManager::RegisterNewProcess(clientPid, targetHandle, chakraBaseAddress, crtBaseAddress);
}
#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;
DWORD clientPid;
HRESULT hr = HRESULT_FROM_WIN32(I_RpcBindingInqLocalClientPID(binding, &clientPid));
if (FAILED(hr))
{
return hr;
}
ProcessContext* processContext = ProcessContextManager::GetProcessContext(clientPid);
if (processContext == nullptr)
{
return E_ACCESSDENIED;
}
try
{
AUTO_NESTED_HANDLED_EXCEPTION_TYPE(static_cast<ExceptionType>(ExceptionType_OutOfMemory));
contextInfo = HeapNew(ServerThreadContext, threadContextData, processContext);
ServerContextManager::RegisterThreadContext(contextInfo);
}
catch (Js::OutOfMemoryException)
{
if (contextInfo)
{
// If we OOM while registering the ThreadContext, we need to free it
HeapDelete(contextInfo);
}
else
{
// If we OOM while creating the ThreadContext, then we haven't transfered ownership
// of the ProcessContext reference, so we must release it here
processContext->Release();
}
return E_OUTOFMEMORY;
}
return ServerCallWrapper(contextInfo, [&]()->HRESULT
{
if (clientPid != contextInfo->GetRuntimePid())
{
return E_ACCESSDENIED;
}
*threadContextInfoAddress = (PTHREADCONTEXT_HANDLE)EncodePointer(contextInfo);
#if defined(_CONTROL_FLOW_GUARD)
if (!PHASE_OFF1(Js::PreReservedHeapAllocPhase))
{
*prereservedRegionAddr = (intptr_t)contextInfo->GetPreReservedSectionAllocator()->EnsurePreReservedRegion();
contextInfo->SetCanCreatePreReservedSegment(*prereservedRegionAddr != 0);
}
#if !defined(_M_ARM)
*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;
}
if (helper < 0 || helper >= IR::JnHelperMethodCount)
{
Assert(UNREACHED);
return E_ACCESSDENIED;
}
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
scriptContextInfo->GetFirstCodeGenProfiler()->ProfilePrint();
#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
);
if (!emitBufferManager->CommitBufferForInterpreter(alloc, runtimeAddress, InterpreterThunkEmitter::BlockSize))
{
Js::Throw::OutOfMemory();
}
// Call to set VALID flag for CFG check
if (CONFIG_FLAG(OOPCFGRegistration))
{
emitBufferManager->SetValidCallTarget(alloc, runtimeAddress, true);
}
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] */ __RPC__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 PSCRIPTCONTEXT_HANDLE scriptContextInfo,
/* [in] */ intptr_t codeAddress)
{
ServerScriptContext* context = (ServerScriptContext*)DecodePointer(scriptContextInfo);
if (context == nullptr)
{
Assert(false);
return RPC_S_INVALID_ARG;
}
return ServerCallWrapper(context, [&]()->HRESULT
{
context->GetCodeGenAllocators()->emitBufferManager.FreeAllocation((void*)codeAddress);
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;
}
#if DBG
size_t serializedRpcDataSize = 0;
const unsigned char* serializedRpcData = nullptr;
JITManager::SerializeRPCData(workItemData, &serializedRpcDataSize, &serializedRpcData);
struct AutoFreeArray
{
const byte* arr = nullptr;
size_t bufferSize = 0;
~AutoFreeArray() { HeapDeleteArray(bufferSize, arr); }
} autoFreeArray;
autoFreeArray.arr = serializedRpcData;
autoFreeArray.bufferSize = serializedRpcDataSize;
#endif
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();
}
#ifdef PROFILE_EXEC
Js::ScriptContextProfiler* profiler = scriptContextInfo->GetCodeGenProfiler(pageAllocator);
#else
Js::ScriptContextProfiler* profiler = nullptr;
#endif
#if !FLOATVAR
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));
}
#endif
Func::Codegen(
&jitArena,
jitWorkItem,
threadContextInfo,
scriptContextInfo,
jitData,
nullptr,
nullptr,
jitWorkItem->GetPolymorphicInlineCacheInfo(),
scriptContextInfo->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;
BaseDictionary<DWORD, ProcessContext*, HeapAllocator> ProcessContextManager::ProcessContexts(&HeapAllocator::Instance);
CriticalSection ProcessContextManager::cs;
HRESULT
ProcessContextManager::RegisterNewProcess(DWORD pid, HANDLE processHandle, intptr_t chakraBaseAddress, intptr_t crtBaseAddress)
{
AutoCriticalSection autoCS(&cs);
for (auto iter = ProcessContexts.GetIteratorWithRemovalSupport(); iter.IsValid(); iter.MoveNext())
{
ProcessContext* context = iter.CurrentValue();
// We can delete a ProcessContext if no ThreadContexts refer to it and the process is terminated
if (!context->HasRef() && WaitForSingleObject(context->processHandle, 0) == WAIT_OBJECT_0)
{
iter.RemoveCurrent();
HeapDelete(context);
}
}
// We cannot register multiple ProcessContexts for a single process
if (ProcessContexts.ContainsKey(pid))
{
Assert(UNREACHED);
return E_ACCESSDENIED;
}
ProcessContext* context = nullptr;
try
{
AUTO_NESTED_HANDLED_EXCEPTION_TYPE(static_cast<ExceptionType>(ExceptionType_OutOfMemory));
context = HeapNew(ProcessContext, processHandle, chakraBaseAddress, crtBaseAddress);
ProcessContexts.Add(pid, context);
}
catch (Js::OutOfMemoryException)
{
if (context != nullptr)
{
// If we OOM while registering the ProcessContext, we should free it
HeapDelete(context);
}
return E_OUTOFMEMORY;
}
return S_OK;
}
ProcessContext*
ProcessContextManager::GetProcessContext(DWORD pid)
{
AutoCriticalSection autoCS(&cs);
ProcessContext* context = nullptr;
// It is possible that we don't have a ProcessContext for a pid in case ProcessContext initialization failed,
// or if the calling process terminated and the ProcessContext was already cleaned up before we got here
if (ProcessContexts.ContainsKey(pid))
{
context = ProcessContexts.Item(pid);
context->AddRef();
}
return context;
}
#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;
}
}