Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 11 additions & 3 deletions lib/Backend/CodeGenNumberAllocator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -333,7 +333,7 @@ Js::JavascriptNumber* XProcNumberPageSegmentImpl::AllocateNumber(Func* func, dou
if (!WriteProcessMemory(hProcess, (void*)number, pLocalNumber, sizeCat, &bytesWritten)
|| bytesWritten != sizeCat)
{
Output::Print(_u("FATAL ERROR: WriteProcessMemory failed, GLE: %d\n"), GetLastError());
Js::Throw::CheckAndThrowJITOperationFailed();
Js::Throw::FatalInternalError(); // TODO: don't bring down whole server process, but pass the last error to main process
}

Expand All @@ -345,9 +345,13 @@ Js::JavascriptNumber* XProcNumberPageSegmentImpl::AllocateNumber(Func* func, dou
{
Assert((unsigned int)((char*)tail->GetEndAddress() - (char*)tail->GetCommitEndAddress()) >= BlockSize);
// TODO: implement guard pages (still necessary for OOP JIT?)
auto ret = ::VirtualAllocEx(hProcess, tail->GetCommitEndAddress(), BlockSize, MEM_COMMIT, PAGE_READWRITE);
if (!ret)
LPVOID addr = ::VirtualAllocEx(hProcess, tail->GetCommitEndAddress(), BlockSize, MEM_COMMIT, PAGE_READWRITE);
if (addr == nullptr)
{
if (hProcess != GetCurrentProcess())
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

maybe we still should throw oom here?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i'm thinking -- the WriteProcessMemory failing is more of a fatal error like AV (and we should at least disable JIT after that). This, it could be that proc legitimately is OOM.


In reply to: 81823255 [](ancestors = 81823255)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

in my next commit, I'm changing such failure to be fatal in client side. if the client process is terminated, it returns E_ACCESSDENIED, if the client process is in middle of terminating, the page might be de-commited, we won't AV in server side, but get back some error code other than E_ACCESSDENIED


In reply to: 81823623 [](ancestors = 81823623,81823255)

{
Js::Throw::CheckAndThrowJITOperationFailed();
}
Js::Throw::OutOfMemory();
}
tail->committedEnd += BlockSize;
Expand All @@ -359,6 +363,10 @@ Js::JavascriptNumber* XProcNumberPageSegmentImpl::AllocateNumber(Func* func, dou
void* pages = ::VirtualAllocEx(hProcess, nullptr, PageCount * AutoSystemInfo::PageSize, MEM_RESERVE, PAGE_READWRITE);
if (pages == nullptr)
{
if (hProcess != GetCurrentProcess())
{
Js::Throw::CheckAndThrowJITOperationFailed();
}
Js::Throw::OutOfMemory();
}

Expand Down
1 change: 0 additions & 1 deletion lib/Backend/CodeGenWorkItem.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@ CodeGenWorkItem::CodeGenWorkItem(
, isAllocationCommitted(false)
, queuedFullJitWorkItem(nullptr)
, allocation(nullptr)
, codeGenResult(0)
#ifdef IR_VIEWER
, isRejitIRViewerFunction(false)
, irViewerOutput(nullptr)
Expand Down
3 changes: 0 additions & 3 deletions lib/Backend/CodeGenWorkItem.h
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,6 @@ struct CodeGenWorkItem : public JsUtil::Job
size_t codeAddress;
ptrdiff_t codeSize;

public:
HRESULT codeGenResult;

public:
virtual uint GetByteCodeCount() const = 0;
virtual size_t GetDisplayName(_Out_writes_opt_z_(sizeInChars) WCHAR* displayName, _In_ size_t sizeInChars) = 0;
Expand Down
7 changes: 7 additions & 0 deletions lib/Backend/EmitBuffer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -290,6 +290,13 @@ EmitBufferAllocation* EmitBufferManager<SyncObject>::AllocateBuffer(__in size_t
#if DBG
MEMORY_BASIC_INFORMATION memBasicInfo;
size_t resultBytes = VirtualQueryEx(this->processHandle, allocation->allocation->address, &memBasicInfo, sizeof(memBasicInfo));
if (resultBytes == 0)
{
if (this->processHandle != GetCurrentProcess())
{
Js::Throw::CheckAndThrowJITOperationFailed();
}
}
Assert(resultBytes != 0 && memBasicInfo.Protect == PAGE_EXECUTE);
#endif

Expand Down
61 changes: 28 additions & 33 deletions lib/Backend/NativeCodeGenerator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -894,24 +894,11 @@ NativeCodeGenerator::CodeGen(PageAllocator * pageAllocator, CodeGenWorkItem* wor
workItem->GetJITData()->startTime = (int64)start_time.QuadPart;
if (JITManager::GetJITManager()->IsOOPJITEnabled())
{
workItem->codeGenResult = JITManager::GetJITManager()->RemoteCodeGenCall(
HRESULT hr = JITManager::GetJITManager()->RemoteCodeGenCall(
workItem->GetJITData(),
scriptContext->GetThreadContext()->GetRemoteThreadContextAddr(),
scriptContext->GetRemoteScriptAddr(),
&jitWriteData);
switch (workItem->codeGenResult)
{
case S_OK:
break;
case E_ABORT:
throw Js::OperationAbortedException();
case E_OUTOFMEMORY:
Js::Throw::OutOfMemory();
case VBSERR_OutOfStack:
throw Js::StackOverflowException();
default:
Js::Throw::FatalInternalError();
}
JITManager::HandleServerCallResult(hr);
}
else
{
Expand Down Expand Up @@ -2020,23 +2007,11 @@ NativeCodeGenerator::UpdateJITState()
{
if (JITManager::GetJITManager()->IsOOPJITEnabled())
{
// ensure jit contexts have been set up
// TODO: OOP JIT, move server calls to background thread to reduce foreground thread delay
if (!scriptContext->GetRemoteScriptAddr())
{
scriptContext->InitializeRemoteScriptContext();
}

bool allowPrereserveAlloc = true;
#if !_M_X64_OR_ARM64
if (this->scriptContext->webWorkerId != Js::Constants::NonWebWorkerContextId)
{
allowPrereserveAlloc = false;
return;
}
#endif
#ifndef _CONTROL_FLOW_GUARD
allowPrereserveAlloc = false;
#endif
scriptContext->GetThreadContext()->EnsureJITThreadContext(allowPrereserveAlloc);

// update all property records on server that have been changed since last jit
ThreadContext::PropertyMap * pendingProps = scriptContext->GetThreadContext()->GetPendingJITProperties();
Expand Down Expand Up @@ -2079,11 +2054,9 @@ NativeCodeGenerator::UpdateJITState()
props.reclaimedPropertyIdArray = reclaimedPropArray;
props.newRecordCount = newCount;
props.newRecordArray = newPropArray;

HRESULT hr = JITManager::GetJITManager()->UpdatePropertyRecordMap(scriptContext->GetThreadContext()->GetRemoteThreadContextAddr(), &props);
if (hr != S_OK)
{
Js::Throw::FatalInternalError();
}

if (newPropArray)
{
HeapDeleteArray(newCount, newPropArray);
Expand All @@ -2092,6 +2065,8 @@ NativeCodeGenerator::UpdateJITState()
{
HeapDeleteArray(reclaimedCount, reclaimedPropArray);
}

JITManager::HandleServerCallResult(hr);
}
}
}
Expand Down Expand Up @@ -3195,6 +3170,7 @@ NativeCodeGenerator::FreeNativeCodeGenAllocation(void* address)
ThreadContext * context = this->scriptContext->GetThreadContext();
if (JITManager::GetJITManager()->IsOOPJITEnabled())
{
// OOP JIT TODO: need error handling?
JITManager::GetJITManager()->FreeAllocation(context->GetRemoteThreadContextAddr(), (intptr_t)address);
}
else
Expand Down Expand Up @@ -3227,6 +3203,7 @@ NativeCodeGenerator::QueueFreeNativeCodeGenAllocation(void* address)
if (JITManager::GetJITManager()->IsOOPJITEnabled())
{
// TODO: OOP JIT, should we always just queue this in background?
// OOP JIT TODO: need error handling?
JITManager::GetJITManager()->FreeAllocation(context->GetRemoteThreadContextAddr(), (intptr_t)address);
return;
}
Expand Down Expand Up @@ -3669,3 +3646,21 @@ bool NativeCodeGenerator::TryAggressiveInlining(Js::FunctionBody *const topFunct
#endif
return true;
}

void
JITManager::HandleServerCallResult(HRESULT hr)
{
switch (hr)
{
case S_OK:
break;
case E_ABORT:
throw Js::OperationAbortedException();
case E_OUTOFMEMORY:
Js::Throw::OutOfMemory();
case VBSERR_OutOfStack:
throw Js::StackOverflowException();
default:
Js::Throw::FatalInternalError();
}
}
26 changes: 13 additions & 13 deletions lib/Backend/ServerScriptContext.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,16 +5,17 @@

#include "Backend.h"

ServerScriptContext::ServerScriptContext(ScriptContextDataIDL * contextData) :
ServerScriptContext::ServerScriptContext(ScriptContextDataIDL * contextData, ServerThreadContext* threadContextInfo) :
m_contextData(*contextData),
threadContextInfo(threadContextInfo),
m_isPRNGSeeded(false),
m_isClosed(false),
m_domFastPathHelperMap(nullptr),
m_moduleRecords(&HeapAllocator::Instance),
#ifdef PROFILE_EXEC
m_codeGenProfiler(nullptr),
#endif
m_activeJITCount(0)
m_refCount(0),
m_isClosed(false)
{
#ifdef PROFILE_EXEC
if (Js::Configuration::Global.flags.IsEnabled(Js::ProfileFlag))
Expand Down Expand Up @@ -279,21 +280,19 @@ ServerScriptContext::Close()
}

void
ServerScriptContext::BeginJIT()
ServerScriptContext::AddRef()
{
InterlockedExchangeAdd(&m_activeJITCount, 1u);
InterlockedExchangeAdd(&m_refCount, 1u);
}

void
ServerScriptContext::EndJIT()
ServerScriptContext::Release()
{
InterlockedExchangeSubtract(&m_activeJITCount, 1u);
}

bool
ServerScriptContext::IsJITActive()
{
return m_activeJITCount != 0;
InterlockedExchangeSubtract(&m_refCount, 1u);
if (m_isClosed && m_refCount == 0)
{
HeapDelete(this);
}
}

Js::Var*
Expand Down Expand Up @@ -328,3 +327,4 @@ ServerScriptContext::GetCodeGenProfiler() const
return nullptr;
#endif
}

13 changes: 8 additions & 5 deletions lib/Backend/ServerScriptContext.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
class ServerScriptContext : public ScriptContextInfo
{
public:
ServerScriptContext(ScriptContextDataIDL * contextData);
ServerScriptContext(ScriptContextDataIDL * contextData, ServerThreadContext* threadContextInfo);
~ServerScriptContext();
virtual intptr_t GetNullAddr() const override;
virtual intptr_t GetUndefinedAddr() const override;
Expand Down Expand Up @@ -62,19 +62,22 @@ class ServerScriptContext : public ScriptContextInfo
void AddModuleRecordInfo(unsigned int moduleId, __int64 localExportSlotsAddr);

Js::ScriptContextProfiler * GetCodeGenProfiler() const;
ServerThreadContext* GetThreadContext() { return threadContextInfo; }

void Close();
void BeginJIT();
void EndJIT();
bool IsJITActive();
void AddRef();
void Release();

private:
JITDOMFastPathHelperMap * m_domFastPathHelperMap;
#ifdef PROFILE_EXEC
Js::ScriptContextProfiler * m_codeGenProfiler;
#endif

ScriptContextDataIDL m_contextData;
uint m_activeJITCount;

ServerThreadContext* threadContextInfo;
uint m_refCount;

bool m_isPRNGSeeded;
bool m_isClosed;
Expand Down
22 changes: 22 additions & 0 deletions lib/Backend/ServerThreadContext.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@

ServerThreadContext::ServerThreadContext(ThreadContextDataIDL * data) :
m_threadContextData(*data),
m_refCount(0),
m_policyManager(true),
m_propertyMap(nullptr),
m_pageAllocs(&HeapAllocator::Instance),
Expand All @@ -21,6 +22,10 @@ ServerThreadContext::ServerThreadContext(ThreadContextDataIDL * data) :
#endif
m_jitCRTBaseAddress((intptr_t)GetModuleHandle(UCrtC99MathApis::LibraryName))
{
#if ENABLE_OOP_NATIVE_CODEGEN
m_pid = GetProcessId((HANDLE)data->processHandle);
#endif

#if !_M_X64_OR_ARM64 && _CONTROL_FLOW_GUARD
m_codeGenAlloc.canCreatePreReservedSegment = data->allowPrereserveAlloc != FALSE;
#endif
Expand Down Expand Up @@ -260,3 +265,20 @@ ServerThreadContext::AddToPropertyMap(const Js::PropertyRecord * origRecord)

PropertyRecordTrace(_u("Added JIT property '%s' at 0x%08x, pid = %d\n"), record->GetBuffer(), record, record->pid);
}

void ServerThreadContext::AddRef()
{
InterlockedExchangeAdd(&m_refCount, (uint)1);
}
void ServerThreadContext::Release()
{
InterlockedExchangeSubtract(&m_refCount, (uint)1);
if (m_isClosed && m_refCount == 0)
{
HeapDelete(this);
}
}
void ServerThreadContext::Close()
{
this->m_isClosed = true;
}
10 changes: 9 additions & 1 deletion lib/Backend/ServerThreadContext.h
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,11 @@ class ServerThreadContext : public ThreadContextInfo
void RemoveFromPropertyMap(Js::PropertyId reclaimedId);
void AddToPropertyMap(const Js::PropertyRecord * propertyRecord);
void SetWellKnownHostTypeId(Js::TypeId typeId) { this->wellKnownHostTypeHTMLAllCollectionTypeId = typeId; }

void AddRef();
void Release();
void Close();

private:
intptr_t GetRuntimeChakraBaseAddress() const;
intptr_t GetRuntimeCRTBaseAddress() const;
Expand All @@ -61,7 +66,10 @@ class ServerThreadContext : public ThreadContextInfo

ThreadContextDataIDL m_threadContextData;

ThreadContext * m_threadContext;
DWORD m_pid; //save client process id for easier diagnose

intptr_t m_jitChakraBaseAddress;
intptr_t m_jitCRTBaseAddress;
uint m_refCount;

};
1 change: 1 addition & 0 deletions lib/Common/Common.h
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,7 @@ template<> struct IntMath<int64> { using Type = Int64Math; };
#include "Exceptions/StackOverflowException.h"
#include "Exceptions/NotImplementedException.h"
#include "Exceptions/AsmJsParseException.h"
#include "Exceptions/JITOperationFailedException.h"

#include "Memory/AutoPtr.h"
#include "Memory/AutoAllocatorObjectPtr.h"
Expand Down
9 changes: 9 additions & 0 deletions lib/Common/Common/Jobs.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
#include "Exceptions/OperationAbortedException.h"
#include "Exceptions/OutOfMemoryException.h"
#include "Exceptions/StackOverflowException.h"
#include "Exceptions/JITOperationFailedException.h"

#include "TemplateParameter.h"
#include "DataStructures/DoublyLinkedListElement.h"
Expand Down Expand Up @@ -1004,6 +1005,14 @@ namespace JsUtil
job->failureReason = Job::FailureReason::Aborted;
#endif
}
catch (Js::JITOperationFailedException)
{
// This can happen for any reason a job needs to be aborted while executing, like for instance, if the script
// context is closed while the job is being processed in the background
#if ENABLE_DEBUG_CONFIG_OPTIONS
job->failureReason = Job::FailureReason::Unknown;
#endif
}

// Since the background job processor processes jobs on a background thread, out-of-memory and stack overflow need to be
// caught here. Script would not be active in the background thread, so (at the time of this writing) a
Expand Down
3 changes: 2 additions & 1 deletion lib/Common/Exceptions/Chakra.Common.Exceptions.vcxproj
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@
<ClInclude Include="ExceptionCheck.h" />
<ClInclude Include="InScriptExceptionBase.h" />
<ClInclude Include="InternalErrorException.h" />
<ClInclude Include="JITOperationFailedException.h" />
<ClInclude Include="NotImplementedException.h" />
<ClInclude Include="OperationAbortedException.h" />
<ClInclude Include="OutOfMemoryException.h" />
Expand All @@ -58,4 +59,4 @@
</ItemGroup>
<Import Project="$(BuildConfigPropsPath)Chakra.Build.targets" Condition="exists('$(BuildConfigPropsPath)Chakra.Build.targets')" />
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
</Project>
</Project>
Loading