|
4 | 4 | #if defined(FEATURE_INTERPRETER) && !defined(TARGET_WASM) |
5 | 5 |
|
6 | 6 | #include "callstubgenerator.h" |
| 7 | +#include "callconvbuilder.hpp" |
7 | 8 | #include "ecall.h" |
| 9 | +#include "dllimport.h" |
8 | 10 |
|
9 | 11 | extern "C" void InjectInterpStackAlign(); |
10 | 12 | extern "C" void Load_Stack(); |
@@ -2267,7 +2269,7 @@ CallStubHeader *CallStubGenerator::GenerateCallStub(MethodDesc *pMD, AllocMemTra |
2267 | 2269 | PCODE *pRoutines = (PCODE*)alloca(tempStorageSize); |
2268 | 2270 | memset(pRoutines, 0, tempStorageSize); |
2269 | 2271 |
|
2270 | | - ComputeCallStub(sig, pRoutines); |
| 2272 | + ComputeCallStub(sig, pRoutines, pMD); |
2271 | 2273 |
|
2272 | 2274 | LoaderAllocator *pLoaderAllocator = pMD->GetLoaderAllocator(); |
2273 | 2275 | S_SIZE_T finalStubSize(sizeof(CallStubHeader) + m_routineIndex * sizeof(PCODE)); |
@@ -2364,7 +2366,7 @@ CallStubHeader *CallStubGenerator::GenerateCallStubForSig(MetaSig &sig) |
2364 | 2366 |
|
2365 | 2367 | m_interpreterToNative = true; // We always generate the interpreter to native call stub here |
2366 | 2368 |
|
2367 | | - ComputeCallStub(sig, pRoutines); |
| 2369 | + ComputeCallStub(sig, pRoutines, NULL); |
2368 | 2370 |
|
2369 | 2371 | xxHash hashState; |
2370 | 2372 | for (int i = 0; i < m_routineIndex; i++) |
@@ -2451,8 +2453,179 @@ void CallStubGenerator::TerminateCurrentRoutineIfNotOfNewType(RoutineType type, |
2451 | 2453 | return; |
2452 | 2454 | } |
2453 | 2455 |
|
2454 | | -void CallStubGenerator::ComputeCallStub(MetaSig &sig, PCODE *pRoutines) |
| 2456 | +//--------------------------------------------------------------------------- |
| 2457 | +// isNativePrimitiveStructType: |
| 2458 | +// Check if the given struct type is an intrinsic type that should be treated as though |
| 2459 | +// it is not a struct at the unmanaged ABI boundary. |
| 2460 | +// |
| 2461 | +// Arguments: |
| 2462 | +// pMT - the handle for the struct type. |
| 2463 | +// |
| 2464 | +// Return Value: |
| 2465 | +// true if the given struct type should be treated as a primitive for unmanaged calls, |
| 2466 | +// false otherwise. |
| 2467 | +// |
| 2468 | +bool isNativePrimitiveStructType(MethodTable* pMT) |
2455 | 2469 | { |
| 2470 | + if (!pMT->IsIntrinsicType()) |
| 2471 | + { |
| 2472 | + return false; |
| 2473 | + } |
| 2474 | + const char* namespaceName = nullptr; |
| 2475 | + const char* typeName = pMT->GetFullyQualifiedNameInfo(&namespaceName); |
| 2476 | + |
| 2477 | + if ((namespaceName == NULL) || (typeName == NULL)) |
| 2478 | + { |
| 2479 | + return false; |
| 2480 | + } |
| 2481 | + |
| 2482 | + if (strcmp(namespaceName, "System.Runtime.InteropServices") != 0) |
| 2483 | + { |
| 2484 | + return false; |
| 2485 | + } |
| 2486 | + |
| 2487 | + return strcmp(typeName, "CLong") == 0 || strcmp(typeName, "CULong") == 0 || strcmp(typeName, "NFloat") == 0; |
| 2488 | +} |
| 2489 | + |
| 2490 | +void CallStubGenerator::ComputeCallStub(MetaSig &sig, PCODE *pRoutines, MethodDesc *pMD) |
| 2491 | +{ |
| 2492 | + bool rewriteMetaSigFromExplicitThisToHasThis = false; |
| 2493 | + bool unmanagedThisCallConv = false; |
| 2494 | + |
| 2495 | + bool hasUnmanagedCallConv = false; |
| 2496 | + CorInfoCallConvExtension unmanagedCallConv = CorInfoCallConvExtension::C; |
| 2497 | + |
| 2498 | + if (pMD != NULL && (pMD->IsPInvoke())) |
| 2499 | + { |
| 2500 | + PInvoke::GetCallingConvention_IgnoreErrors(pMD, &unmanagedCallConv, NULL); |
| 2501 | + hasUnmanagedCallConv = true; |
| 2502 | + } |
| 2503 | + else if (pMD != NULL && pMD->HasUnmanagedCallersOnlyAttribute()) |
| 2504 | + { |
| 2505 | + if (CallConv::TryGetCallingConventionFromUnmanagedCallersOnly(pMD, &unmanagedCallConv)) |
| 2506 | + { |
| 2507 | + if (sig.GetCallingConvention() == IMAGE_CEE_CS_CALLCONV_VARARG) |
| 2508 | + { |
| 2509 | + unmanagedCallConv = CorInfoCallConvExtension::C; |
| 2510 | + } |
| 2511 | + } |
| 2512 | + else |
| 2513 | + { |
| 2514 | + unmanagedCallConv = CallConv::GetDefaultUnmanagedCallingConvention(); |
| 2515 | + } |
| 2516 | + hasUnmanagedCallConv = true; |
| 2517 | + } |
| 2518 | + else |
| 2519 | + { |
| 2520 | + switch (sig.GetCallingConvention()) |
| 2521 | + { |
| 2522 | + case IMAGE_CEE_CS_CALLCONV_THISCALL: |
| 2523 | + unmanagedCallConv = CorInfoCallConvExtension::Thiscall; |
| 2524 | + hasUnmanagedCallConv = true; |
| 2525 | + break; |
| 2526 | + case IMAGE_CEE_CS_CALLCONV_UNMANAGED: |
| 2527 | + unmanagedCallConv = GetUnmanagedCallConvExtension(&sig); |
| 2528 | + hasUnmanagedCallConv = true; |
| 2529 | + break; |
| 2530 | + } |
| 2531 | + } |
| 2532 | + |
| 2533 | + if (hasUnmanagedCallConv) |
| 2534 | + { |
| 2535 | + switch (unmanagedCallConv) |
| 2536 | + { |
| 2537 | + case CorInfoCallConvExtension::Thiscall: |
| 2538 | + case CorInfoCallConvExtension::CMemberFunction: |
| 2539 | + case CorInfoCallConvExtension::StdcallMemberFunction: |
| 2540 | + case CorInfoCallConvExtension::FastcallMemberFunction: |
| 2541 | + unmanagedThisCallConv = true; |
| 2542 | + break; |
| 2543 | + default: |
| 2544 | + break; |
| 2545 | + } |
| 2546 | + } |
| 2547 | + |
| 2548 | +#if defined(TARGET_WINDOWS) |
| 2549 | + // On these platforms, when making a ThisCall, or other call using a C++ MemberFunction calling convention, |
| 2550 | + // the "this" pointer is passed in the first argument slot. |
| 2551 | + bool rewriteReturnTypeToForceRetBuf = false; |
| 2552 | + if (unmanagedThisCallConv) |
| 2553 | + { |
| 2554 | + rewriteMetaSigFromExplicitThisToHasThis = true; |
| 2555 | + // Also, any struct type other than a few special cases is returned via return buffer for unmanaged calls |
| 2556 | + CorElementType retType = sig.GetReturnType(); |
| 2557 | + sig.Reset(); |
| 2558 | + |
| 2559 | + if (retType == ELEMENT_TYPE_VALUETYPE) |
| 2560 | + { |
| 2561 | + TypeHandle thRetType = sig.GetRetTypeHandleThrowing(); |
| 2562 | + MethodTable* pMTRetType = thRetType.AsMethodTable(); |
| 2563 | + |
| 2564 | + if (pMTRetType->GetInternalCorElementType() == ELEMENT_TYPE_VALUETYPE && !isNativePrimitiveStructType(pMTRetType)) |
| 2565 | + { |
| 2566 | + rewriteReturnTypeToForceRetBuf = true; |
| 2567 | + } |
| 2568 | + } |
| 2569 | + } |
| 2570 | +#endif // defined(TARGET_WINDOWS) |
| 2571 | + |
| 2572 | + // Rewrite ExplicitThis to HasThis. This allows us to use ArgIterator which is unaware of ExplicitThis |
| 2573 | + // in the places where it is needed such as computation of return buffers. |
| 2574 | + if (sig.GetCallingConventionInfo() & IMAGE_CEE_CS_CALLCONV_EXPLICITTHIS) |
| 2575 | + { |
| 2576 | +#if LOG_COMPUTE_CALL_STUB |
| 2577 | + printf("Managed ExplicitThis to HasThis conversion needed\n"); |
| 2578 | +#endif // LOG_COMPUTE_CALL_STUB |
| 2579 | + rewriteMetaSigFromExplicitThisToHasThis = true; |
| 2580 | + } |
| 2581 | + |
| 2582 | + SigBuilder sigBuilder; |
| 2583 | + if (rewriteMetaSigFromExplicitThisToHasThis) |
| 2584 | + { |
| 2585 | +#if LOG_COMPUTE_CALL_STUB |
| 2586 | + printf("Rewriting ExplicitThis to implicit this\n"); |
| 2587 | +#endif // LOG_COMPUTE_CALL_STUB |
| 2588 | + sigBuilder.AppendByte(IMAGE_CEE_CS_CALLCONV_DEFAULT_HASTHIS); |
| 2589 | + if ((sig.NumFixedArgs() == 0) || (sig.HasThis() && !sig.HasExplicitThis())) |
| 2590 | + { |
| 2591 | + ThrowHR(COR_E_BADIMAGEFORMAT); |
| 2592 | + } |
| 2593 | + sigBuilder.AppendData(sig.NumFixedArgs() - 1); |
| 2594 | + TypeHandle thRetType = sig.GetRetTypeHandleThrowing(); |
| 2595 | +#if defined(TARGET_WINDOWS) |
| 2596 | + if (rewriteReturnTypeToForceRetBuf) |
| 2597 | + { |
| 2598 | + // Change the return type to type large enough it will always need to be returned via return buffer |
| 2599 | + thRetType = CoreLibBinder::GetClass(CLASS__STACKFRAMEITERATOR); |
| 2600 | + _ASSERTE(thRetType.IsValueType()); |
| 2601 | + _ASSERTE(thRetType.GetSize() > 64); |
| 2602 | + sigBuilder.AppendElementType(ELEMENT_TYPE_INTERNAL); |
| 2603 | + sigBuilder.AppendPointer(thRetType.AsPtr()); |
| 2604 | + } |
| 2605 | + else |
| 2606 | +#endif |
| 2607 | + { |
| 2608 | + SigPointer pReturn = sig.GetReturnProps(); |
| 2609 | + pReturn.ConvertToInternalExactlyOne(sig.GetModule(), sig.GetSigTypeContext(), &sigBuilder); |
| 2610 | + } |
| 2611 | + |
| 2612 | + // Skip the explicit this argument |
| 2613 | + sig.NextArg(); |
| 2614 | + |
| 2615 | + // Copy rest of the arguments |
| 2616 | + sig.NextArg(); |
| 2617 | + SigPointer pArgs = sig.GetArgProps(); |
| 2618 | + for (unsigned i = 1; i < sig.NumFixedArgs(); i++) |
| 2619 | + { |
| 2620 | + pArgs.ConvertToInternalExactlyOne(sig.GetModule(), sig.GetSigTypeContext(), &sigBuilder); |
| 2621 | + } |
| 2622 | + |
| 2623 | + DWORD cSig; |
| 2624 | + PCCOR_SIGNATURE pNewSig = (PCCOR_SIGNATURE)sigBuilder.GetSignature(&cSig); |
| 2625 | + MetaSig newSig(pNewSig, cSig, sig.GetModule(), NULL, MetaSig::sigMember); |
| 2626 | + sig = newSig; |
| 2627 | + } |
| 2628 | + |
2456 | 2629 | ArgIterator argIt(&sig); |
2457 | 2630 | int32_t interpreterStackOffset = 0; |
2458 | 2631 |
|
|
0 commit comments