diff --git a/lib/Backend/Inline.cpp b/lib/Backend/Inline.cpp index 4c2ac9a1c76..9c8dcc1a4e8 100644 --- a/lib/Backend/Inline.cpp +++ b/lib/Backend/Inline.cpp @@ -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); @@ -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); } @@ -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; } diff --git a/lib/Backend/Inline.h b/lib/Backend/Inline.h index e76e9cf118d..0d43aeafa7f 100644 --- a/lib/Backend/Inline.h +++ b/lib/Backend/Inline.h @@ -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); diff --git a/lib/Backend/InliningDecider.cpp b/lib/Backend/InliningDecider.cpp index f56bb6a1f39..33468f03490 100644 --- a/lib/Backend/InliningDecider.cpp +++ b/lib/Backend/InliningDecider.cpp @@ -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++; @@ -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; diff --git a/lib/Backend/InterpreterThunkEmitter.cpp b/lib/Backend/InterpreterThunkEmitter.cpp index edef77016ed..e969b50fbfc 100644 --- a/lib/Backend/InterpreterThunkEmitter.cpp +++ b/lib/Backend/InterpreterThunkEmitter.cpp @@ -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; // @@ -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 @@ -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, 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[] = { @@ -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} @@ -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 @@ -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; @@ -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[] = { @@ -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 @@ -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 @@ -202,7 +208,7 @@ const BYTE InterpreterThunkEmitter::InterpreterThunk[] = { 0x50, // push eax 0xB8, 0x00, 0x00, 0x00, 0x00, // mov eax, 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[] = { @@ -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(); @@ -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"); @@ -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); diff --git a/lib/Backend/InterpreterThunkEmitter.h b/lib/Backend/InterpreterThunkEmitter.h index b80087cf0f9..516536b8149 100644 --- a/lib/Backend/InterpreterThunkEmitter.h +++ b/lib/Backend/InterpreterThunkEmitter.h @@ -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; diff --git a/lib/Backend/Lower.cpp b/lib/Backend/Lower.cpp index 09debe82bfd..c0ba67522fc 100644 --- a/lib/Backend/Lower.cpp +++ b/lib/Backend/Lower.cpp @@ -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); diff --git a/lib/Backend/LowerMDShared.cpp b/lib/Backend/LowerMDShared.cpp index 9464aaac27c..f33d5e7dd73 100644 --- a/lib/Backend/LowerMDShared.cpp +++ b/lib/Backend/LowerMDShared.cpp @@ -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; #endif + } LegalizeOpnds( instr, L_Reg | L_Mem, diff --git a/lib/Backend/NativeCodeGenerator.cpp b/lib/Backend/NativeCodeGenerator.cpp index 98811d4eefb..bdbc51bdebe 100644 --- a/lib/Backend/NativeCodeGenerator.cpp +++ b/lib/Backend/NativeCodeGenerator.cpp @@ -2677,7 +2677,7 @@ NativeCodeGenerator::GatherCodeGenData( if (!isJitTimeDataComputed) { - Js::FunctionCodeGenJitTimeData *inlineeJitTimeData = jitTimeData->AddInlinee(recycler, profiledCallSiteId, inlineeFunctionBodyArray[id], isInlined); + Js::FunctionCodeGenJitTimeData *inlineeJitTimeData = jitTimeData->AddInlinee(recycler, profiledCallSiteId, inlineeFunctionBodyArray[id]->GetFunctionInfo(), isInlined); if (isInlined) { GatherCodeGenData( @@ -2973,7 +2973,7 @@ NativeCodeGenerator::GatherCodeGenData(Js::FunctionBody *const topFunctionBody, const auto recycler = scriptContext->GetRecycler(); { - const auto jitTimeData = RecyclerNew(recycler, Js::FunctionCodeGenJitTimeData, functionBody, entryPoint); + const auto jitTimeData = RecyclerNew(recycler, Js::FunctionCodeGenJitTimeData, functionBody->GetFunctionInfo(), entryPoint); InliningDecider inliningDecider(functionBody, workItem->Type() == JsLoopBodyWorkItemType, functionBody->IsInDebugMode(), workItem->GetJitMode()); BEGIN_TEMP_ALLOCATOR(gatherCodeGenDataAllocator, scriptContext, _u("GatherCodeGenData")); @@ -3630,7 +3630,7 @@ bool NativeCodeGenerator::TryAggressiveInlining(Js::FunctionBody *const topFunct } else { - inlinee = inliningDecider.Inline(inlineeFunctionBody, inlinee, isConstructorCall, false, inliningDecider.GetConstantArgInfo(inlineeFunctionBody, profiledCallSiteId), profiledCallSiteId, inlineeFunctionBody == inlinee ? recursiveInlineDepth + 1 : 0, true); + inlinee = inliningDecider.Inline(inlineeFunctionBody, inlinee, isConstructorCall, false, inliningDecider.GetConstantArgInfo(inlineeFunctionBody, profiledCallSiteId), profiledCallSiteId, inlineeFunctionBody->GetFunctionInfo() == inlinee ? recursiveInlineDepth + 1 : 0, true); if (!inlinee) { return false; diff --git a/lib/Backend/Opnd.cpp b/lib/Backend/Opnd.cpp index 8240677c11f..6cd635c9820 100644 --- a/lib/Backend/Opnd.cpp +++ b/lib/Backend/Opnd.cpp @@ -3342,12 +3342,12 @@ Opnd::GetAddrDescription(__out_ecount(count) char16 *const description, const si WriteToBuffer(&buffer, &n, _u(" (&RecyclerAllocatorFreeList)")); break; - case IR::AddrOpndKindDynamicFunctionBody: + case IR::AddrOpndKindDynamicFunctionInfo: DumpAddress(address, printToConsole, skipMaskedAddress); if (func->IsOOPJIT()) { // TODO: OOP JIT, dump more info - WriteToBuffer(&buffer, &n, _u(" (FunctionBody)")); + WriteToBuffer(&buffer, &n, _u(" (FunctionInfo)")); } else { @@ -3355,6 +3355,11 @@ Opnd::GetAddrDescription(__out_ecount(count) char16 *const description, const si } break; + case IR::AddrOpndKindDynamicFunctionBody: + DumpAddress(address, printToConsole, skipMaskedAddress); + DumpFunctionInfo(&buffer, &n, ((Js::FunctionBody *)address)->GetFunctionInfo(), printToConsole); + break; + case IR::AddrOpndKindDynamicFunctionBodyWeakRef: DumpAddress(address, printToConsole, skipMaskedAddress); @@ -3365,7 +3370,7 @@ Opnd::GetAddrDescription(__out_ecount(count) char16 *const description, const si } else { - DumpFunctionInfo(&buffer, &n, ((RecyclerWeakReference *)address)->FastGet(), printToConsole, _u("FunctionBodyWeakRef")); + DumpFunctionInfo(&buffer, &n, ((RecyclerWeakReference *)address)->FastGet()->GetFunctionInfo(), printToConsole, _u("FunctionBodyWeakRef")); } break; diff --git a/lib/Backend/Opnd.h b/lib/Backend/Opnd.h index e362febf75e..178ba59be8c 100644 --- a/lib/Backend/Opnd.h +++ b/lib/Backend/Opnd.h @@ -59,6 +59,7 @@ enum AddrOpndKind : BYTE { AddrOpndKindDynamicMisc, // no profiling in dynamic JIT AddrOpndKindDynamicFunctionBody, + AddrOpndKindDynamicFunctionInfo, // use LoadRuntimeInlineCacheOpnd for runtime caches, // in relocatable JIT polymorphic inline caches aren't generated and can // be referenced directly (for now) diff --git a/lib/Runtime/Base/FunctionBody.cpp b/lib/Runtime/Base/FunctionBody.cpp index 51f14c235c2..d8c4e8d67aa 100644 --- a/lib/Runtime/Base/FunctionBody.cpp +++ b/lib/Runtime/Base/FunctionBody.cpp @@ -68,8 +68,7 @@ namespace Js #endif // FunctionProxy methods - FunctionProxy::FunctionProxy(JavascriptMethod entryPoint, Attributes attributes, LocalFunctionId functionId, ScriptContext* scriptContext, Utf8SourceInfo* utf8SourceInfo, uint functionNumber): - FunctionInfo(entryPoint, attributes, functionId, this), + FunctionProxy::FunctionProxy(ScriptContext* scriptContext, Utf8SourceInfo* utf8SourceInfo, uint functionNumber): m_isTopLevel(false), m_isPublicLibraryCode(false), m_scriptContext(scriptContext), @@ -392,7 +391,7 @@ namespace Js } FunctionBody * FunctionBody::NewFromRecycler(ScriptContext * scriptContext, const char16 * displayName, uint displayNameLength, uint displayShortNameOffset, uint nestedCount, - Utf8SourceInfo* sourceInfo, uint uScriptId, Js::LocalFunctionId functionId, Js::PropertyRecordList* boundPropertyRecords, Attributes attributes, FunctionBodyFlags flags + Utf8SourceInfo* sourceInfo, uint uScriptId, Js::LocalFunctionId functionId, Js::PropertyRecordList* boundPropertyRecords, FunctionInfo::Attributes attributes, FunctionBodyFlags flags #ifdef PERF_COUNTERS , bool isDeserializedFunction #endif @@ -407,7 +406,7 @@ namespace Js } FunctionBody * FunctionBody::NewFromRecycler(ScriptContext * scriptContext, const char16 * displayName, uint displayNameLength, uint displayShortNameOffset, uint nestedCount, - Utf8SourceInfo* sourceInfo, uint uFunctionNumber, uint uScriptId, Js::LocalFunctionId functionId, Js::PropertyRecordList* boundPropertyRecords, Attributes attributes, FunctionBodyFlags flags + Utf8SourceInfo* sourceInfo, uint uFunctionNumber, uint uScriptId, Js::LocalFunctionId functionId, Js::PropertyRecordList* boundPropertyRecords, FunctionInfo::Attributes attributes, FunctionBodyFlags flags #ifdef PERF_COUNTERS , bool isDeserializedFunction #endif @@ -423,7 +422,7 @@ namespace Js FunctionBody::FunctionBody(ScriptContext* scriptContext, const char16* displayName, uint displayNameLength, uint displayShortNameOffset, uint nestedCount, Utf8SourceInfo* utf8SourceInfo, uint uFunctionNumber, uint uScriptId, - Js::LocalFunctionId functionId, Js::PropertyRecordList* boundPropertyRecords, Attributes attributes, FunctionBodyFlags flags + Js::LocalFunctionId functionId, Js::PropertyRecordList* boundPropertyRecords, FunctionInfo::Attributes attributes, FunctionBodyFlags flags #ifdef PERF_COUNTERS , bool isDeserializedFunction #endif @@ -854,7 +853,7 @@ namespace Js #if DBG BOOL FunctionBody::IsInterpreterThunk() const { - bool isInterpreterThunk = this->originalEntryPoint == DefaultEntryThunk; + bool isInterpreterThunk = this->GetOriginalEntryPoint_Unchecked() == DefaultEntryThunk; #if DYNAMIC_INTERPRETER_THUNK isInterpreterThunk = isInterpreterThunk || IsDynamicInterpreterThunk(); #endif @@ -864,7 +863,7 @@ namespace Js BOOL FunctionBody::IsDynamicInterpreterThunk() const { #if DYNAMIC_INTERPRETER_THUNK - return this->GetScriptContext()->IsDynamicInterpreterThunk(this->originalEntryPoint); + return this->GetScriptContext()->IsDynamicInterpreterThunk(this->GetOriginalEntryPoint_Unchecked()); #else return FALSE; #endif @@ -1083,21 +1082,22 @@ namespace Js // DeferDeserializeFunctionInfo methods - DeferDeserializeFunctionInfo::DeferDeserializeFunctionInfo(int nestedCount, LocalFunctionId functionId, ByteCodeCache* byteCodeCache, const byte* serializedFunction, Utf8SourceInfo* sourceInfo, ScriptContext* scriptContext, uint functionNumber, const char16* displayName, uint displayNameLength, uint displayShortNameOffset, NativeModule *nativeModule, Attributes attributes) : - FunctionProxy(DefaultDeferredDeserializeThunk, (Attributes)(attributes | DeferredDeserialize), functionId, scriptContext, sourceInfo, functionNumber), + DeferDeserializeFunctionInfo::DeferDeserializeFunctionInfo(int nestedCount, LocalFunctionId functionId, ByteCodeCache* byteCodeCache, const byte* serializedFunction, Utf8SourceInfo* sourceInfo, ScriptContext* scriptContext, uint functionNumber, const char16* displayName, uint displayNameLength, uint displayShortNameOffset, NativeModule *nativeModule, FunctionInfo::Attributes attributes) : + FunctionProxy(scriptContext, sourceInfo, functionNumber), m_cache(byteCodeCache), m_functionBytes(serializedFunction), m_displayName(nullptr), m_displayNameLength(0), m_nativeModule(nativeModule) { + this->functionInfo = RecyclerNew(scriptContext->GetRecycler(), FunctionInfo, DefaultDeferredDeserializeThunk, (FunctionInfo::Attributes)(attributes | FunctionInfo::Attributes::DeferredDeserialize), functionId, this); this->m_defaultEntryPointInfo = RecyclerNew(scriptContext->GetRecycler(), ProxyEntryPointInfo, DefaultDeferredDeserializeThunk); PERF_COUNTER_INC(Code, DeferDeserializeFunctionProxy); SetDisplayName(displayName, displayNameLength, displayShortNameOffset, FunctionProxy::SetDisplayNameFlagsDontCopy); } - DeferDeserializeFunctionInfo* DeferDeserializeFunctionInfo::New(ScriptContext* scriptContext, int nestedCount, LocalFunctionId functionId, ByteCodeCache* byteCodeCache, const byte* serializedFunction, Utf8SourceInfo* sourceInfo, const char16* displayName, uint displayNameLength, uint displayShortNameOffset, NativeModule *nativeModule, Attributes attributes) + DeferDeserializeFunctionInfo* DeferDeserializeFunctionInfo::New(ScriptContext* scriptContext, int nestedCount, LocalFunctionId functionId, ByteCodeCache* byteCodeCache, const byte* serializedFunction, Utf8SourceInfo* sourceInfo, const char16* displayName, uint displayNameLength, uint displayShortNameOffset, NativeModule *nativeModule, FunctionInfo::Attributes attributes) { return RecyclerNewFinalized(scriptContext->GetRecycler(), DeferDeserializeFunctionInfo, @@ -1124,8 +1124,8 @@ namespace Js // ParseableFunctionInfo methods ParseableFunctionInfo::ParseableFunctionInfo(JavascriptMethod entryPoint, int nestedCount, LocalFunctionId functionId, Utf8SourceInfo* sourceInfo, ScriptContext* scriptContext, uint functionNumber, - const char16* displayName, uint displayNameLength, uint displayShortNameOffset, Attributes attributes, Js::PropertyRecordList* propertyRecords) : - FunctionProxy(entryPoint, attributes, functionId, scriptContext, sourceInfo, functionNumber), + const char16* displayName, uint displayNameLength, uint displayShortNameOffset, FunctionInfo::Attributes attributes, Js::PropertyRecordList* propertyRecords) : + FunctionProxy(scriptContext, sourceInfo, functionNumber), #if DYNAMIC_INTERPRETER_THUNK m_dynamicInterpreterThunk(nullptr), #endif @@ -1166,6 +1166,8 @@ namespace Js ,scopeObjectSize(0) #endif { + this->functionInfo = RecyclerNew(scriptContext->GetRecycler(), FunctionInfo, entryPoint, attributes, functionId, this); + if (nestedCount > 0) { nestedArray = RecyclerNewPlusZ(m_scriptContext->GetRecycler(), @@ -1194,11 +1196,11 @@ namespace Js } SetDisplayName(displayName, displayNameLength, displayShortNameOffset); - this->originalEntryPoint = DefaultEntryThunk; + this->SetOriginalEntryPoint(DefaultEntryThunk); } ParseableFunctionInfo* ParseableFunctionInfo::New(ScriptContext* scriptContext, int nestedCount, - LocalFunctionId functionId, Utf8SourceInfo* sourceInfo, const char16* displayName, uint displayNameLength, uint displayShortNameOffset, Js::PropertyRecordList* propertyRecords, Attributes attributes) + LocalFunctionId functionId, Utf8SourceInfo* sourceInfo, const char16* displayName, uint displayNameLength, uint displayShortNameOffset, Js::PropertyRecordList* propertyRecords, FunctionInfo::Attributes attributes) { #ifdef ENABLE_SCRIPT_PROFILING Assert( @@ -1233,7 +1235,7 @@ namespace Js displayName, displayNameLength, displayShortNameOffset, - (Attributes)(attributes | DeferredParse), + (FunctionInfo::Attributes)(attributes | FunctionInfo::Attributes::DeferredParse), propertyRecords); } @@ -1461,10 +1463,12 @@ namespace Js void FunctionProxy::UpdateFunctionBodyImpl(FunctionBody * body) { - Assert(functionBodyImpl == ((FunctionProxy*) this)); + FunctionInfo *functionInfo = this->GetFunctionInfo(); + Assert(functionInfo->GetFunctionProxy() == this); Assert(!this->IsFunctionBody() || body == this); - this->functionBodyImpl = body; - this->attributes = (Attributes)(this->attributes & ~(DeferredParse | DeferredDeserialize)); + functionInfo->SetFunctionProxy(body); + body->SetFunctionInfo(functionInfo); + body->SetAttributes((FunctionInfo::Attributes)(functionInfo->GetAttributes() & ~(FunctionInfo::Attributes::DeferredParse | FunctionInfo::Attributes::DeferredDeserialize))); this->UpdateReferenceInParentFunction(body); } @@ -1488,17 +1492,18 @@ namespace Js // ParseableFunctionInfo * FunctionProxy::EnsureDeserialized() { - FunctionProxy * executionFunctionBody = this->functionBodyImpl; + Assert(this == this->GetFunctionInfo()->GetFunctionProxy()); + FunctionProxy * executionFunctionBody = this; - if (executionFunctionBody == this && IsDeferredDeserializeFunction()) + if (IsDeferredDeserializeFunction()) { // No need to deserialize function body if scriptContext closed because we can't execute it. // Bigger problem is the script engine might have released bytecode file mapping and we can't deserialize. Assert(!m_scriptContext->IsClosed()); executionFunctionBody = ((DeferDeserializeFunctionInfo*) this)->Deserialize(); - this->functionBodyImpl = executionFunctionBody; - Assert(executionFunctionBody->HasBody()); + this->GetFunctionInfo()->SetFunctionProxy(executionFunctionBody); + Assert(executionFunctionBody->GetFunctionInfo()->HasBody()); Assert(executionFunctionBody != this); } @@ -1512,7 +1517,7 @@ namespace Js ScriptFunctionType * FunctionProxy::EnsureDeferredPrototypeType() { - Assert(this->GetFunctionProxy() == this); + Assert(this->GetFunctionInfo()->GetFunctionProxy() == this); return deferredPrototypeType != nullptr ? static_cast(deferredPrototypeType) : AllocDeferredPrototypeType(); } @@ -1619,14 +1624,16 @@ namespace Js FunctionBody* DeferDeserializeFunctionInfo::Deserialize() { - if (functionBodyImpl == (FunctionBody*) this) - { - FunctionBody * body = ByteCodeSerializer::DeserializeFunction(this->m_scriptContext, this); - this->Copy(body); - this->UpdateFunctionBodyImpl(body); - } + Assert(this->GetFunctionInfo()->GetFunctionProxy() == this); + + FunctionBody * body = ByteCodeSerializer::DeserializeFunction(this->m_scriptContext, this); + this->SetLocalFunctionId(body->GetLocalFunctionId()); + this->SetOriginalEntryPoint(body->GetOriginalEntryPoint()); + this->Copy(body); + this->UpdateFunctionBodyImpl(body); - return GetFunctionBody(); + Assert(body->GetFunctionBody() == body); + return body; } // @@ -1675,7 +1682,8 @@ namespace Js FunctionBody* ParseableFunctionInfo::Parse(ScriptFunction ** functionRef, bool isByteCodeDeserialization) { - if ((functionBodyImpl != (FunctionBody*) this) || !IsDeferredParseFunction()) + Assert(this == this->GetFunctionInfo()->GetFunctionProxy()); + if (!IsDeferredParseFunction()) { // If not deferredparsed, the functionBodyImpl and this will be the same, just return the current functionBody. Assert(GetFunctionBody()->IsFunctionParsed()); @@ -1706,10 +1714,10 @@ namespace Js this->GetNestedCount(), this->GetUtf8SourceInfo(), this->m_functionNumber, - this->GetUtf8SourceInfo()->GetSrcInfo()->sourceContextInfo->sourceContextId, /* script id */ - this->functionId, /* function id */ + this->GetUtf8SourceInfo()->GetSrcInfo()->sourceContextInfo->sourceContextId, + this->GetLocalFunctionId(), propertyRecordList, - (Attributes)(this->GetAttributes() & ~(Attributes::DeferredDeserialize | Attributes::DeferredParse)), + (FunctionInfo::Attributes)(this->GetAttributes() & ~(FunctionInfo::Attributes::DeferredDeserialize | FunctionInfo::Attributes::DeferredParse)), Js::FunctionBody::FunctionBodyFlags::Flags_HasNoExplicitReturnValue #ifdef PERF_COUNTERS , false /* is function from deferred deserialized proxy */ @@ -1943,9 +1951,12 @@ namespace Js this->UpdateFunctionBodyImpl(funcBody); this->m_hasBeenParsed = true; + returnFunctionBody = funcBody; + } + else + { + returnFunctionBody = this->GetFunctionBody(); } - - returnFunctionBody = GetFunctionBody(); LEAVE_PINNED_SCOPE(); @@ -1973,10 +1984,10 @@ namespace Js this->GetNestedCount(), this->GetUtf8SourceInfo(), this->m_functionNumber, - this->GetUtf8SourceInfo()->GetSrcInfo()->sourceContextInfo->sourceContextId, /* script id */ - this->functionId, /* function id */ + this->GetUtf8SourceInfo()->GetSrcInfo()->sourceContextInfo->sourceContextId, + this->GetLocalFunctionId(), propertyRecordList, - (Attributes)(this->GetAttributes() & ~(Attributes::DeferredDeserialize | Attributes::DeferredParse)), + (FunctionInfo::Attributes)(this->GetAttributes() & ~(FunctionInfo::Attributes::DeferredDeserialize | FunctionInfo::Attributes::DeferredParse)), Js::FunctionBody::FunctionBodyFlags::Flags_HasNoExplicitReturnValue #ifdef PERF_COUNTERS , false /* is function from deferred deserialized proxy */ @@ -2046,7 +2057,9 @@ namespace Js UpdateFunctionBodyImpl(funcBody); m_hasBeenParsed = true; - returnFunctionBody = GetFunctionBody(); + Assert(funcBody->GetFunctionBody() == funcBody); + + returnFunctionBody = funcBody; LEAVE_PINNED_SCOPE(); @@ -2302,17 +2315,14 @@ namespace Js #if DBG_DUMP if (PHASE_TRACE1(Js::FunctionSourceInfoParsePhase)) { - if (this->HasBody()) + Assert(this->GetFunctionInfo()->HasBody()); + if (this->IsFunctionBody()) { - FunctionProxy* proxy = this->GetFunctionProxy(); - if (proxy->IsFunctionBody()) - { - FunctionBody* functionBody = this->GetFunctionBody(); - Assert( functionBody != nullptr ); + FunctionBody* functionBody = this->GetFunctionBody(); + Assert( functionBody != nullptr ); - functionBody->PrintStatementSourceLineFromStartOffset(functionBody->StartInDocument()); - Output::Flush(); - } + functionBody->PrintStatementSourceLineFromStartOffset(functionBody->StartInDocument()); + Output::Flush(); } } #endif @@ -2925,7 +2935,7 @@ namespace Js BOOL FunctionBody::IsNativeOriginalEntryPoint() const { #if ENABLE_NATIVE_CODEGEN - return this->GetScriptContext()->IsNativeAddress((void*)this->originalEntryPoint); + return this->GetScriptContext()->IsNativeAddress(this->GetOriginalEntryPoint_Unchecked()); #else return false; #endif @@ -2936,13 +2946,11 @@ namespace Js const FunctionEntryPointInfo *const simpleJitEntryPointInfo = GetSimpleJitEntryPointInfo(); return simpleJitEntryPointInfo && - reinterpret_cast(simpleJitEntryPointInfo->GetNativeAddress()) == originalEntryPoint; + reinterpret_cast(simpleJitEntryPointInfo->GetNativeAddress()) == GetOriginalEntryPoint_Unchecked(); } void FunctionProxy::Finalize(bool isShutdown) { - __super::Finalize(isShutdown); - this->CleanupFunctionProxyCounters(); } @@ -2986,7 +2994,7 @@ namespace Js bool FunctionProxy::HasValidNonProfileEntryPoint() const { JavascriptMethod directEntryPoint = this->GetDefaultEntryPointInfo()->jsMethod; - JavascriptMethod originalEntryPoint = this->originalEntryPoint; + JavascriptMethod originalEntryPoint = this->GetOriginalEntryPoint_Unchecked(); // Check the direct entry point to see if it is codegen thunk // if it is not, the background codegen thread has updated both original entry point and direct entry point @@ -3006,11 +3014,13 @@ namespace Js bool FunctionProxy::HasValidProfileEntryPoint() const { JavascriptMethod directEntryPoint = this->GetDefaultEntryPointInfo()->jsMethod; - if (this->originalEntryPoint == DefaultDeferredParsingThunk) + JavascriptMethod originalEntryPoint = this->GetOriginalEntryPoint_Unchecked(); + + if (originalEntryPoint == DefaultDeferredParsingThunk) { return directEntryPoint == ProfileDeferredParsingThunk; } - if (this->originalEntryPoint == DefaultDeferredDeserializeThunk) + if (originalEntryPoint == DefaultDeferredDeserializeThunk) { return directEntryPoint == ProfileDeferredDeserializeThunk; } @@ -3067,28 +3077,31 @@ namespace Js #endif this->SetEntryPoint(this->GetDefaultEntryPointInfo(), m_scriptContext->DeferredParsingThunk); - originalEntryPoint = DefaultDeferredParsingThunk; + this->SetOriginalEntryPoint(DefaultDeferredParsingThunk); } void ParseableFunctionInfo::SetInitialDefaultEntryPoint() { #ifdef ENABLE_SCRIPT_PROFILING Assert(m_scriptContext->CurrentThunk == ProfileEntryThunk || m_scriptContext->CurrentThunk == DefaultEntryThunk); - Assert(originalEntryPoint == DefaultDeferredParsingThunk || originalEntryPoint == ProfileDeferredParsingThunk || - originalEntryPoint == DefaultDeferredDeserializeThunk || originalEntryPoint == ProfileDeferredDeserializeThunk || - originalEntryPoint == DefaultEntryThunk || originalEntryPoint == ProfileEntryThunk); + Assert(this->GetOriginalEntryPoint_Unchecked() == DefaultDeferredParsingThunk || + this->GetOriginalEntryPoint_Unchecked() == ProfileDeferredParsingThunk || + this->GetOriginalEntryPoint_Unchecked() == DefaultDeferredDeserializeThunk || + this->GetOriginalEntryPoint_Unchecked() == ProfileDeferredDeserializeThunk || + this->GetOriginalEntryPoint_Unchecked() == DefaultEntryThunk || + this->GetOriginalEntryPoint_Unchecked() == ProfileEntryThunk); #else Assert(m_scriptContext->CurrentThunk == DefaultEntryThunk); - Assert(originalEntryPoint == DefaultDeferredParsingThunk || - originalEntryPoint == DefaultDeferredDeserializeThunk || - originalEntryPoint == DefaultEntryThunk); + Assert(this->GetOriginalEntryPoint_Unchecked() == DefaultDeferredParsingThunk || + this->GetOriginalEntryPoint_Unchecked() == DefaultDeferredDeserializeThunk || + this->GetOriginalEntryPoint_Unchecked() == DefaultEntryThunk); #endif Assert(this->m_defaultEntryPointInfo != nullptr); // CONSIDER: we can optimize this to generate the dynamic interpreter thunk up front // If we know that we are in the defer parsing thunk already this->SetEntryPoint(this->GetDefaultEntryPointInfo(), m_scriptContext->CurrentThunk); - this->originalEntryPoint = DefaultEntryThunk; + this->SetOriginalEntryPoint(DefaultEntryThunk); } void FunctionBody::SetCheckCodeGenEntryPoint(FunctionEntryPointInfo* entryPointInfo, JavascriptMethod entryPoint) @@ -3114,17 +3127,17 @@ namespace Js if (m_isAsmJsFunction) { - this->originalEntryPoint = this->m_scriptContext->GetNextDynamicAsmJsInterpreterThunk(&this->m_dynamicInterpreterThunk); + this->SetOriginalEntryPoint(this->m_scriptContext->GetNextDynamicAsmJsInterpreterThunk(&this->m_dynamicInterpreterThunk)); } else { - this->originalEntryPoint = this->m_scriptContext->GetNextDynamicInterpreterThunk(&this->m_dynamicInterpreterThunk); + this->SetOriginalEntryPoint(this->m_scriptContext->GetNextDynamicInterpreterThunk(&this->m_dynamicInterpreterThunk)); } JS_ETW(EtwTrace::LogMethodInterpreterThunkLoadEvent(this)); } else { - this->originalEntryPoint = (JavascriptMethod)InterpreterThunkEmitter::ConvertToEntryPoint(this->m_dynamicInterpreterThunk); + this->SetOriginalEntryPoint((JavascriptMethod)InterpreterThunkEmitter::ConvertToEntryPoint(this->m_dynamicInterpreterThunk)); } } @@ -3142,18 +3155,18 @@ namespace Js if (InterpreterStackFrame::IsDelayDynamicInterpreterThunk(this->GetEntryPoint(entryPointInfo))) { // We are not doing code gen on this function, just change the entry point directly - Assert(InterpreterStackFrame::IsDelayDynamicInterpreterThunk(originalEntryPoint)); + Assert(InterpreterStackFrame::IsDelayDynamicInterpreterThunk(this->GetOriginalEntryPoint_Unchecked())); GenerateDynamicInterpreterThunk(); - this->SetEntryPoint(entryPointInfo, originalEntryPoint); + this->SetEntryPoint(entryPointInfo, this->GetOriginalEntryPoint_Unchecked()); } else if (this->GetEntryPoint(entryPointInfo) == ProfileEntryThunk) { // We are not doing codegen on this function, just change the entry point directly // Don't replace the profile entry thunk - Assert(InterpreterStackFrame::IsDelayDynamicInterpreterThunk(originalEntryPoint)); + Assert(InterpreterStackFrame::IsDelayDynamicInterpreterThunk(this->GetOriginalEntryPoint_Unchecked())); GenerateDynamicInterpreterThunk(); } - else if (InterpreterStackFrame::IsDelayDynamicInterpreterThunk(originalEntryPoint)) + else if (InterpreterStackFrame::IsDelayDynamicInterpreterThunk(this->GetOriginalEntryPoint_Unchecked())) { JsUtil::JobProcessor * jobProcessor = this->GetScriptContext()->GetThreadContext()->GetJobProcessor(); if (jobProcessor->ProcessesInBackground()) @@ -3161,7 +3174,7 @@ namespace Js JsUtil::BackgroundJobProcessor * backgroundJobProcessor = static_cast(jobProcessor); AutoCriticalSection autocs(backgroundJobProcessor->GetCriticalSection()); // Check again under lock - if (InterpreterStackFrame::IsDelayDynamicInterpreterThunk(originalEntryPoint)) + if (InterpreterStackFrame::IsDelayDynamicInterpreterThunk(this->GetOriginalEntryPoint_Unchecked())) { // If the original entry point is DelayDynamicInterpreterThunk then there must be a version of this // function being codegen'd. @@ -3177,7 +3190,7 @@ namespace Js GenerateDynamicInterpreterThunk(); } } - return this->originalEntryPoint; + return this->GetOriginalEntryPoint_Unchecked(); } #endif @@ -3195,7 +3208,7 @@ namespace Js // keep originalEntryPoint updated with the latest known good native entry point if (entryPointInfo == this->GetDefaultEntryPointInfo()) { - this->originalEntryPoint = originalEntryPoint; + this->SetOriginalEntryPoint(originalEntryPoint); } if (entryPointInfo->entryPointIndex == 0 && this->NeedEnsureDynamicProfileInfo()) @@ -4279,11 +4292,11 @@ namespace Js if (!IsIntermediateCodeGenThunk(defaultEntryPointInfo->jsMethod) && defaultEntryPointInfo->jsMethod != DynamicProfileInfo::EnsureDynamicProfileInfoThunk) { - if (this->originalEntryPoint == DefaultDeferredParsingThunk) + if (this->GetOriginalEntryPoint_Unchecked() == DefaultDeferredParsingThunk) { defaultEntryPointInfo->jsMethod = ProfileDeferredParsingThunk; } - else if (this->originalEntryPoint == DefaultDeferredDeserializeThunk) + else if (this->GetOriginalEntryPoint_Unchecked() == DefaultDeferredDeserializeThunk) { defaultEntryPointInfo->jsMethod = ProfileDeferredDeserializeThunk; } @@ -4305,7 +4318,7 @@ namespace Js if (!this->HasValidEntryPoint()) { OUTPUT_TRACE_DEBUGONLY(Js::ScriptProfilerPhase, _u("FunctionBody::SetEntryToProfileMode, Assert due to HasValidEntryPoint(), directEntrypoint : 0x%0IX, originalentrypoint : 0x%0IX\n"), - this->GetDefaultEntryPointInfo()->jsMethod, this->originalEntryPoint); + this->GetDefaultEntryPointInfo()->jsMethod, this->GetOriginalEntryPoint()); AssertMsg(false, "Not a valid EntryPoint"); } @@ -4354,9 +4367,9 @@ namespace Js #endif // Store the originalEntryPoint to restore it back immediately. - JavascriptMethod originalEntryPoint = this->originalEntryPoint; + JavascriptMethod originalEntryPoint = this->GetOriginalEntryPoint_Unchecked(); this->CreateNewDefaultEntryPoint(); - this->originalEntryPoint = originalEntryPoint; + this->SetOriginalEntryPoint(originalEntryPoint); if (this->m_defaultEntryPointInfo) { this->GetDefaultFunctionEntryPointInfo()->entryPointIndex = 0; @@ -4493,11 +4506,11 @@ namespace Js defaultEntryPointInfo->jsMethod = DefaultDeferredParsingThunk; } - this->originalEntryPoint = DefaultDeferredParsingThunk; + this->SetOriginalEntryPoint(DefaultDeferredParsingThunk); // Abandon the shared type so a new function will get a new one this->deferredPrototypeType = nullptr; - this->attributes = (FunctionInfo::Attributes) (this->attributes | FunctionInfo::Attributes::DeferredParse); + this->SetAttributes((FunctionInfo::Attributes) (this->GetAttributes() | FunctionInfo::Attributes::DeferredParse)); } // Set other state back to before parse as well @@ -4541,7 +4554,7 @@ namespace Js this->entryPoints->ClearAndZero(); this->CreateNewDefaultEntryPoint(); - this->originalEntryPoint = DefaultEntryThunk; + this->SetOriginalEntryPoint(DefaultEntryThunk); m_defaultEntryPointInfo->jsMethod = m_scriptContext->CurrentThunk; if (this->deferredPrototypeType) @@ -4556,12 +4569,12 @@ namespace Js void FunctionBody::AddDeferParseAttribute() { - this->attributes = (FunctionInfo::Attributes) (this->attributes | DeferredParse); + this->SetAttributes((FunctionInfo::Attributes) (this->GetAttributes() | FunctionInfo::Attributes::DeferredParse)); } void FunctionBody::RemoveDeferParseAttribute() { - this->attributes = (FunctionInfo::Attributes) (this->attributes & (~DeferredParse)); + this->SetAttributes((FunctionInfo::Attributes) (this->GetAttributes() & (~FunctionInfo::Attributes::DeferredParse))); } Js::DebuggerScope * FunctionBody::GetDiagCatchScopeObjectAt(int byteCodeOffset) @@ -7473,7 +7486,7 @@ namespace Js void FunctionBody::InitDisableInlineApply() { SetDisableInlineApply( - (this->functionId != Js::Constants::NoFunctionId && PHASE_OFF(Js::InlinePhase, this)) || + (this->GetLocalFunctionId() != Js::Constants::NoFunctionId && PHASE_OFF(Js::InlinePhase, this)) || PHASE_OFF(Js::InlineApplyPhase, this)); } @@ -9035,7 +9048,7 @@ namespace Js { if (this->IsCodeGenDone()) { - Assert(this->functionProxy->HasBody()); + Assert(this->functionProxy->GetFunctionInfo()->HasBody()); #if ENABLE_NATIVE_CODEGEN if (nullptr != this->inlineeFrameMap) { diff --git a/lib/Runtime/Base/FunctionBody.h b/lib/Runtime/Base/FunctionBody.h index b50db983bce..6f001bbf664 100644 --- a/lib/Runtime/Base/FunctionBody.h +++ b/lib/Runtime/Base/FunctionBody.h @@ -1299,7 +1299,7 @@ namespace Js // The function need not have been compiled yet- it could be parsed or compiled // at a later time // - class FunctionProxy : public FunctionInfo + class FunctionProxy : public FinalizableObject { static CriticalSection GlobalLock; public: @@ -1308,9 +1308,8 @@ namespace Js typedef JsUtil::List FunctionTypeWeakRefList; protected: - FunctionProxy(JavascriptMethod entryPoint, Attributes attributes, - LocalFunctionId functionId, ScriptContext* scriptContext, Utf8SourceInfo* utf8SourceInfo, uint functionNumber); - DEFINE_VTABLE_CTOR_NO_REGISTER(FunctionProxy, FunctionInfo); + FunctionProxy(ScriptContext* scriptContext, Utf8SourceInfo* utf8SourceInfo, uint functionNumber); + DEFINE_VTABLE_CTOR_NOBASE(FunctionProxy); enum class AuxPointerType : uint8 { DeferredStubs = 0, @@ -1348,6 +1347,8 @@ namespace Js void* GetAuxPtrWithLock(AuxPointerType e) const; void SetAuxPtr(AuxPointerType e, void* ptr); + FunctionInfo *functionInfo; + public: enum SetDisplayNameFlags { @@ -1356,6 +1357,54 @@ namespace Js SetDisplayNameFlagsRecyclerAllocated = 2 }; + virtual void Dispose(bool isShutdown) override + { + } + + virtual void Mark(Recycler *recycler) override { AssertMsg(false, "Mark called on object that isn't TrackableObject"); } + + static const uint GetOffsetOfFunctionInfo() { return offsetof(FunctionProxy, functionInfo); } + FunctionInfo * GetFunctionInfo() const + { + return this->functionInfo; + } + void SetFunctionInfo(FunctionInfo * functionInfo) + { + this->functionInfo = functionInfo; + } + + LocalFunctionId GetLocalFunctionId() const; + void SetLocalFunctionId(LocalFunctionId functionId); + + ParseableFunctionInfo* GetParseableFunctionInfo() const; + ParseableFunctionInfo** GetParseableFunctionInfoRef() const; + DeferDeserializeFunctionInfo* GetDeferDeserializeFunctionInfo() const; + FunctionBody * GetFunctionBody() const; + + void VerifyOriginalEntryPoint() const; + JavascriptMethod GetOriginalEntryPoint() const; + JavascriptMethod GetOriginalEntryPoint_Unchecked() const; + void SetOriginalEntryPoint(const JavascriptMethod originalEntryPoint); + + bool IsAsync() const; + bool IsDeferred() const; + bool IsLambda() const; + bool IsConstructor() const; + bool IsGenerator() const; + bool IsClassConstructor() const; + bool IsClassMethod() const; + bool IsModule() const; + bool HasSuperReference() const; + bool IsCoroutine() const; + bool GetCapturesThis() const; + void SetCapturesThis(); + bool GetEnclosedByGlobalFunc() const; + void SetEnclosedByGlobalFunc(); + BOOL IsDeferredDeserializeFunction() const; + BOOL IsDeferredParseFunction() const; + FunctionInfo::Attributes GetAttributes() const; + void SetAttributes(FunctionInfo::Attributes attributes); + Recycler* GetRecycler() const; uint32 GetSourceContextId() const; char16* GetDebugNumberSet(wchar(&bufferToWriteTo)[MAX_FUNCTION_BODY_DEBUG_STRING_SIZE]) const; @@ -1472,6 +1521,198 @@ namespace Js ScriptFunctionType * AllocDeferredPrototypeType(); }; + inline Js::LocalFunctionId FunctionProxy::GetLocalFunctionId() const + { + Assert(GetFunctionInfo()); + return GetFunctionInfo()->GetLocalFunctionId(); + } + + inline void FunctionProxy::SetLocalFunctionId(LocalFunctionId functionId) + { + Assert(GetFunctionInfo()); + Assert(GetFunctionInfo()->GetFunctionProxy() == this); + return GetFunctionInfo()->SetLocalFunctionId(functionId); + } + + inline void FunctionProxy::VerifyOriginalEntryPoint() const + { + Assert(GetFunctionInfo()); + Assert(GetFunctionInfo()->GetFunctionProxy() == this); + return GetFunctionInfo()->VerifyOriginalEntryPoint(); + } + + inline JavascriptMethod FunctionProxy::GetOriginalEntryPoint() const + { + Assert(GetFunctionInfo()); + Assert(GetFunctionInfo()->GetFunctionProxy() == this); + return GetFunctionInfo()->GetOriginalEntryPoint(); + } + + inline JavascriptMethod FunctionProxy::GetOriginalEntryPoint_Unchecked() const + { + Assert(GetFunctionInfo()); + Assert(GetFunctionInfo()->GetFunctionProxy() == this); + return GetFunctionInfo()->GetOriginalEntryPoint_Unchecked(); + } + + inline void FunctionProxy::SetOriginalEntryPoint(const JavascriptMethod originalEntryPoint) + { + Assert(GetFunctionInfo()); + Assert(GetFunctionInfo()->GetFunctionProxy() == this); + GetFunctionInfo()->SetOriginalEntryPoint(originalEntryPoint); + } + + inline bool FunctionProxy::IsAsync() const + { + Assert(GetFunctionInfo()); + Assert(GetFunctionInfo()->GetFunctionProxy() == this); + return GetFunctionInfo()->IsAsync(); + } + + inline bool FunctionProxy::IsDeferred() const + { + Assert(GetFunctionInfo()); + Assert(GetFunctionInfo()->GetFunctionProxy() == this); + return GetFunctionInfo()->IsDeferred(); + } + + inline bool FunctionProxy::IsConstructor() const + { + Assert(GetFunctionInfo()); + Assert(GetFunctionInfo()->GetFunctionProxy() == this); + return GetFunctionInfo()->IsConstructor(); + } + + inline bool FunctionProxy::IsGenerator() const + { + Assert(GetFunctionInfo()); + Assert(GetFunctionInfo()->GetFunctionProxy() == this); + return GetFunctionInfo()->IsGenerator(); + } + + inline bool FunctionProxy::HasSuperReference() const + { + Assert(GetFunctionInfo()); + Assert(GetFunctionInfo()->GetFunctionProxy() == this); + return GetFunctionInfo()->HasSuperReference(); + } + + inline bool FunctionProxy::IsCoroutine() const + { + Assert(GetFunctionInfo()); + Assert(GetFunctionInfo()->GetFunctionProxy() == this); + return GetFunctionInfo()->IsCoroutine(); + } + + inline bool FunctionProxy::GetCapturesThis() const + { + Assert(GetFunctionInfo()); + Assert(GetFunctionInfo()->GetFunctionProxy() == this); + return GetFunctionInfo()->GetCapturesThis(); + } + + inline void FunctionProxy::SetCapturesThis() + { + Assert(GetFunctionInfo()); + Assert(GetFunctionInfo()->GetFunctionProxy() == this); + GetFunctionInfo()->SetCapturesThis(); + } + + inline bool FunctionProxy::GetEnclosedByGlobalFunc() const + { + Assert(GetFunctionInfo()); + Assert(GetFunctionInfo()->GetFunctionProxy() == this); + return GetFunctionInfo()->GetEnclosedByGlobalFunc(); + } + + inline void FunctionProxy::SetEnclosedByGlobalFunc() + { + Assert(GetFunctionInfo()); + Assert(GetFunctionInfo()->GetFunctionProxy() == this); + GetFunctionInfo()->SetEnclosedByGlobalFunc(); + } + + inline BOOL FunctionProxy::IsDeferredDeserializeFunction() const + { + Assert(GetFunctionInfo()); + Assert(GetFunctionInfo()->GetFunctionProxy() == this); + return GetFunctionInfo()->IsDeferredDeserializeFunction(); + } + + inline BOOL FunctionProxy::IsDeferredParseFunction() const + { + Assert(GetFunctionInfo()); + Assert(GetFunctionInfo()->GetFunctionProxy() == this); + return GetFunctionInfo()->IsDeferredParseFunction(); + } + + inline FunctionInfo::Attributes FunctionProxy::GetAttributes() const + { + Assert(GetFunctionInfo()); + Assert(GetFunctionInfo()->GetFunctionProxy() == this); + return GetFunctionInfo()->GetAttributes(); + } + + inline void FunctionProxy::SetAttributes(FunctionInfo::Attributes attributes) + { + Assert(GetFunctionInfo()); + Assert(GetFunctionInfo()->GetFunctionProxy() == this); + GetFunctionInfo()->SetAttributes(attributes); + } + + inline ParseableFunctionInfo** FunctionProxy::GetParseableFunctionInfoRef() const + { + Assert(GetFunctionInfo()); + Assert(GetFunctionInfo()->GetFunctionProxy() == this); + return GetFunctionInfo()->GetParseableFunctionInfoRef(); + } + + inline bool FunctionProxy::IsLambda() const + { + Assert(GetFunctionInfo()); + Assert(GetFunctionInfo()->GetFunctionProxy() == this); + return GetFunctionInfo()->IsLambda(); + } + + inline bool FunctionProxy::IsClassConstructor() const + { + Assert(GetFunctionInfo()); + Assert(GetFunctionInfo()->GetFunctionProxy() == this); + return GetFunctionInfo()->IsClassConstructor(); + } + + inline bool FunctionProxy::IsClassMethod() const + { + Assert(GetFunctionInfo()); + Assert(GetFunctionInfo()->GetFunctionProxy() == this); + return GetFunctionInfo()->IsClassMethod(); + } + + inline bool FunctionProxy::IsModule() const + { + Assert(GetFunctionInfo()); + Assert(GetFunctionInfo()->GetFunctionProxy() == this); + return GetFunctionInfo()->IsModule(); + } + + inline ParseableFunctionInfo* FunctionProxy::GetParseableFunctionInfo() const + { + Assert(!IsDeferredDeserializeFunction()); + return (ParseableFunctionInfo*)this; + } + + inline DeferDeserializeFunctionInfo* FunctionProxy::GetDeferDeserializeFunctionInfo() const + { + Assert(IsDeferredDeserializeFunction()); + return (DeferDeserializeFunctionInfo*)this; + } + + inline FunctionBody * FunctionProxy::GetFunctionBody() const + { + Assert(IsFunctionBody()); + return (FunctionBody*)this; + } + // Represents a function from the byte code cache which will // be deserialized upon use class DeferDeserializeFunctionInfo: public FunctionProxy @@ -1479,9 +1720,9 @@ namespace Js friend struct ByteCodeSerializer; private: - DeferDeserializeFunctionInfo(int nestedFunctionCount, LocalFunctionId functionId, ByteCodeCache* byteCodeCache, const byte* serializedFunction, Utf8SourceInfo* sourceInfo, ScriptContext* scriptContext, uint functionNumber, const char16* displayName, uint displayNameLength, uint displayShortNameOffset, NativeModule *nativeModule, Attributes attributes); + DeferDeserializeFunctionInfo(int nestedFunctionCount, LocalFunctionId functionId, ByteCodeCache* byteCodeCache, const byte* serializedFunction, Utf8SourceInfo* sourceInfo, ScriptContext* scriptContext, uint functionNumber, const char16* displayName, uint displayNameLength, uint displayShortNameOffset, NativeModule *nativeModule, FunctionInfo::Attributes attributes); public: - static DeferDeserializeFunctionInfo* New(ScriptContext* scriptContext, int nestedFunctionCount, LocalFunctionId functionId, ByteCodeCache* byteCodeCache, const byte* serializedFunction, Utf8SourceInfo* utf8SourceInfo, const char16* displayName, uint displayNameLength, uint displayShortNameOffset, NativeModule *nativeModule, Attributes attributes); + static DeferDeserializeFunctionInfo* New(ScriptContext* scriptContext, int nestedFunctionCount, LocalFunctionId functionId, ByteCodeCache* byteCodeCache, const byte* serializedFunction, Utf8SourceInfo* utf8SourceInfo, const char16* displayName, uint displayNameLength, uint displayShortNameOffset, NativeModule *nativeModule, FunctionInfo::Attributes attributes); virtual void Finalize(bool isShutdown) override; FunctionBody* Deserialize(); @@ -1506,7 +1747,7 @@ namespace Js friend class ByteCodeBufferReader; protected: - ParseableFunctionInfo(JavascriptMethod method, int nestedFunctionCount, LocalFunctionId functionId, Utf8SourceInfo* sourceInfo, ScriptContext* scriptContext, uint functionNumber, const char16* displayName, uint m_displayNameLength, uint displayShortNameOffset, Attributes attributes, Js::PropertyRecordList* propertyRecordList); + ParseableFunctionInfo(JavascriptMethod method, int nestedFunctionCount, LocalFunctionId functionId, Utf8SourceInfo* sourceInfo, ScriptContext* scriptContext, uint functionNumber, const char16* displayName, uint m_displayNameLength, uint displayShortNameOffset, FunctionInfo::Attributes attributes, Js::PropertyRecordList* propertyRecordList); public: struct NestedArray @@ -1535,7 +1776,7 @@ namespace Js uint GetNestedCount() const { return nestedArray == nullptr ? 0 : nestedArray->nestedCount; } public: - static ParseableFunctionInfo* New(ScriptContext* scriptContext, int nestedFunctionCount, LocalFunctionId functionId, Utf8SourceInfo* utf8SourceInfo, const char16* displayName, uint m_displayNameLength, uint displayShortNameOffset, Js::PropertyRecordList* propertyRecordList, Attributes attributes); + static ParseableFunctionInfo* New(ScriptContext* scriptContext, int nestedFunctionCount, LocalFunctionId functionId, Utf8SourceInfo* utf8SourceInfo, const char16* displayName, uint m_displayNameLength, uint displayShortNameOffset, Js::PropertyRecordList* propertyRecordList, FunctionInfo::Attributes attributes); DEFINE_VTABLE_CTOR_NO_REGISTER(ParseableFunctionInfo, FunctionProxy); FunctionBody* Parse(ScriptFunction ** functionRef = nullptr, bool isByteCodeDeserialization = false); @@ -1723,12 +1964,6 @@ namespace Js void SetNestedFunc(FunctionProxy* nestedFunc, uint index, uint32 flags); void ClearNestedFunctionParentFunctionReference(); - void SetCapturesThis() { attributes = (Attributes)(attributes | Attributes::CapturesThis); } - bool GetCapturesThis() { return (attributes & Attributes::CapturesThis) != 0; } - - void SetEnclosedByGlobalFunc() { attributes = (Attributes)(attributes | Attributes::EnclosedByGlobalFunc ); } - bool GetEnclosedByGlobalFunc() { return (attributes & Attributes::EnclosedByGlobalFunc) != 0; } - void BuildDeferredStubs(ParseNode *pnodeFnc); DeferredFunctionStub *GetDeferredStubs() const { return static_cast(this->GetAuxPtr(AuxPointerType::DeferredStubs)); } void SetDeferredStubs(DeferredFunctionStub *stub) { this->SetAuxPtr(AuxPointerType::DeferredStubs, stub); } @@ -2194,7 +2429,7 @@ namespace Js #endif FunctionBody(ScriptContext* scriptContext, const char16* displayName, uint displayNameLength, uint displayShortNameOffset, uint nestedCount, Utf8SourceInfo* sourceInfo, - uint uFunctionNumber, uint uScriptId, Js::LocalFunctionId functionId, Js::PropertyRecordList* propRecordList, Attributes attributes, FunctionBodyFlags flags + uint uFunctionNumber, uint uScriptId, Js::LocalFunctionId functionId, Js::PropertyRecordList* propRecordList, FunctionInfo::Attributes attributes, FunctionBodyFlags flags #ifdef PERF_COUNTERS , bool isDeserializedFunction = false #endif @@ -2213,7 +2448,7 @@ namespace Js public: FunctionBody(ByteCodeCache* cache, Utf8SourceInfo* sourceInfo, ScriptContext* scriptContext): - ParseableFunctionInfo((JavascriptMethod) nullptr, 0, (LocalFunctionId) 0, sourceInfo, scriptContext, 0, nullptr, 0, 0, None, nullptr) + ParseableFunctionInfo((JavascriptMethod) nullptr, 0, (LocalFunctionId) 0, sourceInfo, scriptContext, 0, nullptr, 0, 0, FunctionInfo::Attributes::None, nullptr) { // Dummy constructor- does nothing // Must be stack allocated @@ -2221,14 +2456,14 @@ namespace Js } static FunctionBody * NewFromRecycler(Js::ScriptContext * scriptContext, const char16 * displayName, uint displayNameLength, uint displayShortNameOffset, uint nestedCount, - Utf8SourceInfo* sourceInfo, uint uScriptId, Js::LocalFunctionId functionId, Js::PropertyRecordList* boundPropertyRecords, Attributes attributes + Utf8SourceInfo* sourceInfo, uint uScriptId, Js::LocalFunctionId functionId, Js::PropertyRecordList* boundPropertyRecords, FunctionInfo::Attributes attributes , FunctionBodyFlags flags #ifdef PERF_COUNTERS , bool isDeserializedFunction #endif ); static FunctionBody * NewFromRecycler(Js::ScriptContext * scriptContext, const char16 * displayName, uint displayNameLength, uint displayShortNameOffset, uint nestedCount, - Utf8SourceInfo* sourceInfo, uint uFunctionNumber, uint uScriptId, Js::LocalFunctionId functionId, Js::PropertyRecordList* boundPropertyRecords, Attributes attributes + Utf8SourceInfo* sourceInfo, uint uFunctionNumber, uint uScriptId, Js::LocalFunctionId functionId, Js::PropertyRecordList* boundPropertyRecords, FunctionInfo::Attributes attributes , FunctionBodyFlags flags #ifdef PERF_COUNTERS , bool isDeserializedFunction @@ -2496,8 +2731,6 @@ namespace Js void CleanupPerfCounter(); #endif - virtual void Dispose(bool isShutdown) override { } - bool HasRejit() const { if(this->entryPoints) @@ -2671,7 +2904,7 @@ namespace Js void SetDisableInlineApply(bool set); bool IsInlineSpreadDisabled() const { return disableInlineSpread; } - void InitDisableInlineSpread() { disableInlineSpread = this->functionId != Js::Constants::NoFunctionId && PHASE_OFF(Js::InlinePhase, this); } + void InitDisableInlineSpread() { disableInlineSpread = this->GetLocalFunctionId() != Js::Constants::NoFunctionId && PHASE_OFF(Js::InlinePhase, this); } void SetDisableInlineSpread(bool set) { disableInlineSpread = set; } bool CheckCalleeContextForInlining(FunctionProxy* calleeFunctionProxy); diff --git a/lib/Runtime/Base/FunctionInfo.cpp b/lib/Runtime/Base/FunctionInfo.cpp index ae9f93c7f02..a6c4cb45b7d 100644 --- a/lib/Runtime/Base/FunctionInfo.cpp +++ b/lib/Runtime/Base/FunctionInfo.cpp @@ -40,8 +40,7 @@ namespace Js FunctionBody * FunctionInfo::GetFunctionBody() const { - Assert(functionBodyImpl == nullptr || functionBodyImpl->IsFunctionBody()); - return (FunctionBody *)functionBodyImpl; + return functionBodyImpl == nullptr ? nullptr : functionBodyImpl->GetFunctionBody(); } FunctionInfo::Attributes FunctionInfo::GetAttributes(Js::RecyclableObject * function) diff --git a/lib/Runtime/Base/FunctionInfo.h b/lib/Runtime/Base/FunctionInfo.h index 89f7c4cff73..47b946b1a46 100644 --- a/lib/Runtime/Base/FunctionInfo.h +++ b/lib/Runtime/Base/FunctionInfo.h @@ -39,9 +39,14 @@ namespace Js Module = 0x20000, // The function is the function body wrapper for a module EnclosedByGlobalFunc = 0x40000, }; - FunctionInfo(JavascriptMethod entryPoint, Attributes attributes = None, LocalFunctionId functionId = Js::Constants::NoFunctionId, FunctionProxy* functionBodyImpl = NULL); + FunctionInfo(JavascriptMethod entryPoint, Attributes attributes = None, LocalFunctionId functionId = Js::Constants::NoFunctionId, FunctionProxy* functionBodyImpl = nullptr); static DWORD GetFunctionBodyImplOffset() { return offsetof(FunctionInfo, functionBodyImpl); } + static BYTE GetOffsetOfFunctionProxy() + { + CompileAssert(offsetof(FunctionInfo, functionBodyImpl) <= UCHAR_MAX); + return offsetof(FunctionInfo, functionBodyImpl); + } static DWORD GetAttributesOffset() { return offsetof(FunctionInfo, attributes); } void VerifyOriginalEntryPoint() const; @@ -73,10 +78,14 @@ namespace Js { return functionBodyImpl; } + void SetFunctionProxy(FunctionProxy * proxy) + { + functionBodyImpl = proxy; + } ParseableFunctionInfo* GetParseableFunctionInfo() const { - Assert(functionBodyImpl == NULL || !IsDeferredDeserializeFunction()); - return (ParseableFunctionInfo*) functionBodyImpl; + Assert(functionBodyImpl == nullptr || !IsDeferredDeserializeFunction()); + return (ParseableFunctionInfo*)functionBodyImpl; } ParseableFunctionInfo** GetParseableFunctionInfoRef() const { @@ -85,19 +94,23 @@ namespace Js } DeferDeserializeFunctionInfo* GetDeferDeserializeFunctionInfo() const { - Assert(functionBodyImpl == NULL || IsDeferredDeserializeFunction()); + Assert(functionBodyImpl == nullptr || IsDeferredDeserializeFunction()); return (DeferDeserializeFunctionInfo*)functionBodyImpl; } FunctionBody * GetFunctionBody() const; Attributes GetAttributes() const { return attributes; } static Attributes GetAttributes(Js::RecyclableObject * function); - Js::LocalFunctionId GetLocalFunctionId() const { return functionId; } - virtual void Finalize(bool isShutdown) + void SetAttributes(Attributes attr) { attributes = attr; } + + LocalFunctionId GetLocalFunctionId() const { return functionId; } + void SetLocalFunctionId(LocalFunctionId functionId) { this->functionId = functionId; } + + virtual void Finalize(bool isShutdown) override { } - virtual void Dispose(bool isShutdown) + virtual void Dispose(bool isShutdown) override { } @@ -105,6 +118,10 @@ namespace Js BOOL IsDeferredDeserializeFunction() const { return ((this->attributes & DeferredDeserialize) == DeferredDeserialize); } BOOL IsDeferredParseFunction() const { return ((this->attributes & DeferredParse) == DeferredParse); } + void SetCapturesThis() { attributes = (Attributes)(attributes | Attributes::CapturesThis); } + bool GetCapturesThis() const { return (attributes & Attributes::CapturesThis) != 0; } + void SetEnclosedByGlobalFunc() { attributes = (Attributes)(attributes | Attributes::EnclosedByGlobalFunc ); } + bool GetEnclosedByGlobalFunc() const { return (attributes & Attributes::EnclosedByGlobalFunc) != 0; } protected: JavascriptMethod originalEntryPoint; diff --git a/lib/Runtime/Base/ScriptContext.cpp b/lib/Runtime/Base/ScriptContext.cpp index 08f1a661a08..e35e86e0703 100644 --- a/lib/Runtime/Base/ScriptContext.cpp +++ b/lib/Runtime/Base/ScriptContext.cpp @@ -2161,7 +2161,7 @@ if (!sourceList) dict->Add(key, pFuncScript); } - bool ScriptContext::IsInNewFunctionMap(EvalMapString const& key, ParseableFunctionInfo **ppFuncBody) + bool ScriptContext::IsInNewFunctionMap(EvalMapString const& key, FunctionInfo **ppFuncInfo) { if (this->cache->newFunctionCache == nullptr) { @@ -2169,7 +2169,7 @@ if (!sourceList) } // If eval map cleanup is false, to preserve existing behavior, add it to the eval map MRU list - bool success = this->cache->newFunctionCache->TryGetValue(key, ppFuncBody); + bool success = this->cache->newFunctionCache->TryGetValue(key, ppFuncInfo); if (success) { this->cache->newFunctionCache->NotifyAdd(key); @@ -2183,13 +2183,13 @@ if (!sourceList) return success; } - void ScriptContext::AddToNewFunctionMap(EvalMapString const& key, ParseableFunctionInfo *pFuncBody) + void ScriptContext::AddToNewFunctionMap(EvalMapString const& key, FunctionInfo *pFuncInfo) { if (this->cache->newFunctionCache == nullptr) { this->cache->newFunctionCache = RecyclerNew(this->recycler, NewFunctionCache, this->recycler); } - this->cache->newFunctionCache->Add(key, pFuncBody); + this->cache->newFunctionCache->Add(key, pFuncInfo); } @@ -3225,6 +3225,8 @@ if (!sourceList) JavascriptMethod entryPoint = pFunction->GetEntryPoint(); FunctionInfo * info = pFunction->GetFunctionInfo(); FunctionProxy * proxy = info->GetFunctionProxy(); + +#if 0 if (proxy != info) { #ifdef ENABLE_SCRIPT_PROFILING @@ -3269,6 +3271,13 @@ if (!sourceList) return; } +#else + if (proxy == nullptr) + { + return; + } + Assert(proxy->GetFunctionInfo() == info); +#endif if (!proxy->IsFunctionBody()) { @@ -3371,27 +3380,6 @@ if (!sourceList) #endif OUTPUT_TRACE(Js::ScriptProfilerPhase, _u("\n")); - FunctionInfo * info = pFunction->GetFunctionInfo(); - if (proxy != info) - { - // The thunk can deal with moving to the function body -#ifdef ENABLE_SCRIPT_PROFILING - Assert(entryPoint == DefaultDeferredParsingThunk || entryPoint == ProfileDeferredParsingThunk - || entryPoint == DefaultDeferredDeserializeThunk || entryPoint == ProfileDeferredDeserializeThunk - || entryPoint == CrossSite::DefaultThunk || entryPoint == CrossSite::ProfileThunk); -#else - Assert(entryPoint == DefaultDeferredParsingThunk - || entryPoint == DefaultDeferredDeserializeThunk - || entryPoint == CrossSite::DefaultThunk); -#endif - - Assert(!proxy->IsDeferred()); - Assert(proxy->GetFunctionBody()->GetProfileSession() == proxy->GetScriptContext()->GetProfileSession()); - - return; - } - - #if ENABLE_NATIVE_CODEGEN if (!IsIntermediateCodeGenThunk(entryPoint) && entryPoint != DynamicProfileInfo::EnsureDynamicProfileInfoThunk) #endif diff --git a/lib/Runtime/Base/ScriptContext.h b/lib/Runtime/Base/ScriptContext.h index 95c2e9d8728..021af799165 100644 --- a/lib/Runtime/Base/ScriptContext.h +++ b/lib/Runtime/Base/ScriptContext.h @@ -324,7 +324,7 @@ namespace Js typedef JsUtil::BaseDictionary SecondLevelEvalCache; typedef TwoLevelHashRecord EvalMapRecord; typedef JsUtil::Cache, FastEvalMapStringComparer> EvalCacheTopLevelDictionary; - typedef JsUtil::Cache> NewFunctionCache; + typedef JsUtil::Cache> NewFunctionCache; typedef JsUtil::BaseDictionary ParseableFunctionInfoMap; // This is the dictionary used by script context to cache the eval. typedef TwoLevelHashDictionary EvalCacheDictionary; @@ -1024,8 +1024,8 @@ namespace Js inline bool EnableEvalMapCleanup() { return CONFIG_FLAG(EnableEvalMapCleanup); }; uint GetNextSourceContextId(); - bool IsInNewFunctionMap(EvalMapString const& key, ParseableFunctionInfo **ppFuncBody); - void AddToNewFunctionMap(EvalMapString const& key, ParseableFunctionInfo *pFuncBody); + bool IsInNewFunctionMap(EvalMapString const& key, FunctionInfo **ppFuncInfo); + void AddToNewFunctionMap(EvalMapString const& key, FunctionInfo *pFuncInfo); SourceContextInfo * GetSourceContextInfo(DWORD_PTR hostSourceContext, IActiveScriptDataCache* profileDataCache); SourceContextInfo * GetSourceContextInfo(uint hash); diff --git a/lib/Runtime/ByteCode/ByteCodeDumper.cpp b/lib/Runtime/ByteCode/ByteCodeDumper.cpp index d2315e6487a..70b13361650 100644 --- a/lib/Runtime/ByteCode/ByteCodeDumper.cpp +++ b/lib/Runtime/ByteCode/ByteCodeDumper.cpp @@ -822,7 +822,7 @@ namespace Js case OpCode::NewInnerScFunc: case OpCode::NewInnerScGenFunc: { - FunctionProxy* pfuncActual = dumpFunction->GetNestedFunc((uint)data->SlotIndex)->GetFunctionProxy(); + FunctionProxy* pfuncActual = dumpFunction->GetNestedFunc((uint)data->SlotIndex); Output::Print(_u(" R%d = env:R%d, %s()"), data->Value, data->Instance, pfuncActual->EnsureDeserialized()->GetDisplayName()); break; @@ -872,7 +872,7 @@ namespace Js case OpCode::NewStackScFunc: case OpCode::NewScGenFunc: { - FunctionProxy* pfuncActual = dumpFunction->GetNestedFunc((uint)data->SlotIndex)->GetFunctionProxy(); + FunctionProxy* pfuncActual = dumpFunction->GetNestedFunc((uint)data->SlotIndex); Output::Print(_u(" R%d = %s()"), data->Value, pfuncActual->EnsureDeserialized()->GetDisplayName()); break; diff --git a/lib/Runtime/ByteCode/ByteCodeSerializer.cpp b/lib/Runtime/ByteCode/ByteCodeSerializer.cpp index ff7ceb3e5d1..026cc03be07 100644 --- a/lib/Runtime/ByteCode/ByteCodeSerializer.cpp +++ b/lib/Runtime/ByteCode/ByteCodeSerializer.cpp @@ -2001,7 +2001,7 @@ class ByteCodeBufferBuilder ; PrependInt32(builder, _u("BitFlags"), bitFlags); - PrependInt32(builder, _u("Relative Function ID"), function->functionId - topFunctionId); // Serialized function ids are relative to the top function ID + PrependInt32(builder, _u("Relative Function ID"), function->GetLocalFunctionId() - topFunctionId); // Serialized function ids are relative to the top function ID PrependInt32(builder, _u("Attributes"), function->GetAttributes()); AssertMsg((function->GetAttributes() & ~(FunctionInfo::Attributes::ErrorOnNew @@ -2193,7 +2193,7 @@ class ByteCodeBufferBuilder HRESULT AddTopFunctionBody(FunctionBody * function, SRCINFO const * srcInfo) { - topFunctionId = function->functionId; + topFunctionId = function->GetLocalFunctionId(); return AddFunctionBody(functionsTable, function, srcInfo); } diff --git a/lib/Runtime/Debug/TTSnapValues.cpp b/lib/Runtime/Debug/TTSnapValues.cpp index 1d58d58ecf8..5b49436051b 100644 --- a/lib/Runtime/Debug/TTSnapValues.cpp +++ b/lib/Runtime/Debug/TTSnapValues.cpp @@ -1289,7 +1289,7 @@ namespace TTD functionInfo->SetGrfscr(functionInfo->GetGrfscr() | fscrGlobalCode); Js::EvalMapString key(source, length, moduleID, strictMode, /* isLibraryCode = */ false); - ctx->AddToNewFunctionMap(key, functionInfo); + ctx->AddToNewFunctionMap(key, functionInfo->GetFunctionInfo()); Js::FunctionBody* fb = JsSupport::ForceAndGetFunctionBody(pfuncScript->GetParseableFunctionInfo()); diff --git a/lib/Runtime/Language/AsmJsModule.cpp b/lib/Runtime/Language/AsmJsModule.cpp index 3283247cccc..ccc2fa2b8c2 100644 --- a/lib/Runtime/Language/AsmJsModule.cpp +++ b/lib/Runtime/Language/AsmJsModule.cpp @@ -621,6 +621,7 @@ namespace Js CompileScriptException se; funcBody = deferParseFunction->ParseAsmJs(&ps, &se, &parseTree); + fncNode->sxFnc.funcInfo->byteCodeFunction = funcBody; TRACE_BYTECODE(_u("\nDeferred parse %s\n"), funcBody->GetDisplayName()); if (parseTree && parseTree->nop == knopProg) @@ -637,7 +638,6 @@ namespace Js } } GetByteCodeGenerator()->PushFuncInfo(_u("Start asm.js AST prepass"), fncNode->sxFnc.funcInfo); - fncNode->sxFnc.funcInfo->byteCodeFunction->SetBoundPropertyRecords(GetByteCodeGenerator()->EnsurePropertyRecordList()); BindArguments(fncNode->sxFnc.pnodeParams); ASTPrepass(pnodeBody, func); GetByteCodeGenerator()->PopFuncInfo(_u("End asm.js AST prepass")); diff --git a/lib/Runtime/Language/DynamicProfileInfo.cpp b/lib/Runtime/Language/DynamicProfileInfo.cpp index c7c6c224262..cc0bf093b58 100644 --- a/lib/Runtime/Language/DynamicProfileInfo.cpp +++ b/lib/Runtime/Language/DynamicProfileInfo.cpp @@ -413,7 +413,7 @@ namespace Js } // Mark the callsite bit where caller and callee is same function - if (functionBody == calleeFunctionInfo && callSiteId < 32) + if (calleeFunctionInfo && functionBody == calleeFunctionInfo->GetFunctionProxy() && callSiteId < 32) { this->m_recursiveInlineInfo = this->m_recursiveInlineInfo | (1 << callSiteId); } @@ -770,7 +770,8 @@ namespace Js if (sourceId == CurrentSourceId) // caller and callee in same file { - return functionBody->GetUtf8SourceInfo()->FindFunction(functionId); + FunctionProxy *inlineeProxy = functionBody->GetUtf8SourceInfo()->FindFunction(functionId); + return inlineeProxy ? inlineeProxy->GetFunctionInfo() : nullptr; } if (sourceId != NoSourceId && sourceId != InvalidSourceId) @@ -784,7 +785,8 @@ namespace Js Utf8SourceInfo *srcInfo = sourceList->Item(i)->Get(); if (srcInfo && srcInfo->GetHostSourceContext() == sourceId) { - return srcInfo->FindFunction(functionId); + FunctionProxy *inlineeProxy = srcInfo->FindFunction(functionId); + return inlineeProxy ? inlineeProxy->GetFunctionInfo() : nullptr; } } } diff --git a/lib/Runtime/Language/FunctionCodeGenJitTimeData.h b/lib/Runtime/Language/FunctionCodeGenJitTimeData.h index c8dd797de2f..e9ae6636597 100644 --- a/lib/Runtime/Language/FunctionCodeGenJitTimeData.h +++ b/lib/Runtime/Language/FunctionCodeGenJitTimeData.h @@ -117,7 +117,7 @@ namespace Js bool IsPolymorphicCallSite(const ProfileId profiledCallSiteId) const; // This function walks all the chained jittimedata and returns the one which match the functionInfo. // This can return null, if the functionInfo doesn't match. - const FunctionCodeGenJitTimeData *GetJitTimeDataFromFunctionInfo(FunctionInfo *polyFunctionInfo) const; + const FunctionCodeGenJitTimeData *GetJitTimeDataFromFunctionInfo(FunctionInfo *polyFunctioInfoy) const; uint GetGlobalObjTypeSpecFldInfoCount() const { return this->globalObjTypeSpecFldInfoCount; } ObjTypeSpecFldInfo** GetGlobalObjTypeSpecFldInfoArray() const {return this->globalObjTypeSpecFldInfoArray; } diff --git a/lib/Runtime/Language/FunctionCodeGenRuntimeData.cpp b/lib/Runtime/Language/FunctionCodeGenRuntimeData.cpp index 5c5c64efaf9..4c7dd91fc0a 100644 --- a/lib/Runtime/Language/FunctionCodeGenRuntimeData.cpp +++ b/lib/Runtime/Language/FunctionCodeGenRuntimeData.cpp @@ -122,7 +122,8 @@ namespace Js const FunctionCodeGenRuntimeData *FunctionCodeGenRuntimeData::GetRuntimeDataFromFunctionInfo(FunctionInfo *polyFunctionInfo) const { const FunctionCodeGenRuntimeData *next = this; - while (next && next->functionBody != polyFunctionInfo) + FunctionProxy *polyFunctionProxy = polyFunctionInfo->GetFunctionProxy(); + while (next && next->functionBody != polyFunctionProxy) { next = next->next; } diff --git a/lib/Runtime/Language/JavascriptOperators.cpp b/lib/Runtime/Language/JavascriptOperators.cpp index 5ef3cf1bdaa..22e1f962026 100644 --- a/lib/Runtime/Language/JavascriptOperators.cpp +++ b/lib/Runtime/Language/JavascriptOperators.cpp @@ -5541,13 +5541,6 @@ namespace Js ScriptFunction *func = entry->func; FunctionProxy * proxy = func->GetFunctionProxy(); - if (proxy != proxy->GetFunctionProxy()) - { - // The FunctionProxy has changed since the object was cached, e.g., due to execution - // of a deferred function through a different object. - proxy = proxy->GetFunctionProxy(); - func->SetFunctionInfo(proxy); - } // Reset the function's type to the default type with no properties // Use the cached type on the function proxy rather than the type in the func cache entry @@ -9815,10 +9808,7 @@ namespace Js JavascriptOperators::GetDeferredDeserializedFunctionProxy(JavascriptFunction* func) { FunctionProxy* proxy = func->GetFunctionProxy(); - if (proxy->GetFunctionProxy() != proxy) - { - proxy = proxy->GetFunctionProxy(); - } + Assert(proxy->GetFunctionInfo()->GetFunctionProxy() != proxy); return proxy; } diff --git a/lib/Runtime/Library/GlobalObject.cpp b/lib/Runtime/Library/GlobalObject.cpp index 948e6023a42..abe81d3186f 100644 --- a/lib/Runtime/Library/GlobalObject.cpp +++ b/lib/Runtime/Library/GlobalObject.cpp @@ -764,6 +764,7 @@ namespace Js { // This could happen if the top level function is marked as deferred, we need to parse this to generate the script compile information (RegisterScript depends on that) Js::JavascriptFunction::DeferredParse(&pEvalFunction); + proxy = pEvalFunction->GetFunctionProxy(); } scriptContext->RegisterScript(proxy); @@ -984,7 +985,7 @@ namespace Js { FunctionBody* parentFuncBody = pfuncCaller->GetFunctionBody(); Utf8SourceInfo* parentUtf8SourceInfo = parentFuncBody->GetUtf8SourceInfo(); - Utf8SourceInfo* utf8SourceInfo = funcBody->GetFunctionProxy()->GetUtf8SourceInfo(); + Utf8SourceInfo* utf8SourceInfo = funcBody->GetUtf8SourceInfo(); utf8SourceInfo->SetCallerUtf8SourceInfo(parentUtf8SourceInfo); } } diff --git a/lib/Runtime/Library/JavascriptFunction.cpp b/lib/Runtime/Library/JavascriptFunction.cpp index ed578a7236a..62e71bb5ef7 100644 --- a/lib/Runtime/Library/JavascriptFunction.cpp +++ b/lib/Runtime/Library/JavascriptFunction.cpp @@ -208,11 +208,11 @@ namespace Js BOOL strictMode = FALSE; JavascriptFunction *pfuncScript; - ParseableFunctionInfo *pfuncBodyCache = NULL; + FunctionInfo *pfuncInfoCache = NULL; char16 const * sourceString = bs->GetSz(); charcount_t sourceLen = bs->GetLength(); EvalMapString key(sourceString, sourceLen, moduleID, strictMode, /* isLibraryCode = */ false); - if (!scriptContext->IsInNewFunctionMap(key, &pfuncBodyCache)) + if (!scriptContext->IsInNewFunctionMap(key, &pfuncInfoCache)) { // Validate formals here scriptContext->GetGlobalObject()->ValidateSyntax( @@ -237,20 +237,15 @@ namespace Js Assert(functionInfo); functionInfo->SetGrfscr(functionInfo->GetGrfscr() | fscrGlobalCode); - scriptContext->AddToNewFunctionMap(key, functionInfo); + scriptContext->AddToNewFunctionMap(key, functionInfo->GetFunctionInfo()); + } + else if (pfuncInfoCache->IsCoroutine()) + { + pfuncScript = scriptContext->GetLibrary()->CreateGeneratorVirtualScriptFunction(pfuncInfoCache->GetFunctionProxy()); } else { - // Get the latest proxy - FunctionProxy * proxy = pfuncBodyCache->GetFunctionProxy(); - if (proxy->IsCoroutine()) - { - pfuncScript = scriptContext->GetLibrary()->CreateGeneratorVirtualScriptFunction(proxy); - } - else - { - pfuncScript = scriptContext->GetLibrary()->CreateScriptFunction(proxy); - } + pfuncScript = scriptContext->GetLibrary()->CreateScriptFunction(pfuncInfoCache->GetFunctionProxy()); } #if ENABLE_TTD @@ -1556,7 +1551,6 @@ void __cdecl _alloca_probe_16() ParseableFunctionInfo* functionInfo = (*functionRef)->GetParseableFunctionInfo(); Assert(functionInfo); - Assert(functionInfo->HasBody()); functionInfo->GetFunctionBody()->AddDeferParseAttribute(); functionInfo->GetFunctionBody()->ResetEntryPoint(); functionInfo->GetFunctionBody()->ResetInParams(); @@ -1671,7 +1665,7 @@ void __cdecl _alloca_probe_16() // calls the default entry point the next time around if (funcInfo->IsDeferredDeserializeFunction()) { - DeferDeserializeFunctionInfo* deferDeserializeFunction = (DeferDeserializeFunctionInfo*) funcInfo; + DeferDeserializeFunctionInfo* deferDeserializeFunction = funcInfo->GetDeferDeserializeFunctionInfo(); // This is the first call to the function, ensure dynamic profile info // Deserialize is a no-op if the function has already been deserialized diff --git a/lib/Runtime/Library/ScriptFunction.cpp b/lib/Runtime/Library/ScriptFunction.cpp index 7d27184060c..736ae2c9eb1 100644 --- a/lib/Runtime/Library/ScriptFunction.cpp +++ b/lib/Runtime/Library/ScriptFunction.cpp @@ -32,11 +32,11 @@ namespace Js {} ScriptFunction::ScriptFunction(FunctionProxy * proxy, ScriptFunctionType* deferredPrototypeType) - : ScriptFunctionBase(deferredPrototypeType, proxy), + : ScriptFunctionBase(deferredPrototypeType, proxy->GetFunctionInfo()), environment((FrameDisplay*)&NullFrameDisplay), cachedScopeObj(nullptr), homeObj(nullptr), hasInlineCaches(false), hasSuperReference(false), isActiveScript(false) { - Assert(proxy->GetFunctionProxy() == proxy); + Assert(proxy->GetFunctionInfo()->GetFunctionProxy() == proxy); Assert(proxy->EnsureDeferredPrototypeType() == deferredPrototypeType); DebugOnly(VerifyEntryPoint()); @@ -260,31 +260,25 @@ namespace Js FunctionProxy * ScriptFunction::GetFunctionProxy() const { Assert(this->functionInfo->HasBody()); - return reinterpret_cast(this->functionInfo); + return this->functionInfo->GetFunctionProxy(); } JavascriptMethod ScriptFunction::UpdateUndeferredBody(FunctionBody* newFunctionInfo) { // Update deferred parsed/serialized function to the real function body Assert(this->functionInfo->HasBody()); - if (this->functionInfo != newFunctionInfo) - { - Assert(this->functionInfo->GetFunctionBody() == newFunctionInfo); - Assert(!newFunctionInfo->IsDeferred()); - DynamicType * type = this->GetDynamicType(); + Assert(this->functionInfo->GetFunctionBody() == newFunctionInfo); + Assert(!newFunctionInfo->IsDeferred()); - // If the type is shared, it must be the shared one in the old function proxy + DynamicType * type = this->GetDynamicType(); - DebugOnly(FunctionProxy * oldProxy = this->GetFunctionProxy()); - this->functionInfo = newFunctionInfo; + // If the type is shared, it must be the shared one in the old function proxy - if (type->GetIsShared()) - { - // if it is shared, it must still be the deferred prototype from the old proxy - Assert(type == oldProxy->GetDeferredPrototypeType()); + this->functionInfo = newFunctionInfo->GetFunctionInfo(); - // the type is still shared, we can't modify it, just migrate to the shared one in the function body - this->ReplaceType(newFunctionInfo->EnsureDeferredPrototypeType()); - } + if (type->GetIsShared()) + { + // the type is still shared, we can't modify it, just migrate to the shared one in the function body + this->ReplaceType(newFunctionInfo->EnsureDeferredPrototypeType()); } // The type has change from the default, it is not share, just use that one. @@ -297,8 +291,7 @@ namespace Js #endif Js::FunctionEntryPointInfo* defaultEntryPointInfo = newFunctionInfo->GetDefaultFunctionEntryPointInfo(); - JavascriptMethod thunkEntryPoint = this->UpdateThunkEntryPoint(defaultEntryPointInfo, - directEntryPoint); + JavascriptMethod thunkEntryPoint = this->UpdateThunkEntryPoint(defaultEntryPointInfo, directEntryPoint); this->GetScriptFunctionType()->SetEntryPointInfo(defaultEntryPointInfo); diff --git a/lib/Runtime/Library/StackScriptFunction.cpp b/lib/Runtime/Library/StackScriptFunction.cpp index 00b93184867..9e027520def 100644 --- a/lib/Runtime/Library/StackScriptFunction.cpp +++ b/lib/Runtime/Library/StackScriptFunction.cpp @@ -125,7 +125,7 @@ namespace Js for (uint i = 0; i < current->GetNestedCount(); i++) { FunctionProxy * nested = current->GetNestedFunc(i); - functionObjectToBox.Add(nested->GetFunctionProxy()); + functionObjectToBox.Add(nested); if (nested->IsFunctionBody()) { nested->GetFunctionBody()->ClearStackNestedFuncParent(); @@ -143,7 +143,7 @@ namespace Js bool StackScriptFunction::BoxState::NeedBoxScriptFunction(ScriptFunction * scriptFunction) { - return functionObjectToBox.Contains(scriptFunction->GetFunctionProxy()->GetFunctionProxy()); + return functionObjectToBox.Contains(scriptFunction->GetFunctionProxy()); } void StackScriptFunction::BoxState::Box() @@ -727,8 +727,7 @@ namespace Js Output::Flush(); } - // Make sure we use the latest function proxy (if it is parsed or deserialized) - FunctionProxy * functionBody = stackFunction->GetFunctionProxy()->GetFunctionProxy(); + FunctionProxy * functionBody = stackFunction->GetFunctionProxy(); boxedFunction = ScriptFunction::OP_NewScFunc(boxedFrameDisplay, &functionBody); stackFunction->boxedScriptFunction = boxedFunction; stackFunction->SetEnvironment(boxedFrameDisplay); diff --git a/lib/Runtime/Runtime.h b/lib/Runtime/Runtime.h index 823e89f35f5..2733c08fda0 100644 --- a/lib/Runtime/Runtime.h +++ b/lib/Runtime/Runtime.h @@ -243,6 +243,7 @@ namespace Js struct TickDelta; class ByteBlock; class FunctionInfo; + class FunctionProxy; class FunctionBody; class ParseableFunctionInfo; struct StatementLocation; diff --git a/lib/Runtime/Types/ScriptFunctionType.cpp b/lib/Runtime/Types/ScriptFunctionType.cpp index fd76a03654a..76c7eb57731 100644 --- a/lib/Runtime/Types/ScriptFunctionType.cpp +++ b/lib/Runtime/Types/ScriptFunctionType.cpp @@ -21,7 +21,7 @@ namespace Js ScriptFunctionType * ScriptFunctionType::New(FunctionProxy * proxy, bool isShared) { - Assert(proxy->GetFunctionProxy() == proxy); + Assert(proxy->GetFunctionInfo()->GetFunctionProxy() == proxy); ScriptContext * scriptContext = proxy->GetScriptContext(); JavascriptLibrary * library = scriptContext->GetLibrary(); DynamicObject * functionPrototype = proxy->IsAsync() ? library->GetAsyncFunctionPrototype() : library->GetFunctionPrototype();