Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merge from unreleased/rs2 to release/1.4 #2826

Merged
merged 1 commit into from
Apr 25, 2017
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
5 changes: 0 additions & 5 deletions .gitattributes

This file was deleted.

2 changes: 2 additions & 0 deletions lib/Backend/Chakra.Backend.vcxproj
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,8 @@
</AdditionalIncludeDirectories>
<PrecompiledHeader>Use</PrecompiledHeader>
<PrecompiledHeaderFile>BackEnd.h</PrecompiledHeaderFile>
<!-- # Check out https://osgwiki.com/wiki/Dev_14_Migration for more details about -Zc:implicitNoexcept- -->
<AdditionalOptions>-Zc:implicitNoexcept- %(AdditionalOptions)</AdditionalOptions>
</ClCompile>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(OptimizedBuild)'!='true'">
Expand Down
1 change: 1 addition & 0 deletions lib/Backend/GlobOptFields.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2215,6 +2215,7 @@ GlobOpt::FinishOptPropOp(IR::Instr *instr, IR::PropertySymOpnd *opnd, BasicBlock
// changed by the addition of a property.

SymID opndId = opnd->HasObjectTypeSym() ? opnd->GetObjectTypeSym()->m_id : -1;

if (!isObjTypeChecked)
{
if (block->globOptData.maybeWrittenTypeSyms == nullptr)
Expand Down
4 changes: 4 additions & 0 deletions lib/Backend/IR.h
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,9 @@ class Instr
m_src2(nullptr),
#if DBG_DUMP
globOptInstrString(nullptr),
#endif
#if _CONTROL_FLOW_GUARD_SHADOW_STACK
isFsBased(false),
#endif
dstIsTempNumber(false),
dstIsTempNumberTransferred(false),
Expand Down Expand Up @@ -467,6 +470,7 @@ class Instr
Js::OpCode m_opcode;
uint8 ignoreOverflowBitCount; // Number of bits after which ovf matters. Currently used for MULs.

bool isFsBased : 1; // TEMP : just for BS testing
bool dstIsTempNumber : 1;
bool dstIsTempNumberTransferred : 1;
bool dstIsTempObject : 1;
Expand Down
1 change: 0 additions & 1 deletion lib/Backend/Inline.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2341,7 +2341,6 @@ IR::Instr* Inline::InlineApply(IR::Instr *callInstr, const FunctionJITTimeInfo *
*pIsInlined = false;
return callInstr;
}

*pIsInlined = true;

#if defined(ENABLE_DEBUG_CONFIG_OPTIONS)
Expand Down
118 changes: 95 additions & 23 deletions lib/Backend/InterpreterThunkEmitter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,51 @@ const BYTE InterpreterThunkEmitter::Epilog[] = {
0x48, 0x83, 0xC4, StackAllocSize, // add rsp,28h
0xC3 // ret
};

#if _CONTROL_FLOW_GUARD_SHADOW_STACK
#define RFG_PROLOGUE_SIZE 9

const BYTE InterpreterThunkEmitter::InterpreterThunkRFG[] = {
0x48, 0x8b, 0x04, 0x24, // mov rax,qword ptr [rsp]
0x64, 0x48, 0x89, 0x04, 0x24, // mov qword ptr fs:[rsp],rax
0x48, 0x89, 0x54, 0x24, 0x10, // mov qword ptr [rsp+10h],rdx
0x48, 0x89, 0x4C, 0x24, 0x08, // mov qword ptr [rsp+8],rcx
0x4C, 0x89, 0x44, 0x24, 0x18, // mov qword ptr [rsp+18h],r8
0x4C, 0x89, 0x4C, 0x24, 0x20, // mov qword ptr [rsp+20h],r9
0x48, 0x8B, 0x41, 0x00, // mov rax, qword ptr [rcx+FunctionInfoOffset]
0x48, 0x8B, 0x48, 0x00, // mov rcx, qword ptr [rax+FunctionProxyOffset]
0x48, 0x8B, 0x51, 0x00, // mov rdx, qword ptr [rcx+DynamicThunkAddressOffset]
// Range Check for Valid call target
0x48, 0x83, 0xE2, 0xF8, // and rdx, 0xFFFFFFFFFFFFFFF8h ;Force 8 byte alignment
0x48, 0x8b, 0xca, // mov rcx, rdx
0x48, 0xb8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // mov rax, CallBlockStartAddress
0x48, 0x2b, 0xc8, // sub rcx, rax
0x48, 0x81, 0xf9, 0x00, 0x00, 0x00, 0x00, // cmp rcx, ThunkSize
0x76, 0x09, // jbe $safe
0x48, 0xc7, 0xc1, 0x00, 0x00, 0x00, 0x00, // mov rcx, errorcode
0xcd, 0x29, // int 29h

// $safe:
0x48, 0x8D, 0x4C, 0x24, 0x08, // lea rcx, [rsp+8] ;Load the address to stack
0x48, 0x83, 0xEC, StackAllocSize, // sub rsp,28h
0x48, 0xB8, 0x00, 0x00, 0x00 ,0x00, 0x00, 0x00, 0x00, 0x00, // mov rax, <thunk>
0xFF, 0xE2, // jmp rdx
0xCC, 0xCC, 0xCC, 0xCC // int 3 ;for alignment to size of 8 we are adding this
};

const BYTE InterpreterThunkEmitter::EpilogRFG[] = {
0x48, 0x83, 0xC4, StackAllocSize, // add rsp,28h
0x64, 0x4c, 0x8b, 0x1c, 0x24, // mov r11,qword ptr fs:[rsp]
0x4c, 0x3b, 0x1c, 0x24, // cmp r11,qword ptr [rsp]
0x75, 0x01, // jne $fail
0xC3, // ret

// $fail:
0xb9, 0x2c, 0x00, 0x00, 0x00, // mov ecx, errorcode
0xcd, 0x29, // int 29h
};
#endif

#else // Sys V AMD64
const BYTE InterpreterThunkEmitter::FunctionInfoOffset = 7;
const BYTE InterpreterThunkEmitter::FunctionProxyOffset = 11;
Expand Down Expand Up @@ -230,9 +275,19 @@ const BYTE InterpreterThunkEmitter::Call[] = {

#endif

const BYTE InterpreterThunkEmitter::HeaderSize = sizeof(InterpreterThunk);
const BYTE InterpreterThunkEmitter::_HeaderSize = sizeof(InterpreterThunk);
const BYTE InterpreterThunkEmitter::ThunkSize = sizeof(Call);
const uint InterpreterThunkEmitter::ThunksPerBlock = (BlockSize - HeaderSize) / ThunkSize;

const BYTE InterpreterThunkEmitter::HeaderSize()
{
#if _CONTROL_FLOW_GUARD_SHADOW_STACK
if (_guard_rf_checks_enforced()) {
return sizeof(InterpreterThunkRFG);
}
#endif

return _HeaderSize;
}

InterpreterThunkEmitter::InterpreterThunkEmitter(Js::ScriptContext* context, ArenaAllocator* allocator, CustomHeap::InProcCodePageAllocators * codePageAllocators, bool isAsmInterpreterThunk) :
emitBufferManager(allocator, codePageAllocators, /*scriptContext*/ nullptr, _u("Interpreter thunk buffer"), GetCurrentProcess()),
Expand Down Expand Up @@ -272,7 +327,7 @@ BYTE* InterpreterThunkEmitter::GetNextThunk(PVOID* ppDynamicInterpreterThunk)
#if _M_ARM
thunk = (BYTE*)((DWORD)thunk | 0x01);
#endif
*ppDynamicInterpreterThunk = thunk + HeaderSize + ((--thunkCount) * ThunkSize);
*ppDynamicInterpreterThunk = thunk + HeaderSize() + ((--thunkCount) * ThunkSize);
#if _M_ARM
AssertMsg(((uintptr_t)(*ppDynamicInterpreterThunk) & 0x6) == 0, "Not 8 byte aligned?");
#else
Expand Down Expand Up @@ -347,7 +402,7 @@ void InterpreterThunkEmitter::NewThunkBlock()
ThreadContext::GetContextForCurrentThread()->SetValidCallTargetForCFG(buffer);

// Update object state only at the end when everything has succeeded - and no exceptions can be thrown.
auto block = this->thunkBlocks.PrependNode(allocator, buffer);
auto block = this->thunkBlocks.PrependNode(allocator, buffer, count);
#if PDATA_ENABLED
void* pdataTable;
PDataManager::RegisterPdata((PRUNTIME_FUNCTION)pdataStart, (ULONG_PTR)buffer, (ULONG_PTR)epilogEnd, &pdataTable);
Expand Down Expand Up @@ -382,7 +437,7 @@ void InterpreterThunkEmitter::NewOOPJITThunkBlock()
}

// Update object state only at the end when everything has succeeded - and no exceptions can be thrown.
auto block = this->thunkBlocks.PrependNode(allocator, buffer);
auto block = this->thunkBlocks.PrependNode(allocator, buffer, thunkOutput.thunkCount);
#if PDATA_ENABLED
void* pdataTable;
PDataManager::RegisterPdata((PRUNTIME_FUNCTION)thunkOutput.pdataTableStart, (ULONG_PTR)thunkOutput.mappedBaseAddr, (ULONG_PTR)thunkOutput.epilogEndAddr, &pdataTable);
Expand Down Expand Up @@ -421,8 +476,10 @@ void InterpreterThunkEmitter::FillBuffer(
#endif
DWORD bytesRemaining = BlockSize;
DWORD bytesWritten = 0;
DWORD epilogSize = sizeof(Epilog);
DWORD thunks = 0;
DWORD epilogSize = sizeof(Epilog);
const BYTE *epilog = Epilog;
const BYTE *header = InterpreterThunk;

intptr_t interpreterThunk;

Expand All @@ -438,6 +495,14 @@ void InterpreterThunkEmitter::FillBuffer(
interpreterThunk = SHIFT_ADDR(threadContext, &Js::InterpreterStackFrame::InterpreterThunk);
}

#if _CONTROL_FLOW_GUARD_SHADOW_STACK
if (_guard_rf_checks_enforced()) {
header = InterpreterThunkRFG;
epilog = EpilogRFG;
epilogSize = sizeof(EpilogRFG);
}
#endif

BYTE * currentBuffer = buffer;
// Ensure there is space for PDATA at the end
BYTE* pdataStart = currentBuffer + (BlockSize - Math::Align(pdataSize, EMIT_BUFFER_ALIGNMENT));
Expand All @@ -448,10 +513,10 @@ void InterpreterThunkEmitter::FillBuffer(
intptr_t finalEpilogStart = finalPdataStart - Math::Align(epilogSize, EMIT_BUFFER_ALIGNMENT);

// Copy the thunk buffer and modify it.
js_memcpy_s(currentBuffer, bytesRemaining, InterpreterThunk, HeaderSize);
EncodeInterpreterThunk(currentBuffer, finalAddr, HeaderSize, finalEpilogStart, epilogSize, interpreterThunk);
currentBuffer += HeaderSize;
bytesRemaining -= HeaderSize;
js_memcpy_s(currentBuffer, bytesRemaining, header, HeaderSize());
EncodeInterpreterThunk(currentBuffer, finalAddr, HeaderSize(), finalEpilogStart, epilogSize, interpreterThunk);
currentBuffer += HeaderSize();
bytesRemaining -= HeaderSize();

// Copy call buffer
DWORD callSize = sizeof(Call);
Expand Down Expand Up @@ -487,7 +552,7 @@ void InterpreterThunkEmitter::FillBuffer(
currentBuffer += bytesWritten;

// Copy epilog
bytesWritten = CopyWithAlignment(currentBuffer, bytesRemaining, Epilog, epilogSize, EMIT_BUFFER_ALIGNMENT);
bytesWritten = CopyWithAlignment(currentBuffer, bytesRemaining, epilog, epilogSize, EMIT_BUFFER_ALIGNMENT);
currentBuffer += bytesWritten;
bytesRemaining -= bytesWritten;

Expand Down Expand Up @@ -520,7 +585,7 @@ void InterpreterThunkEmitter::EncodeInterpreterThunk(
__in const DWORD epilogSize,
__in const intptr_t interpreterThunk)
{
_Analysis_assume_(thunkSize == HeaderSize);
_Analysis_assume_(thunkSize == HeaderSize());
// Encode MOVW
DWORD lowerThunkBits = (uint32)interpreterThunk & 0x0000FFFF;
DWORD movW = EncodeMove(/*Opcode*/ 0x0000F240, /*register*/1, lowerThunkBits);
Expand All @@ -539,7 +604,7 @@ void InterpreterThunkEmitter::EncodeInterpreterThunk(
thunkBuffer[DynamicThunkAddressOffset] = Js::FunctionBody::GetOffsetOfDynamicInterpreterThunk();

// Encode MOVW R12, CallBlockStartAddress
uintptr_t callBlockStartAddress = (uintptr_t)thunkBufferStartAddress + HeaderSize;
uintptr_t callBlockStartAddress = (uintptr_t)thunkBufferStartAddress + HeaderSize();
uint totalThunkSize = (uint)(epilogStart - callBlockStartAddress);

DWORD lowerCallBlockStartAddress = callBlockStartAddress & 0x0000FFFF;
Expand Down Expand Up @@ -594,8 +659,8 @@ void InterpreterThunkEmitter::EncodeInterpreterThunk(
{
int addrOffset = ThunkAddressOffset;

_Analysis_assume_(thunkSize == HeaderSize);
AssertMsg(thunkSize == HeaderSize, "Mismatch in the size of the InterpreterHeaderThunk and the thunkSize used in this API (EncodeInterpreterThunk)");
_Analysis_assume_(thunkSize == HeaderSize());
AssertMsg(thunkSize == HeaderSize(), "Mismatch in the size of the InterpreterHeaderThunk and the thunkSize used in this API (EncodeInterpreterThunk)");

// Following 4 MOV Instrs are to move the 64-bit address of the InterpreterThunk address into register x1.

Expand Down Expand Up @@ -677,13 +742,20 @@ void InterpreterThunkEmitter::EncodeInterpreterThunk(
__in const DWORD epilogSize,
__in const intptr_t interpreterThunk)
{
_Analysis_assume_(thunkSize == HeaderSize);
_Analysis_assume_(thunkSize == HeaderSize());

#if _CONTROL_FLOW_GUARD_SHADOW_STACK
if (_guard_rf_checks_enforced()) {
thunkBuffer += RFG_PROLOGUE_SIZE;
}
#endif

Emit(thunkBuffer, ThunkAddressOffset, (uintptr_t)interpreterThunk);
thunkBuffer[DynamicThunkAddressOffset] = Js::FunctionBody::GetOffsetOfDynamicInterpreterThunk();
thunkBuffer[FunctionInfoOffset] = Js::JavascriptFunction::GetOffsetOfFunctionInfo();
thunkBuffer[FunctionProxyOffset] = Js::FunctionInfo::GetOffsetOfFunctionProxy();
Emit(thunkBuffer, CallBlockStartAddrOffset, (uintptr_t) thunkBufferStartAddress + HeaderSize);
uint totalThunkSize = (uint)(epilogStart - (thunkBufferStartAddress + HeaderSize));
Emit(thunkBuffer, CallBlockStartAddrOffset, (uintptr_t) thunkBufferStartAddress + HeaderSize());
uint totalThunkSize = (uint)(epilogStart - (thunkBufferStartAddress + HeaderSize()));
Emit(thunkBuffer, ThunkSizeOffset, totalThunkSize);
Emit(thunkBuffer, ErrorOffset, (BYTE) FAST_FAIL_INVALID_ARG);
}
Expand Down Expand Up @@ -859,23 +931,23 @@ BYTE* ThunkBlock::AllocateFromFreeList()

BVIndex ThunkBlock::FromThunkAddress(BYTE* address)
{
int index = ((uint)(address - start) - InterpreterThunkEmitter::HeaderSize) / InterpreterThunkEmitter::ThunkSize;
Assert(index < InterpreterThunkEmitter::ThunksPerBlock);
uint index = ((uint)(address - start) - InterpreterThunkEmitter::HeaderSize()) / InterpreterThunkEmitter::ThunkSize;
Assert(index < this->thunkCount);
return index;
}

BYTE* ThunkBlock::ToThunkAddress(BVIndex index)
{
Assert(index < InterpreterThunkEmitter::ThunksPerBlock);
BYTE* address = start + InterpreterThunkEmitter::HeaderSize + InterpreterThunkEmitter::ThunkSize * index;
Assert(index < this->thunkCount);
BYTE* address = start + InterpreterThunkEmitter::HeaderSize() + InterpreterThunkEmitter::ThunkSize * index;
return address;
}

bool ThunkBlock::EnsureFreeList(ArenaAllocator* allocator)
{
if(!this->freeList)
{
this->freeList = BVFixed::NewNoThrow(InterpreterThunkEmitter::ThunksPerBlock, allocator);
this->freeList = BVFixed::NewNoThrow(this->thunkCount, allocator);
}
return this->freeList != nullptr;
}
Expand Down
13 changes: 10 additions & 3 deletions lib/Backend/InterpreterThunkEmitter.h
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,12 @@ class ThunkBlock
#endif
BYTE* start;
BVFixed* freeList;
DWORD thunkCount;

public:
ThunkBlock(BYTE* start) :
ThunkBlock(BYTE* start, DWORD thunkCount) :
start(start),
thunkCount(thunkCount),
freeList(NULL)
#if PDATA_ENABLED
, registeredPdataTable(NULL)
Expand Down Expand Up @@ -87,6 +89,11 @@ class InterpreterThunkEmitter

static const BYTE Epilog[];

#if _CONTROL_FLOW_GUARD_SHADOW_STACK
static const BYTE InterpreterThunkRFG[];
static const BYTE EpilogRFG[];
#endif

static const BYTE PageCount = 1;
#if defined(_M_X64)
static const BYTE PrologSize;
Expand Down Expand Up @@ -123,10 +130,10 @@ class InterpreterThunkEmitter
};

BYTE* AllocateFromFreeList(PVOID* ppDynamicInterpreterThunk);
static const BYTE _HeaderSize;
public:
static const BYTE HeaderSize;
static const BYTE HeaderSize();
static const BYTE ThunkSize;
static const uint ThunksPerBlock;
static const uint BlockSize= AutoSystemInfo::PageSize * PageCount;
static void* ConvertToEntryPoint(PVOID dynamicInterpreterThunk);

Expand Down
4 changes: 4 additions & 0 deletions lib/Backend/JnHelperMethod.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,10 @@ extern "C"
extern "C" PVOID __guard_check_icall_fptr;
#endif

#if _CONTROL_FLOW_GUARD_SHADOW_STACK
extern "C" void __guard_ss_verify_failure();
#endif

namespace IR
{
enum JnHelperMethod
Expand Down
5 changes: 5 additions & 0 deletions lib/Backend/JnHelperMethodList.h
Original file line number Diff line number Diff line change
Expand Up @@ -612,6 +612,11 @@ HELPERCALL( CRT_chkstk, _chkstk, 0 )
HELPERCALL(CRT_chkstk, __chkstk, 0)
#endif

#if _CONTROL_FLOW_GUARD_SHADOW_STACK
// Statically linked CRT routine used when RFG violations.
HELPERCALL(ReturnFlowGuardFailureRoutine, __guard_ss_verify_failure, 0)
#endif

#undef HELPERCALL_MATH
#undef HELPERCALL_FULL_OR_INPLACE_MATH

Expand Down
Loading