Skip to content
Closed
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: 7 additions & 7 deletions lib/Backend/Inline.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1026,7 +1026,7 @@ Inline::InlinePolymorphicFunction(IR::Instr *callInstr, const FunctionJITTimeInf
IR::RegOpnd* functionObject = callInstr->GetSrc1()->AsRegOpnd();
dispatchStartLabel->InsertBefore(IR::BranchInstr::New(Js::OpCode::BrAddr_A, inlineeStartLabel,
IR::IndirOpnd::New(functionObject, Js::JavascriptFunction::GetOffsetOfFunctionInfo(), TyMachPtr, dispatchStartLabel->m_func),
IR::AddrOpnd::New(inlineesDataArray[i]->GetBody()->GetAddr(), IR::AddrOpndKindDynamicFunctionBody, dispatchStartLabel->m_func), dispatchStartLabel->m_func));
IR::AddrOpnd::New((void*)inlineesDataArray[i], IR::AddrOpndKindDynamicFunctionBody, dispatchStartLabel->m_func), dispatchStartLabel->m_func));
}

CompletePolymorphicInlining(callInstr, returnValueOpnd, doneLabel, dispatchStartLabel, /*ldMethodFldInstr*/nullptr, IR::BailOutOnPolymorphicInlineFunction);
Expand Down Expand Up @@ -4063,14 +4063,14 @@ Inline::InsertJsFunctionCheck(IR::Instr *callInstr, IR::Instr *insertBeforeInstr
}

void
Inline::InsertFunctionBodyCheck(IR::Instr *callInstr, IR::Instr *insertBeforeInstr, IR::Instr* bailoutInstr, const FunctionJITTimeInfo *funcInfo)
Inline::InsertFunctionInfoCheck(IR::Instr *callInstr, IR::Instr *insertBeforeInstr, IR::Instr* bailoutInstr, const FunctionJITTimeInfo *funcInfo)
{
// if (JavascriptFunction::FromVar(r1)->functionInfo != funcInfo) goto noInlineLabel
// BrNeq_I4 noInlineLabel, r1->functionInfo, funcInfo
IR::IndirOpnd* funcBody = IR::IndirOpnd::New(callInstr->GetSrc1()->AsRegOpnd(), Js::JavascriptFunction::GetOffsetOfFunctionInfo(), TyMachPtr, callInstr->m_func);
IR::AddrOpnd* inlinedFuncBody = IR::AddrOpnd::New(funcInfo->GetFunctionInfoAddr(), IR::AddrOpndKindDynamicFunctionBody, callInstr->m_func);
bailoutInstr->SetSrc1(funcBody);
bailoutInstr->SetSrc2(inlinedFuncBody);
IR::IndirOpnd* opndFuncInfo = IR::IndirOpnd::New(callInstr->GetSrc1()->AsRegOpnd(), Js::JavascriptFunction::GetOffsetOfFunctionInfo(), TyMachPtr, callInstr->m_func);
IR::AddrOpnd* inlinedFuncInfo = IR::AddrOpnd::New(funcInfo->GetFunctionInfoAddr(), IR::AddrOpndKindDynamicFunctionInfo, callInstr->m_func);
bailoutInstr->SetSrc1(opndFuncInfo);
bailoutInstr->SetSrc2(inlinedFuncInfo);

insertBeforeInstr->InsertBefore(bailoutInstr);
}
Expand Down Expand Up @@ -4108,7 +4108,7 @@ Inline::PrepareInsertionPoint(IR::Instr *callInstr, const FunctionJITTimeInfo *f
InsertFunctionTypeIdCheck(callInstr, insertBeforeInstr, bailOutIfNotJsFunction);

// 3. Bailout if function body doesn't match funcInfo
InsertFunctionBodyCheck(callInstr, insertBeforeInstr, primaryBailOutInstr, funcInfo);
InsertFunctionInfoCheck(callInstr, insertBeforeInstr, primaryBailOutInstr, funcInfo);

return primaryBailOutInstr;
}
Expand Down
2 changes: 1 addition & 1 deletion lib/Backend/Inline.h
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,7 @@ class Inline
void InsertObjectCheck(IR::Instr *callInstr, IR::Instr* insertBeforeInstr, IR::Instr*bailOutInstr);
void InsertFunctionTypeIdCheck(IR::Instr *callInstr, IR::Instr* insertBeforeInstr, IR::Instr*bailOutInstr);
void InsertJsFunctionCheck(IR::Instr *callInstr, IR::Instr *insertBeforeInstr, IR::BailOutKind bailOutKind);
void InsertFunctionBodyCheck(IR::Instr *callInstr, IR::Instr *insertBeforeInstr, IR::Instr* bailoutInstr, const FunctionJITTimeInfo *funcInfo);
void InsertFunctionInfoCheck(IR::Instr *callInstr, IR::Instr *insertBeforeInstr, IR::Instr* bailoutInstr, const FunctionJITTimeInfo *funcInfo);
void InsertFunctionObjectCheck(IR::Instr *callInstr, IR::Instr *insertBeforeInstr, IR::Instr* bailoutInstr, const FunctionJITTimeInfo *funcInfo);

void TryResetObjTypeSpecFldInfoOn(IR::PropertySymOpnd* propertySymOpnd);
Expand Down
4 changes: 2 additions & 2 deletions lib/Backend/InliningDecider.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -151,7 +151,7 @@ uint InliningDecider::InlinePolymorphicCallSite(Js::FunctionBody *const inliner,
AssertMsg(inlineeCount >= 2, "There are at least two polymorphic call site");
break;
}
if (Inline(inliner, functionBodyArray[inlineeCount], isConstructorCall, true /*isPolymorphicCall*/, 0, profiledCallSiteId, recursiveInlineDepth, false))
if (Inline(inliner, functionBodyArray[inlineeCount]->GetFunctionInfo(), isConstructorCall, true /*isPolymorphicCall*/, 0, profiledCallSiteId, recursiveInlineDepth, false))
{
canInlineArray[inlineeCount] = true;
actualInlineeCount++;
Expand Down Expand Up @@ -272,7 +272,7 @@ Js::FunctionInfo *InliningDecider::Inline(Js::FunctionBody *const inliner, Js::F
#endif

this->bytecodeInlinedCount += inlinee->GetByteCodeCount();
return inlinee;
return inlinee->GetFunctionInfo();
}

Js::OpCode builtInInlineCandidateOpCode;
Expand Down
81 changes: 47 additions & 34 deletions lib/Backend/InterpreterThunkEmitter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,15 @@
#ifdef ENABLE_NATIVE_CODEGEN
#ifdef _M_X64
#ifdef _WIN32
const BYTE InterpreterThunkEmitter::FunctionBodyOffset = 23;
const BYTE InterpreterThunkEmitter::DynamicThunkAddressOffset = 27;
const BYTE InterpreterThunkEmitter::CallBlockStartAddrOffset = 37;
const BYTE InterpreterThunkEmitter::ThunkSizeOffset = 51;
const BYTE InterpreterThunkEmitter::ErrorOffset = 60;
const BYTE InterpreterThunkEmitter::ThunkAddressOffset = 77;

const BYTE InterpreterThunkEmitter::PrologSize = 76;
const BYTE InterpreterThunkEmitter::FunctionInfoOffset = 23;
const BYTE InterpreterThunkEmitter::FunctionProxyOffset = 27;
const BYTE InterpreterThunkEmitter::DynamicThunkAddressOffset = 31;
const BYTE InterpreterThunkEmitter::CallBlockStartAddrOffset = 41;
const BYTE InterpreterThunkEmitter::ThunkSizeOffset = 55;
const BYTE InterpreterThunkEmitter::ErrorOffset = 64;
const BYTE InterpreterThunkEmitter::ThunkAddressOffset = 81;

const BYTE InterpreterThunkEmitter::PrologSize = 80;
const BYTE InterpreterThunkEmitter::StackAllocSize = 0x28;

//
Expand All @@ -29,8 +30,9 @@ const BYTE InterpreterThunkEmitter::InterpreterThunk[] = {
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+FunctionBodyOffset]
0x48, 0x8B, 0x50, 0x00, // mov rdx, qword ptr [rax+DynamicThunkAddressOffset]
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
Expand All @@ -46,7 +48,7 @@ const BYTE InterpreterThunkEmitter::InterpreterThunk[] = {
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 // int 3 ;for alignment to size of 8 we are adding this
0xCC, 0xCC, 0xCC, 0xCC, 0xCC // int 3 ;for alignment to size of 8 we are adding this
};

const BYTE InterpreterThunkEmitter::Epilog[] = {
Expand Down Expand Up @@ -93,11 +95,12 @@ const BYTE InterpreterThunkEmitter::Epilog[] = {
#endif
#elif defined(_M_ARM)
const BYTE InterpreterThunkEmitter::ThunkAddressOffset = 8;
const BYTE InterpreterThunkEmitter::FunctionBodyOffset = 18;
const BYTE InterpreterThunkEmitter::DynamicThunkAddressOffset = 22;
const BYTE InterpreterThunkEmitter::CallBlockStartAddressInstrOffset = 38;
const BYTE InterpreterThunkEmitter::CallThunkSizeInstrOffset = 50;
const BYTE InterpreterThunkEmitter::ErrorOffset = 60;
const BYTE InterpreterThunkEmitter::FunctionInfoOffset = 18;
const BYTE InterpreterThunkEmitter::FunctionProxyOffset = 22;
const BYTE InterpreterThunkEmitter::DynamicThunkAddressOffset = 26;
const BYTE InterpreterThunkEmitter::CallBlockStartAddressInstrOffset = 42;
const BYTE InterpreterThunkEmitter::CallThunkSizeInstrOffset = 54;
const BYTE InterpreterThunkEmitter::ErrorOffset = 64;

const BYTE InterpreterThunkEmitter::InterpreterThunk[] = {
0x0F, 0xB4, // push {r0-r3}
Expand All @@ -106,7 +109,8 @@ const BYTE InterpreterThunkEmitter::InterpreterThunk[] = {
0x00, 0x00, 0x00, 0x00, // movw r1,ThunkAddress
0x00, 0x00, 0x00, 0x00, // movt r1,ThunkAddress
0xD0, 0xF8, 0x00, 0x20, // ldr.w r2,[r0,#0x00]
0xD2, 0xF8, 0x00, 0x30, // ldr.w r3,[r2,#0x00]
0xD2, 0xF8, 0x00, 0x00, // ldr.w r0,[r2,#0x00]
0xD0, 0xF8, 0x00, 0x30, // ldr.w r3,[r0,#0x00]
0x4F, 0xF6, 0xF9, 0x70, // mov r0,#0xFFF9
0xCF, 0xF6, 0xFF, 0x70, // movt r0,#0xFFFF
0x03, 0xEA, 0x00, 0x03, // and r3,r3,r0
Expand All @@ -122,9 +126,7 @@ const BYTE InterpreterThunkEmitter::InterpreterThunk[] = {

//$safe:
0x02, 0xA8, // add r0,sp,#8
0x18, 0x47, // bx r3
0xFE, 0xDE, // int 3 ;Required for alignment
0xFE, 0xDE // int 3 ;Required for alignment
0x18, 0x47 // bx r3
};

const BYTE InterpreterThunkEmitter::JmpOffset = 2;
Expand All @@ -140,9 +142,10 @@ const BYTE InterpreterThunkEmitter::Epilog[] = {
0x5D, 0xF8, 0x14, 0xFB // ldr pc,[sp],#0x14
};
#elif defined(_M_ARM64)
const BYTE InterpreterThunkEmitter::FunctionBodyOffset = 24;
const BYTE InterpreterThunkEmitter::DynamicThunkAddressOffset = 28;
const BYTE InterpreterThunkEmitter::ThunkAddressOffset = 32;
const BYTE InterpreterThunkEmitter::FunctionInfoOffset = 24;
const BYTE InterpreterThunkEmitter::FunctionProxyOffset = 28;
const BYTE InterpreterThunkEmitter::DynamicThunkAddressOffset = 32;
const BYTE InterpreterThunkEmitter::ThunkAddressOffset = 36;

//TODO: saravind :Implement Range Check for ARM64
const BYTE InterpreterThunkEmitter::InterpreterThunk[] = {
Expand All @@ -153,7 +156,8 @@ const BYTE InterpreterThunkEmitter::InterpreterThunk[] = {
0xE4, 0x17, 0x03, 0xA9, //stp x4, x5, [sp, #48]
0xE6, 0x1F, 0x04, 0xA9, //stp x6, x7, [sp, #64]
0x02, 0x00, 0x40, 0xF9, //ldr x2, [x0, #0x00] ;offset will be replaced with Offset of FunctionInfo
0x43, 0x00, 0x40, 0xF9, //ldr x3, [x2, #0x00] ;offset will be replaced with offset of DynamicInterpreterThunk
0x40, 0x00, 0x40, 0xF9, //ldr x0, [x2, #0x00] ;offset will be replaced with Offset of FunctionProxy
0x03, 0x00, 0x40, 0xF9, //ldr x3, [x0, #0x00] ;offset will be replaced with offset of DynamicInterpreterThunk
//Following 4 MOV Instrs are to move the 64-bit address of the InterpreterThunk address into register x1.
0x00, 0x00, 0x00, 0x00, //movz x1, #0x00 ;This is overwritten with the actual thunk address(16 - 0 bits) move
0x00, 0x00, 0x00, 0x00, //movk x1, #0x00, lsl #16 ;This is overwritten with the actual thunk address(32 - 16 bits) move
Expand All @@ -175,18 +179,20 @@ const BYTE InterpreterThunkEmitter::Epilog[] = {
0xc0, 0x03, 0x5f, 0xd6 // ret
};
#else
const BYTE InterpreterThunkEmitter::FunctionBodyOffset = 8;
const BYTE InterpreterThunkEmitter::DynamicThunkAddressOffset = 11;
const BYTE InterpreterThunkEmitter::CallBlockStartAddrOffset = 18;
const BYTE InterpreterThunkEmitter::ThunkSizeOffset = 23;
const BYTE InterpreterThunkEmitter::ErrorOffset = 30;
const BYTE InterpreterThunkEmitter::ThunkAddressOffset = 41;
const BYTE InterpreterThunkEmitter::FunctionInfoOffset = 8;
const BYTE InterpreterThunkEmitter::FunctionProxyOffset = 11;
const BYTE InterpreterThunkEmitter::DynamicThunkAddressOffset = 14;
const BYTE InterpreterThunkEmitter::CallBlockStartAddrOffset = 21;
const BYTE InterpreterThunkEmitter::ThunkSizeOffset = 26;
const BYTE InterpreterThunkEmitter::ErrorOffset = 33;
const BYTE InterpreterThunkEmitter::ThunkAddressOffset = 44;

const BYTE InterpreterThunkEmitter::InterpreterThunk[] = {
0x55, // push ebp ;Prolog - setup the stack frame
0x8B, 0xEC, // mov ebp,esp
0x8B, 0x45, 0x08, // mov eax, dword ptr [ebp+8]
0x8B, 0x40, 0x00, // mov eax, dword ptr [eax+FunctionBodyOffset]
0x8B, 0x40, 0x00, // mov eax, dword ptr [eax+FunctionInfoOffset]
0x8B, 0x40, 0x00, // mov eax, dword ptr [eax+FunctionProxyOffset]
0x8B, 0x48, 0x00, // mov ecx, dword ptr [eax+DynamicThunkAddressOffset]
// Range Check for Valid call target
0x83, 0xE1, 0xF8, // and ecx, 0FFFFFFF8h
Expand All @@ -202,7 +208,7 @@ const BYTE InterpreterThunkEmitter::InterpreterThunk[] = {
0x50, // push eax
0xB8, 0x00, 0x00, 0x00, 0x00, // mov eax, <thunk>
0xFF, 0xE1, // jmp ecx
0xCC // int 3 for 8byte alignment
0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC // int 3 for 8byte alignment
};

const BYTE InterpreterThunkEmitter::Epilog[] = {
Expand Down Expand Up @@ -512,7 +518,8 @@ void InterpreterThunkEmitter::EncodeInterpreterThunk(
Emit(thunkBuffer, ThunkAddressOffset + sizeof(movW), movT);

// Encode LDR - Load of function Body
thunkBuffer[FunctionBodyOffset] = Js::JavascriptFunction::GetOffsetOfFunctionInfo();
thunkBuffer[FunctionInfoOffset] = Js::JavascriptFunction::GetOffsetOfFunctionInfo();
thunkBuffer[FunctionProxyOffset] = Js::FunctionInfo::GetOffsetOfFunctionProxy();

// Encode LDR - Load of interpreter thunk number
thunkBuffer[DynamicThunkAddressOffset] = Js::FunctionBody::GetOffsetOfDynamicInterpreterThunk();
Expand Down Expand Up @@ -611,6 +618,11 @@ void InterpreterThunkEmitter::EncodeInterpreterThunk(
AssertMsg(offsetOfFunctionInfo < 0x8000, "Immediate offset for LDR must be less than 0x8000");
*(PULONG)&thunkBuffer[FunctionBodyOffset] |= (offsetOfFunctionInfo / 8) << 10;

ULONG offsetOfFunctionProxy = Js::FunctionInfo::GetOffsetOfFunctionProxy();
AssertMsg(offsetOfFunctionProxy % 8 == 0, "Immediate offset for LDR must be 8 byte aligned");
AssertMsg(offsetOfFunctionProxy < 0x8000, "Immediate offset for LDR must be less than 0x8000");
*(PULONG)&thunkBuffer[FunctionProxyOffset] |= (offsetOfFunctionInfo / 8) << 10;

// Encode LDR - Load of interpreter thunk number
ULONG offsetOfDynamicInterpreterThunk = Js::FunctionBody::GetOffsetOfDynamicInterpreterThunk();
AssertMsg(offsetOfDynamicInterpreterThunk % 8 == 0, "Immediate offset for LDR must be 8 byte aligned");
Expand Down Expand Up @@ -654,7 +666,8 @@ void InterpreterThunkEmitter::EncodeInterpreterThunk(
_Analysis_assume_(thunkSize == HeaderSize);
Emit(thunkBuffer, ThunkAddressOffset, (uintptr_t)interpreterThunk);
thunkBuffer[DynamicThunkAddressOffset] = Js::FunctionBody::GetOffsetOfDynamicInterpreterThunk();
thunkBuffer[FunctionBodyOffset] = Js::JavascriptFunction::GetOffsetOfFunctionInfo();
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, ThunkSizeOffset, totalThunkSize);
Expand Down
3 changes: 2 additions & 1 deletion lib/Backend/InterpreterThunkEmitter.h
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,8 @@ class InterpreterThunkEmitter
/* -------static constants ----------*/
// Interpreter thunk buffer includes function prolog, setting up of arguments, jumping to the appropriate calling point.
static const BYTE ThunkAddressOffset;
static const BYTE FunctionBodyOffset;
static const BYTE FunctionInfoOffset;
static const BYTE FunctionProxyOffset;
static const BYTE DynamicThunkAddressOffset;
static const BYTE InterpreterThunkEmitter::CallBlockStartAddrOffset;
static const BYTE InterpreterThunkEmitter::ThunkSizeOffset;
Expand Down
11 changes: 10 additions & 1 deletion lib/Backend/Lower.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6446,7 +6446,16 @@ Lowerer::GenerateScriptFunctionInit(IR::RegOpnd * regOpnd, IR::Opnd * vtableAddr
GenerateMemInit(regOpnd, Js::ScriptFunction::GetOffsetOfConstructorCache(),
LoadLibraryValueOpnd(insertBeforeInstr, LibraryValue::ValueConstructorCacheDefaultInstance),
insertBeforeInstr, isZeroed);
GenerateMemInit(regOpnd, Js::ScriptFunction::GetOffsetOfFunctionInfo(), functionProxyOpnd, insertBeforeInstr, isZeroed);
IR::Opnd *functionInfoOpnd;
if (functionProxyOpnd->IsRegOpnd())
{
functionInfoOpnd = IR::IndirOpnd::New(functionProxyOpnd->AsRegOpnd(), Js::FunctionProxy::GetOffsetOfFunctionInfo(), TyMachReg, func);
}
else
{
functionInfoOpnd = IR::MemRefOpnd::New((BYTE*)functionProxyOpnd->AsAddrOpnd()->m_address + Js::FunctionProxy::GetOffsetOfFunctionInfo(), TyMachReg, func);
}
GenerateMemInit(regOpnd, Js::ScriptFunction::GetOffsetOfFunctionInfo(), functionInfoOpnd, insertBeforeInstr, isZeroed);
GenerateMemInit(regOpnd, Js::ScriptFunction::GetOffsetOfEnvironment(), envOpnd, insertBeforeInstr, isZeroed);
GenerateMemInitNull(regOpnd, Js::ScriptFunction::GetOffsetOfCachedScopeObj(), insertBeforeInstr, isZeroed);
GenerateMemInitNull(regOpnd, Js::ScriptFunction::GetOffsetOfHasInlineCaches(), insertBeforeInstr, isZeroed);
Expand Down
6 changes: 4 additions & 2 deletions lib/Backend/LowerMDShared.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1445,13 +1445,15 @@ LowererMD::Legalize(IR::Instr *const instr, bool fPostRegAlloc)
if(instr->m_opcode == Js::OpCode::MOV)
{
uint src1Forms = L_Reg | L_Mem | L_Ptr; // Allow 64 bit values in x64 as well
#if _M_X64
if (dst->IsMemoryOpnd())
{
#if _M_X64
// Only allow <= 32 bit values
src1Forms = L_Reg | L_Imm32;
}
#else
src1Forms = L_Reg | L_Ptr;
Copy link
Collaborator

Choose a reason for hiding this comment

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

Is this a related change?

#endif
}
LegalizeOpnds<verify>(
instr,
L_Reg | L_Mem,
Expand Down
Loading