template <typename TAlloc> inline
void
JITThunkEmitter<TAlloc>::FreeThunk(uintptr_t thunkAddress)
{
    AutoCriticalSection autoCs(&this->cs);
    BVIndex thunkIndex = GetThunkIndexFromAddress(thunkAddress);
    if (thunkIndex >= this->freeThunks.Length() || this->freeThunks.TestAndSet(thunkIndex))
    {
        Assert(UNREACHED);
        this->firstBitToCheck = 0;
        return;
    }

    if (thunkIndex < firstBitToCheck)
    {
        this->firstBitToCheck = thunkIndex;
    }

    if (CONFIG_FLAG(OOPCFGRegistration))
    {
#if ENABLE_OOP_NATIVE_CODEGEN
        if (JITManager::GetJITManager()->IsJITServer())
        {
            HANDLE fileHandle = nullptr;
            PVOID baseAddress = nullptr;
            bool found = this->codeAllocator->GetFileInfo((PVOID)thunkAddress, &fileHandle, &baseAddress);
            AssertOrFailFast(found);
            this->threadContext->SetValidCallTargetFile((PVOID)thunkAddress, fileHandle, baseAddress, false);
        }
        else
#endif
        {
            this->threadContext->SetValidCallTargetForCFG((PVOID)thunkAddress, false);
        }
    }

    uintptr_t pageStartAddress = GetThunkPageStart(thunkAddress);
    if (IsThunkPageEmpty(pageStartAddress))
    {
        this->codeAllocator->Free((PVOID)pageStartAddress, AutoSystemInfo::PageSize, MEM_DECOMMIT);
    }
    else
    {
        char * localAddress = (char *)this->codeAllocator->AllocLocal((PVOID)thunkAddress, ThunkSize);
        if (localAddress == nullptr)
        {
            return;
        }
        UnprotectPage(localAddress);
        memset(localAddress, 0xCC, ThunkSize);
        ProtectPage(localAddress);
        this->codeAllocator->FreeLocal(localAddress);
    }
    FlushInstructionCache(this->processHandle, (PVOID)thunkAddress, ThunkSize);
}
Пример #2
0
void
EmitBufferManager<TAlloc, TPreReservedAlloc, SyncObject>::FreeAllocations(bool release)
{
#if PDATA_ENABLED && defined(_WIN32)
    DelayDeletingFunctionTable::Clear();
#endif

    AutoRealOrFakeCriticalSection<SyncObject> autoCs(&this->criticalSection);

#if DBG_DUMP
    if (!release && PHASE_STATS1(Js::EmitterPhase))
    {
        this->DumpAndResetStats(Js::Configuration::Global.flags.Filename);
    }
#endif

    TEmitBufferAllocation * allocation = this->allocations;
    while (allocation != nullptr)
    {
#ifdef ENABLE_DEBUG_CONFIG_OPTIONS
        if(CONFIG_FLAG(CheckEmitBufferPermissions))
        {
            CheckBufferPermissions(allocation);
        }
#endif
        if (release)
        {
            this->allocationHeap.Free(allocation->allocation);
        }
        else if ((scriptContext != nullptr) && allocation->recorded)
        {
            // In case of ThunkEmitter the script context would be null and we don't want to track that as code size.
            this->scriptContext->GetThreadContext()->SubCodeSize(allocation->bytesCommitted);
            allocation->recorded = false;
        }

        allocation = allocation->nextAllocation;
    }
    if (release)
    {
        this->allocations = nullptr;
    }
    else
    {
        this->allocationHeap.DecommitAll();
    }
}
template <typename TAlloc> inline
uintptr_t
JITThunkEmitter<TAlloc>::EnsureInitialized()
{
    if (this->baseAddress != NULL)
    {
        return this->baseAddress;
    }

    // only take a lock if we need to initialize
    {
        AutoCriticalSection autoCs(&this->cs);
        // check again because we did the first one outside of lock
        if (this->baseAddress == NULL)
        {
            this->baseAddress = (uintptr_t)this->codeAllocator->AllocPages(nullptr, PageCount, MEM_RESERVE, PAGE_EXECUTE_READ, true);
        }
    }
    return this->baseAddress;
}
Пример #4
0
bool
EmitBufferManager<SyncObject>::FreeAllocation(void* address)
{
    AutoRealOrFakeCriticalSection<SyncObject> autoCs(&this->criticalSection);

    EmitBufferAllocation* previous = nullptr;
    EmitBufferAllocation* allocation = allocations;
    while(allocation != nullptr)
    {
        if (address >= allocation->allocation->address && address < (allocation->allocation->address + allocation->bytesUsed))
        {
            if (previous == nullptr)
            {
                this->allocations = allocation->nextAllocation;
            }
            else
            {
                previous->nextAllocation = allocation->nextAllocation;
            }

            if ((scriptContext != nullptr) && allocation->recorded)
            {
                this->scriptContext->GetThreadContext()->SubCodeSize(allocation->bytesCommitted);
            }

            VerboseHeapTrace(_u("Freeing 0x%p, allocation: 0x%p\n"), address, allocation->allocation->address);

            this->allocationHeap.Free(allocation->allocation);
            this->allocator->Free(allocation, sizeof(EmitBufferAllocation));

            return true;
        }
        previous = allocation;
        allocation = allocation->nextAllocation;
    }
    return false;
}
Пример #5
0
bool
EmitBufferManager<TAlloc, TPreReservedAlloc, SyncObject>::FreeAllocation(void* address)
{
#if PDATA_ENABLED && defined(_WIN32)
    DelayDeletingFunctionTable::Clear();
#endif

    AutoRealOrFakeCriticalSection<SyncObject> autoCs(&this->criticalSection);

#if _M_ARM
    address = (void*)((uintptr_t)address & ~0x1); // clear the thumb bit
#endif
    TEmitBufferAllocation* previous = nullptr;
    TEmitBufferAllocation* allocation = allocations;
    while(allocation != nullptr)
    {
        if (address == allocation->allocation->address)
        {
            if (previous == nullptr)
            {
                this->allocations = allocation->nextAllocation;
            }
            else
            {
                previous->nextAllocation = allocation->nextAllocation;
            }

            if ((scriptContext != nullptr) && allocation->recorded)
            {
                this->scriptContext->GetThreadContext()->SubCodeSize(allocation->bytesCommitted);
            }

#if defined(_CONTROL_FLOW_GUARD) && !defined(_M_ARM)
            if (allocation->allocation->thunkAddress)
            {
                if (JITManager::GetJITManager()->IsJITServer())
                {
                    ((ServerThreadContext*)this->threadContext)->GetJITThunkEmitter()->FreeThunk(allocation->allocation->thunkAddress);
                }
                else
                {
                    ((ThreadContext*)this->threadContext)->GetJITThunkEmitter()->FreeThunk(allocation->allocation->thunkAddress);
                }
            }
            else
#endif
            {
                if (!JITManager::GetJITManager()->IsJITServer() || CONFIG_FLAG(OOPCFGRegistration))
                {
                    void* callTarget = address;
#if _M_ARM
                    callTarget = (void*)((uintptr_t)callTarget | 0x1); // add the thumb bit back, so we CFG-unregister the actual call target
#endif
                    threadContext->SetValidCallTargetForCFG(callTarget, false);
                }
            }
            VerboseHeapTrace(_u("Freeing 0x%p, allocation: 0x%p\n"), address, allocation->allocation->address);

            this->allocationHeap.Free(allocation->allocation);
            this->allocator->Free(allocation, sizeof(TEmitBufferAllocation));

            return true;
        }
        previous = allocation;
        allocation = allocation->nextAllocation;
    }
    return false;
}
template <typename TAlloc> inline
uintptr_t
JITThunkEmitter<TAlloc>::CreateThunk(uintptr_t entryPoint)
{
    AutoCriticalSection autoCs(&this->cs);
    if(EnsureInitialized() == NULL)
    {
        return NULL;
    }

    // find available thunk
    BVIndex thunkIndex = this->freeThunks.GetNextBit(this->firstBitToCheck);
    if (thunkIndex == BVInvalidIndex)
    {
        return NULL;
    }
    uintptr_t thunkAddress = GetThunkAddressFromIndex(thunkIndex);

    uintptr_t pageStartAddress = GetThunkPageStart(thunkAddress);
    char * localPageAddress = (char *)this->codeAllocator->AllocLocal((PVOID)pageStartAddress, AutoSystemInfo::PageSize);
    if (localPageAddress == nullptr)
    {
        return NULL;
    }

    if (IsThunkPageEmpty(pageStartAddress))
    {
        if (this->codeAllocator->AllocPages((PVOID)pageStartAddress, 1, MEM_COMMIT, PAGE_EXECUTE_READ, true) == nullptr)
        {
            this->codeAllocator->FreeLocal(localPageAddress);
            return NULL;
        }
        UnprotectPage(localPageAddress);
        memset(localPageAddress, 0xCC, AutoSystemInfo::PageSize);
    }
    else
    {
        UnprotectPage(localPageAddress);
    }

    EncodeJmp(localPageAddress, thunkAddress, entryPoint);

    ProtectPage(localPageAddress);
    this->codeAllocator->FreeLocal(localPageAddress);

    if (CONFIG_FLAG(OOPCFGRegistration))
    {
#if ENABLE_OOP_NATIVE_CODEGEN
        if (JITManager::GetJITManager()->IsJITServer())
        {
            HANDLE fileHandle = nullptr;
            PVOID baseAddress = nullptr;
            bool found = this->codeAllocator->GetFileInfo((PVOID)thunkAddress, &fileHandle, &baseAddress);
            AssertOrFailFast(found);
            this->threadContext->SetValidCallTargetFile((PVOID)thunkAddress, fileHandle, baseAddress, true);
        }
        else
#endif
        {
            this->threadContext->SetValidCallTargetForCFG((PVOID)thunkAddress);
        }
    }
    this->firstBitToCheck = (thunkIndex + 1 < JITThunkEmitter<TAlloc>::TotalThunkCount) ? thunkIndex + 1 : 0;
    this->freeThunks.Clear(thunkIndex);

    if (!FlushInstructionCache(this->processHandle, (PVOID)thunkAddress, ThunkSize))
    {
        return NULL;
    }

    return thunkAddress;
}